| @@ -19,6 +19,7 @@ | |||
| #define __CARLA_NATIVE_H__ | |||
| #ifdef __cplusplus | |||
| # include <cstddef> | |||
| # include <cstdint> | |||
| extern "C" { | |||
| #else | |||
| @@ -54,7 +55,8 @@ typedef enum _PluginHints { | |||
| PLUGIN_IS_RTSAFE = 1 << 0, | |||
| PLUGIN_IS_SYNTH = 1 << 1, | |||
| PLUGIN_HAS_GUI = 1 << 2, | |||
| PLUGIN_USES_SINGLE_THREAD = 1 << 3 | |||
| PLUGIN_USES_CHUNKS = 1 << 3, | |||
| PLUGIN_USES_SINGLE_THREAD = 1 << 4 | |||
| } PluginHints; | |||
| typedef enum _ParameterHints { | |||
| @@ -100,7 +102,8 @@ typedef struct _Parameter { | |||
| typedef struct _MidiEvent { | |||
| uint8_t port; | |||
| uint32_t time; | |||
| uint8_t data[3]; | |||
| uint8_t data[4]; | |||
| uint8_t size; | |||
| } MidiEvent; | |||
| typedef struct _MidiProgram { | |||
| @@ -189,6 +192,9 @@ typedef struct _PluginDescriptor { | |||
| void (*deactivate)(PluginHandle handle); | |||
| void (*process)(PluginHandle handle, float** inBuffer, float** outBuffer, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents); | |||
| size_t (*get_chunk)(PluginHandle handle, void** data); | |||
| void (*set_chunk)(PluginHandle handle, void* data, size_t size); | |||
| } PluginDescriptor; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -129,7 +129,6 @@ protected: | |||
| virtual const Parameter* getParameterInfo(const uint32_t index) | |||
| { | |||
| CARLA_ASSERT(index < getParameterCount()); | |||
| return nullptr; | |||
| // unused | |||
| @@ -139,7 +138,6 @@ protected: | |||
| virtual float getParameterValue(const uint32_t index) | |||
| { | |||
| CARLA_ASSERT(index < getParameterCount()); | |||
| return 0.0f; | |||
| // unused | |||
| @@ -149,7 +147,6 @@ protected: | |||
| virtual const char* getParameterText(const uint32_t index) | |||
| { | |||
| CARLA_ASSERT(index < getParameterCount()); | |||
| return nullptr; | |||
| // unused | |||
| @@ -167,7 +164,6 @@ protected: | |||
| virtual const MidiProgram* getMidiProgramInfo(const uint32_t index) | |||
| { | |||
| CARLA_ASSERT(index < getMidiProgramCount()); | |||
| return nullptr; | |||
| // unused | |||
| @@ -180,7 +176,6 @@ protected: | |||
| virtual void setParameterValue(const uint32_t index, const float value) | |||
| { | |||
| CARLA_ASSERT(index < getParameterCount()); | |||
| return; | |||
| // unused | |||
| @@ -199,14 +194,13 @@ protected: | |||
| virtual void setCustomData(const char* const key, const char* const value) | |||
| { | |||
| CARLA_ASSERT(key); | |||
| CARLA_ASSERT(value); | |||
| CARLA_ASSERT(key != nullptr); | |||
| CARLA_ASSERT(value != nullptr); | |||
| return; | |||
| // unused | |||
| CARLA_ASSERT(key); | |||
| CARLA_ASSERT(value); | |||
| (void)key; | |||
| (void)value; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| @@ -240,7 +234,6 @@ protected: | |||
| virtual void uiSetParameterValue(const uint32_t index, const float value) | |||
| { | |||
| CARLA_ASSERT(index < getParameterCount()); | |||
| return; | |||
| // unused | |||
| @@ -258,9 +251,8 @@ protected: | |||
| virtual void uiSetCustomData(const char* const key, const char* const value) | |||
| { | |||
| CARLA_ASSERT(key); | |||
| CARLA_ASSERT(value); | |||
| CARLA_ASSERT(key != nullptr); | |||
| CARLA_ASSERT(value != nullptr); | |||
| return; | |||
| // unused | |||
| @@ -269,6 +261,24 @@ protected: | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin chunk calls | |||
| virtual size_t getChunk(void** const data) | |||
| { | |||
| CARLA_ASSERT(data != nullptr); | |||
| return 0; | |||
| // unused | |||
| (void)data; | |||
| } | |||
| virtual void setChunk(void* const data, const size_t size) | |||
| { | |||
| CARLA_ASSERT(data != nullptr); | |||
| CARLA_ASSERT(size > 0); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| private: | |||
| const HostDescriptor* const kHost; | |||
| @@ -364,6 +374,16 @@ public: | |||
| return handlePtr->process(inBuffer, outBuffer, frames, midiEventCount, midiEvents); | |||
| } | |||
| static size_t _get_chunk(PluginHandle handle, void** data) | |||
| { | |||
| return handlePtr->getChunk(data); | |||
| } | |||
| static void _set_chunk(PluginHandle handle, void* data, size_t size) | |||
| { | |||
| handlePtr->setChunk(data, size); | |||
| } | |||
| #undef handlePtr | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginDescriptorClass) | |||
| @@ -404,6 +424,8 @@ public: | |||
| className::_ui_set_custom_data, \ | |||
| className::_activate, \ | |||
| className::_deactivate, \ | |||
| className::_process | |||
| className::_process, \ | |||
| className::_get_chunk, \ | |||
| className::_set_chunk | |||
| #endif // __CARLA_NATIVE_HPP__ | |||
| @@ -417,6 +417,9 @@ static float audiofile_get_parameter_value(PluginHandle handle, uint32_t index) | |||
| static uint32_t audiofile_get_program_count(PluginHandle handle) | |||
| { | |||
| return PROGRAM_COUNT; | |||
| // unused | |||
| (void)handle; | |||
| } | |||
| const MidiProgram* audiofile_get_program_info(PluginHandle handle, uint32_t index) | |||
| @@ -642,7 +645,10 @@ static const PluginDescriptor audiofileDesc = { | |||
| .activate = NULL, | |||
| .deactivate = NULL, | |||
| .process = audiofile_process | |||
| .process = audiofile_process, | |||
| .get_chunk = NULL, | |||
| .set_chunk = NULL | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -83,7 +83,10 @@ static const PluginDescriptor bypassDesc = { | |||
| .activate = NULL, | |||
| .deactivate = NULL, | |||
| .process = bypass_process | |||
| .process = bypass_process, | |||
| .get_chunk = NULL, | |||
| .set_chunk = NULL | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -117,7 +117,10 @@ static const PluginDescriptor midiSplitDesc = { | |||
| .activate = NULL, | |||
| .deactivate = NULL, | |||
| .process = midiSplit_process | |||
| .process = midiSplit_process, | |||
| .get_chunk = NULL, | |||
| .set_chunk = NULL | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -100,7 +100,10 @@ static const PluginDescriptor midiThroughDesc = { | |||
| .activate = NULL, | |||
| .deactivate = NULL, | |||
| .process = midiThrough_process | |||
| .process = midiThrough_process, | |||
| .get_chunk = NULL, | |||
| .set_chunk = NULL | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -180,7 +180,10 @@ static const PluginDescriptor midiTransposeDesc = { | |||
| .activate = NULL, | |||
| .deactivate = NULL, | |||
| .process = midiTranspose_process | |||
| .process = midiTranspose_process, | |||
| .get_chunk = NULL, | |||
| .set_chunk = NULL | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -62,7 +62,10 @@ static const PluginDescriptor nekofilterDesc = { | |||
| .activate = NULL, | |||
| .deactivate = NULL, | |||
| .process = nekofilter_process | |||
| .process = nekofilter_process, | |||
| .get_chunk = NULL, | |||
| .set_chunk = NULL | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -58,6 +58,15 @@ public: | |||
| kSampleRate(getSampleRate()) | |||
| { | |||
| _maybeInitPrograms(kMaster); | |||
| // pre-run to create static data | |||
| { | |||
| const size_t bufSize = getBufferSize(); | |||
| float out[bufSize]; | |||
| carla_stdout("BEFORE %li %i", bufSize, kSampleRate); | |||
| //kMaster->GetAudioOutSamples(bufSize, kSampleRate, out, out); | |||
| carla_stdout("AFTER %li %i", bufSize, kSampleRate); | |||
| } | |||
| } | |||
| ~ZynAddSubFxPlugin() | |||
| @@ -197,13 +206,15 @@ protected: | |||
| void process(float**, float** const outBuffer, const uint32_t frames, const uint32_t midiEventCount, const MidiEvent* const midiEvents) | |||
| { | |||
| if (pthread_mutex_trylock(&kMaster->mutex) != 0) | |||
| //if (pthread_mutex_trylock(&kMaster->mutex) != 0) | |||
| { | |||
| carla_zeroFloat(outBuffer[0], frames); | |||
| carla_zeroFloat(outBuffer[1], frames); | |||
| return; | |||
| } | |||
| pthread_mutex_lock(&kMaster->mutex); | |||
| for (uint32_t i=0; i < midiEventCount; i++) | |||
| { | |||
| const MidiEvent* const midiEvent = &midiEvents[i]; | |||
| @@ -239,6 +250,19 @@ protected: | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Plugin chunk calls | |||
| size_t getChunk(void** const data) | |||
| { | |||
| return kMaster->getalldata((char**)data); | |||
| } | |||
| void setChunk(void* const data, const size_t size) | |||
| { | |||
| kMaster->putalldata((char*)data, size); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| private: | |||
| struct ProgramInfo { | |||
| @@ -276,7 +300,10 @@ public: | |||
| { | |||
| if (sInstanceCount++ == 0) | |||
| { | |||
| synth = new SYNTH_T; | |||
| CARLA_ASSERT(synth == nullptr); | |||
| CARLA_ASSERT(denormalkillbuf == nullptr); | |||
| synth = new SYNTH_T(); | |||
| synth->buffersize = host->get_buffer_size(host->handle); | |||
| synth->samplerate = host->get_sample_rate(host->handle); | |||
| synth->alias(); | |||
| @@ -284,12 +311,14 @@ public: | |||
| config.init(); | |||
| config.cfg.SoundBufferSize = synth->buffersize; | |||
| config.cfg.SampleRate = synth->samplerate; | |||
| //config.cfg.GzipCompression = 0; | |||
| config.cfg.GzipCompression = 0; | |||
| sprng(std::time(nullptr)); | |||
| denormalkillbuf = new float[synth->buffersize]; | |||
| for (int i=0; i < synth->buffersize; i++) | |||
| denormalkillbuf[i] = (RND - 0.5f) * 1e-16; | |||
| Master::getInstance(); | |||
| } | |||
| return new ZynAddSubFxPlugin(host); | |||
| @@ -301,6 +330,11 @@ public: | |||
| if (--sInstanceCount == 0) | |||
| { | |||
| CARLA_ASSERT(synth != nullptr); | |||
| CARLA_ASSERT(denormalkillbuf != nullptr); | |||
| Master::deleteInstance(); | |||
| delete[] denormalkillbuf; | |||
| denormalkillbuf = nullptr; | |||
| @@ -354,7 +388,7 @@ NonRtList<ZynAddSubFxPlugin::ProgramInfo*> ZynAddSubFxPlugin::sPrograms; | |||
| static const PluginDescriptor zynAddSubFxDesc = { | |||
| /* category */ PLUGIN_CATEGORY_SYNTH, | |||
| /* hints */ PLUGIN_IS_SYNTH, | |||
| /* hints */ static_cast<PluginHints>(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS), | |||
| /* audioIns */ 2, | |||
| /* audioOuts */ 2, | |||
| /* midiIns */ 1, | |||
| @@ -240,6 +240,21 @@ public: | |||
| return 0; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Information (current data) | |||
| int32_t chunkData(void** const dataPtr) | |||
| { | |||
| CARLA_ASSERT(fOptions & PLUGIN_OPTION_USE_CHUNKS); | |||
| CARLA_ASSERT(fDescriptor != nullptr); | |||
| CARLA_ASSERT(fHandle != nullptr); | |||
| if (fDescriptor != nullptr && fHandle != nullptr) | |||
| return fDescriptor->get_chunk(fHandle, dataPtr); | |||
| return 0; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Information (per-plugin data) | |||
| @@ -264,6 +279,9 @@ public: | |||
| options |= PLUGIN_OPTION_FIXED_BUFFER; | |||
| options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES; | |||
| if (fDescriptor->hints & ::PLUGIN_USES_CHUNKS) | |||
| options |= PLUGIN_OPTION_USE_CHUNKS; | |||
| //if ((kData->audioIns.count() == 1 || kData->audioOuts.count() == 0) || (kData->audioIns.count() == 0 || kData->audioOuts.count() == 1)) | |||
| // options |= PLUGIN_OPTION_FORCE_STEREO; | |||
| @@ -498,6 +516,20 @@ public: | |||
| CarlaPlugin::setCustomData(type, key, value, sendGui); | |||
| } | |||
| void setChunkData(const char* const stringData) | |||
| { | |||
| CARLA_ASSERT(fDescriptor != nullptr); | |||
| CARLA_ASSERT(fHandle != nullptr); | |||
| CARLA_ASSERT(stringData != nullptr); | |||
| // FIXME | |||
| fChunk = QByteArray::fromBase64(QByteArray(stringData)); | |||
| //fChunk.toBase64(); | |||
| const ScopedProcessLocker spl(this, true); | |||
| fDescriptor->set_chunk(fHandle, fChunk.data(), fChunk.size()); | |||
| } | |||
| void setMidiProgram(int32_t index, const bool sendGui, const bool sendOsc, const bool sendCallback) | |||
| { | |||
| CARLA_ASSERT(fDescriptor != nullptr); | |||
| @@ -943,6 +975,9 @@ public: | |||
| if (forcedStereoIn || forcedStereoOut) | |||
| fOptions |= PLUGIN_OPTION_FORCE_STEREO; | |||
| if (fDescriptor->hints & ::PLUGIN_USES_CHUNKS) | |||
| fOptions |= PLUGIN_OPTION_USE_CHUNKS; | |||
| if (mIns > 0) | |||
| { | |||
| fOptions |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE; | |||
| @@ -1980,6 +2015,7 @@ private: | |||
| bool fIsProcessing; | |||
| bool fIsUiVisible; | |||
| QByteArray fChunk; | |||
| float** fAudioInBuffers; | |||
| float** fAudioOutBuffers; | |||
| uint32_t fMidiEventCount; | |||