audio: don't use a shared QIODevice
This system was kind of janky anyway. It makes more sense ultimately for the audio management classes to contain the file handle rather than the renderer.
This commit is contained in:
@@ -80,9 +80,9 @@ void AudioManager::PushToOutput(const QByteArray &samples)
|
||||
output_manager_.Push(samples);
|
||||
}
|
||||
|
||||
void AudioManager::StartOutput(QIODevice *device, int playback_speed)
|
||||
void AudioManager::StartOutput(const QString &filename, qint64 offset, int playback_speed)
|
||||
{
|
||||
output_manager_.PullFromDevice(device, playback_speed);
|
||||
output_manager_.PullFromDevice(filename, offset, playback_speed);
|
||||
}
|
||||
|
||||
void AudioManager::StopOutput()
|
||||
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
*
|
||||
* This takes ownership of the QIODevice and will delete it when StopOutput() is called
|
||||
*/
|
||||
void StartOutput(QIODevice* device, int playback_speed);
|
||||
void StartOutput(const QString& filename, qint64 offset, int playback_speed);
|
||||
|
||||
/**
|
||||
* @brief Stop audio output immediately
|
||||
|
||||
@@ -25,26 +25,37 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
AudioOutputDeviceProxy::AudioOutputDeviceProxy() :
|
||||
device_(nullptr)
|
||||
AudioOutputDeviceProxy::AudioOutputDeviceProxy()
|
||||
{
|
||||
}
|
||||
|
||||
AudioOutputDeviceProxy::~AudioOutputDeviceProxy()
|
||||
{
|
||||
if (file_.isOpen()) {
|
||||
file_.close();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioOutputDeviceProxy::SetParameters(const AudioRenderingParams ¶ms)
|
||||
{
|
||||
params_ = params;
|
||||
}
|
||||
|
||||
void AudioOutputDeviceProxy::SetDevice(QIODevice *device, int playback_speed)
|
||||
void AudioOutputDeviceProxy::SetDevice(const QString &filename, qint64 offset, int playback_speed)
|
||||
{
|
||||
device_ = device;
|
||||
|
||||
if (!device_->isOpen()) {
|
||||
if (!device_->open(QIODevice::ReadOnly)) {
|
||||
qWarning() << "Failed to open sub-device";
|
||||
}
|
||||
if (file_.isOpen()) {
|
||||
file_.close();
|
||||
}
|
||||
|
||||
file_.setFileName(filename);
|
||||
|
||||
if (!file_.open(QFile::ReadOnly)) {
|
||||
qCritical() << "Failed to open" << filename << "for audio playback";
|
||||
return;
|
||||
}
|
||||
|
||||
file_.seek(offset);
|
||||
|
||||
playback_speed_ = playback_speed;
|
||||
|
||||
if (qAbs(playback_speed_) != 1) {
|
||||
@@ -56,7 +67,7 @@ void AudioOutputDeviceProxy::close()
|
||||
{
|
||||
QIODevice::close();
|
||||
|
||||
device_->close();
|
||||
file_.close();
|
||||
|
||||
if (tempo_processor_.IsOpen()) {
|
||||
tempo_processor_.Close();
|
||||
@@ -65,7 +76,7 @@ void AudioOutputDeviceProxy::close()
|
||||
|
||||
qint64 AudioOutputDeviceProxy::readData(char *data, qint64 maxlen)
|
||||
{
|
||||
if (device_) {
|
||||
if (file_.isOpen()) {
|
||||
|
||||
qint64 read_count;
|
||||
|
||||
@@ -106,21 +117,21 @@ qint64 AudioOutputDeviceProxy::ReverseAwareRead(char *data, qint64 maxlen)
|
||||
|
||||
if (playback_speed_ < 0) {
|
||||
// If we're reversing, we'll seek back by maxlen bytes before we read
|
||||
new_pos = device_->pos() - maxlen;
|
||||
new_pos = file_.pos() - maxlen;
|
||||
|
||||
if (new_pos < 0) {
|
||||
maxlen = device_->pos();
|
||||
maxlen = file_.pos();
|
||||
|
||||
new_pos = 0;
|
||||
}
|
||||
|
||||
device_->seek(new_pos);
|
||||
file_.seek(new_pos);
|
||||
}
|
||||
|
||||
qint64 read_count = device_->read(data, maxlen);
|
||||
qint64 read_count = file_.read(data, maxlen);
|
||||
|
||||
if (playback_speed_ < 0) {
|
||||
device_->seek(new_pos);
|
||||
file_.seek(new_pos);
|
||||
|
||||
// Reverse the samples here
|
||||
AudioManager::ReverseBuffer(data, static_cast<int>(read_count), params_.samples_to_bytes(1));
|
||||
|
||||
@@ -21,22 +21,27 @@
|
||||
#ifndef AUDIOOUTPUTDEVICEPROXY_H
|
||||
#define AUDIOOUTPUTDEVICEPROXY_H
|
||||
|
||||
#include <QIODevice>
|
||||
#include <QFile>
|
||||
|
||||
#include "common/define.h"
|
||||
#include "tempoprocessor.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
/**
|
||||
* @brief QIODevice wrapper that can adjust speed/reverse an audio file
|
||||
*/
|
||||
class AudioOutputDeviceProxy : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AudioOutputDeviceProxy();
|
||||
|
||||
virtual ~AudioOutputDeviceProxy() override;
|
||||
|
||||
void SetParameters(const AudioRenderingParams& params);
|
||||
|
||||
void SetDevice(QIODevice* device, int playback_speed);
|
||||
void SetDevice(const QString &filename, qint64 offset, int playback_speed);
|
||||
|
||||
virtual void close() override;
|
||||
|
||||
@@ -48,7 +53,7 @@ protected:
|
||||
private:
|
||||
qint64 ReverseAwareRead(char* data, qint64 maxlen);
|
||||
|
||||
QIODevice* device_;
|
||||
QFile file_;
|
||||
|
||||
TempoProcessor tempo_processor_;
|
||||
|
||||
|
||||
@@ -82,9 +82,9 @@ void AudioOutputManager::SetParameters(const AudioRenderingParams ¶ms)
|
||||
device_proxy_.SetParameters(params);
|
||||
}
|
||||
|
||||
void AudioOutputManager::PullFromDevice(QIODevice *device, int playback_speed)
|
||||
void AudioOutputManager::PullFromDevice(const QString &filename, qint64 offset, int playback_speed)
|
||||
{
|
||||
if (!output_ || !device) {
|
||||
if (!output_) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ void AudioOutputManager::PullFromDevice(QIODevice *device, int playback_speed)
|
||||
pushed_samples_.clear();
|
||||
|
||||
// Pull from the device
|
||||
device_proxy_.SetDevice(device, playback_speed);
|
||||
device_proxy_.SetDevice(filename, offset, playback_speed);
|
||||
device_proxy_.open(QIODevice::ReadOnly);
|
||||
output_->start(&device_proxy_);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
* This will clear any pushed samples or QIODevices currently being read and will start reading from this next time
|
||||
* the audio output requests data.
|
||||
*/
|
||||
void PullFromDevice(QIODevice* device, int playback_speed);
|
||||
void PullFromDevice(const QString &filename, qint64 offset, int playback_speed);
|
||||
|
||||
void ResetToPushMode();
|
||||
|
||||
|
||||
@@ -34,13 +34,6 @@ AudioBackend::~AudioBackend()
|
||||
Close();
|
||||
}
|
||||
|
||||
QIODevice *AudioBackend::GetAudioPullDevice()
|
||||
{
|
||||
pull_device_.setFileName(CachePathName());
|
||||
|
||||
return &pull_device_;
|
||||
}
|
||||
|
||||
bool AudioBackend::InitInternal()
|
||||
{
|
||||
// Initiate one thread per CPU core
|
||||
|
||||
@@ -35,8 +35,6 @@ public:
|
||||
|
||||
virtual ~AudioBackend() override;
|
||||
|
||||
virtual QIODevice* GetAudioPullDevice() override;
|
||||
|
||||
protected:
|
||||
virtual bool InitInternal() override;
|
||||
|
||||
@@ -51,9 +49,6 @@ protected:
|
||||
private slots:
|
||||
void ThreadCompletedCache(NodeDependency dep, NodeValueTable data, qint64 job_time);
|
||||
|
||||
private:
|
||||
QFile pull_device_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -40,8 +40,6 @@ public:
|
||||
*/
|
||||
void SetParameters(const AudioRenderingParams ¶ms);
|
||||
|
||||
virtual QIODevice* GetAudioPullDevice() = 0;
|
||||
|
||||
const AudioRenderingParams& params() const;
|
||||
|
||||
QString CachePathName() const;
|
||||
|
||||
@@ -355,11 +355,10 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
|
||||
playback_speed_ = speed;
|
||||
play_in_to_out_only_ = in_to_out_only;
|
||||
|
||||
QIODevice* audio_src = audio_renderer_->GetAudioPullDevice();
|
||||
if (audio_src != nullptr && audio_src->open(QIODevice::ReadOnly)) {
|
||||
audio_src->seek(audio_renderer_->params().time_to_bytes(GetTime()));
|
||||
QString audio_fn = audio_renderer_->CachePathName();
|
||||
if (!audio_fn.isEmpty()) {
|
||||
AudioManager::instance()->SetOutputParams(audio_renderer_->params());
|
||||
AudioManager::instance()->StartOutput(audio_src, playback_speed_);
|
||||
AudioManager::instance()->StartOutput(audio_fn, audio_renderer_->params().time_to_bytes(GetTime()), playback_speed_);
|
||||
}
|
||||
|
||||
start_msec_ = QDateTime::currentMSecsSinceEpoch();
|
||||
@@ -378,19 +377,20 @@ void ViewerWidget::PushScrubbedAudio()
|
||||
{
|
||||
if (!IsPlaying() && Config::Current()["AudioScrubbing"].toBool()) {
|
||||
// Get audio src device from renderer
|
||||
QIODevice* audio_src = audio_renderer_->GetAudioPullDevice();
|
||||
QString audio_fn = audio_renderer_->CachePathName();
|
||||
QFile audio_src(audio_fn);
|
||||
|
||||
if (audio_src && audio_src->open(QFile::ReadOnly)) {
|
||||
if (audio_src.open(QFile::ReadOnly)) {
|
||||
// FIXME: Hardcoded scrubbing interval (20ms)
|
||||
int size_of_sample = audio_renderer_->params().time_to_bytes(rational(20, 1000));
|
||||
|
||||
// Push audio
|
||||
audio_src->seek(audio_renderer_->params().time_to_bytes(GetTime()));
|
||||
QByteArray frame_audio = audio_src->read(size_of_sample);
|
||||
audio_src.seek(audio_renderer_->params().time_to_bytes(GetTime()));
|
||||
QByteArray frame_audio = audio_src.read(size_of_sample);
|
||||
AudioManager::instance()->SetOutputParams(audio_renderer_->params());
|
||||
AudioManager::instance()->PushToOutput(frame_audio);
|
||||
|
||||
audio_src->close();
|
||||
audio_src.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user