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