From 8afab56952ba0c25618fe16e3b45cdee06354f99 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 6 Feb 2021 14:49:43 +0000 Subject: [PATCH] send audiofile preview as lv2 vector Signed-off-by: falkTX --- source/includes/CarlaNative.h | 3 +- source/includes/CarlaNative.hpp | 7 ++ source/native-plugins/audio-base.hpp | 34 +++++-- source/native-plugins/audio-file.cpp | 17 +++- source/plugin/carla-lv2.cpp | 128 ++++++++++++++++++++------- source/utils/CarlaLv2Utils.hpp | 3 + 6 files changed, 151 insertions(+), 41 deletions(-) diff --git a/source/includes/CarlaNative.h b/source/includes/CarlaNative.h index 51e855d1e..ab228b808 100644 --- a/source/includes/CarlaNative.h +++ b/source/includes/CarlaNative.h @@ -117,7 +117,8 @@ typedef enum { NATIVE_HOST_OPCODE_UI_TOUCH_PARAMETER = 10, /** uses index, value as bool */ NATIVE_HOST_OPCODE_REQUEST_IDLE = 11, /** nothing */ NATIVE_HOST_OPCODE_GET_FILE_PATH = 12, /** uses ptr as string for file type */ - NATIVE_HOST_OPCODE_UI_RESIZE = 13 /** uses index and value */ + NATIVE_HOST_OPCODE_UI_RESIZE = 13, /** uses index and value */ + NATIVE_HOST_OPCODE_PREVIEW_BUFFER_DATA = 14 /** uses index as type, value as size, and ptr */ } NativeHostDispatcherOpcode; /* ------------------------------------------------------------------------------------------------------------ diff --git a/source/includes/CarlaNative.hpp b/source/includes/CarlaNative.hpp index ec4c222a2..d21a3b5fa 100644 --- a/source/includes/CarlaNative.hpp +++ b/source/includes/CarlaNative.hpp @@ -250,6 +250,13 @@ protected: 0.0f); } + void hostSendPreviewBufferData(const char type, const uint32_t size, const void* const buffer) + { + CARLA_SAFE_ASSERT_RETURN(pHost != nullptr,); + + pHost->dispatcher(pHost->handle, NATIVE_HOST_OPCODE_PREVIEW_BUFFER_DATA, type, size, (void*)buffer, 0.0f); + } + // ------------------------------------------------------------------- // Plugin parameter calls diff --git a/source/native-plugins/audio-base.hpp b/source/native-plugins/audio-base.hpp index 61df9b3fc..4b8ec9bbd 100644 --- a/source/native-plugins/audio-base.hpp +++ b/source/native-plugins/audio-base.hpp @@ -271,7 +271,8 @@ public: fNeedsRead = true; } - bool loadFilename(const char* const filename, const uint32_t sampleRate) + bool loadFilename(const char* const filename, const uint32_t sampleRate, + const uint32_t previewDataSize, float* previewData) { CARLA_SAFE_ASSERT_RETURN(filename != nullptr && *filename != '\0', false); @@ -329,6 +330,15 @@ public: readEntireFileIntoPool(needsResample); ad_close(fFilePtr); fFilePtr = nullptr; + + const float fileNumFramesF = static_cast(fileNumFrames); + const float previewDataSizeF = static_cast(previewDataSize); + for (uint i=0; i(i)/previewDataSizeF * fileNumFramesF; + const uint step = carla_fixedValue(0U, fileNumFrames-1U, static_cast(stepF + 0.5f)); + previewData[i] = fPool.buffer[0][step]; + } } else { @@ -337,6 +347,8 @@ public: const uint pollTempSize = poolNumFrames * fFileNfo.channels; uint resampleTempSize = 0; + carla_zeroFloats(previewData, 300); + fPool.create(poolNumFrames, true); try { @@ -392,14 +404,24 @@ public: } } - void putAllData(AudioFilePool& pool) + void putAndSwapAllData(AudioFilePool& pool) { - const water::GenericScopedLock gsl(fPool.mutex); - CARLA_SAFE_ASSERT_RETURN(pool.numFrames == fPool.numFrames,); + const water::GenericScopedLock gsl1(fPool.mutex); + const water::GenericScopedLock gsl2(pool.mutex); + CARLA_SAFE_ASSERT_RETURN(fPool.numFrames != 0,); + CARLA_SAFE_ASSERT_RETURN(pool.numFrames == 0,); + CARLA_SAFE_ASSERT_RETURN(fPool.tmpbuf[0] == nullptr,); + CARLA_SAFE_ASSERT_RETURN(pool.tmpbuf[0] == nullptr,); pool.startFrame = fPool.startFrame; - carla_copyFloats(pool.buffer[0], fPool.buffer[0], fPool.numFrames); - carla_copyFloats(pool.buffer[1], fPool.buffer[1], fPool.numFrames); + pool.numFrames = fPool.numFrames; + pool.buffer[0] = fPool.buffer[0]; + pool.buffer[1] = fPool.buffer[1]; + + fPool.startFrame = 0; + fPool.numFrames = 0; + fPool.buffer[0] = nullptr; + fPool.buffer[1] = nullptr; } bool tryPutData(float* const out1, diff --git a/source/native-plugins/audio-file.cpp b/source/native-plugins/audio-file.cpp index ef3ea336e..2a4a4ce02 100644 --- a/source/native-plugins/audio-file.cpp +++ b/source/native-plugins/audio-file.cpp @@ -75,7 +75,8 @@ public: fMaxFrame(0), fPool(), fReader(), - fPrograms(hostGetFilePath("audio"), audiofilesWildcard) + fPrograms(hostGetFilePath("audio"), audiofilesWildcard), + fPreviewData() #ifndef __MOD_DEVICES__ , fInlineDisplay() #endif @@ -551,6 +552,7 @@ private: AudioFileReader fReader; NativeMidiPrograms fPrograms; + float fPreviewData[300]; #ifndef __MOD_DEVICES__ struct InlineDisplay : NativeInlineDisplayImageSurfaceCompat { @@ -603,17 +605,24 @@ private: return; } - if (fReader.loadFilename(filename, static_cast(getSampleRate()))) + const uint32_t previewDataSize = sizeof(fPreviewData)/sizeof(float); + + if (fReader.loadFilename(filename, static_cast(getSampleRate()), previewDataSize, fPreviewData)) { - fPool.create(fReader.getPoolNumFrames(), false); fMaxFrame = fReader.getMaxFrame(); if (fReader.isEntireFileLoaded()) - fReader.putAllData(fPool); + { + fReader.putAndSwapAllData(fPool); + } else + { + fPool.create(fReader.getPoolNumFrames(), false); fReader.readPoll(); + } fDoProcess = true; + hostSendPreviewBufferData('f', previewDataSize, fPreviewData); } else { diff --git a/source/plugin/carla-lv2.cpp b/source/plugin/carla-lv2.cpp index b2b145b14..8cbb2d4cc 100644 --- a/source/plugin/carla-lv2.cpp +++ b/source/plugin/carla-lv2.cpp @@ -34,6 +34,19 @@ void Lv2PluginBaseClass::clearTimeData() noexcept carla_zeroStruct(fTimeInfo); } +struct PreviewData { + char type; + uint32_t size; + const void* buffer; + bool shouldSend; + + PreviewData() + : type(0), + size(0), + buffer(nullptr), + shouldSend(false) {} +}; + // -------------------------------------------------------------------------------------------------------------------- // Carla Internal Plugin API exposed as LV2 plugin @@ -58,6 +71,7 @@ public: fMidiEventCount(0), fLastProjectPath(), fLoadedFile(), + fPreviewData(), fNeedsNotifyFileChanged(false), fPluginNeedsIdle(0), fWorkerUISignal(0) @@ -298,6 +312,8 @@ public: { if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) fNeedsNotifyFileChanged = true; + if (fPreviewData.buffer != nullptr) + fPreviewData.shouldSend = true; } continue; } @@ -328,51 +344,88 @@ public: } } - if (fNeedsNotifyFileChanged) + if (fNeedsNotifyFileChanged || fPreviewData.shouldSend) { - fNeedsNotifyFileChanged = false; - uint8_t atomBuf[4096]; LV2_Atom_Forge atomForge = fAtomForge; lv2_atom_forge_set_buffer(&atomForge, atomBuf, sizeof(atomBuf)); - LV2_Atom_Forge_Frame forgeFrame; - lv2_atom_forge_object(&atomForge, &forgeFrame, 0, fURIs.patchSet); + const int numEvents = fNeedsNotifyFileChanged && fPreviewData.shouldSend ? 2 : 1; + + if (fNeedsNotifyFileChanged) + { + fNeedsNotifyFileChanged = false; + + LV2_Atom_Forge_Frame forgeFrame; + lv2_atom_forge_object(&atomForge, &forgeFrame, 0, fURIs.patchSet); + + lv2_atom_forge_key(&atomForge, fURIs.patchProperty); - lv2_atom_forge_key(&atomForge, fURIs.patchProperty); + /* */ if (std::strcmp(fDescriptor->label, "audiofile") == 0) { + lv2_atom_forge_urid(&atomForge, fURIs.carlaFileAudio); + } else if (std::strcmp(fDescriptor->label, "midifile") == 0) { + lv2_atom_forge_urid(&atomForge, fURIs.carlaFileMIDI); + } else { + lv2_atom_forge_urid(&atomForge, fURIs.carlaFile); + } + + lv2_atom_forge_key(&atomForge, fURIs.patchValue); + lv2_atom_forge_path(&atomForge, + fLoadedFile.buffer(), + static_cast(fLoadedFile.length()+1)); - /* */ if (std::strcmp(fDescriptor->label, "audiofile") == 0) { - lv2_atom_forge_urid(&atomForge, fURIs.carlaFileAudio); - } else if (std::strcmp(fDescriptor->label, "midifile") == 0) { - lv2_atom_forge_urid(&atomForge, fURIs.carlaFileMIDI); - } else { - lv2_atom_forge_urid(&atomForge, fURIs.carlaFile); + lv2_atom_forge_pop(&atomForge, &forgeFrame); } - lv2_atom_forge_key(&atomForge, fURIs.patchValue); - lv2_atom_forge_path(&atomForge, - fLoadedFile.buffer(), - static_cast(fLoadedFile.length()+1)); + if (fPreviewData.shouldSend) + { + const char ptype = fPreviewData.type; + const uint32_t psize = fPreviewData.size; + const void* const pbuffer = fPreviewData.buffer; + fPreviewData.shouldSend = false; + + LV2_Atom_Forge_Frame forgeFrame; + lv2_atom_forge_object(&atomForge, &forgeFrame, 0, fURIs.patchSet); - lv2_atom_forge_pop(&atomForge, &forgeFrame); + lv2_atom_forge_key(&atomForge, fURIs.patchProperty); + lv2_atom_forge_urid(&atomForge, fURIs.carlaPreview); + + lv2_atom_forge_key(&atomForge, fURIs.patchValue); + + switch (ptype) + { + case 'f': + lv2_atom_forge_vector(&atomForge, sizeof(float), fURIs.atomFloat, psize, pbuffer); + break; + default: + carla_stderr2("Preview data buffer has wrong type '%c' (and size %u)", ptype, psize); + break; + } - LV2_Atom* const atom = (LV2_Atom*)atomBuf; + lv2_atom_forge_pop(&atomForge, &forgeFrame); + } + LV2_Atom* atom = (LV2_Atom*)atomBuf; LV2_Atom_Sequence* const seq = fPorts.eventsOut[0]; Ports::EventsOutData& mData(fPorts.eventsOutData[0]); - if (sizeof(LV2_Atom_Event) + atom->size <= mData.capacity - mData.offset) + for (int i=0; isize <= mData.capacity - mData.offset) + { + LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq) + mData.offset); + + aev->time.frames = 0; + aev->body.size = atom->size; + aev->body.type = atom->type; + std::memcpy(LV2_ATOM_BODY(&aev->body), atom + 1, atom->size); - aev->time.frames = 0; - aev->body.size = atom->size; - aev->body.type = atom->type; - std::memcpy(LV2_ATOM_BODY(&aev->body), atom + 1, atom->size); + const uint32_t size = lv2_atom_pad_size(static_cast(sizeof(LV2_Atom_Event) + atom->size)); + mData.offset += size; + seq->atom.size += size; + } - const uint32_t size = lv2_atom_pad_size(static_cast(sizeof(LV2_Atom_Event) + atom->size)); - mData.offset += size; - seq->atom.size += size; + atom = (LV2_Atom*)(atomBuf + lv2_atom_total_size(atom)); } } } @@ -940,6 +993,14 @@ protected: // nothing here } + void handlePreviewBufferData(const char type, const uint32_t size, const void* const buffer) noexcept + { + fPreviewData.type = type; + fPreviewData.size = size; + fPreviewData.buffer = buffer; + fPreviewData.shouldSend = true; + } + void handleUiCustomDataChanged(const char* const key, const char* const value) const { carla_stdout("TODO: handleUiCustomDataChanged %s %s", key, value); @@ -1039,14 +1100,20 @@ protected: CARLA_SAFE_ASSERT_RETURN(value > 0, 0); handleUiResize(static_cast(index), static_cast(value)); break; + + case NATIVE_HOST_OPCODE_PREVIEW_BUFFER_DATA: + CARLA_SAFE_ASSERT_RETURN(index != 0, 0); + CARLA_SAFE_ASSERT_RETURN(index >= 'a', 0); + CARLA_SAFE_ASSERT_RETURN(index <= 'z', 0); + CARLA_SAFE_ASSERT_RETURN(value > 0, 0); + CARLA_SAFE_ASSERT_RETURN(ptr != nullptr, 0); + handlePreviewBufferData(static_cast(index), static_cast(value), (const void*)ptr); + break; } return ret; // unused for now - (void)index; - (void)value; - (void)ptr; (void)opt; } @@ -1084,6 +1151,7 @@ private: CarlaString fLastProjectPath; CarlaString fLoadedFile; + PreviewData fPreviewData; volatile bool fNeedsNotifyFileChanged; volatile int fPluginNeedsIdle; diff --git a/source/utils/CarlaLv2Utils.hpp b/source/utils/CarlaLv2Utils.hpp index 8a0ff70a2..0a12d52ab 100644 --- a/source/utils/CarlaLv2Utils.hpp +++ b/source/utils/CarlaLv2Utils.hpp @@ -1522,6 +1522,7 @@ protected: LV2_URID carlaFile; LV2_URID carlaFileAudio; LV2_URID carlaFileMIDI; + LV2_URID carlaPreview; LV2_URID midiEvent; LV2_URID patchProperty; LV2_URID patchGet; @@ -1553,6 +1554,7 @@ protected: carlaFile(0), carlaFileAudio(0), carlaFileMIDI(0), + carlaPreview(0), midiEvent(0), patchProperty(0), patchGet(0), @@ -1585,6 +1587,7 @@ protected: carlaFile = uridMap->map(uridMap->handle, "http://kxstudio.sf.net/carla/file"); carlaFileAudio = uridMap->map(uridMap->handle, "http://kxstudio.sf.net/carla/file/audio"); carlaFileMIDI = uridMap->map(uridMap->handle, "http://kxstudio.sf.net/carla/file/midi"); + carlaPreview = uridMap->map(uridMap->handle, "http://kxstudio.sf.net/carla/preview"); midiEvent = uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent); patchProperty = uridMap->map(uridMap->handle, LV2_PATCH__property); patchGet = uridMap->map(uridMap->handle, LV2_PATCH__Get);