audio: rewrote audio cache to write to contiguous segments rather than one long file
Fixes issues with PCM file placement, optimizes some audio-based timeline and cache operations, just generally a better approach.
This commit is contained in:
@@ -82,16 +82,23 @@ void AudioManager::PushToOutput(const QByteArray &samples)
|
||||
emit OutputPushed(samples);
|
||||
}
|
||||
|
||||
void AudioManager::StartOutput(const QString &filename, qint64 offset, int playback_speed)
|
||||
void AudioManager::StartOutput(AudioPlaybackCache *cache, qint64 offset, int playback_speed)
|
||||
{
|
||||
// Create device
|
||||
QIODevice* device = cache->CreatePlaybackDevice();
|
||||
|
||||
// Move to output manager's thread
|
||||
device->moveToThread(output_manager_.thread());
|
||||
|
||||
// Queue to output manger in other thread
|
||||
QMetaObject::invokeMethod(&output_manager_,
|
||||
"PullFromDevice",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(const QString&, filename),
|
||||
Q_ARG(QIODevice*, device),
|
||||
Q_ARG(qint64, offset),
|
||||
Q_ARG(int, playback_speed));
|
||||
|
||||
emit OutputDeviceStarted(filename, offset, playback_speed);
|
||||
emit OutputDeviceStarted(cache, offset, playback_speed);
|
||||
}
|
||||
|
||||
void AudioManager::StopOutput()
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "common/define.h"
|
||||
#include "outputmanager.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/audioplaybackcache.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
@@ -57,11 +58,9 @@ public:
|
||||
void PushToOutput(const QByteArray& samples);
|
||||
|
||||
/**
|
||||
* @brief Start playing audio from QIODevice
|
||||
*
|
||||
* This takes ownership of the QIODevice and will delete it when StopOutput() is called
|
||||
* @brief Start playing audio from AudioPlaybackCache
|
||||
*/
|
||||
void StartOutput(const QString& filename, qint64 offset, int playback_speed);
|
||||
void StartOutput(AudioPlaybackCache* cache, qint64 offset, int playback_speed);
|
||||
|
||||
/**
|
||||
* @brief Stop audio output immediately
|
||||
@@ -86,7 +85,7 @@ signals:
|
||||
|
||||
void OutputNotified();
|
||||
|
||||
void OutputDeviceStarted(const QString& filename, qint64 offset, int playback_speed);
|
||||
void OutputDeviceStarted(AudioPlaybackCache* cache, qint64 offset, int playback_speed);
|
||||
|
||||
void AudioParamsChanged(const AudioParams& params);
|
||||
|
||||
|
||||
@@ -24,11 +24,10 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
AudioOutputDeviceProxy::~AudioOutputDeviceProxy()
|
||||
AudioOutputDeviceProxy::AudioOutputDeviceProxy(QObject *parent) :
|
||||
QIODevice(parent),
|
||||
device_(nullptr)
|
||||
{
|
||||
if (file_.isOpen()) {
|
||||
file_.close();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioOutputDeviceProxy::SetParameters(const AudioParams ¶ms)
|
||||
@@ -36,20 +35,23 @@ void AudioOutputDeviceProxy::SetParameters(const AudioParams ¶ms)
|
||||
params_ = params;
|
||||
}
|
||||
|
||||
void AudioOutputDeviceProxy::SetDevice(const QString &filename, qint64 offset, int playback_speed)
|
||||
void AudioOutputDeviceProxy::SetDevice(QIODevice* device, qint64 offset, int playback_speed)
|
||||
{
|
||||
if (file_.isOpen()) {
|
||||
file_.close();
|
||||
if (device_) {
|
||||
delete device_;
|
||||
}
|
||||
|
||||
file_.setFileName(filename);
|
||||
device_ = device;
|
||||
device_->setParent(this);
|
||||
|
||||
if (!file_.open(QFile::ReadOnly)) {
|
||||
qCritical() << "Failed to open" << filename << "for audio playback";
|
||||
if (!device_->open(QFile::ReadOnly)) {
|
||||
qCritical() << "Failed to open IO device for audio playback";
|
||||
delete device_;
|
||||
device_ = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
file_.seek(offset);
|
||||
device_->seek(offset);
|
||||
|
||||
playback_speed_ = playback_speed;
|
||||
|
||||
@@ -62,7 +64,8 @@ void AudioOutputDeviceProxy::close()
|
||||
{
|
||||
QIODevice::close();
|
||||
|
||||
file_.close();
|
||||
delete device_;
|
||||
device_ = nullptr;
|
||||
|
||||
if (tempo_processor_.IsOpen()) {
|
||||
tempo_processor_.Close();
|
||||
@@ -71,7 +74,7 @@ void AudioOutputDeviceProxy::close()
|
||||
|
||||
qint64 AudioOutputDeviceProxy::readData(char *data, qint64 maxlen)
|
||||
{
|
||||
if (!file_.isOpen()) {
|
||||
if (!device_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -111,21 +114,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 = file_.pos() - maxlen;
|
||||
new_pos = device_->pos() - maxlen;
|
||||
|
||||
if (new_pos < 0) {
|
||||
maxlen = file_.pos();
|
||||
maxlen = device_->pos();
|
||||
|
||||
new_pos = 0;
|
||||
}
|
||||
|
||||
file_.seek(new_pos);
|
||||
device_->seek(new_pos);
|
||||
}
|
||||
|
||||
qint64 read_count = file_.read(data, maxlen);
|
||||
qint64 read_count = device_->read(data, maxlen);
|
||||
|
||||
if (playback_speed_ < 0) {
|
||||
file_.seek(new_pos);
|
||||
device_->seek(new_pos);
|
||||
|
||||
// Reverse the samples here
|
||||
AudioManager::ReverseBuffer(data, static_cast<int>(read_count), params_.samples_to_bytes(1));
|
||||
|
||||
@@ -35,13 +35,11 @@ class AudioOutputDeviceProxy : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AudioOutputDeviceProxy() = default;
|
||||
|
||||
virtual ~AudioOutputDeviceProxy() override;
|
||||
AudioOutputDeviceProxy(QObject* parent = nullptr);
|
||||
|
||||
void SetParameters(const AudioParams& params);
|
||||
|
||||
void SetDevice(const QString &filename, qint64 offset, int playback_speed);
|
||||
void SetDevice(QIODevice *device, qint64 offset, int playback_speed);
|
||||
|
||||
virtual void close() override;
|
||||
|
||||
@@ -53,7 +51,7 @@ protected:
|
||||
private:
|
||||
qint64 ReverseAwareRead(char* data, qint64 maxlen);
|
||||
|
||||
QFile file_;
|
||||
QIODevice* device_;
|
||||
|
||||
TempoProcessor tempo_processor_;
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ OLIVE_NAMESPACE_ENTER
|
||||
AudioOutputManager::AudioOutputManager(QObject *parent) :
|
||||
QObject(parent),
|
||||
output_(nullptr),
|
||||
device_proxy_(this),
|
||||
push_device_(nullptr)
|
||||
{
|
||||
}
|
||||
@@ -87,7 +88,7 @@ void AudioOutputManager::Close()
|
||||
}
|
||||
}
|
||||
|
||||
void AudioOutputManager::PullFromDevice(const QString &filename, qint64 offset, int playback_speed)
|
||||
void AudioOutputManager::PullFromDevice(QIODevice *device, qint64 offset, int playback_speed)
|
||||
{
|
||||
if (!output_) {
|
||||
return;
|
||||
@@ -99,7 +100,7 @@ void AudioOutputManager::PullFromDevice(const QString &filename, qint64 offset,
|
||||
push_samples_.clear();
|
||||
|
||||
// Pull from the device
|
||||
device_proxy_.SetDevice(filename, offset, playback_speed);
|
||||
device_proxy_.SetDevice(device, offset, playback_speed);
|
||||
device_proxy_.open(QIODevice::ReadOnly);
|
||||
output_->start(&device_proxy_);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public slots:
|
||||
* 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(const QString &filename, qint64 offset, int playback_speed);
|
||||
void PullFromDevice(QIODevice* device, qint64 offset, int playback_speed);
|
||||
|
||||
// Queued
|
||||
void ResetToPushMode();
|
||||
|
||||
Reference in New Issue
Block a user