@@ -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; | |||