Browse Source

Fixup last audiofile player details

Signed-off-by: falkTX <falktx@falktx.com>
fix-audiofile-buffering
falkTX 2 years ago
parent
commit
7cdb284daf
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
4 changed files with 135 additions and 69 deletions
  1. +2
    -2
      source/modules/audio_decoder/ad_dr_mp3.c
  2. +2
    -2
      source/modules/audio_decoder/ad_minimp3.c
  3. +74
    -36
      source/native-plugins/audio-base.hpp
  4. +57
    -29
      source/native-plugins/audio-file.cpp

+ 2
- 2
source/modules/audio_decoder/ad_dr_mp3.c View File

@@ -52,7 +52,7 @@ static int ad_info_dr_mp3(void *sf, struct adinfo *nfo) {
nfo->sample_rate = priv->mp3.sampleRate; nfo->sample_rate = priv->mp3.sampleRate;
nfo->length = nfo->sample_rate ? (nfo->frames * 1000) / nfo->sample_rate : 0; nfo->length = nfo->sample_rate ? (nfo->frames * 1000) / nfo->sample_rate : 0;
nfo->bit_depth = 16; nfo->bit_depth = 16;
nfo->bit_rate = priv->mp3.frameInfo.bitrate_kbps;
nfo->bit_rate = priv->mp3.frameInfo.bitrate_kbps * 1000;
nfo->meta_data = NULL; nfo->meta_data = NULL;
nfo->can_seek = 1; nfo->can_seek = 1;
} }
@@ -103,7 +103,7 @@ static ssize_t ad_read_dr_mp3(void *sf, float* d, size_t len)
static int ad_get_bitrate_dr_mp3(void *sf) { static int ad_get_bitrate_dr_mp3(void *sf) {
drmp3_audio_decoder *priv = (drmp3_audio_decoder*) sf; drmp3_audio_decoder *priv = (drmp3_audio_decoder*) sf;
if (!priv) return -1; if (!priv) return -1;
return priv->mp3.frameInfo.bitrate_kbps;
return priv->mp3.frameInfo.bitrate_kbps * 1000;
} }


static int ad_eval_dr_mp3(const char *f) static int ad_eval_dr_mp3(const char *f)


+ 2
- 2
source/modules/audio_decoder/ad_minimp3.c View File

@@ -80,7 +80,7 @@ static int ad_info_minimp3(void *sf, struct adinfo *nfo) {
nfo->sample_rate = priv->dec_ex.info.hz; nfo->sample_rate = priv->dec_ex.info.hz;
nfo->length = nfo->sample_rate ? (nfo->frames * 1000) / nfo->sample_rate : 0; nfo->length = nfo->sample_rate ? (nfo->frames * 1000) / nfo->sample_rate : 0;
nfo->bit_depth = 16; nfo->bit_depth = 16;
nfo->bit_rate = priv->dec_ex.info.bitrate_kbps;
nfo->bit_rate = priv->dec_ex.info.bitrate_kbps * 1000;
nfo->meta_data = NULL; nfo->meta_data = NULL;
nfo->can_seek = 0; nfo->can_seek = 0;
} }
@@ -132,7 +132,7 @@ static ssize_t ad_read_minimp3(void *sf, float* d, size_t len)
static int ad_get_bitrate_minimp3(void *sf) { static int ad_get_bitrate_minimp3(void *sf) {
minimp3_audio_decoder *priv = (minimp3_audio_decoder*) sf; minimp3_audio_decoder *priv = (minimp3_audio_decoder*) sf;
if (!priv) return -1; if (!priv) return -1;
return priv->dec_ex.info.bitrate_kbps;
return priv->dec_ex.info.bitrate_kbps * 1000;
} }


static int ad_eval_minimp3(const char *f) static int ad_eval_minimp3(const char *f)


+ 74
- 36
source/native-plugins/audio-base.hpp View File

@@ -44,6 +44,18 @@ extern "C" {


typedef struct adinfo ADInfo; typedef struct adinfo ADInfo;


// --------------------------------------------------------------------------------------------------------------------
// tuning

// disk streaming buffer size
static constexpr const uint16_t kFileReaderBufferSize = 1024;

// if reading a file smaller than this, load it all in memory
static constexpr const uint16_t kMinLengthSeconds = 30;

// size of the audio file ring buffer
static constexpr const uint16_t kRingBufferLengthSeconds = 6;

// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------


struct AudioMemoryPool { struct AudioMemoryPool {
@@ -195,23 +207,25 @@ public:


fResampleRatio = static_cast<double>(sampleRate) / static_cast<double>(fFileNfo.sample_rate); fResampleRatio = static_cast<double>(sampleRate) / static_cast<double>(fFileNfo.sample_rate);
numResampledFrames = static_cast<uint64_t>(static_cast<double>(numFileFrames) * fResampleRatio + 0.5); numResampledFrames = static_cast<uint64_t>(static_cast<double>(numFileFrames) * fResampleRatio + 0.5);

if (fPreviousResampledBuffer.buffer == nullptr)
fPreviousResampledBuffer.buffer = new float[kFileReaderBufferSize];
} }
else else
{ {
fResampler.clear();
fResampleRatio = 1.0;
numResampledFrames = numFileFrames; numResampledFrames = numFileFrames;
} }


if (fFileNfo.can_seek == 0 || numResampledFrames <= sampleRate * 30)
if (fFileNfo.can_seek == 0 || numResampledFrames <= sampleRate * kMinLengthSeconds)
{ {
// read the first 30s of the file if seekable
// read and cache the first few seconds of the file if seekable
const uint64_t initialFrames = fFileNfo.can_seek == 0 const uint64_t initialFrames = fFileNfo.can_seek == 0
? numFileFrames ? numFileFrames
: std::min<uint64_t>(numFileFrames, fFileNfo.sample_rate * 30);
: std::min<uint64_t>(numFileFrames, fFileNfo.sample_rate * kMinLengthSeconds);
const uint64_t initialResampledFrames = fFileNfo.can_seek == 0 const uint64_t initialResampledFrames = fFileNfo.can_seek == 0
? numResampledFrames ? numResampledFrames
: std::min<uint64_t>(numResampledFrames, sampleRate * 30);
: std::min<uint64_t>(numResampledFrames,
sampleRate * kMinLengthSeconds);


fInitialMemoryPool.create(initialResampledFrames); fInitialMemoryPool.create(initialResampledFrames);
readIntoInitialMemoryPool(initialFrames, initialResampledFrames); readIntoInitialMemoryPool(initialFrames, initialResampledFrames);
@@ -236,12 +250,14 @@ public:
{ {
readFilePreview(previewDataSize, previewData); readFilePreview(previewDataSize, previewData);


// read only the first 4s, let disk streaming handle the rest
const uint64_t initialFrames = std::min<uint64_t>(numFileFrames, fFileNfo.sample_rate * 4);
const uint64_t initialResampledFrames = std::min<uint64_t>(numResampledFrames, sampleRate * 4);
// cache only the first few initial seconds, let disk streaming handle the rest
const uint64_t initialFrames = std::min<uint64_t>(numFileFrames,
fFileNfo.sample_rate * kRingBufferLengthSeconds / 2);
const uint64_t initialResampledFrames = std::min<uint64_t>(numResampledFrames,
sampleRate * kRingBufferLengthSeconds / 2);


fRingBufferL.createBuffer(sampleRate * 6 * sizeof(float), true);
fRingBufferR.createBuffer(sampleRate * 6 * sizeof(float), true);
fRingBufferL.createBuffer(sampleRate * kRingBufferLengthSeconds * sizeof(float), true);
fRingBufferR.createBuffer(sampleRate * kRingBufferLengthSeconds * sizeof(float), true);


fInitialMemoryPool.create(initialResampledFrames); fInitialMemoryPool.create(initialResampledFrames);
readIntoInitialMemoryPool(initialFrames, initialResampledFrames); readIntoInitialMemoryPool(initialFrames, initialResampledFrames);
@@ -292,7 +308,6 @@ public:
carla_zeroFloats(outL, frames); carla_zeroFloats(outL, frames);
carla_zeroFloats(outR, frames); carla_zeroFloats(outR, frames);
carla_zeroFloats(playCV, frames); carla_zeroFloats(playCV, frames);
carla_stdout("tickFrames not loaded");
return false; return false;
} }


@@ -371,6 +386,7 @@ public:
fRingBufferR.skipRead(diffFrames * sizeof(float)); fRingBufferR.skipRead(diffFrames * sizeof(float));
totalFramesAvailable -= diffFrames; totalFramesAvailable -= diffFrames;
fRingBufferFramePos = framePos; fRingBufferFramePos = framePos;
carla_stdout("tickFrames adjusted frame unaligned position");
} }


usableFrames = std::min<uint32_t>(frames, totalFramesAvailable); usableFrames = std::min<uint32_t>(frames, totalFramesAvailable);
@@ -454,6 +470,7 @@ public:


fCurrentBitRate = ad_get_bitrate(fFilePtr); fCurrentBitRate = ad_get_bitrate(fFilePtr);


const bool needsResample = carla_isNotEqual(fResampleRatio, 1.0);
const int64_t nextFileReadPos = fNextFileReadPos; const int64_t nextFileReadPos = fNextFileReadPos;


if (nextFileReadPos != -1) if (nextFileReadPos != -1)
@@ -463,26 +480,35 @@ public:
fRingBufferL.flush(); fRingBufferL.flush();
fRingBufferR.flush(); fRingBufferR.flush();


fPreviousResampledBuffer.frames = 0;
fRingBufferFramePos = nextFileReadPos; fRingBufferFramePos = nextFileReadPos;
ad_seek(fFilePtr, nextFileReadPos / fResampleRatio); ad_seek(fFilePtr, nextFileReadPos / fResampleRatio);
}


bool written = false;
uint test = 0;
if (needsResample)
fResampler.reset();
}


if (carla_isNotEqual(fResampleRatio, 1.0))
if (needsResample)
{ {
float buffer[8192];
float rbuffer[8192];
float buffer[kFileReaderBufferSize];
float rbuffer[kFileReaderBufferSize];
ssize_t r; ssize_t r;
uint prev_inp_count = 0; uint prev_inp_count = 0;


while (fRingBufferR.getWritableDataSize() >= sizeof(rbuffer)) while (fRingBufferR.getWritableDataSize() >= sizeof(rbuffer))
{ {
if (prev_inp_count != 0)
if (const uint32_t oldframes = fPreviousResampledBuffer.frames)
{
prev_inp_count = oldframes;
fPreviousResampledBuffer.frames = 0;
std::memcpy(buffer, fPreviousResampledBuffer.buffer, sizeof(float) * oldframes * channels);
}
else if (prev_inp_count != 0)
{
std::memmove(buffer, std::memmove(buffer,
buffer + (sizeof(buffer) / sizeof(float) - prev_inp_count * channels), buffer + (sizeof(buffer) / sizeof(float) - prev_inp_count * channels),
sizeof(float) * prev_inp_count * channels); sizeof(float) * prev_inp_count * channels);
}


r = ad_read(fFilePtr, r = ad_read(fFilePtr,
buffer + (prev_inp_count * channels), buffer + (prev_inp_count * channels),
@@ -510,7 +536,6 @@ public:
if (fResampler.out_count == 0) if (fResampler.out_count == 0)
{ {
CARLA_SAFE_ASSERT_UINT(fResampler.inp_count != 0, fResampler.inp_count); CARLA_SAFE_ASSERT_UINT(fResampler.inp_count != 0, fResampler.inp_count);
prev_inp_count = fResampler.inp_count;
} }
else else
{ {
@@ -522,31 +547,40 @@ public:
CARLA_SAFE_ASSERT(fResampler.inp_count == 0); CARLA_SAFE_ASSERT(fResampler.inp_count == 0);
} }


prev_inp_count = fResampler.inp_count;

if (r == 0) if (r == 0)
break; break;


test += r;

if (channels == 1) if (channels == 1)
{ {
written = true;
fRingBufferL.writeCustomData(rbuffer, r * sizeof(float)); fRingBufferL.writeCustomData(rbuffer, r * sizeof(float));
fRingBufferR.writeCustomData(rbuffer, r * sizeof(float)); fRingBufferR.writeCustomData(rbuffer, r * sizeof(float));
} }
else else
{ {
written = true;
for (ssize_t i=0; i < r;) for (ssize_t i=0; i < r;)
{ {
fRingBufferL.writeCustomData(&rbuffer[i++], sizeof(float)); fRingBufferL.writeCustomData(&rbuffer[i++], sizeof(float));
fRingBufferR.writeCustomData(&rbuffer[i++], sizeof(float)); fRingBufferR.writeCustomData(&rbuffer[i++], sizeof(float));
} }
} }

fRingBufferL.commitWrite();
fRingBufferR.commitWrite();
}

if (prev_inp_count != 0)
{
fPreviousResampledBuffer.frames = prev_inp_count;
std::memcpy(fPreviousResampledBuffer.buffer,
buffer + (sizeof(buffer) / sizeof(float) - prev_inp_count * channels),
sizeof(float) * prev_inp_count * channels);
} }
} }
else else
{ {
float buffer[1024];
float buffer[kFileReaderBufferSize];
ssize_t r; ssize_t r;


while (fRingBufferR.getWritableDataSize() >= sizeof(buffer)) while (fRingBufferR.getWritableDataSize() >= sizeof(buffer))
@@ -562,31 +596,23 @@ public:
if (r == 0) if (r == 0)
break; break;


test += r;

if (channels == 1) if (channels == 1)
{ {
written = true;
fRingBufferL.writeCustomData(buffer, r * sizeof(float)); fRingBufferL.writeCustomData(buffer, r * sizeof(float));
fRingBufferR.writeCustomData(buffer, r * sizeof(float)); fRingBufferR.writeCustomData(buffer, r * sizeof(float));
} }
else else
{ {
written = true;
for (ssize_t i=0; i < r;) for (ssize_t i=0; i < r;)
{ {
fRingBufferL.writeCustomData(&buffer[i++], sizeof(float)); fRingBufferL.writeCustomData(&buffer[i++], sizeof(float));
fRingBufferR.writeCustomData(&buffer[i++], sizeof(float)); fRingBufferR.writeCustomData(&buffer[i++], sizeof(float));
} }
} }
}
}


carla_stdout("readPoll written %d", test);
if (written)
{
fRingBufferL.commitWrite();
fRingBufferR.commitWrite();
fRingBufferL.commitWrite();
fRingBufferR.commitWrite();
}
} }


if (nextFileReadPos != -1) if (nextFileReadPos != -1)
@@ -610,6 +636,11 @@ private:
Resampler fResampler; Resampler fResampler;
CarlaMutex fReaderMutex; CarlaMutex fReaderMutex;


struct PreviousResampledBuffer {
float* buffer = nullptr;
uint32_t frames = 0;
} fPreviousResampledBuffer;

CarlaHeapRingBuffer fRingBufferL, fRingBufferR; CarlaHeapRingBuffer fRingBufferL, fRingBufferR;
uint64_t fRingBufferFramePos = 0; uint64_t fRingBufferFramePos = 0;


@@ -623,6 +654,9 @@ private:
fTotalResampledFrames = 0; fTotalResampledFrames = 0;
fSampleRate = 0; fSampleRate = 0;
fRingBufferFramePos = 0; fRingBufferFramePos = 0;
fResampleRatio = 1.0;

fResampler.clear();
fInitialMemoryPool.destroy(); fInitialMemoryPool.destroy();
fRingBufferL.deleteBuffer(); fRingBufferL.deleteBuffer();
fRingBufferR.deleteBuffer(); fRingBufferR.deleteBuffer();
@@ -632,6 +666,10 @@ private:
ad_close(fFilePtr); ad_close(fFilePtr);
fFilePtr = nullptr; fFilePtr = nullptr;
} }

delete[] fPreviousResampledBuffer.buffer;
fPreviousResampledBuffer.buffer = nullptr;
fPreviousResampledBuffer.frames = 0;
} }


void readIntoInitialMemoryPool(const uint numFrames, const uint numResampledFrames) void readIntoInitialMemoryPool(const uint numFrames, const uint numResampledFrames)


+ 57
- 29
source/native-plugins/audio-file.cpp View File

@@ -20,8 +20,57 @@


#include "audio-base.hpp" #include "audio-base.hpp"


#include <cmath>

// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------


// static constexpr const float M_PIf = static_cast<float>(M_PI);

class VolumeFilter
{
float a0, b1, z1;

public:
VolumeFilter(const float sampleRate) noexcept
{
setSampleRate(sampleRate);
}

void reset() noexcept
{
a0 = 1.f - b1;
z1 = 0.f;
}

void setSampleRate(const float sampleRate) noexcept
{
const float frequency = 30.0f / sampleRate;

b1 = std::exp(-2.f * M_PIf * frequency);
a0 = 1.f - b1;
z1 = 0.f;
}

void processStereo(const float gain, float* buffers[2], const uint32_t frames) noexcept
{
const float _a0 = a0;
const float _b1 = b1;
float _z1 = z1;

for (uint32_t i=0; i < frames; ++i)
{
_z1 = gain * _a0 + _z1 * _b1;
buffers[0][i] *= _z1;
buffers[1][i] *= _z1;
}

z1 = _z1;
}
};

// --------------------------------------------------------------------------------------------------------------------


#ifndef __MOD_DEVICES__ #ifndef __MOD_DEVICES__
class AudioFilePlugin : public NativePluginWithMidiPrograms<FileAudio> class AudioFilePlugin : public NativePluginWithMidiPrograms<FileAudio>
#else #else
@@ -70,30 +119,11 @@ public:
AudioFilePlugin(const NativeHostDescriptor* const host) AudioFilePlugin(const NativeHostDescriptor* const host)
#ifndef __MOD_DEVICES__ #ifndef __MOD_DEVICES__
: NativePluginWithMidiPrograms<FileAudio>(host, fPrograms, 3), : NativePluginWithMidiPrograms<FileAudio>(host, fPrograms, 3),
fPrograms(hostGetFilePath("audio"), audiofilesWildcard)
fPrograms(hostGetFilePath("audio"), audiofilesWildcard),
#else #else
: NativePluginClass(host)
: NativePluginClass(host),
#endif #endif
// fWasPlayingBefore(false),
// fNeedsFileRead(false),
// fEntireFileLoaded(false),
// fMaxFrame(0),
// fReadableBufferFill(0.0f),
// fPool(),
// fReader(),
// fFilename(),
// fPreviewData()
// #ifndef __MOD_DEVICES__
// , fInlineDisplay()
// #endif
{
}

~AudioFilePlugin() override
{
// fReader.destroy();
// fPool.destroy();
}
fVolumeFilter(getSampleRate()) {}


protected: protected:
// ---------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------
@@ -358,7 +388,6 @@ protected:
return; return;
} }


bool needsIdleRequest = false;
bool playing; bool playing;
uint64_t framePos; uint64_t framePos;


@@ -386,6 +415,8 @@ protected:
return; return;
} }


bool needsIdleRequest = false;

if (fReader.tickFrames(outBuffer, 0, frames, framePos, fLoopMode, isOffline()) && ! fPendingFileRead) if (fReader.tickFrames(outBuffer, 0, frames, framePos, fLoopMode, isOffline()) && ! fPendingFileRead)
{ {
fPendingFileRead = true; fPendingFileRead = true;
@@ -395,12 +426,7 @@ protected:
fLastPosition = fReader.getLastPlayPosition() * 100.f; fLastPosition = fReader.getLastPlayPosition() * 100.f;
fReadableBufferFill = fReader.getReadableBufferFill() * 100.f; fReadableBufferFill = fReader.getReadableBufferFill() * 100.f;


const float volume = fVolume;
if (carla_isNotEqual(volume, 1.0f))
{
carla_multiply(out1, volume, frames);
carla_multiply(out2, volume, frames);
}
fVolumeFilter.processStereo(fVolume, outBuffer, frames);


#ifndef __MOD_DEVICES__ #ifndef __MOD_DEVICES__
if (fInlineDisplay.writtenValues < 32) if (fInlineDisplay.writtenValues < 32)
@@ -626,6 +652,8 @@ private:
} fInlineDisplay; } fInlineDisplay;
#endif #endif


VolumeFilter fVolumeFilter;

void loadFilename(const char* const filename) void loadFilename(const char* const filename)
{ {
CARLA_ASSERT(filename != nullptr); CARLA_ASSERT(filename != nullptr);


Loading…
Cancel
Save