|
@@ -96,6 +96,452 @@ void set_module_parameters(Fl_Widget* o) |
|
|
} |
|
|
} |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
|
|
|
class ZynAddSubFxPrograms |
|
|
|
|
|
{ |
|
|
|
|
|
public: |
|
|
|
|
|
ZynAddSubFxPrograms() |
|
|
|
|
|
: fInitiated(false) |
|
|
|
|
|
{ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
~ZynAddSubFxPrograms() |
|
|
|
|
|
{ |
|
|
|
|
|
if (! fInitiated) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
for (auto it = fPrograms.begin(); it.valid(); it.next()) |
|
|
|
|
|
{ |
|
|
|
|
|
const ProgramInfo*& pInfo(*it); |
|
|
|
|
|
delete pInfo; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fPrograms.clear(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void init(Master& master) |
|
|
|
|
|
{ |
|
|
|
|
|
if (fInitiated) |
|
|
|
|
|
return; |
|
|
|
|
|
fInitiated = true; |
|
|
|
|
|
|
|
|
|
|
|
fPrograms.append(new ProgramInfo(0, 0, "default")); |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&master.mutex); |
|
|
|
|
|
|
|
|
|
|
|
// refresh banks |
|
|
|
|
|
master.bank.rescanforbanks(); |
|
|
|
|
|
|
|
|
|
|
|
for (uint32_t i=0, size = master.bank.banks.size(); i < size; ++i) |
|
|
|
|
|
{ |
|
|
|
|
|
if (master.bank.banks[i].dir.empty()) |
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
master.bank.loadbank(master.bank.banks[i].dir); |
|
|
|
|
|
|
|
|
|
|
|
for (unsigned int instrument = 0; instrument < BANK_SIZE; ++instrument) |
|
|
|
|
|
{ |
|
|
|
|
|
const std::string insName(master.bank.getname(instrument)); |
|
|
|
|
|
|
|
|
|
|
|
if (insName.empty() || insName[0] == '\0' || insName[0] == ' ') |
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
fPrograms.append(new ProgramInfo(i+1, instrument, insName.c_str())); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&master.mutex); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void load(Master* const master, const uint8_t channel, const uint32_t bank, const uint32_t program) |
|
|
|
|
|
{ |
|
|
|
|
|
if (bank == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
pthread_mutex_lock(&master->mutex); |
|
|
|
|
|
|
|
|
|
|
|
master->partonoff(channel, 1); |
|
|
|
|
|
master->part[channel]->defaults(); |
|
|
|
|
|
master->part[channel]->applyparameters(false); |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&master->mutex); |
|
|
|
|
|
|
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const std::string& bankdir(master->bank.banks[bank-1].dir); |
|
|
|
|
|
|
|
|
|
|
|
if (! bankdir.empty()) |
|
|
|
|
|
{ |
|
|
|
|
|
pthread_mutex_lock(&master->mutex); |
|
|
|
|
|
|
|
|
|
|
|
master->partonoff(channel, 1); |
|
|
|
|
|
|
|
|
|
|
|
master->bank.loadbank(bankdir); |
|
|
|
|
|
master->bank.loadfromslot(program, master->part[channel]); |
|
|
|
|
|
|
|
|
|
|
|
master->part[channel]->applyparameters(false); |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&master->mutex); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint32_t count() |
|
|
|
|
|
{ |
|
|
|
|
|
return fPrograms.count(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const MidiProgram* getInfo(const uint32_t index) |
|
|
|
|
|
{ |
|
|
|
|
|
if (index >= fPrograms.count()) |
|
|
|
|
|
return nullptr; |
|
|
|
|
|
|
|
|
|
|
|
const ProgramInfo*& pInfo(fPrograms.getAt(index)); |
|
|
|
|
|
|
|
|
|
|
|
fRetProgram.bank = pInfo->bank; |
|
|
|
|
|
fRetProgram.program = pInfo->prog; |
|
|
|
|
|
fRetProgram.name = pInfo->name; |
|
|
|
|
|
|
|
|
|
|
|
return &fRetProgram; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
struct ProgramInfo { |
|
|
|
|
|
uint32_t bank; |
|
|
|
|
|
uint32_t prog; |
|
|
|
|
|
const char* name; |
|
|
|
|
|
|
|
|
|
|
|
ProgramInfo(uint32_t bank_, uint32_t prog_, const char* name_) |
|
|
|
|
|
: bank(bank_), |
|
|
|
|
|
prog(prog_), |
|
|
|
|
|
name(carla_strdup(name_)) {} |
|
|
|
|
|
|
|
|
|
|
|
~ProgramInfo() |
|
|
|
|
|
{ |
|
|
|
|
|
if (name != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
delete[] name; |
|
|
|
|
|
name = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef CARLA_PROPER_CPP11_SUPPORT |
|
|
|
|
|
ProgramInfo() = delete; |
|
|
|
|
|
ProgramInfo(ProgramInfo&) = delete; |
|
|
|
|
|
ProgramInfo(const ProgramInfo&) = delete; |
|
|
|
|
|
#endif |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
bool fInitiated; |
|
|
|
|
|
MidiProgram fRetProgram; |
|
|
|
|
|
NonRtList<const ProgramInfo*> fPrograms; |
|
|
|
|
|
|
|
|
|
|
|
CARLA_DECLARE_NON_COPYABLE(ZynAddSubFxPrograms) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static ZynAddSubFxPrograms sPrograms; |
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
|
|
|
class ZynAddSubFxInstanceCount |
|
|
|
|
|
{ |
|
|
|
|
|
public: |
|
|
|
|
|
ZynAddSubFxInstanceCount() |
|
|
|
|
|
: fCount(0) |
|
|
|
|
|
{ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
~ZynAddSubFxInstanceCount() |
|
|
|
|
|
{ |
|
|
|
|
|
CARLA_ASSERT(fCount == 0); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void addOne(HostDescriptor* host) |
|
|
|
|
|
{ |
|
|
|
|
|
if (fCount++ == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
CARLA_ASSERT(synth == nullptr); |
|
|
|
|
|
CARLA_ASSERT(denormalkillbuf == nullptr); |
|
|
|
|
|
|
|
|
|
|
|
reinit(host); |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
if (gPixmapPath.isEmpty()) |
|
|
|
|
|
{ |
|
|
|
|
|
gPixmapPath = host->resource_dir; |
|
|
|
|
|
gPixmapPath += PIXMAP_PATH; |
|
|
|
|
|
gUiPixmapPath = gPixmapPath; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void removeOne() |
|
|
|
|
|
{ |
|
|
|
|
|
if (--fCount == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
CARLA_ASSERT(synth != nullptr); |
|
|
|
|
|
CARLA_ASSERT(denormalkillbuf != nullptr); |
|
|
|
|
|
|
|
|
|
|
|
Master::deleteInstance(); |
|
|
|
|
|
|
|
|
|
|
|
delete[] denormalkillbuf; |
|
|
|
|
|
denormalkillbuf = nullptr; |
|
|
|
|
|
|
|
|
|
|
|
delete synth; |
|
|
|
|
|
synth = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void reinit(HostDescriptor* host) |
|
|
|
|
|
{ |
|
|
|
|
|
Master::deleteInstance(); |
|
|
|
|
|
|
|
|
|
|
|
if (denormalkillbuf != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
delete[] denormalkillbuf; |
|
|
|
|
|
denormalkillbuf = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (synth != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
delete synth; |
|
|
|
|
|
synth = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
synth = new SYNTH_T(); |
|
|
|
|
|
synth->buffersize = host->get_buffer_size(host->handle); |
|
|
|
|
|
synth->samplerate = host->get_sample_rate(host->handle); |
|
|
|
|
|
synth->alias(); |
|
|
|
|
|
|
|
|
|
|
|
config.init(); |
|
|
|
|
|
config.cfg.SoundBufferSize = synth->buffersize; |
|
|
|
|
|
config.cfg.SampleRate = synth->samplerate; |
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
|
|
sPrograms.init(Master::getInstance()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
int fCount; |
|
|
|
|
|
|
|
|
|
|
|
CARLA_DECLARE_NON_COPYABLE(ZynAddSubFxInstanceCount) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static ZynAddSubFxInstanceCount sInstanceCount; |
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
|
|
|
class ZynAddSubFxThread : public QThread |
|
|
|
|
|
{ |
|
|
|
|
|
public: |
|
|
|
|
|
ZynAddSubFxThread(Master* const master, const HostDescriptor* const host) |
|
|
|
|
|
: fMaster(master), |
|
|
|
|
|
kHost(host), |
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
fUi(nullptr), |
|
|
|
|
|
fUiClosed(0), |
|
|
|
|
|
fNextUiAction(-1), |
|
|
|
|
|
#endif |
|
|
|
|
|
fQuit(false), |
|
|
|
|
|
fChangeProgram(false), |
|
|
|
|
|
fNextChannel(0), |
|
|
|
|
|
fNextBank(0), |
|
|
|
|
|
fNextProgram(0) |
|
|
|
|
|
{ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
~ZynAddSubFxThread() |
|
|
|
|
|
{ |
|
|
|
|
|
// must be closed by now |
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
CARLA_ASSERT(fUi == nullptr); |
|
|
|
|
|
#endif |
|
|
|
|
|
CARLA_ASSERT(fQuit); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void loadProgramLater(const uint8_t channel, const uint32_t bank, const uint32_t program) |
|
|
|
|
|
{ |
|
|
|
|
|
fNextChannel = channel; |
|
|
|
|
|
fNextBank = bank; |
|
|
|
|
|
fNextProgram = program; |
|
|
|
|
|
fChangeProgram = true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void stopLoadProgramLater() |
|
|
|
|
|
{ |
|
|
|
|
|
fChangeProgram = false; |
|
|
|
|
|
fNextChannel = 0; |
|
|
|
|
|
fNextBank = 0; |
|
|
|
|
|
fNextProgram = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void setMaster(Master* const master) |
|
|
|
|
|
{ |
|
|
|
|
|
fMaster = master; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void stop() |
|
|
|
|
|
{ |
|
|
|
|
|
fQuit = true; |
|
|
|
|
|
quit(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
void uiHide() |
|
|
|
|
|
{ |
|
|
|
|
|
fNextUiAction = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void uiShow() |
|
|
|
|
|
{ |
|
|
|
|
|
fNextUiAction = 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void uiRepaint() |
|
|
|
|
|
{ |
|
|
|
|
|
if (fUi != nullptr) |
|
|
|
|
|
fNextUiAction = 2; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
|
void run() override |
|
|
|
|
|
{ |
|
|
|
|
|
while (! fQuit) |
|
|
|
|
|
{ |
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
Fl::lock(); |
|
|
|
|
|
|
|
|
|
|
|
if (fNextUiAction == 2) // repaint |
|
|
|
|
|
{ |
|
|
|
|
|
CARLA_ASSERT(fUi != nullptr); |
|
|
|
|
|
|
|
|
|
|
|
if (fUi != nullptr) |
|
|
|
|
|
fUi->refresh_master_ui(); |
|
|
|
|
|
} |
|
|
|
|
|
else if (fNextUiAction == 1) // init/show |
|
|
|
|
|
{ |
|
|
|
|
|
static bool initialized = false; |
|
|
|
|
|
|
|
|
|
|
|
if (! initialized) |
|
|
|
|
|
{ |
|
|
|
|
|
initialized = true; |
|
|
|
|
|
fl_register_images(); |
|
|
|
|
|
|
|
|
|
|
|
Fl_Dial::default_style(Fl_Dial::PIXMAP_DIAL); |
|
|
|
|
|
|
|
|
|
|
|
if (Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "knob.png")) |
|
|
|
|
|
Fl_Dial::default_image(img); |
|
|
|
|
|
|
|
|
|
|
|
if (Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "window_backdrop.png")) |
|
|
|
|
|
Fl::scheme_bg(new Fl_Tiled_Image(img)); |
|
|
|
|
|
|
|
|
|
|
|
if(Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "module_backdrop.png")) |
|
|
|
|
|
gModuleBackdrop = new Fl_Tiled_Image(img); |
|
|
|
|
|
|
|
|
|
|
|
Fl::background(50, 50, 50); |
|
|
|
|
|
Fl::background2(70, 70, 70); |
|
|
|
|
|
Fl::foreground(255, 255, 255); |
|
|
|
|
|
|
|
|
|
|
|
Fl_Theme::set("Cairo"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CARLA_ASSERT(fUi == nullptr); |
|
|
|
|
|
|
|
|
|
|
|
if (fUi == nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
fUiClosed = 0; |
|
|
|
|
|
fUi = new MasterUI(fMaster, &fUiClosed); |
|
|
|
|
|
fUi->showUI(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else if (fNextUiAction == 0) // close |
|
|
|
|
|
{ |
|
|
|
|
|
CARLA_ASSERT(fUi != nullptr); |
|
|
|
|
|
|
|
|
|
|
|
if (fUi != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
delete fUi; |
|
|
|
|
|
fUi = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fNextUiAction = -1; |
|
|
|
|
|
|
|
|
|
|
|
if (fUiClosed != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
fUiClosed = 0; |
|
|
|
|
|
fNextUiAction = 0; |
|
|
|
|
|
kHost->ui_closed(kHost->handle); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Fl::check(); |
|
|
|
|
|
Fl::unlock(); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
if (fChangeProgram) |
|
|
|
|
|
{ |
|
|
|
|
|
fChangeProgram = false; |
|
|
|
|
|
sPrograms.load(fMaster, fNextChannel, fNextBank, fNextProgram); |
|
|
|
|
|
fNextChannel = 0; |
|
|
|
|
|
fNextBank = 0; |
|
|
|
|
|
fNextProgram = 0; |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
if (fUi != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
Fl::lock(); |
|
|
|
|
|
fUi->refresh_master_ui(); |
|
|
|
|
|
Fl::unlock(); |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
carla_msleep(15); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
carla_msleep(30); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
if (fQuit && fUi != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
Fl::lock(); |
|
|
|
|
|
delete fUi; |
|
|
|
|
|
fUi = nullptr; |
|
|
|
|
|
Fl::check(); |
|
|
|
|
|
Fl::unlock(); |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
Master* fMaster; |
|
|
|
|
|
const HostDescriptor* const kHost; |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
MasterUI* fUi; |
|
|
|
|
|
int fUiClosed; |
|
|
|
|
|
int fNextUiAction; |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
bool fQuit; |
|
|
|
|
|
bool fChangeProgram; |
|
|
|
|
|
uint8_t fNextChannel; |
|
|
|
|
|
uint32_t fNextBank; |
|
|
|
|
|
uint32_t fNextProgram; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
class ZynAddSubFxPlugin : public PluginDescriptorClass |
|
|
class ZynAddSubFxPlugin : public PluginDescriptorClass |
|
|
{ |
|
|
{ |
|
|
public: |
|
|
public: |
|
@@ -111,7 +557,6 @@ public: |
|
|
fThread(fMaster, host) |
|
|
fThread(fMaster, host) |
|
|
{ |
|
|
{ |
|
|
fThread.start(); |
|
|
fThread.start(); |
|
|
maybeInitPrograms(fMaster); |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < NUM_MIDI_PARTS; ++i) |
|
|
for (int i = 0; i < NUM_MIDI_PARTS; ++i) |
|
|
fMaster->partonoff(i, 1); |
|
|
fMaster->partonoff(i, 1); |
|
@@ -195,19 +640,7 @@ protected: |
|
|
|
|
|
|
|
|
const MidiProgram* getMidiProgramInfo(const uint32_t index) override |
|
|
const MidiProgram* getMidiProgramInfo(const uint32_t index) override |
|
|
{ |
|
|
{ |
|
|
CARLA_ASSERT(index < getMidiProgramCount()); |
|
|
|
|
|
|
|
|
|
|
|
if (index >= sPrograms.count()) |
|
|
|
|
|
return nullptr; |
|
|
|
|
|
|
|
|
|
|
|
const ProgramInfo* const pInfo(sPrograms.getAt(index)); |
|
|
|
|
|
|
|
|
|
|
|
static MidiProgram midiProgram; |
|
|
|
|
|
midiProgram.bank = pInfo->bank; |
|
|
|
|
|
midiProgram.program = pInfo->prog; |
|
|
|
|
|
midiProgram.name = pInfo->name; |
|
|
|
|
|
|
|
|
|
|
|
return &midiProgram; |
|
|
|
|
|
|
|
|
return sPrograms.getInfo(index); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------- |
|
|
// ------------------------------------------------------------------- |
|
@@ -236,13 +669,13 @@ protected: |
|
|
|
|
|
|
|
|
if (isOffline() || ! fIsActive) |
|
|
if (isOffline() || ! fIsActive) |
|
|
{ |
|
|
{ |
|
|
loadProgram(fMaster, channel, bank, program); |
|
|
|
|
|
|
|
|
sPrograms.load(fMaster, channel, bank, program); |
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
fThread.uiRepaint(); |
|
|
fThread.uiRepaint(); |
|
|
#endif |
|
|
#endif |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
fThread.loadLater(channel, bank, program); |
|
|
|
|
|
|
|
|
fThread.loadProgramLater(channel, bank, program); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void setCustomData(const char* const key, const char* const value) override |
|
|
void setCustomData(const char* const key, const char* const value) override |
|
@@ -354,7 +787,7 @@ protected: |
|
|
|
|
|
|
|
|
void setState(const char* const data) override |
|
|
void setState(const char* const data) override |
|
|
{ |
|
|
{ |
|
|
fThread.stopLoadLater(); |
|
|
|
|
|
|
|
|
fThread.stopLoadProgramLater(); |
|
|
fMaster->putalldata((char*)data, 0); |
|
|
fMaster->putalldata((char*)data, 0); |
|
|
fMaster->applyparameters(true); |
|
|
fMaster->applyparameters(true); |
|
|
} |
|
|
} |
|
@@ -394,340 +827,16 @@ protected: |
|
|
// ------------------------------------------------------------------- |
|
|
// ------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
struct ProgramInfo { |
|
|
|
|
|
uint32_t bank; |
|
|
|
|
|
uint32_t prog; |
|
|
|
|
|
const char* name; |
|
|
|
|
|
|
|
|
|
|
|
ProgramInfo(uint32_t bank_, uint32_t prog_, const char* name_) |
|
|
|
|
|
: bank(bank_), |
|
|
|
|
|
prog(prog_), |
|
|
|
|
|
name(carla_strdup(name_)) {} |
|
|
|
|
|
|
|
|
|
|
|
~ProgramInfo() |
|
|
|
|
|
{ |
|
|
|
|
|
if (name != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
delete[] name; |
|
|
|
|
|
name = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef CARLA_PROPER_CPP11_SUPPORT |
|
|
|
|
|
ProgramInfo() = delete; |
|
|
|
|
|
ProgramInfo(ProgramInfo&) = delete; |
|
|
|
|
|
ProgramInfo(const ProgramInfo&) = delete; |
|
|
|
|
|
#endif |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
class ZynThread : public QThread |
|
|
|
|
|
{ |
|
|
|
|
|
public: |
|
|
|
|
|
ZynThread(Master* const master, const HostDescriptor* const host) |
|
|
|
|
|
: fMaster(master), |
|
|
|
|
|
kHost(host), |
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
fUi(nullptr), |
|
|
|
|
|
fUiClosed(0), |
|
|
|
|
|
fNextUiAction(-1), |
|
|
|
|
|
#endif |
|
|
|
|
|
fQuit(false), |
|
|
|
|
|
fChangeProgram(false), |
|
|
|
|
|
fNextChannel(0), |
|
|
|
|
|
fNextBank(0), |
|
|
|
|
|
fNextProgram(0) |
|
|
|
|
|
{ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
~ZynThread() |
|
|
|
|
|
{ |
|
|
|
|
|
// must be closed by now |
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
CARLA_ASSERT(fUi == nullptr); |
|
|
|
|
|
#endif |
|
|
|
|
|
CARLA_ASSERT(fQuit); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void loadLater(const uint8_t channel, const uint32_t bank, const uint32_t program) |
|
|
|
|
|
{ |
|
|
|
|
|
fNextChannel = channel; |
|
|
|
|
|
fNextBank = bank; |
|
|
|
|
|
fNextProgram = program; |
|
|
|
|
|
fChangeProgram = true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void stopLoadLater() |
|
|
|
|
|
{ |
|
|
|
|
|
fChangeProgram = false; |
|
|
|
|
|
fNextChannel = 0; |
|
|
|
|
|
fNextBank = 0; |
|
|
|
|
|
fNextProgram = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void stop() |
|
|
|
|
|
{ |
|
|
|
|
|
fQuit = true; |
|
|
|
|
|
quit(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
void uiHide() |
|
|
|
|
|
{ |
|
|
|
|
|
fNextUiAction = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void uiShow() |
|
|
|
|
|
{ |
|
|
|
|
|
fNextUiAction = 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void uiRepaint() |
|
|
|
|
|
{ |
|
|
|
|
|
if (fUi != nullptr) |
|
|
|
|
|
fNextUiAction = 2; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
|
void run() override |
|
|
|
|
|
{ |
|
|
|
|
|
while (! fQuit) |
|
|
|
|
|
{ |
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
Fl::lock(); |
|
|
|
|
|
|
|
|
|
|
|
if (fNextUiAction == 2) // repaint |
|
|
|
|
|
{ |
|
|
|
|
|
CARLA_ASSERT(fUi != nullptr); |
|
|
|
|
|
|
|
|
|
|
|
if (fUi != nullptr) |
|
|
|
|
|
fUi->refresh_master_ui(); |
|
|
|
|
|
} |
|
|
|
|
|
else if (fNextUiAction == 1) // init/show |
|
|
|
|
|
{ |
|
|
|
|
|
static bool initialized = false; |
|
|
|
|
|
|
|
|
|
|
|
if (! initialized) |
|
|
|
|
|
{ |
|
|
|
|
|
initialized = true; |
|
|
|
|
|
fl_register_images(); |
|
|
|
|
|
|
|
|
|
|
|
Fl_Dial::default_style(Fl_Dial::PIXMAP_DIAL); |
|
|
|
|
|
|
|
|
|
|
|
if (Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "knob.png")) |
|
|
|
|
|
Fl_Dial::default_image(img); |
|
|
|
|
|
|
|
|
|
|
|
if (Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "window_backdrop.png")) |
|
|
|
|
|
Fl::scheme_bg(new Fl_Tiled_Image(img)); |
|
|
|
|
|
|
|
|
|
|
|
if(Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "module_backdrop.png")) |
|
|
|
|
|
gModuleBackdrop = new Fl_Tiled_Image(img); |
|
|
|
|
|
|
|
|
|
|
|
Fl::background(50, 50, 50); |
|
|
|
|
|
Fl::background2(70, 70, 70); |
|
|
|
|
|
Fl::foreground(255, 255, 255); |
|
|
|
|
|
|
|
|
|
|
|
Fl_Theme::set("Cairo"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CARLA_ASSERT(fUi == nullptr); |
|
|
|
|
|
|
|
|
|
|
|
if (fUi == nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
fUiClosed = 0; |
|
|
|
|
|
fUi = new MasterUI(fMaster, &fUiClosed); |
|
|
|
|
|
fUi->showUI(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else if (fNextUiAction == 0) // close |
|
|
|
|
|
{ |
|
|
|
|
|
CARLA_ASSERT(fUi != nullptr); |
|
|
|
|
|
|
|
|
|
|
|
if (fUi != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
delete fUi; |
|
|
|
|
|
fUi = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fNextUiAction = -1; |
|
|
|
|
|
|
|
|
|
|
|
if (fUiClosed != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
fUiClosed = 0; |
|
|
|
|
|
fNextUiAction = 0; |
|
|
|
|
|
kHost->ui_closed(kHost->handle); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Fl::check(); |
|
|
|
|
|
Fl::unlock(); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
if (fChangeProgram) |
|
|
|
|
|
{ |
|
|
|
|
|
fChangeProgram = false; |
|
|
|
|
|
loadProgram(fMaster, fNextChannel, fNextBank, fNextProgram); |
|
|
|
|
|
fNextChannel = 0; |
|
|
|
|
|
fNextBank = 0; |
|
|
|
|
|
fNextProgram = 0; |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
if (fUi != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
Fl::lock(); |
|
|
|
|
|
fUi->refresh_master_ui(); |
|
|
|
|
|
Fl::unlock(); |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
carla_msleep(15); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
carla_msleep(30); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
if (fQuit && fUi != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
Fl::lock(); |
|
|
|
|
|
delete fUi; |
|
|
|
|
|
fUi = nullptr; |
|
|
|
|
|
Fl::check(); |
|
|
|
|
|
Fl::unlock(); |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
Master* const fMaster; |
|
|
|
|
|
const HostDescriptor* const kHost; |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
MasterUI* fUi; |
|
|
|
|
|
int fUiClosed; |
|
|
|
|
|
int fNextUiAction; |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
bool fQuit; |
|
|
|
|
|
bool fChangeProgram; |
|
|
|
|
|
uint8_t fNextChannel; |
|
|
|
|
|
uint32_t fNextBank; |
|
|
|
|
|
uint32_t fNextProgram; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Master* fMaster; |
|
|
Master* fMaster; |
|
|
unsigned fSampleRate; |
|
|
unsigned fSampleRate; |
|
|
bool fIsActive; |
|
|
|
|
|
|
|
|
|
|
|
ZynThread fThread; |
|
|
|
|
|
|
|
|
|
|
|
static int sInstanceCount; |
|
|
|
|
|
static NonRtList<ProgramInfo*> sPrograms; |
|
|
|
|
|
|
|
|
|
|
|
static void maybeInitPrograms(Master* const master) |
|
|
|
|
|
{ |
|
|
|
|
|
static bool doSearch = true; |
|
|
|
|
|
|
|
|
|
|
|
if (! doSearch) |
|
|
|
|
|
return; |
|
|
|
|
|
doSearch = false; |
|
|
|
|
|
|
|
|
|
|
|
sPrograms.append(new ProgramInfo(0, 0, "default")); |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&master->mutex); |
|
|
|
|
|
|
|
|
|
|
|
// refresh banks |
|
|
|
|
|
master->bank.rescanforbanks(); |
|
|
|
|
|
|
|
|
|
|
|
for (uint32_t i=0, size = master->bank.banks.size(); i < size; ++i) |
|
|
|
|
|
{ |
|
|
|
|
|
if (master->bank.banks[i].dir.empty()) |
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
master->bank.loadbank(master->bank.banks[i].dir); |
|
|
|
|
|
|
|
|
|
|
|
for (unsigned int instrument = 0; instrument < BANK_SIZE; ++instrument) |
|
|
|
|
|
{ |
|
|
|
|
|
const std::string insName(master->bank.getname(instrument)); |
|
|
|
|
|
|
|
|
|
|
|
if (insName.empty() || insName[0] == '\0' || insName[0] == ' ') |
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
sPrograms.append(new ProgramInfo(i+1, instrument, insName.c_str())); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&master->mutex); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void loadProgram(Master* const master, const uint8_t channel, const uint32_t bank, const uint32_t program) |
|
|
|
|
|
{ |
|
|
|
|
|
if (bank == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
pthread_mutex_lock(&master->mutex); |
|
|
|
|
|
|
|
|
|
|
|
master->part[channel]->defaults(); |
|
|
|
|
|
master->part[channel]->applyparameters(false); |
|
|
|
|
|
master->partonoff(channel, 1); |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&master->mutex); |
|
|
|
|
|
|
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const std::string& bankdir(master->bank.banks[bank-1].dir); |
|
|
|
|
|
|
|
|
|
|
|
if (! bankdir.empty()) |
|
|
|
|
|
{ |
|
|
|
|
|
pthread_mutex_lock(&master->mutex); |
|
|
|
|
|
|
|
|
|
|
|
master->partonoff(channel, 1); |
|
|
|
|
|
|
|
|
|
|
|
master->bank.loadbank(bankdir); |
|
|
|
|
|
master->bank.loadfromslot(program, master->part[channel]); |
|
|
|
|
|
|
|
|
|
|
|
master->part[channel]->applyparameters(false); |
|
|
|
|
|
|
|
|
bool fIsActive; |
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&master->mutex); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
ZynAddSubFxThread fThread; |
|
|
|
|
|
|
|
|
public: |
|
|
public: |
|
|
static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host) |
|
|
static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host) |
|
|
{ |
|
|
{ |
|
|
if (sInstanceCount++ == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
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(); |
|
|
|
|
|
|
|
|
|
|
|
config.init(); |
|
|
|
|
|
config.cfg.SoundBufferSize = synth->buffersize; |
|
|
|
|
|
config.cfg.SampleRate = synth->samplerate; |
|
|
|
|
|
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(); |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WANT_ZYNADDSUBFX_UI |
|
|
|
|
|
if (gPixmapPath.isEmpty()) |
|
|
|
|
|
{ |
|
|
|
|
|
gPixmapPath = host->resource_dir; |
|
|
|
|
|
gPixmapPath += PIXMAP_PATH; |
|
|
|
|
|
gUiPixmapPath = gPixmapPath; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
sInstanceCount.addOne(host); |
|
|
|
|
|
|
|
|
return new ZynAddSubFxPlugin(host); |
|
|
return new ZynAddSubFxPlugin(host); |
|
|
} |
|
|
} |
|
@@ -736,46 +845,13 @@ public: |
|
|
{ |
|
|
{ |
|
|
delete (ZynAddSubFxPlugin*)handle; |
|
|
delete (ZynAddSubFxPlugin*)handle; |
|
|
|
|
|
|
|
|
if (--sInstanceCount == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
CARLA_ASSERT(synth != nullptr); |
|
|
|
|
|
CARLA_ASSERT(denormalkillbuf != nullptr); |
|
|
|
|
|
|
|
|
|
|
|
Master::deleteInstance(); |
|
|
|
|
|
|
|
|
|
|
|
delete[] denormalkillbuf; |
|
|
|
|
|
denormalkillbuf = nullptr; |
|
|
|
|
|
|
|
|
|
|
|
delete synth; |
|
|
|
|
|
synth = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void _clearPrograms() |
|
|
|
|
|
{ |
|
|
|
|
|
for (auto it = sPrograms.begin(); it.valid(); it.next()) |
|
|
|
|
|
{ |
|
|
|
|
|
ProgramInfo* const programInfo(*it); |
|
|
|
|
|
delete programInfo; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
sPrograms.clear(); |
|
|
|
|
|
|
|
|
sInstanceCount.removeOne(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ZynAddSubFxPlugin) |
|
|
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ZynAddSubFxPlugin) |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
int ZynAddSubFxPlugin::sInstanceCount = 0; |
|
|
|
|
|
NonRtList<ZynAddSubFxPlugin::ProgramInfo*> ZynAddSubFxPlugin::sPrograms; |
|
|
|
|
|
|
|
|
|
|
|
static const struct ProgramsDestructor { |
|
|
|
|
|
ProgramsDestructor() {} |
|
|
|
|
|
~ProgramsDestructor() { |
|
|
|
|
|
ZynAddSubFxPlugin::_clearPrograms(); |
|
|
|
|
|
} |
|
|
|
|
|
} _programsDestructor; |
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
static const PluginDescriptor zynaddsubfxDesc = { |
|
|
static const PluginDescriptor zynaddsubfxDesc = { |
|
|