Browse Source

Continue audiofile rework, almost done

Signed-off-by: falkTX <falktx@falktx.com>
fix-audiofile-buffering
falkTX 1 year ago
parent
commit
ccc1203ec3
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
11 changed files with 552 additions and 841 deletions
  1. +6
    -4
      source/backend/plugin/CarlaPluginLV2.cpp
  2. +1
    -0
      source/modules/zita-resampler/.kdev_include_paths
  3. +3
    -0
      source/native-plugins/.kdev_include_paths
  4. +8
    -1
      source/native-plugins/_data.cpp
  5. +403
    -621
      source/native-plugins/audio-base.hpp
  6. +34
    -189
      source/native-plugins/audio-file.cpp
  7. +1
    -0
      source/utils/.kdev_include_paths
  8. +45
    -0
      source/utils/CarlaMemUtils.hpp
  9. +30
    -10
      source/utils/CarlaRingBuffer.hpp
  10. +2
    -0
      source/utils/CarlaShmUtils.hpp
  11. +19
    -16
      source/utils/Lv2AtomRingBuffer.hpp

+ 6
- 4
source/backend/plugin/CarlaPluginLV2.cpp View File

@@ -3255,29 +3255,31 @@ public:

if (fExt.worker != nullptr && fEventsIn.ctrl != nullptr)
{
fAtomBufferWorkerIn.createBuffer(eventBufferSize);
fAtomBufferWorkerResp.createBuffer(eventBufferSize);
fAtomBufferWorkerIn.createBuffer(eventBufferSize, true);
fAtomBufferWorkerResp.createBuffer(eventBufferSize, true);
fAtomBufferRealtimeSize = fAtomBufferWorkerIn.getSize(); // actual buffer size will be next power of 2
fAtomBufferRealtime = static_cast<LV2_Atom*>(std::malloc(fAtomBufferRealtimeSize));
fAtomBufferWorkerInTmpData = new uint8_t[fAtomBufferRealtimeSize];
carla_mlock(fAtomBufferRealtime, fAtomBufferRealtimeSize);
}

if (fRdfDescriptor->ParameterCount > 0 ||
(fUI.type != UI::TYPE_NULL && fEventsIn.count > 0 && (fEventsIn.data[0].type & CARLA_EVENT_DATA_ATOM) != 0))
{
fAtomBufferEvIn.createBuffer(eventBufferSize);
fAtomBufferEvIn.createBuffer(eventBufferSize, true);

if (fAtomBufferRealtimeSize == 0)
{
fAtomBufferRealtimeSize = fAtomBufferEvIn.getSize(); // actual buffer size will be next power of 2
fAtomBufferRealtime = static_cast<LV2_Atom*>(std::malloc(fAtomBufferRealtimeSize));
carla_mlock(fAtomBufferRealtime, fAtomBufferRealtimeSize);
}
}

if (hasPatchParameterOutputs ||
(fUI.type != UI::TYPE_NULL && fEventsOut.count > 0 && (fEventsOut.data[0].type & CARLA_EVENT_DATA_ATOM) != 0))
{
fAtomBufferUiOut.createBuffer(std::min(eventBufferSize*32, 1638400U));
fAtomBufferUiOut.createBuffer(std::min(eventBufferSize*32, 1638400U), true);
fAtomBufferUiOutTmpData = new uint8_t[fAtomBufferUiOut.getSize()];
}



+ 1
- 0
source/modules/zita-resampler/.kdev_include_paths View File

@@ -0,0 +1 @@
../../includes/

+ 3
- 0
source/native-plugins/.kdev_include_paths View File

@@ -0,0 +1,3 @@
../includes/
../modules/
../utils/

+ 8
- 1
source/native-plugins/_data.cpp View File

@@ -284,6 +284,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = {
|NATIVE_PLUGIN_HAS_UI
|NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE
|NATIVE_PLUGIN_REQUESTS_IDLE
|NATIVE_PLUGIN_USES_CONTROL_VOLTAGE
|NATIVE_PLUGIN_USES_TIME),
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING,
/* audioIns */ 0,
@@ -296,7 +297,13 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = {
/* label */ "audiofile",
/* maker */ "falkTX",
/* copyright */ "GNU GPL v2+",
DESCFUNCS_WITHOUTCV
DESCFUNCS_WITHCV,
/* cvIns */ 0,
/* cvOuts */ 1,
/* bufnamefn */ nullptr,
/* bufrangefn */ nullptr,
/* ui_width */ 0,
/* ui_height */ 0
},

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


+ 403
- 621
source/native-plugins/audio-base.hpp
File diff suppressed because it is too large
View File


+ 34
- 189
source/native-plugins/audio-file.cpp View File

@@ -78,7 +78,7 @@ public:
// fNeedsFileRead(false),
// fEntireFileLoaded(false),
// fMaxFrame(0),
// fLastPoolFill(0.0f),
// fReadableBufferFill(0.0f),
// fPool(),
// fReader(),
// fFilename(),
@@ -253,8 +253,8 @@ protected:
return fVolume * 100.f;
case kParameterInfoPosition:
return fLastPosition;
// case kParameterInfoPoolFill:
// return fLastPoolFill;
case kParameterInfoPoolFill:
return fReadableBufferFill;
case kParameterInfoBitRate:
return static_cast<float>(fReader.getCurrentBitRate());
}
@@ -290,10 +290,7 @@ protected:
{
case kParameterLooping:
if (fLoopMode != b)
{
fLoopMode = b;
// fReader.setLoopingMode(b);
}
break;
case kParameterHostSync:
if (fHostSync != b)
@@ -350,19 +347,17 @@ protected:
float* const out2 = outBuffer[1];
float* const playCV = outBuffer[2];

// const water::GenericScopedLock<water::SpinLock> gsl(fPool.mutex);

if (! fDoProcess)
{
// carla_stderr("P: no process");
carla_zeroFloats(out1, frames);
carla_zeroFloats(out2, frames);
carla_zeroFloats(playCV, frames);
fLastPosition = 0.0f;
fLastPosition = 0.f;
fReadableBufferFill = 0.f;
return;
}

// const bool loopMode = fLoopMode;
bool needsIdleRequest = false;
bool playing;
uint64_t framePos;
@@ -385,152 +380,20 @@ protected:
// not playing
if (! playing)
{
// // carla_stderr("P: not playing");
// if (framePos == 0 && fWasPlayingBefore)
// fReader.setNeedsRead(framePos);

carla_zeroFloats(out1, frames);
carla_zeroFloats(out2, frames);
carla_zeroFloats(playCV, frames);
// fWasPlayingBefore = false;
return;
}
// else
// {
// fWasPlayingBefore = true;
// }

fLastPosition = fReader.tickFrames(outBuffer, 0, frames, framePos, fLoopMode, isOffline()) * 100.f;

// // out of reach
// if ((frame < fPool.startFrame || frame >= fMaxFrame) && !loopMode)
// {
// if (frame < fPool.startFrame)
// {
// needsIdleRequest = true;
// fNeedsFileRead = true;
// fReader.setNeedsRead(frame);
// }
//
// carla_zeroFloats(out1, frames);
// carla_zeroFloats(out2, frames);
// carla_zeroFloats(playCV, frames);
//
// #ifndef __MOD_DEVICES__
// if (fInlineDisplay.writtenValues < 32)
// {
// fInlineDisplay.lastValuesL[fInlineDisplay.writtenValues] = 0.0f;
// fInlineDisplay.lastValuesR[fInlineDisplay.writtenValues] = 0.0f;
// ++fInlineDisplay.writtenValues;
// }
// if (fInlineDisplay.pending == InlineDisplayNotPending)
// {
// needsIdleRequest = true;
// fInlineDisplay.pending = InlineDisplayNeedRequest;
// }
// #endif

// if (needsIdleRequest)
// hostRequestIdle();
//
// if (frame == 0)
// fLastPosition = 0.0f;
// else if (frame >= fMaxFrame)
// fLastPosition = 100.0f;
// else
// fLastPosition = static_cast<float>(frame) / static_cast<float>(fMaxFrame) * 100.0f;
// return;
// }

// if (fEntireFileLoaded)
// {
// // NOTE: frame is always < fMaxFrame (or looping)
// uint32_t targetStartFrame = static_cast<uint32_t>(loopMode ? frame % fMaxFrame : frame);
//
// for (uint32_t framesDone=0, framesToDo=frames, remainingFrames; framesDone < frames;)
// {
// if (targetStartFrame + framesToDo <= fMaxFrame)
// {
// // everything fits together
// carla_copyFloats(out1+framesDone, fPool.buffer[0]+targetStartFrame, framesToDo);
// carla_copyFloats(out2+framesDone, fPool.buffer[1]+targetStartFrame, framesToDo);
// carla_fillFloatsWithSingleValue(playCV+framesDone, 10.f, framesToDo);
// break;
// }
//
// remainingFrames = std::min(fMaxFrame - targetStartFrame, framesToDo);
// carla_copyFloats(out1+framesDone, fPool.buffer[0]+targetStartFrame, remainingFrames);
// carla_copyFloats(out2+framesDone, fPool.buffer[1]+targetStartFrame, remainingFrames);
// carla_fillFloatsWithSingleValue(playCV+framesDone, 10.f, remainingFrames);
// framesDone += remainingFrames;
// framesToDo -= remainingFrames;
//
// if (! loopMode)
// {
// // not looping, stop here
// if (framesToDo != 0)
// {
// carla_zeroFloats(out1+framesDone, framesToDo);
// carla_zeroFloats(out2+framesDone, framesToDo);
// carla_zeroFloats(playCV+framesDone, framesToDo);
// }
// break;
// }
//
// // reset for next loop
// targetStartFrame = 0;
// }

// fLastPosition = static_cast<float>(targetStartFrame) / static_cast<float>(fMaxFrame) * 100.0f;
// }
// else
// {
// const bool offline = isOffline();

// if (fReader.tryPutData(fPool, out1, out2, frame, frames, loopMode, offline, needsIdleRequest))
// {
// carla_fillFloatsWithSingleValue(playCV, 10.f, frames);
// }
// else
// {
// carla_zeroFloats(out1, frames);
// carla_zeroFloats(out2, frames);
// carla_zeroFloats(playCV, frames);
// }
//
// if (needsIdleRequest)
// {
// fNeedsFileRead = true;
//
// if (isOffline())
// {
// needsIdleRequest = false;
// fReader.readPoll();
//
// if (fReader.tryPutData(fPool, out1, out2, frame, frames, loopMode, offline, needsIdleRequest))
// {
// carla_fillFloatsWithSingleValue(playCV, 10.f, frames);
// }
// else
// {
// carla_zeroFloats(out1, frames);
// carla_zeroFloats(out2, frames);
// carla_zeroFloats(playCV, frames);
// }
//
// if (needsIdleRequest)
// fNeedsFileRead = true;
// }
// }
//
// const uint32_t modframe = static_cast<uint32_t>(frame % fMaxFrame);
// fLastPosition = static_cast<float>(modframe) / static_cast<float>(fMaxFrame) * 100.0f;
//
// if (modframe > fPool.startFrame)
// fLastPoolFill = static_cast<float>(modframe - fPool.startFrame) / static_cast<float>(fPool.numFrames) * 100.0f;
// else
// fLastPoolFill = 100.0f;
// }

if (fReader.tickFrames(outBuffer, 0, frames, framePos, fLoopMode, isOffline()) && ! fPendingFileRead)
{
fPendingFileRead = true;
needsIdleRequest = true;
}

fLastPosition = fReader.getLastPlayPosition() * 100.f;
fReadableBufferFill = fReader.getReadableBufferFill() * 100.f;

const float volume = fVolume;
if (carla_isNotEqual(volume, 1.0f))
@@ -586,11 +449,11 @@ protected:
}
#endif

// if (fNeedsFileRead)
// {
// fReader.readPoll();
// fNeedsFileRead = false;
// }
if (fPendingFileRead)
{
fPendingFileRead = false;
fReader.readPoll();
}
}

void sampleRateChanged(double) override
@@ -725,17 +588,13 @@ private:
#endif
bool fEnabled = true;
bool fDoProcess = false;
// bool fWasPlayingBefore;
// volatile bool fNeedsFileRead;
//
// bool fEntireFileLoaded;
// uint32_t fMaxFrame;
bool fPendingFileRead = false;

uint32_t fInternalTransportFrame = 0;
float fLastPosition = 0.f;
// float fLastPoolFill;
float fReadableBufferFill = 0.f;
float fVolume = 1.f;

// AudioFilePool fPool;
AudioFileReader fReader;
CarlaString fFilename;

@@ -773,55 +632,41 @@ private:
carla_stdout("AudioFilePlugin::loadFilename(\"%s\")", filename);

fDoProcess = false;
// fLastPoolFill = 0.0f;
// fPool.destroy();
fReader.destroy();
fFilename.clear();

if (filename == nullptr || *filename == '\0')
{
// fMaxFrame = 0;
return;
}

constexpr uint32_t kPreviewDataLen = sizeof(fPreviewData)/sizeof(float);

if (fReader.loadFilename(filename, static_cast<uint32_t>(getSampleRate()), kPreviewDataLen, fPreviewData))
{
// fEntireFileLoaded = fReader.isEntireFileLoaded();
// fMaxFrame = fReader.getMaxFrame();
//
// if (fEntireFileLoaded)
// {
// fReader.putAndSwapAllData(fPool);
// fLastPoolFill = 100.0f;
// }
// else
// {
// fReader.createSwapablePool(fPool);
// fReader.readPoll();
// }

fInternalTransportFrame = 0;
fDoProcess = true;
fFilename = filename;
hostSendPreviewBufferData('f', kPreviewDataLen, fPreviewData);
}
else
{
// fEntireFileLoaded = false;
// fMaxFrame = 0;
}
}

PluginClassEND(AudioFilePlugin)

static const char* _get_buffer_port_name(NativePluginHandle, const uint32_t index, const bool isOutput)
{
if (!isOutput || index != 2)
if (!isOutput)
return nullptr;

return "Play status";
switch (index)
{
case 0:
return "output_1";
case 1:
return "output_2";
case 2:
return "Play status";
}

return nullptr;
}

static const NativePortRange* _get_buffer_port_range(NativePluginHandle, const uint32_t index, const bool isOutput)


+ 1
- 0
source/utils/.kdev_include_paths View File

@@ -0,0 +1 @@
../includes/

+ 45
- 0
source/utils/CarlaMemUtils.hpp View File

@@ -0,0 +1,45 @@
/*
* Carla shared memory utils
* Copyright (C) 2023 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/

#ifndef CARLA_MEM_UTILS_HPP_INCLUDED
#define CARLA_MEM_UTILS_HPP_INCLUDED

#include "CarlaUtils.hpp"

#if !defined(CARLA_OS_WASM) && !defined(CARLA_OS_WIN)
# include <sys/mman.h>
#endif

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

static inline
bool carla_mlock(void* const ptr, const size_t size)
{
#if defined(CARLA_OS_WASM)
// unsupported
return false;
(void)ptr; (void)size;
#elif defined(CARLA_OS_WIN)
return ::VirtualLock(ptr, size) != FALSE;
#else
return ::mlock(ptr, size) == 0;
#endif
}

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

#endif // CARLA_MEM_UTILS_HPP_INCLUDED

+ 30
- 10
source/utils/CarlaRingBuffer.hpp View File

@@ -19,6 +19,7 @@
#define CARLA_RING_BUFFER_HPP_INCLUDED

#include "CarlaMathUtils.hpp"
#include "CarlaMemUtils.hpp"

// --------------------------------------------------------------------------------------------------------------------
// Buffer structs
@@ -102,12 +103,22 @@ public:
{
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);

fBuffer->head = 0;
fBuffer->tail = 0;
fBuffer->wrtn = 0;
fBuffer->head = fBuffer->tail = fBuffer->wrtn = 0;
fBuffer->invalidateCommit = false;

carla_zeroBytes(fBuffer->buf, fBuffer->size);

fErrorReading = fErrorWriting = false;
}

void flush() noexcept
{
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);

fBuffer->head = fBuffer->tail = fBuffer->wrtn = 0;
fBuffer->invalidateCommit = false;

fErrorWriting = false;
}

// ----------------------------------------------------------------------------------------------------------------
@@ -141,6 +152,11 @@ public:
return fBuffer->buf == nullptr || fBuffer->head == fBuffer->tail;
}

uint32_t getSize() const noexcept
{
return fBuffer != nullptr ? fBuffer->size : 0;
}

uint32_t getReadableDataSize() const noexcept
{
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, 0);
@@ -154,7 +170,7 @@ public:
{
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, 0);

const uint32_t wrap = (fBuffer->tail >= fBuffer->wrtn) ? 0 : fBuffer->size;
const uint32_t wrap = fBuffer->tail > fBuffer->wrtn ? 0 : fBuffer->size;

return wrap + fBuffer->tail - fBuffer->wrtn;
}
@@ -502,10 +518,7 @@ class CarlaHeapRingBuffer : public CarlaRingBufferControl<HeapBuffer>
{
public:
CarlaHeapRingBuffer() noexcept
: fHeapBuffer{0, 0, 0, 0, false, nullptr}
{
carla_zeroStruct(fHeapBuffer);
}
: fHeapBuffer{0, 0, 0, 0, false, nullptr} {}

~CarlaHeapRingBuffer() noexcept override
{
@@ -516,7 +529,7 @@ public:
fHeapBuffer.buf = nullptr;
}

void createBuffer(const uint32_t size) noexcept
void createBuffer(const uint32_t size, const bool mlock) noexcept
{
CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf == nullptr,);
CARLA_SAFE_ASSERT_RETURN(size > 0,);
@@ -529,11 +542,18 @@ public:

fHeapBuffer.size = p2size;
setRingBuffer(&fHeapBuffer, true);

if (mlock)
{
carla_mlock(&fHeapBuffer, sizeof(fHeapBuffer));
carla_mlock(fHeapBuffer.buf, p2size);
}
}

void deleteBuffer() noexcept
{
CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf != nullptr,);
if (fHeapBuffer.buf == nullptr)
return;

setRingBuffer(nullptr, false);



+ 2
- 0
source/utils/CarlaShmUtils.hpp View File

@@ -208,6 +208,8 @@ void* carla_shm_map(carla_shm_t& shm, const std::size_t size) noexcept
return nullptr;
}

::VirtualLock(ptr, size);

shm.map = map;
return ptr;
#else


+ 19
- 16
source/utils/Lv2AtomRingBuffer.hpp View File

@@ -1,6 +1,6 @@
/*
* LV2 Atom Ring Buffer
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,26 +23,23 @@

#include "lv2/atom.h"

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

class Lv2AtomRingBuffer : public CarlaRingBufferControl<HeapBuffer>
{
public:
Lv2AtomRingBuffer() noexcept
: fMutex(),
fHeapBuffer(HeapBuffer_INIT),
fHeapBuffer{0, 0, 0, 0, false, nullptr},
fNeedsDataDelete(true)
{
carla_zeroStruct(fHeapBuffer);
}

Lv2AtomRingBuffer(Lv2AtomRingBuffer& ringBuf, uint8_t buf[]) noexcept
: fMutex(),
fHeapBuffer(HeapBuffer_INIT),
fHeapBuffer{0, 0, 0, 0, false, nullptr},
fNeedsDataDelete(false)
{
carla_zeroStruct(fHeapBuffer);

fHeapBuffer.buf = buf;
fHeapBuffer.size = ringBuf.fHeapBuffer.size;

@@ -64,15 +61,15 @@ public:
fHeapBuffer.buf = nullptr;
}

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

void createBuffer(const uint32_t size) noexcept
void createBuffer(const uint32_t size, const bool mlock) noexcept
{
CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf == nullptr,);
CARLA_SAFE_ASSERT_RETURN(fNeedsDataDelete,);
CARLA_SAFE_ASSERT_RETURN(size > 0,);

const uint32_t p2size(carla_nextPowerOf2(size));
const uint32_t p2size = carla_nextPowerOf2(size);

try {
fHeapBuffer.buf = new uint8_t[p2size];
@@ -80,6 +77,12 @@ public:

fHeapBuffer.size = p2size;
setRingBuffer(&fHeapBuffer, true);

if (mlock)
{
carla_mlock(&fHeapBuffer, sizeof(fHeapBuffer));
carla_mlock(fHeapBuffer.buf, p2size);
}
}

void deleteBuffer() noexcept
@@ -99,7 +102,7 @@ public:
return fHeapBuffer.size;
}

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

bool tryLock() const noexcept
{
@@ -111,7 +114,7 @@ public:
fMutex.unlock();
}

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

// NOTE: must have been locked before
bool get(uint32_t& portIndex, LV2_Atom* const retAtom) noexcept
@@ -145,7 +148,7 @@ public:
}

protected:
// -------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------

bool readAtom(uint32_t& portIndex, LV2_Atom* const retAtom) noexcept
{
@@ -175,7 +178,7 @@ protected:
return true;
}

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

bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex) noexcept
{
@@ -191,7 +194,7 @@ protected:
return commitWrite();
}

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

private:
CarlaMutex fMutex;
@@ -204,6 +207,6 @@ private:
CARLA_DECLARE_NON_COPYABLE(Lv2AtomRingBuffer)
};

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

#endif // LV2_ATOM_RING_BUFFER_HPP_INCLUDED

Loading…
Cancel
Save