Browse Source

Rework zynaddsubfx code

tags/1.9.4
falkTX 11 years ago
parent
commit
ffc8fb3e7b
1 changed files with 454 additions and 378 deletions
  1. +454
    -378
      source/backend/native/zynaddsubfx.cpp

+ 454
- 378
source/backend/native/zynaddsubfx.cpp View File

@@ -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 = {


Loading…
Cancel
Save