| @@ -221,7 +221,7 @@ protected: | |||
| float* efxoutr; | |||
| // FIXME - is this thread-safe? | |||
| SharedResourcePointer<Allocator> fAllocator; | |||
| SharedResourcePointer<AllocatorClass> fAllocator; | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FxAbstractPlugin) | |||
| }; | |||
| @@ -69,8 +69,11 @@ public: | |||
| fPrograms.append(new ProgramInfo(0, 0, "default", "")); | |||
| Config config; | |||
| config.init(); | |||
| SYNTH_T synth; | |||
| Master master(synth); | |||
| Master master(synth, &config); | |||
| // refresh banks | |||
| master.bank.rescanforbanks(); | |||
| @@ -210,6 +213,7 @@ public: | |||
| fMutex() | |||
| { | |||
| sPrograms.initIfNeeded(); | |||
| fConfig.init(); | |||
| // init parameters to default | |||
| fParameters[kParamPart01Enabled] = 1.0f; | |||
| @@ -716,6 +720,7 @@ private: | |||
| MiddleWare* fMiddleWare; | |||
| Master* fMaster; | |||
| SYNTH_T fSynth; | |||
| Config fConfig; | |||
| bool fIsActive; | |||
| float fParameters[kParamCount]; | |||
| @@ -768,7 +773,7 @@ private: | |||
| void _initMaster() | |||
| { | |||
| fMiddleWare = new MiddleWare(fSynth); | |||
| fMiddleWare = new MiddleWare(std::move(fSynth), &fConfig); | |||
| fMiddleWare->setUiCallback(__uiCallback, this); | |||
| fMiddleWare->setIdleCallback(_idleCallback, this); | |||
| _masterChangedCallback(fMiddleWare->spawnMaster()); | |||
| @@ -891,32 +896,7 @@ private: | |||
| // ------------------------------------------------------------------- | |||
| public: | |||
| static NativePluginHandle _instantiate(const NativeHostDescriptor* host) | |||
| { | |||
| static bool needsInit = true; | |||
| if (needsInit) | |||
| { | |||
| needsInit = false; | |||
| config.init(); | |||
| sprng(static_cast<prng_t>(std::time(nullptr))); | |||
| // FIXME - kill this | |||
| denormalkillbuf = new float[8192]; | |||
| for (int i=0; i < 8192; ++i) | |||
| denormalkillbuf[i] = (RND - 0.5f) * 1e-16f; | |||
| } | |||
| return new ZynAddSubFxPlugin(host); | |||
| } | |||
| static void _cleanup(NativePluginHandle handle) | |||
| { | |||
| delete (ZynAddSubFxPlugin*)handle; | |||
| } | |||
| PluginClassEND(ZynAddSubFxPlugin) | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ZynAddSubFxPlugin) | |||
| }; | |||
| @@ -24,6 +24,7 @@ | |||
| #include "../Misc/Allocator.h" | |||
| #include "Unison.h" | |||
| #include "globals.h" | |||
| #ifndef errx | |||
| #include <err.h> | |||
| @@ -205,41 +205,26 @@ float EQ::getfreqresponse(float freq) | |||
| return rap2dB(resp * outvolume); | |||
| } | |||
| //full taps & three filter taps | |||
| static void convolve(float *a, const float *filter) | |||
| { | |||
| float tmp[MAX_EQ_BANDS*2+1]; | |||
| for(int i=0; i<MAX_EQ_BANDS*2+1; ++i) | |||
| tmp[i] = a[i]; | |||
| //Base Case | |||
| a[0] = tmp[0]*filter[0]; | |||
| a[1] = tmp[0]*filter[1] + tmp[1]*filter[0]; | |||
| for(int i=2; i<MAX_EQ_BANDS+1; ++i) { | |||
| a[i] = filter[0]*tmp[i] + | |||
| filter[1]*tmp[i-1] + | |||
| filter[2]*tmp[i-2]; | |||
| } | |||
| } | |||
| //Not exactly the most efficient manner to derive the total taps, but it should | |||
| //be fast enough in practice | |||
| void EQ::getFilter(float *a, float *b) const | |||
| { | |||
| a[0] = 1; | |||
| b[0] = 1; | |||
| off_t off=0; | |||
| for(int i = 0; i < MAX_EQ_BANDS; ++i) { | |||
| auto &F = filter[i]; | |||
| if(F.Ptype == 0) | |||
| continue; | |||
| float Fb[3] = {F.l->coeff.c[0], F.l->coeff.c[1], F.l->coeff.c[2]}; | |||
| float Fa[3] = {1.0f, -F.l->coeff.d[1], -F.l->coeff.d[2]}; | |||
| const double Fb[3] = {F.l->coeff.c[0], F.l->coeff.c[1], F.l->coeff.c[2]}; | |||
| const double Fa[3] = {1.0f, -F.l->coeff.d[1], -F.l->coeff.d[2]}; | |||
| for(int j=0; j<F.Pstages+1; ++j) { | |||
| convolve(b, Fb); | |||
| convolve(a, Fa); | |||
| for(int k=0; k<3; ++k) { | |||
| a[off] = Fa[k]; | |||
| b[off] = Fb[k]; | |||
| off++; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -38,8 +38,8 @@ class EQ:public Effect | |||
| void cleanup(void); | |||
| float getfreqresponse(float freq); | |||
| void getFilter(float *a/*[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]*/, | |||
| float *b/*[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]*/) const; | |||
| void getFilter(float *a/*[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]*/, | |||
| float *b/*[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]*/) const; | |||
| private: | |||
| //Parameters | |||
| unsigned char Pvolume; | |||
| @@ -24,6 +24,7 @@ | |||
| #include "../Misc/Util.h" | |||
| #include <cmath> | |||
| #include "globals.h" | |||
| EffectLFO::EffectLFO(float srate_f, float bufsize_f) | |||
| :Pfreq(40), | |||
| @@ -79,7 +80,7 @@ float EffectLFO::getlfoshape(float x) | |||
| break; | |||
| //when adding more, ensure ::updateparams() gets updated | |||
| default: | |||
| out = cosf(x * 2.0f * PI); //EffectLFO_SINE | |||
| out = cosf(x * 2.0f * PI); //EffectLFO_SINE // TODO: use M_PI ? | |||
| } | |||
| return out; | |||
| } | |||
| @@ -26,12 +26,14 @@ | |||
| #include "EffectMgr.h" | |||
| #include "Effect.h" | |||
| #include "Alienwah.h" | |||
| #include "Reverb.h" | |||
| #include "Echo.h" | |||
| #include "Chorus.h" | |||
| #include "Distorsion.h" | |||
| #include "EQ.h" | |||
| #include "DynamicFilter.h" | |||
| #include "Phaser.h" | |||
| #include "../Misc/XMLwrapper.h" | |||
| #include "../Misc/Util.h" | |||
| #include "../Params/FilterParams.h" | |||
| @@ -75,8 +77,8 @@ static const rtosc::Ports local_ports = { | |||
| if(eff->nefx != 7) | |||
| return; | |||
| EQ *eq = (EQ*)eff->efx; | |||
| float a[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]; | |||
| float b[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]; | |||
| float a[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]; | |||
| float b[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]; | |||
| memset(a, 0, sizeof(a)); | |||
| memset(b, 0, sizeof(b)); | |||
| eq->getFilter(a,b); | |||
| @@ -307,8 +309,8 @@ void EffectMgr::out(float *smpsl, float *smpsr) | |||
| return; | |||
| } | |||
| for(int i = 0; i < synth.buffersize; ++i) { | |||
| smpsl[i] += denormalkillbuf[i]; | |||
| smpsr[i] += denormalkillbuf[i]; | |||
| smpsl[i] += synth.denormalkillbuf[i]; | |||
| smpsr[i] += synth.denormalkillbuf[i]; | |||
| efxoutl[i] = 0.0f; | |||
| efxoutr[i] = 0.0f; | |||
| } | |||
| @@ -24,22 +24,15 @@ | |||
| #include <pthread.h> | |||
| #include "Alienwah.h" | |||
| #include "Phaser.h" | |||
| #include "../Params/Presets.h" | |||
| class Effect; | |||
| class FilterParams; | |||
| class XMLwrapper; | |||
| class Allocator; | |||
| #include "Distorsion.h" | |||
| #include "EQ.h" | |||
| #include "DynamicFilter.h" | |||
| #include "../Params/FilterParams.h" | |||
| #include "../Params/Presets.h" | |||
| /**Effect manager, an interface betwen the program and effects*/ | |||
| /** Effect manager, an interface between the program and effects */ | |||
| class EffectMgr:public Presets | |||
| { | |||
| public: | |||
| @@ -7,7 +7,7 @@ | |||
| #include "Allocator.h" | |||
| //Used for dummy allocations | |||
| Allocator DummyAlloc; | |||
| DummyAllocator DummyAlloc; | |||
| //recursive type class to avoid void *v = *(void**)v style casting | |||
| struct next_t | |||
| @@ -57,7 +57,7 @@ Allocator::~Allocator(void) | |||
| delete impl; | |||
| } | |||
| void *Allocator::alloc_mem(size_t mem_size) | |||
| void *AllocatorClass::alloc_mem(size_t mem_size) | |||
| { | |||
| impl->totalAlloced += mem_size; | |||
| void *mem = tlsf_malloc(impl->tlsf, mem_size); | |||
| @@ -66,14 +66,14 @@ void *Allocator::alloc_mem(size_t mem_size) | |||
| //printf("Allocator result = %p\n", mem); | |||
| return mem; | |||
| } | |||
| void Allocator::dealloc_mem(void *memory) | |||
| void AllocatorClass::dealloc_mem(void *memory) | |||
| { | |||
| //printf("dealloc_mem(%d)\n", tlsf_block_size(memory)); | |||
| tlsf_free(impl->tlsf, memory); | |||
| //free(memory); | |||
| } | |||
| bool Allocator::lowMemory(unsigned n, size_t chunk_size) | |||
| bool AllocatorClass::lowMemory(unsigned n, size_t chunk_size) const | |||
| { | |||
| //This should stay on the stack | |||
| void *buf[n]; | |||
| @@ -90,7 +90,7 @@ bool Allocator::lowMemory(unsigned n, size_t chunk_size) | |||
| } | |||
| void Allocator::addMemory(void *v, size_t mem_size) | |||
| void AllocatorClass::addMemory(void *v, size_t mem_size) | |||
| { | |||
| next_t *n = impl->pools; | |||
| while(n->next) n = n->next; | |||
| @@ -124,7 +124,7 @@ typedef struct block_header_t | |||
| static const size_t block_header_free_bit = 1 << 0; | |||
| #endif | |||
| bool Allocator::memFree(void *pool) | |||
| bool Allocator::memFree(void *pool) const | |||
| { | |||
| size_t bh_shift = sizeof(next_t)+sizeof(size_t); | |||
| //Assume that memory is free to start with | |||
| @@ -145,7 +145,7 @@ bool Allocator::memFree(void *pool) | |||
| return isFree; | |||
| } | |||
| int Allocator::memPools() | |||
| int Allocator::memPools() const | |||
| { | |||
| int i = 1; | |||
| next_t *n = impl->pools; | |||
| @@ -156,7 +156,7 @@ int Allocator::memPools() | |||
| return i; | |||
| } | |||
| int Allocator::freePools() | |||
| int Allocator::freePools() const | |||
| { | |||
| int i = 0; | |||
| next_t *n = impl->pools->next; | |||
| @@ -169,7 +169,7 @@ int Allocator::freePools() | |||
| } | |||
| unsigned long long Allocator::totalAlloced() | |||
| unsigned long long Allocator::totalAlloced() const | |||
| { | |||
| return impl->totalAlloced; | |||
| } | |||
| @@ -2,14 +2,17 @@ | |||
| #include <cstdlib> | |||
| #include <utility> | |||
| //! Allocator Base class | |||
| //! subclasses must specify allocation and deallocation | |||
| class Allocator | |||
| { | |||
| public: | |||
| Allocator(void); | |||
| Allocator(const Allocator&) = delete; | |||
| ~Allocator(void); | |||
| void *alloc_mem(size_t mem_size); | |||
| void dealloc_mem(void *memory); | |||
| virtual ~Allocator(void); | |||
| virtual void *alloc_mem(size_t mem_size) = 0; | |||
| virtual void dealloc_mem(void *memory) = 0; | |||
| template <typename T, typename... Ts> | |||
| T *alloc(Ts&&... ts) | |||
| @@ -64,23 +67,47 @@ class Allocator | |||
| } | |||
| } | |||
| void addMemory(void *, size_t mem_size); | |||
| virtual void addMemory(void *, size_t mem_size) = 0; | |||
| //Return true if the current pool cannot allocate n chunks of chunk_size | |||
| bool lowMemory(unsigned n, size_t chunk_size); | |||
| bool memFree(void *pool); | |||
| virtual bool lowMemory(unsigned n, size_t chunk_size) const = 0; | |||
| bool memFree(void *pool) const; | |||
| //returns number of pools | |||
| int memPools(); | |||
| int memPools() const; | |||
| int freePools(); | |||
| int freePools() const; | |||
| unsigned long long totalAlloced(); | |||
| unsigned long long totalAlloced() const; | |||
| struct AllocatorImpl *impl; | |||
| }; | |||
| extern Allocator DummyAlloc; | |||
| //! the allocator for normal use | |||
| class AllocatorClass : public Allocator | |||
| { | |||
| void *alloc_mem(size_t mem_size); | |||
| void dealloc_mem(void *memory); | |||
| void addMemory(void *, size_t mem_size); | |||
| bool lowMemory(unsigned n, size_t chunk_size) const; | |||
| using Allocator::Allocator; | |||
| }; | |||
| //! the dummy allocator, which does not allow any allocation | |||
| class DummyAllocator : public Allocator | |||
| { | |||
| void not_allowed() const { | |||
| throw "(de)allocation forbidden"; // TODO: std exception | |||
| } | |||
| public: | |||
| void *alloc_mem(size_t ) { return not_allowed(), nullptr; } | |||
| void dealloc_mem(void* ) { not_allowed(); } // TODO: more functions? | |||
| void addMemory(void *, size_t ) { not_allowed(); } | |||
| bool lowMemory(unsigned , size_t ) const { return not_allowed(), true; } | |||
| using Allocator::Allocator; | |||
| }; | |||
| extern DummyAllocator DummyAlloc; | |||
| /** | |||
| * General notes on Memory Allocation Within ZynAddSubFX | |||
| @@ -46,16 +46,16 @@ | |||
| using namespace std; | |||
| Bank::Bank() | |||
| :bankpos(0), defaultinsname(" ") | |||
| Bank::Bank(Config *config) | |||
| :bankpos(0), defaultinsname(" "), config(config) | |||
| { | |||
| clearbank(); | |||
| bankfiletitle = dirname; | |||
| rescanforbanks(); | |||
| loadbank(config.cfg.currentBankDir); | |||
| loadbank(config->cfg.currentBankDir); | |||
| for(unsigned i=0; i<banks.size(); ++i) { | |||
| if(banks[i].dir == config.cfg.currentBankDir) { | |||
| if(banks[i].dir == config->cfg.currentBankDir) { | |||
| bankpos = i; | |||
| break; | |||
| } | |||
| @@ -270,7 +270,7 @@ int Bank::loadbank(string bankdirname) | |||
| closedir(dir); | |||
| if(!dirname.empty()) | |||
| config.cfg.currentBankDir = dirname; | |||
| config->cfg.currentBankDir = dirname; | |||
| return 0; | |||
| } | |||
| @@ -281,7 +281,7 @@ int Bank::loadbank(string bankdirname) | |||
| int Bank::newbank(string newbankdirname) | |||
| { | |||
| string bankdir; | |||
| bankdir = config.cfg.bankRootDirList[0]; | |||
| bankdir = config->cfg.bankRootDirList[0]; | |||
| if(((bankdir[bankdir.size() - 1]) != '/') | |||
| && ((bankdir[bankdir.size() - 1]) != '\\')) | |||
| @@ -361,8 +361,8 @@ void Bank::rescanforbanks() | |||
| banks.clear(); | |||
| for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) | |||
| if(!config.cfg.bankRootDirList[i].empty()) | |||
| scanrootdir(config.cfg.bankRootDirList[i]); | |||
| if(!config->cfg.bankRootDirList[i].empty()) | |||
| scanrootdir(config->cfg.bankRootDirList[i]); | |||
| //sort the banks | |||
| sort(banks.begin(), banks.end()); | |||
| @@ -26,6 +26,7 @@ | |||
| #include <string> | |||
| #include <vector> | |||
| #include "../globals.h" | |||
| #include "Config.h" | |||
| //entries in a bank | |||
| #define BANK_SIZE 160 | |||
| @@ -35,7 +36,7 @@ class Bank | |||
| { | |||
| public: | |||
| /**Constructor*/ | |||
| Bank(); | |||
| Bank(Config* config); | |||
| ~Bank(); | |||
| std::string getname(unsigned int ninstrument); | |||
| std::string getnamenumbered(unsigned int ninstrument); | |||
| @@ -96,6 +97,8 @@ class Bank | |||
| std::string dirname; | |||
| void scanrootdir(std::string rootdir); //scans a root dir for banks | |||
| Config* const config; | |||
| }; | |||
| #endif | |||
| @@ -28,6 +28,7 @@ | |||
| #include <rtosc/port-sugar.h> | |||
| #include "Config.h" | |||
| #include "globals.h" | |||
| #include "XMLwrapper.h" | |||
| #define rStdString(name, len, ...) \ | |||
| @@ -46,7 +47,7 @@ | |||
| #if 1 | |||
| #define rObject Config | |||
| static rtosc::Ports ports = { | |||
| static const rtosc::Ports ports = { | |||
| //rString(cfg.LinuxOSSWaveOutDev), | |||
| //rString(cfg.LinuxOSSSeqInDev), | |||
| rParamI(cfg.SampleRate, "samples of audio per second"), | |||
| @@ -145,7 +146,7 @@ static rtosc::Ports ports = { | |||
| d.broadcast(d.loc, "i", (int)(log(c.cfg.OscilSize*1.0)/log(2.0))); | |||
| }}, | |||
| }; | |||
| rtosc::Ports &Config::ports = ::ports; | |||
| const rtosc::Ports &Config::ports = ::ports; | |||
| #endif | |||
| Config::Config() | |||
| @@ -160,10 +161,10 @@ void Config::init() | |||
| cfg.OscilSize = 1024; | |||
| cfg.SwapStereo = 0; | |||
| cfg.LinuxOSSWaveOutDev = new char[MAX_STRING_SIZE]; | |||
| snprintf(cfg.LinuxOSSWaveOutDev, MAX_STRING_SIZE, "/dev/dsp"); | |||
| cfg.LinuxOSSSeqInDev = new char[MAX_STRING_SIZE]; | |||
| snprintf(cfg.LinuxOSSSeqInDev, MAX_STRING_SIZE, "/dev/sequencer"); | |||
| cfg.oss_devs.linux_wave_out = new char[MAX_STRING_SIZE]; | |||
| snprintf(cfg.oss_devs.linux_wave_out, MAX_STRING_SIZE, "/dev/dsp"); | |||
| cfg.oss_devs.linux_seq_in = new char[MAX_STRING_SIZE]; | |||
| snprintf(cfg.oss_devs.linux_seq_in, MAX_STRING_SIZE, "/dev/sequencer"); | |||
| cfg.WindowsWaveOutId = 0; | |||
| cfg.WindowsMidiInId = 0; | |||
| @@ -228,8 +229,8 @@ void Config::init() | |||
| Config::~Config() | |||
| { | |||
| delete [] cfg.LinuxOSSWaveOutDev; | |||
| delete [] cfg.LinuxOSSSeqInDev; | |||
| delete [] cfg.oss_devs.linux_wave_out; | |||
| delete [] cfg.oss_devs.linux_seq_in; | |||
| for(int i = 0; i < winmidimax; ++i) | |||
| delete [] winmididevices[i].name; | |||
| @@ -237,7 +238,7 @@ Config::~Config() | |||
| } | |||
| void Config::save() | |||
| void Config::save() const | |||
| { | |||
| char filename[MAX_STRING_SIZE]; | |||
| getConfigFileName(filename, MAX_STRING_SIZE); | |||
| @@ -330,10 +331,10 @@ void Config::readConfig(const char *filename) | |||
| //linux stuff | |||
| xmlcfg.getparstr("linux_oss_wave_out_dev", | |||
| cfg.LinuxOSSWaveOutDev, | |||
| cfg.oss_devs.linux_wave_out, | |||
| MAX_STRING_SIZE); | |||
| xmlcfg.getparstr("linux_oss_seq_in_dev", | |||
| cfg.LinuxOSSSeqInDev, | |||
| cfg.oss_devs.linux_seq_in, | |||
| MAX_STRING_SIZE); | |||
| //windows stuff | |||
| @@ -352,7 +353,7 @@ void Config::readConfig(const char *filename) | |||
| cfg.OscilSize = (int) powf(2, ceil(logf(cfg.OscilSize - 1.0f) / logf(2.0f))); | |||
| } | |||
| void Config::saveConfig(const char *filename) | |||
| void Config::saveConfig(const char *filename) const | |||
| { | |||
| XMLwrapper *xmlcfg = new XMLwrapper(); | |||
| @@ -392,8 +393,8 @@ void Config::saveConfig(const char *filename) | |||
| xmlcfg->addpar("interpolation", cfg.Interpolation); | |||
| //linux stuff | |||
| xmlcfg->addparstr("linux_oss_wave_out_dev", cfg.LinuxOSSWaveOutDev); | |||
| xmlcfg->addparstr("linux_oss_seq_in_dev", cfg.LinuxOSSSeqInDev); | |||
| xmlcfg->addparstr("linux_oss_wave_out_dev", cfg.oss_devs.linux_wave_out); | |||
| xmlcfg->addparstr("linux_oss_seq_in_dev", cfg.oss_devs.linux_seq_in); | |||
| //windows stuff | |||
| xmlcfg->addpar("windows_wave_out_id", cfg.WindowsWaveOutId); | |||
| @@ -401,15 +402,13 @@ void Config::saveConfig(const char *filename) | |||
| xmlcfg->endbranch(); | |||
| int tmp = cfg.GzipCompression; | |||
| cfg.GzipCompression = 0; | |||
| xmlcfg->saveXMLfile(filename); | |||
| cfg.GzipCompression = tmp; | |||
| // for some reason (which one?), the gzip compression is bashed to 0 | |||
| xmlcfg->saveXMLfile(filename, 0); | |||
| delete (xmlcfg); | |||
| } | |||
| void Config::getConfigFileName(char *name, int namesize) | |||
| void Config::getConfigFileName(char *name, int namesize) const | |||
| { | |||
| name[0] = 0; | |||
| snprintf(name, namesize, "%s%s", getenv("HOME"), "/.zynaddsubfxXML.cfg"); | |||
| @@ -22,21 +22,32 @@ | |||
| #ifndef CONFIG_H | |||
| #define CONFIG_H | |||
| #include "../globals.h" | |||
| #include <string> | |||
| #define MAX_STRING_SIZE 4000 | |||
| #define MAX_BANK_ROOT_DIRS 100 | |||
| namespace rtosc | |||
| { | |||
| struct Ports; | |||
| } | |||
| class oss_devs_t | |||
| { | |||
| public: | |||
| char *linux_wave_out, *linux_seq_in; | |||
| }; | |||
| /**Configuration file functions*/ | |||
| class Config | |||
| { | |||
| public: | |||
| /** Constructor*/ | |||
| Config(); | |||
| /** Destructor*/ | |||
| Config(const Config& ) = delete; | |||
| ~Config(); | |||
| struct { | |||
| char *LinuxOSSWaveOutDev, *LinuxOSSSeqInDev; | |||
| oss_devs_t oss_devs; | |||
| int SampleRate, SoundBufferSize, OscilSize, SwapStereo; | |||
| int WindowsWaveOutId, WindowsMidiInId; | |||
| int BankUIAutoClose; | |||
| @@ -62,12 +73,12 @@ class Config | |||
| void clearbankrootdirlist(); | |||
| void clearpresetsdirlist(); | |||
| void init(); | |||
| void save(); | |||
| void save() const; | |||
| static rtosc::Ports &ports; | |||
| static const rtosc::Ports &ports; | |||
| private: | |||
| void readConfig(const char *filename); | |||
| void saveConfig(const char *filename); | |||
| void getConfigFileName(char *name, int namesize); | |||
| void saveConfig(const char *filename) const; | |||
| void getConfigFileName(char *name, int namesize) const; | |||
| }; | |||
| #endif | |||
| @@ -25,6 +25,8 @@ | |||
| #include "Part.h" | |||
| #include "../Misc/Stereo.h" | |||
| #include "../Misc/Util.h" | |||
| #include "../Params/LFOParams.h" | |||
| #include "../Effects/EffectMgr.h" | |||
| #include "../DSP/FFTwrapper.h" | |||
| @@ -286,12 +288,15 @@ vuData::vuData(void) | |||
| rmspeakl(0.0f), rmspeakr(0.0f), clipped(0) | |||
| {} | |||
| Master::Master(const SYNTH_T &synth_) | |||
| :HDDRecorder(synth_), ctl(synth_), midi(Master::ports), frozenState(false), pendingMemory(false), synth(synth_) | |||
| Master::Master(const SYNTH_T &synth_, Config* config) | |||
| :HDDRecorder(synth_), ctl(synth_), | |||
| microtonal(config->cfg.GzipCompression), bank(config), | |||
| midi(Master::ports), frozenState(false), pendingMemory(false), | |||
| synth(synth_), gzip_compression(config->cfg.GzipCompression) | |||
| { | |||
| bToU = NULL; | |||
| uToB = NULL; | |||
| memory = new Allocator(); | |||
| memory = new AllocatorClass(); | |||
| swaplr = 0; | |||
| off = 0; | |||
| smps = 0; | |||
| @@ -310,7 +315,8 @@ Master::Master(const SYNTH_T &synth_) | |||
| } | |||
| for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) | |||
| part[npart] = new Part(*memory, synth, µtonal, fft); | |||
| part[npart] = new Part(*memory, synth, config->cfg.GzipCompression, | |||
| config->cfg.Interpolation, µtonal, fft); | |||
| //Insertion Effects init | |||
| for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) | |||
| @@ -1044,7 +1050,7 @@ int Master::saveXML(const char *filename) | |||
| add2XML(xml); | |||
| xml->endbranch(); | |||
| int result = xml->saveXMLfile(filename); | |||
| int result = xml->saveXMLfile(filename, gzip_compression); | |||
| delete (xml); | |||
| return result; | |||
| } | |||
| @@ -49,7 +49,7 @@ class Master | |||
| { | |||
| public: | |||
| /** Constructor TODO make private*/ | |||
| Master(const SYNTH_T &synth); | |||
| Master(const SYNTH_T &synth, class Config *config); | |||
| /** Destructor*/ | |||
| ~Master(); | |||
| @@ -171,6 +171,7 @@ class Master | |||
| rtosc::ThreadLink *uToB; | |||
| bool pendingMemory; | |||
| const SYNTH_T &synth; | |||
| const int& gzip_compression; //!< value from config | |||
| private: | |||
| float sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; | |||
| float sysefxsend[NUM_SYS_EFX][NUM_SYS_EFX]; | |||
| @@ -75,7 +75,8 @@ const rtosc::Ports Microtonal::ports = { | |||
| }; | |||
| Microtonal::Microtonal() | |||
| Microtonal::Microtonal(const int &gzip_compression) | |||
| : gzip_compression(gzip_compression) | |||
| { | |||
| defaults(); | |||
| } | |||
| @@ -688,7 +689,7 @@ int Microtonal::saveXML(const char *filename) const | |||
| add2XML(xml); | |||
| xml->endbranch(); | |||
| int result = xml->saveXMLfile(filename); | |||
| int result = xml->saveXMLfile(filename, gzip_compression); | |||
| delete (xml); | |||
| return result; | |||
| } | |||
| @@ -36,7 +36,7 @@ class Microtonal | |||
| { | |||
| public: | |||
| /**Constructor*/ | |||
| Microtonal(); | |||
| Microtonal(const int& gzip_compression); | |||
| /**Destructor*/ | |||
| ~Microtonal(); | |||
| void defaults(); | |||
| @@ -131,6 +131,8 @@ class Microtonal | |||
| //the real tunning is x1/x2 | |||
| unsigned int x1, x2; | |||
| } octave[MAX_OCTAVE_SIZE], tmpoctave[MAX_OCTAVE_SIZE]; | |||
| const int& gzip_compression; | |||
| }; | |||
| #endif | |||
| @@ -12,7 +12,6 @@ | |||
| #include <lo/lo.h> | |||
| #include <unistd.h> | |||
| #include <dirent.h> | |||
| #include "../UI/Connection.h" | |||
| #include "../UI/Fl_Osc_Interface.h" | |||
| @@ -20,6 +19,7 @@ | |||
| #include <map> | |||
| #include "Util.h" | |||
| #include "TmpFileMgr.h" | |||
| #include "Master.h" | |||
| #include "Part.h" | |||
| #include "PresetExtractor.h" | |||
| @@ -459,13 +459,12 @@ namespace Nio | |||
| } | |||
| /* Implementation */ | |||
| class MiddleWareImpl | |||
| class MiddleWareImpl : TmpFileMgr | |||
| { | |||
| static constexpr const char* tmp_nam_prefix = "/tmp/zynaddsubfx_"; | |||
| MiddleWare *parent; | |||
| //Detect if the name of the process is 'zynaddsubfx' | |||
| bool isPlugin() | |||
| bool isPlugin() const | |||
| { | |||
| std::string proc_file = "/proc/" + to_s(getpid()) + "/comm"; | |||
| std::ifstream ifs(proc_file); | |||
| @@ -477,113 +476,11 @@ class MiddleWareImpl | |||
| return true; | |||
| } | |||
| //! returns file name to where UDP port is saved | |||
| std::string get_tmp_nam() const | |||
| { | |||
| return tmp_nam_prefix + to_s(getpid()); | |||
| } | |||
| void create_tmp_file(unsigned server_port) | |||
| { | |||
| std::string tmp_nam = get_tmp_nam(); | |||
| if(0 == access(tmp_nam.c_str(), F_OK)) { | |||
| fprintf(stderr, "Error: Cannot overwrite file %s. " | |||
| "You should probably remove it.", tmp_nam.c_str()); | |||
| exit(EXIT_FAILURE); | |||
| } | |||
| FILE* tmp_fp = fopen(tmp_nam.c_str(), "w"); | |||
| if(!tmp_fp) | |||
| fprintf(stderr, "Warning: could not create new file %s.\n", | |||
| tmp_nam.c_str()); | |||
| else | |||
| fprintf(tmp_fp, "%u", server_port); | |||
| fclose(tmp_fp); | |||
| } | |||
| void clean_up_tmp_nams() const | |||
| { | |||
| DIR *dir; | |||
| struct dirent *entry; | |||
| if ((dir = opendir ("/tmp/")) != nullptr) | |||
| { | |||
| while ((entry = readdir (dir)) != nullptr) | |||
| { | |||
| std::string name = std::string("/tmp/") + entry->d_name; | |||
| if(!name.compare(0, strlen(tmp_nam_prefix),tmp_nam_prefix)) | |||
| { | |||
| std::string pid = name.substr(strlen(tmp_nam_prefix)); | |||
| std::string proc_file = "/proc/" + std::move(pid) + | |||
| "/comm"; | |||
| std::ifstream ifs(proc_file); | |||
| bool remove = false; | |||
| if(!ifs.good()) | |||
| { | |||
| fprintf(stderr, "Note: trying to remove %s - the " | |||
| "process does not exist anymore.\n", | |||
| name.c_str()); | |||
| remove = true; | |||
| } | |||
| else | |||
| { | |||
| std::string comm_name; | |||
| ifs >> comm_name; | |||
| if(comm_name == "zynaddsubfx") | |||
| fprintf(stderr, "Note: detected running " | |||
| "zynaddsubfx with PID %s.\n", | |||
| name.c_str() + strlen(tmp_nam_prefix)); | |||
| else { | |||
| fprintf(stderr, "Note: trying to remove %s - the " | |||
| "PID is owned by\n another " | |||
| "process: %s\n", | |||
| name.c_str(), comm_name.c_str()); | |||
| remove = true; | |||
| } | |||
| } | |||
| if(remove) | |||
| { | |||
| // make sure this file contains only one unsigned | |||
| unsigned udp_port; | |||
| std::ifstream ifs2(name); | |||
| if(!ifs2.good()) | |||
| fprintf(stderr, "Warning: could not open %s.\n", | |||
| name.c_str()); | |||
| else | |||
| { | |||
| ifs2 >> udp_port; | |||
| if(ifs.good()) | |||
| fprintf(stderr, "Warning: could not remove " | |||
| "%s, \n it has not been " | |||
| "written by zynaddsubfx\n", | |||
| name.c_str()); | |||
| else | |||
| { | |||
| if(std::remove(name.c_str()) != 0) | |||
| fprintf(stderr, "Warning: can not remove " | |||
| "%s.\n", name.c_str()); | |||
| } | |||
| } | |||
| } | |||
| /* one might want to connect to zyn here, | |||
| but it is not necessary: | |||
| lo_address la = lo_address_new(nullptr, udp_port.c_str()); | |||
| if(lo_send(la, "/echo", nullptr) <= 0) | |||
| fputs("Note: found crashed file %s\n", stderr); | |||
| lo_address_free(la);*/ | |||
| } | |||
| } | |||
| closedir (dir); | |||
| } else { | |||
| fputs("Warning: can not read /tmp.\n", stderr); | |||
| } | |||
| } | |||
| Config* const config; | |||
| public: | |||
| MiddleWareImpl(MiddleWare *mw, SYNTH_T synth, int prefered_port); | |||
| MiddleWareImpl(MiddleWare *mw, SYNTH_T synth, Config* config, | |||
| int preferred_port); | |||
| ~MiddleWareImpl(void); | |||
| void warnMemoryLeaks(void); | |||
| @@ -670,7 +567,10 @@ public: | |||
| auto alloc = std::async(std::launch::async, | |||
| [master,filename,this,npart](){ | |||
| Part *p = new Part(*master->memory, synth, &master->microtonal, master->fft); | |||
| Part *p = new Part(*master->memory, synth, | |||
| config->cfg.GzipCompression, | |||
| config->cfg.Interpolation, | |||
| &master->microtonal, master->fft); | |||
| if(p->loadXMLinstrument(filename)) | |||
| fprintf(stderr, "Warning: failed to load part<%s>!\n", filename); | |||
| @@ -704,7 +604,10 @@ public: | |||
| { | |||
| if(npart == -1) | |||
| return; | |||
| Part *p = new Part(*master->memory, synth, &master->microtonal, master->fft); | |||
| Part *p = new Part(*master->memory, synth, | |||
| config->cfg.GzipCompression, | |||
| config->cfg.Interpolation, | |||
| &master->microtonal, master->fft); | |||
| p->applyparameters(); | |||
| obj_store.extractPart(p, npart); | |||
| kits.extractPart(p, npart); | |||
| @@ -721,7 +624,7 @@ public: | |||
| //structures at once... TODO error handling | |||
| void loadMaster(const char *filename) | |||
| { | |||
| Master *m = new Master(synth); | |||
| Master *m = new Master(synth, config); | |||
| m->uToB = uToB; | |||
| m->bToU = bToU; | |||
| if(filename) { | |||
| @@ -829,7 +732,7 @@ public: | |||
| { | |||
| char buffer[1024]; | |||
| memset(buffer, 0, sizeof(buffer)); | |||
| DummyDataObj d(buffer, 1024, (void*)&config, this, uToB); | |||
| DummyDataObj d(buffer, 1024, (void*)config, this, uToB); | |||
| strcpy(buffer, "/config/"); | |||
| Config::ports.dispatch(msg+8, d); | |||
| @@ -896,15 +799,20 @@ public: | |||
| //Synthesis Rate Parameters | |||
| const SYNTH_T synth; | |||
| PresetsStore presetsstore; | |||
| }; | |||
| MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, int prefered_port) | |||
| :parent(mw), ui(nullptr), synth(synth_) | |||
| MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, | |||
| Config* config, int preferrred_port) | |||
| :parent(mw), config(config), ui(nullptr), synth(std::move(synth_)), | |||
| presetsstore(*config) | |||
| { | |||
| bToU = new rtosc::ThreadLink(4096*2,1024); | |||
| uToB = new rtosc::ThreadLink(4096*2,1024); | |||
| if(prefered_port != -1) | |||
| server = lo_server_new_with_proto(to_s(prefered_port).c_str(), LO_UDP, liblo_error_cb); | |||
| if(preferrred_port != -1) | |||
| server = lo_server_new_with_proto(to_s(preferrred_port).c_str(), | |||
| LO_UDP, liblo_error_cb); | |||
| else | |||
| server = lo_server_new_with_proto(NULL, LO_UDP, liblo_error_cb); | |||
| lo_server_add_method(server, NULL, NULL, handler_function, mw); | |||
| @@ -925,7 +833,7 @@ MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, int prefered_port | |||
| #ifndef PLUGINVERSION | |||
| the_bToU = bToU; | |||
| #endif | |||
| master = new Master(synth); | |||
| master = new Master(synth, config); | |||
| master->bToU = bToU; | |||
| master->uToB = uToB; | |||
| osc = GUI::genOscInterface(mw); | |||
| @@ -1340,8 +1248,9 @@ void MiddleWareImpl::warnMemoryLeaks(void) | |||
| /****************************************************************************** | |||
| * MidleWare Forwarding Stubs * | |||
| ******************************************************************************/ | |||
| MiddleWare::MiddleWare(SYNTH_T synth, int prefered_port) | |||
| :impl(new MiddleWareImpl(this, synth, prefered_port)) | |||
| MiddleWare::MiddleWare(SYNTH_T synth, Config* config, | |||
| int preferred_port) | |||
| :impl(new MiddleWareImpl(this, std::move(synth), config, preferred_port)) | |||
| {} | |||
| MiddleWare::~MiddleWare(void) | |||
| { | |||
| @@ -1432,3 +1341,13 @@ const char* MiddleWare::getServerAddress(void) const | |||
| { | |||
| return lo_server_get_url(impl->server); | |||
| } | |||
| const PresetsStore& MiddleWare::getPresetsStore() const | |||
| { | |||
| return impl->presetsstore; | |||
| } | |||
| PresetsStore& MiddleWare::getPresetsStore() | |||
| { | |||
| return impl->presetsstore; | |||
| } | |||
| @@ -4,12 +4,16 @@ | |||
| #include <string> | |||
| struct SYNTH_T; | |||
| class Master; | |||
| class Config; | |||
| class Master; | |||
| class PresetsStore; | |||
| //Link between realtime and non-realtime layers | |||
| class MiddleWare | |||
| { | |||
| public: | |||
| MiddleWare(SYNTH_T synth, int prefered_port = -1); | |||
| MiddleWare(SYNTH_T synth, Config *config, | |||
| int preferred_port = -1); | |||
| ~MiddleWare(void); | |||
| void updateResources(Master *m); | |||
| //returns internal master pointer | |||
| @@ -39,6 +43,9 @@ class MiddleWare | |||
| const SYNTH_T &getSynth(void) const; | |||
| //liblo stuff | |||
| const char* getServerAddress(void) const; | |||
| const PresetsStore& getPresetsStore() const; | |||
| PresetsStore& getPresetsStore(); | |||
| private: | |||
| class MiddleWareImpl *impl; | |||
| }; | |||
| @@ -159,6 +159,10 @@ static const Ports kitPorts = { | |||
| rToggle(Ppadenabled, "PADsynth enable"), | |||
| rParamZyn(Psendtoparteffect, "Effect Levels"), | |||
| rString(Pname, PART_MAX_NAME_LEN, "Kit User Specified Label"), | |||
| {"captureMin:", NULL, NULL, [](const char *, RtData &r) | |||
| {Part::Kit *p = (Part::Kit*)r.obj; p->Pminkey = p->parent->lastnote;}}, | |||
| {"captureMax:", NULL, NULL, [](const char *, RtData &r) | |||
| {Part::Kit *p = (Part::Kit*)r.obj; p->Pmaxkey = p->parent->lastnote;}}, | |||
| {"padpars-data:b", rProp(internal), 0, | |||
| [](const char *msg, RtData &d) { | |||
| rObject &o = *(rObject*)d.obj; | |||
| @@ -184,8 +188,12 @@ static const Ports kitPorts = { | |||
| const Ports &Part::Kit::ports = kitPorts; | |||
| const Ports &Part::ports = partPorts; | |||
| Part::Part(Allocator &alloc, const SYNTH_T &synth_, Microtonal *microtonal_, FFTwrapper *fft_) | |||
| :ctl(synth_), memory(alloc), synth(synth_) | |||
| Part::Part(Allocator &alloc, const SYNTH_T &synth_, | |||
| const int &gzip_compression, const int &interpolation, | |||
| Microtonal *microtonal_, FFTwrapper *fft_) | |||
| :ctl(synth_), memory(alloc), synth(synth_), | |||
| gzip_compression(gzip_compression), | |||
| interpolation(interpolation) | |||
| { | |||
| microtonal = microtonal_; | |||
| fft = fft_; | |||
| @@ -195,6 +203,7 @@ Part::Part(Allocator &alloc, const SYNTH_T &synth_, Microtonal *microtonal_, FFT | |||
| monomemClear(); | |||
| for(int n = 0; n < NUM_KIT_ITEMS; ++n) { | |||
| kit[n].parent = this; | |||
| kit[n].Pname = new char [PART_MAX_NAME_LEN]; | |||
| kit[n].adpars = nullptr; | |||
| kit[n].subpars = nullptr; | |||
| @@ -328,16 +337,16 @@ void Part::cleanup(bool final_) | |||
| for(int k = 0; k < POLYPHONY; ++k) | |||
| KillNotePos(k); | |||
| for(int i = 0; i < synth.buffersize; ++i) { | |||
| partoutl[i] = final_ ? 0.0f : denormalkillbuf[i]; | |||
| partoutr[i] = final_ ? 0.0f : denormalkillbuf[i]; | |||
| partoutl[i] = final_ ? 0.0f : synth.denormalkillbuf[i]; | |||
| partoutr[i] = final_ ? 0.0f : synth.denormalkillbuf[i]; | |||
| } | |||
| ctl.resetall(); | |||
| for(int nefx = 0; nefx < NUM_PART_EFX; ++nefx) | |||
| partefx[nefx]->cleanup(); | |||
| for(int n = 0; n < NUM_PART_EFX + 1; ++n) | |||
| for(int i = 0; i < synth.buffersize; ++i) { | |||
| partfxinputl[n][i] = final_ ? 0.0f : denormalkillbuf[i]; | |||
| partfxinputr[n][i] = final_ ? 0.0f : denormalkillbuf[i]; | |||
| partfxinputl[n][i] = final_ ? 0.0f : synth.denormalkillbuf[i]; | |||
| partfxinputr[n][i] = final_ ? 0.0f : synth.denormalkillbuf[i]; | |||
| } | |||
| } | |||
| @@ -579,7 +588,8 @@ void Part::NoteOn(unsigned char note, | |||
| memory.alloc<SUBnote>(kit[0].subpars, pars); | |||
| if(kit[0].Ppadenabled) | |||
| partnote[pos].kititem[0].padnote = | |||
| memory.alloc<PADnote>(kit[0].padpars, pars); | |||
| memory.alloc<PADnote>(kit[0].padpars, pars, | |||
| interpolation); | |||
| if(kit[0].Padenabled || kit[0].Psubenabled || kit[0].Ppadenabled) | |||
| @@ -598,7 +608,8 @@ void Part::NoteOn(unsigned char note, | |||
| memory.alloc<SUBnote>(kit[0].subpars, pars); | |||
| if(kit[0].Ppadenabled) | |||
| partnote[posb].kititem[0].padnote = | |||
| memory.alloc<PADnote>(kit[0].padpars, pars); | |||
| memory.alloc<PADnote>(kit[0].padpars, pars, | |||
| interpolation); | |||
| if(kit[0].Padenabled || kit[0].Psubenabled || kit[0].Ppadenabled) | |||
| partnote[posb].itemsplaying++; | |||
| @@ -627,7 +638,8 @@ void Part::NoteOn(unsigned char note, | |||
| if(kit[item].padpars && kit[item].Ppadenabled) | |||
| note1.padnote = | |||
| memory.alloc<PADnote>(kit[item].padpars, pars); | |||
| memory.alloc<PADnote>(kit[item].padpars, pars, | |||
| interpolation); | |||
| // Spawn another note (but silent) if legatomodevalid==true | |||
| if(legatomodevalid) { | |||
| @@ -643,7 +655,8 @@ void Part::NoteOn(unsigned char note, | |||
| memory.alloc<SUBnote>(kit[item].subpars, pars); | |||
| if(kit[item].padpars && kit[item].Ppadenabled) | |||
| note2.padnote = | |||
| memory.alloc<PADnote>(kit[item].padpars, pars); | |||
| memory.alloc<PADnote>(kit[item].padpars, pars, | |||
| interpolation); | |||
| if(kit[item].adpars || kit[item].subpars || kit[item].padpars) | |||
| partnote[posb].itemsplaying++; | |||
| @@ -1193,7 +1206,7 @@ int Part::saveXML(const char *filename) | |||
| add2XMLinstrument(&xml); | |||
| xml.endbranch(); | |||
| int result = xml.saveXMLfile(filename); | |||
| int result = xml.saveXMLfile(filename, gzip_compression); | |||
| return result; | |||
| } | |||
| @@ -37,7 +37,9 @@ class Part | |||
| /**Constructor | |||
| * @param microtonal_ Pointer to the microtonal object | |||
| * @param fft_ Pointer to the FFTwrapper*/ | |||
| Part(Allocator &alloc, const SYNTH_T &synth, Microtonal *microtonal_, FFTwrapper *fft_); | |||
| Part(Allocator &alloc, const SYNTH_T &synth, | |||
| const int& gzip_compression, const int& interpolation, | |||
| Microtonal *microtonal_, FFTwrapper *fft_); | |||
| /**Destructor*/ | |||
| ~Part(); | |||
| @@ -85,6 +87,7 @@ class Part | |||
| //the part's kit | |||
| struct Kit { | |||
| Part *parent; | |||
| bool Penabled, Pmuted; | |||
| unsigned char Pminkey, Pmaxkey; | |||
| char *Pname; | |||
| @@ -198,6 +201,7 @@ class Part | |||
| FFTwrapper *fft; | |||
| Allocator &memory; | |||
| const SYNTH_T &synth; | |||
| const int &gzip_compression, &interpolation; | |||
| }; | |||
| #endif | |||
| @@ -17,7 +17,6 @@ | |||
| #include "../Params/PADnoteParameters.h" | |||
| #include "../Params/Presets.h" | |||
| #include "../Params/PresetsArray.h" | |||
| #include "../Params/PresetsStore.h" | |||
| #include "../Params/SUBnoteParameters.h" | |||
| #include "../Misc/MiddleWare.h" | |||
| #include "PresetExtractor.h" | |||
| @@ -32,8 +31,9 @@ const rtosc::Ports real_preset_ports = | |||
| { | |||
| {"scan-for-presets:", 0, 0, | |||
| [](const char *msg, rtosc::RtData &d) { | |||
| presetsstore.scanforpresets(); | |||
| auto &pre = presetsstore.presets; | |||
| MiddleWare &mw = *(MiddleWare*)d.obj; | |||
| mw.getPresetsStore().scanforpresets(); | |||
| auto &pre = mw.getPresetsStore().presets; | |||
| d.reply(d.loc, "i", pre.size()); | |||
| for(unsigned i=0; i<pre.size();++i) | |||
| d.reply(d.loc, "isss", i, | |||
| @@ -84,11 +84,13 @@ const rtosc::Ports real_preset_ports = | |||
| }}, | |||
| {"clipboard-type:", 0, 0, | |||
| [](const char *msg, rtosc::RtData &d) { | |||
| d.reply(d.loc, "s", presetsstore.clipboard.type.c_str()); | |||
| const MiddleWare &mw = *(MiddleWare*)d.obj; | |||
| d.reply(d.loc, "s", mw.getPresetsStore().clipboard.type.c_str()); | |||
| }}, | |||
| {"delete:s", 0, 0, | |||
| [](const char *msg, rtosc::RtData &d) { | |||
| presetsstore.deletepreset(rtosc_argument(msg,0).s); | |||
| MiddleWare &mw = *(MiddleWare*)d.obj; | |||
| mw.getPresetsStore().deletepreset(rtosc_argument(msg,0).s); | |||
| }}, | |||
| }; | |||
| @@ -202,7 +204,7 @@ std::string doCopy(MiddleWare &mw, string url, string name) | |||
| T *t = (T*)capture<void*>(m, url+"self"); | |||
| //Extract Via mxml | |||
| //t->add2XML(&xml); | |||
| t->copy(presetsstore, name.empty()? NULL:name.c_str()); | |||
| t->copy(mw.getPresetsStore(), name.empty()? NULL:name.c_str()); | |||
| }); | |||
| return "";//xml.getXMLdata(); | |||
| @@ -241,7 +243,7 @@ std::string doArrayCopy(MiddleWare &mw, int field, string url, string name) | |||
| //Get the pointer | |||
| T *t = (T*)capture<void*>(m, url+"self"); | |||
| //Extract Via mxml | |||
| t->copy(presetsstore, field, name.empty()?NULL:name.c_str()); | |||
| t->copy(mw.getPresetsStore(), field, name.empty()?NULL:name.c_str()); | |||
| }); | |||
| return "";//xml.getXMLdata(); | |||
| @@ -415,7 +417,7 @@ void presetPaste(MiddleWare &mw, std::string url, std::string name) | |||
| string data = ""; | |||
| XMLwrapper xml; | |||
| if(name.empty()) { | |||
| data = presetsstore.clipboard.data; | |||
| data = mw.getPresetsStore().clipboard.data; | |||
| if(data.length() < 20) | |||
| return; | |||
| if(!xml.putXMLdata(data.c_str())) | |||
| @@ -440,7 +442,7 @@ void presetPasteArray(MiddleWare &mw, std::string url, int field, std::string na | |||
| string data = ""; | |||
| XMLwrapper xml; | |||
| if(name.empty()) { | |||
| data = presetsstore.clipboard.data; | |||
| data = mw.getPresetsStore().clipboard.data; | |||
| if(data.length() < 20) | |||
| return; | |||
| if(!xml.putXMLdata(data.c_str())) | |||
| @@ -0,0 +1,114 @@ | |||
| #include <cstdlib> | |||
| #include <cstring> | |||
| #include <string> | |||
| #include <cstdio> | |||
| #include <fstream> | |||
| #include <unistd.h> | |||
| #include <dirent.h> | |||
| #include "Util.h" | |||
| #include "TmpFileMgr.h" | |||
| std::string TmpFileMgr::get_tmp_nam() const | |||
| { | |||
| return tmp_nam_prefix + to_s(getpid()); | |||
| } | |||
| void TmpFileMgr::create_tmp_file(unsigned server_port) const | |||
| { | |||
| std::string tmp_nam = get_tmp_nam(); | |||
| if(0 == access(tmp_nam.c_str(), F_OK)) { | |||
| fprintf(stderr, "Error: Cannot overwrite file %s. " | |||
| "You should probably remove it.", tmp_nam.c_str()); | |||
| exit(EXIT_FAILURE); | |||
| } | |||
| FILE* tmp_fp = fopen(tmp_nam.c_str(), "w"); | |||
| if(!tmp_fp) | |||
| fprintf(stderr, "Warning: could not create new file %s.\n", | |||
| tmp_nam.c_str()); | |||
| else | |||
| fprintf(tmp_fp, "%u", server_port); | |||
| fclose(tmp_fp); | |||
| } | |||
| void TmpFileMgr::clean_up_tmp_nams() const | |||
| { | |||
| DIR *dir; | |||
| struct dirent *entry; | |||
| if ((dir = opendir ("/tmp/")) != nullptr) | |||
| { | |||
| while ((entry = readdir (dir)) != nullptr) | |||
| { | |||
| std::string name = std::string("/tmp/") + entry->d_name; | |||
| if(!name.compare(0, strlen(tmp_nam_prefix),tmp_nam_prefix)) | |||
| { | |||
| std::string pid = name.substr(strlen(tmp_nam_prefix)); | |||
| std::string proc_file = "/proc/" + std::move(pid) + | |||
| "/comm"; | |||
| std::ifstream ifs(proc_file); | |||
| bool remove = false; | |||
| if(!ifs.good()) | |||
| { | |||
| fprintf(stderr, "Note: trying to remove %s - the " | |||
| "process does not exist anymore.\n", | |||
| name.c_str()); | |||
| remove = true; | |||
| } | |||
| else | |||
| { | |||
| std::string comm_name; | |||
| ifs >> comm_name; | |||
| if(comm_name == "zynaddsubfx") | |||
| fprintf(stderr, "Note: detected running " | |||
| "zynaddsubfx with PID %s.\n", | |||
| name.c_str() + strlen(tmp_nam_prefix)); | |||
| else { | |||
| fprintf(stderr, "Note: trying to remove %s - the " | |||
| "PID is owned by\n another " | |||
| "process: %s\n", | |||
| name.c_str(), comm_name.c_str()); | |||
| remove = true; | |||
| } | |||
| } | |||
| if(remove) | |||
| { | |||
| // make sure this file contains only one unsigned | |||
| unsigned udp_port; | |||
| std::ifstream ifs2(name); | |||
| if(!ifs2.good()) | |||
| fprintf(stderr, "Warning: could not open %s.\n", | |||
| name.c_str()); | |||
| else | |||
| { | |||
| ifs2 >> udp_port; | |||
| if(ifs.good()) | |||
| fprintf(stderr, "Warning: could not remove " | |||
| "%s, \n it has not been " | |||
| "written by zynaddsubfx\n", | |||
| name.c_str()); | |||
| else | |||
| { | |||
| if(std::remove(name.c_str()) != 0) | |||
| fprintf(stderr, "Warning: can not remove " | |||
| "%s.\n", name.c_str()); | |||
| } | |||
| } | |||
| } | |||
| /* one might want to connect to zyn here, | |||
| but it is not necessary: | |||
| lo_address la = lo_address_new(nullptr, udp_port.c_str()); | |||
| if(lo_send(la, "/echo", nullptr) <= 0) | |||
| fputs("Note: found crashed file %s\n", stderr); | |||
| lo_address_free(la);*/ | |||
| } | |||
| } | |||
| closedir (dir); | |||
| } else { | |||
| fputs("Warning: can not read /tmp.\n", stderr); | |||
| } | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| /** | |||
| This file provides routines for using zyn's tmp files. | |||
| */ | |||
| class TmpFileMgr | |||
| { | |||
| static constexpr const char* tmp_nam_prefix = "/tmp/zynaddsubfx_"; | |||
| public: | |||
| //! returns file name to where UDP port is saved | |||
| std::string get_tmp_nam() const; | |||
| //! creates a tmp file with given UDP port information | |||
| void create_tmp_file(unsigned server_port) const; | |||
| //! cleans up as many tmp files as possible | |||
| void clean_up_tmp_nams() const; | |||
| }; | |||
| @@ -20,6 +20,7 @@ | |||
| */ | |||
| #include "globals.h" | |||
| #include "Util.h" | |||
| #include <vector> | |||
| #include <cassert> | |||
| @@ -45,10 +46,6 @@ | |||
| prng_t prng_state = 0x1234; | |||
| Config config; | |||
| float *denormalkillbuf; | |||
| /* | |||
| * Transform the velocity according the scaling parameter (velocity sensing) | |||
| */ | |||
| @@ -28,8 +28,6 @@ | |||
| #include <stdint.h> | |||
| #include <algorithm> | |||
| #include <set> | |||
| #include "Config.h" | |||
| #include "../globals.h" | |||
| using std::min; | |||
| using std::max; | |||
| @@ -58,10 +56,6 @@ std::string os_pid_as_padded_string(); | |||
| std::string legalizeFilename(std::string filename); | |||
| extern float *denormalkillbuf; /**<the buffer to add noise in order to avoid denormalisation*/ | |||
| extern class Config config; | |||
| void invSignal(float *sig, size_t len); | |||
| template<class T> | |||
| @@ -31,7 +31,7 @@ | |||
| #include <iostream> | |||
| #include <sstream> | |||
| #include "../globals.h" | |||
| #include "globals.h" | |||
| #include "Util.h" | |||
| using namespace std; | |||
| @@ -187,13 +187,12 @@ bool XMLwrapper::hasPadSynth() const | |||
| /* SAVE XML members */ | |||
| int XMLwrapper::saveXMLfile(const string &filename) const | |||
| int XMLwrapper::saveXMLfile(const string &filename, int compression) const | |||
| { | |||
| char *xmldata = getXMLdata(); | |||
| if(xmldata == NULL) | |||
| return -2; | |||
| int compression = config.cfg.GzipCompression; | |||
| int result = dosavefile(filename.c_str(), compression, xmldata); | |||
| free(xmldata); | |||
| @@ -49,7 +49,7 @@ class XMLwrapper | |||
| * @param filename the name of the destination file. | |||
| * @returns 0 if ok or -1 if the file cannot be saved. | |||
| */ | |||
| int saveXMLfile(const std::string &filename) const; | |||
| int saveXMLfile(const std::string &filename, int compression) const; | |||
| /** | |||
| * Return XML tree as a string. | |||
| @@ -25,13 +25,14 @@ | |||
| using namespace std; | |||
| EngineMgr &EngineMgr::getInstance(const SYNTH_T *synth) | |||
| EngineMgr &EngineMgr::getInstance(const SYNTH_T *synth, | |||
| const oss_devs_t *oss_devs) | |||
| { | |||
| static EngineMgr instance(synth); | |||
| static EngineMgr instance(synth, *oss_devs); | |||
| return instance; | |||
| } | |||
| EngineMgr::EngineMgr(const SYNTH_T *synth) | |||
| EngineMgr::EngineMgr(const SYNTH_T *synth, const oss_devs_t& oss_devs) | |||
| { | |||
| assert(synth); | |||
| Engine *defaultEng = new NulEngine(*synth); | |||
| @@ -39,8 +40,8 @@ EngineMgr::EngineMgr(const SYNTH_T *synth) | |||
| //conditional compiling mess (but contained) | |||
| engines.push_back(defaultEng); | |||
| #if OSS | |||
| engines.push_back(new OssEngine(*synth)); | |||
| engines.push_back(new OssMultiEngine(*synth)); | |||
| engines.push_back(new OssEngine(*synth, oss_devs)); | |||
| engines.push_back(new OssMultiEngine(*synth, oss_devs)); | |||
| #endif | |||
| #if ALSA | |||
| engines.push_back(new AlsaEngine(*synth)); | |||
| @@ -14,7 +14,9 @@ struct SYNTH_T; | |||
| class EngineMgr | |||
| { | |||
| public: | |||
| static EngineMgr &getInstance(const SYNTH_T *synth=NULL); | |||
| static EngineMgr &getInstance( | |||
| const SYNTH_T *synth = nullptr, | |||
| const class oss_devs_t* oss_devs = nullptr); | |||
| ~EngineMgr(); | |||
| /**Gets requested engine | |||
| @@ -39,6 +41,6 @@ class EngineMgr | |||
| AudioOut *defaultOut; | |||
| MidiIn *defaultIn; | |||
| private: | |||
| EngineMgr(const SYNTH_T *synth); | |||
| EngineMgr(const SYNTH_T *synth, const oss_devs_t &oss_devs); | |||
| }; | |||
| #endif | |||
| @@ -5,6 +5,7 @@ | |||
| #include "MidiIn.h" | |||
| #include "AudioOut.h" | |||
| #include "WavEngine.h" | |||
| #include "../Misc/Config.h" | |||
| #include <cstring> | |||
| #include <iostream> | |||
| #include <algorithm> | |||
| @@ -30,11 +31,12 @@ bool Nio::pidInClientName = false; | |||
| string Nio::defaultSource = IN_DEFAULT; | |||
| string Nio::defaultSink = OUT_DEFAULT; | |||
| void Nio::init(const SYNTH_T &synth, class Master *master) | |||
| void Nio::init(const SYNTH_T &synth, const oss_devs_t& oss_devs, | |||
| class Master *master) | |||
| { | |||
| in = &InMgr::getInstance(); //Enable input wrapper | |||
| out = &OutMgr::getInstance(&synth); //Initialize the Output Systems | |||
| eng = &EngineMgr::getInstance(&synth); //Initialize The Engines | |||
| eng = &EngineMgr::getInstance(&synth, &oss_devs); //Initialize the Engines | |||
| in->setMaster(master); | |||
| out->setMaster(master); | |||
| @@ -6,13 +6,14 @@ | |||
| class WavFile; | |||
| class Master; | |||
| struct SYNTH_T; | |||
| class oss_devs_t; | |||
| /**Interface to Nio Subsystem | |||
| * | |||
| * Should be only externally included header */ | |||
| namespace Nio | |||
| { | |||
| void init(const SYNTH_T &synth, Master *master); | |||
| void init(const SYNTH_T &synth, const oss_devs_t &oss_devs, Master *master); | |||
| bool start(void); | |||
| void stop(void); | |||
| @@ -22,6 +22,7 @@ | |||
| #include "OssEngine.h" | |||
| #include "../Misc/Util.h" | |||
| #include "../Misc/Config.h" | |||
| #include "../globals.h" | |||
| #include <cstring> | |||
| @@ -179,8 +180,11 @@ OssMidiParse(struct OssMidiParse &midi_parse, | |||
| return (0); | |||
| } | |||
| OssEngine::OssEngine(const SYNTH_T &synth) | |||
| :AudioOut(synth), audioThread(NULL), midiThread(NULL) | |||
| OssEngine::OssEngine(const SYNTH_T &synth, | |||
| const oss_devs_t& oss_devs) | |||
| :AudioOut(synth), audioThread(NULL), midiThread(NULL), | |||
| linux_oss_wave_out_dev(oss_devs.linux_wave_out), | |||
| linux_oss_seq_in_dev(oss_devs.linux_seq_in) | |||
| { | |||
| name = "OSS"; | |||
| @@ -212,7 +216,7 @@ bool OssEngine::openAudio() | |||
| const char *device = getenv("DSP_DEVICE"); | |||
| if(device == NULL) | |||
| device = config.cfg.LinuxOSSWaveOutDev; | |||
| device = linux_oss_wave_out_dev; | |||
| /* NOTE: PIPEs and FIFOs can block when opening them */ | |||
| audio.handle = open(device, O_WRONLY, O_NONBLOCK); | |||
| @@ -350,7 +354,7 @@ bool OssEngine::openMidi() | |||
| const char *device = getenv("MIDI_DEVICE"); | |||
| if(device == NULL) | |||
| device = config.cfg.LinuxOSSSeqInDev; | |||
| device = linux_oss_seq_in_dev; | |||
| /* NOTE: PIPEs and FIFOs can block when opening them */ | |||
| handle = open(device, O_RDONLY, O_NONBLOCK); | |||
| @@ -45,7 +45,7 @@ struct OssMidiParse { | |||
| class OssEngine:public AudioOut, MidiIn | |||
| { | |||
| public: | |||
| OssEngine(const SYNTH_T &synth); | |||
| OssEngine(const SYNTH_T &synth, const class oss_devs_t& oss_devs); | |||
| ~OssEngine(); | |||
| bool Start(); | |||
| @@ -83,6 +83,8 @@ class OssEngine:public AudioOut, MidiIn | |||
| bool en; | |||
| bool is32bit; | |||
| } audio; | |||
| const char* linux_oss_wave_out_dev; | |||
| //Midi | |||
| bool openMidi(); | |||
| @@ -94,6 +96,8 @@ class OssEngine:public AudioOut, MidiIn | |||
| bool en; | |||
| bool run; | |||
| } midi; | |||
| const char* linux_oss_seq_in_dev; | |||
| }; | |||
| #endif | |||
| @@ -43,8 +43,10 @@ extern MiddleWare *middleware; | |||
| using namespace std; | |||
| OssMultiEngine :: OssMultiEngine(const SYNTH_T &synth) | |||
| :AudioOut(synth) | |||
| OssMultiEngine :: OssMultiEngine(const SYNTH_T &synth, | |||
| const oss_devs_t &oss_devs) | |||
| :AudioOut(synth), | |||
| linux_oss_wave_out_dev(oss_devs.linux_wave_out) | |||
| { | |||
| /* setup variables */ | |||
| name = "OSS-MULTI"; | |||
| @@ -81,7 +83,7 @@ OssMultiEngine :: openAudio() | |||
| const char *device = getenv("DSP_DEVICE"); | |||
| if(device == 0) | |||
| device = config.cfg.LinuxOSSWaveOutDev; | |||
| device = linux_oss_wave_out_dev; | |||
| /* NOTE: PIPEs and FIFOs can block when opening them */ | |||
| handle = open(device, O_WRONLY, O_NONBLOCK); | |||
| @@ -29,7 +29,8 @@ | |||
| class OssMultiEngine : public AudioOut | |||
| { | |||
| public: | |||
| OssMultiEngine(const SYNTH_T &synth); | |||
| OssMultiEngine(const SYNTH_T &synth, | |||
| const class oss_devs_t& oss_devs); | |||
| ~OssMultiEngine(); | |||
| bool Start(); | |||
| @@ -62,6 +63,8 @@ class OssMultiEngine : public AudioOut | |||
| bool en; | |||
| bool is32bit; | |||
| const char* linux_oss_wave_out_dev; | |||
| }; | |||
| #endif | |||
| @@ -2,6 +2,7 @@ | |||
| #define OUTMGR_H | |||
| #include "../Misc/Stereo.h" | |||
| #include "../globals.h" | |||
| #include <list> | |||
| #include <string> | |||
| #include <semaphore.h> | |||
| @@ -16,7 +17,7 @@ class OutMgr | |||
| ~OutMgr(); | |||
| /**Execute a tick*/ | |||
| const Stereo<float *> tick(unsigned int frameSize) __attribute__((annotate("realtime"))); | |||
| const Stereo<float *> tick(unsigned int frameSize) REALTIME; | |||
| /**Request a new set of samples | |||
| * @param n number of requested samples (defaults to 1) | |||
| @@ -30,13 +30,14 @@ | |||
| #include "PresetsStore.h" | |||
| #include "../Misc/XMLwrapper.h" | |||
| #include "../Misc/Util.h" | |||
| #include "../Misc/Config.h" | |||
| using namespace std; | |||
| //XXX to remove | |||
| PresetsStore presetsstore; | |||
| //PresetsStore presetsstore; | |||
| PresetsStore::PresetsStore() | |||
| PresetsStore::PresetsStore(const Config& config) : config(config) | |||
| { | |||
| } | |||
| @@ -154,7 +155,7 @@ void PresetsStore::copypreset(XMLwrapper &xml, char *type, string name) | |||
| string filename("" + dirname + tmps + name + "." + &type[1] + ".xpz"); | |||
| xml.saveXMLfile(filename); | |||
| xml.saveXMLfile(filename, config.cfg.GzipCompression); | |||
| } | |||
| bool PresetsStore::pastepreset(XMLwrapper &xml, unsigned int npreset) | |||
| @@ -29,8 +29,9 @@ | |||
| class XMLwrapper; | |||
| class PresetsStore | |||
| { | |||
| const class Config& config; | |||
| public: | |||
| PresetsStore(); | |||
| PresetsStore(const class Config &config); | |||
| ~PresetsStore(); | |||
| //Clipboard stuff | |||
| @@ -62,5 +63,5 @@ class PresetsStore | |||
| void clearpresets(); | |||
| }; | |||
| extern PresetsStore presetsstore; | |||
| //extern PresetsStore presetsstore; | |||
| #endif | |||
| @@ -1434,8 +1434,8 @@ inline void ADnote::ComputeVoiceNoise(int nvoice) | |||
| */ | |||
| int ADnote::noteout(float *outl, float *outr) | |||
| { | |||
| memcpy(outl, denormalkillbuf, synth.bufferbytes); | |||
| memcpy(outr, denormalkillbuf, synth.bufferbytes); | |||
| memcpy(outl, synth.denormalkillbuf, synth.bufferbytes); | |||
| memcpy(outr, synth.denormalkillbuf, synth.bufferbytes); | |||
| if(NoteEnabled == OFF) | |||
| return 0; | |||
| @@ -482,7 +482,8 @@ void OscilGen::changebasefunction(void) | |||
| { | |||
| if(Pcurrentbasefunc != 0) { | |||
| getbasefunction(tmpsmps); | |||
| fft->smps2freqs(tmpsmps, basefuncFFTfreqs); | |||
| if(fft) | |||
| fft->smps2freqs(tmpsmps, basefuncFFTfreqs); | |||
| clearDC(basefuncFFTfreqs); | |||
| } | |||
| else //in this case basefuncFFTfreqs are not used | |||
| @@ -1139,6 +1140,8 @@ void OscilGen::paste(OscilGen &o) | |||
| RESTORE(fft); | |||
| RESTORE(basefuncFFTfreqs); | |||
| RESTORE(res); | |||
| if(this->Pcurrentbasefunc) | |||
| changebasefunction(); | |||
| this->prepare(); | |||
| } | |||
| @@ -29,8 +29,8 @@ | |||
| #include "../Misc/Util.h" | |||
| PADnote::PADnote(PADnoteParameters *parameters, | |||
| SynthParams pars) | |||
| :SynthNote(pars), pars(*parameters) | |||
| SynthParams pars, const int& interpolation) | |||
| :SynthNote(pars), pars(*parameters), interpolation(interpolation) | |||
| { | |||
| firsttime = true; | |||
| setup(pars.frequency, pars.velocity, pars.portamento, pars.note); | |||
| @@ -347,7 +347,7 @@ int PADnote::noteout(float *outl, float *outr) | |||
| float freqlo = freqrap - floor(freqrap); | |||
| if(config.cfg.Interpolation) | |||
| if(interpolation) | |||
| Compute_Cubic(outl, outr, freqhi, freqlo); | |||
| else | |||
| Compute_Linear(outl, outr, freqhi, freqlo); | |||
| @@ -30,7 +30,8 @@ | |||
| class PADnote:public SynthNote | |||
| { | |||
| public: | |||
| PADnote(PADnoteParameters *parameters, SynthParams pars); | |||
| PADnote(PADnoteParameters *parameters, SynthParams pars, | |||
| const int &interpolation); | |||
| ~PADnote(); | |||
| void legatonote(LegatoParams pars); | |||
| @@ -104,6 +105,7 @@ class PADnote:public SynthNote | |||
| float globaloldamplitude, globalnewamplitude, velocity, realfreq; | |||
| const int& interpolation; | |||
| }; | |||
| @@ -491,8 +491,8 @@ void SUBnote::computecurrentparameters() | |||
| */ | |||
| int SUBnote::noteout(float *outl, float *outr) | |||
| { | |||
| memcpy(outl, denormalkillbuf, synth.bufferbytes); | |||
| memcpy(outr, denormalkillbuf, synth.bufferbytes); | |||
| memcpy(outl, synth.denormalkillbuf, synth.bufferbytes); | |||
| memcpy(outr, synth.denormalkillbuf, synth.bufferbytes); | |||
| if(NoteEnabled == OFF) | |||
| return 0; | |||
| @@ -39,7 +39,13 @@ decl {\#include "../Misc/Util.h"} {public local | |||
| } | |||
| decl {\#include "../Effects/EffectMgr.h"} {public local | |||
| } | |||
| } | |||
| decl {\#include "../Effects/Phaser.h" /* for macros only, TODO */} {public local | |||
| } | |||
| decl {\#include "../Effects/Alienwah.h" /* for macros only, TODO */ } {public local | |||
| } | |||
| decl {\#include "PresetsUI.h"} {public local | |||
| } | |||
| @@ -943,7 +949,7 @@ stagescounter->oscMove("parameter"+to_s(npb+4));} | |||
| Fl_Counter stagescounter { | |||
| label {St.} | |||
| callback {eqgraph->update();} | |||
| tooltip {Additional filter stages} xywh {340 60 30 15} type Simple labelfont 1 labelsize 10 minimum 1 maximum 127 step 1 textfont 1 textsize 11 | |||
| tooltip {Additional filter stages} xywh {340 60 30 15} type Simple labelfont 1 labelsize 10 minimum 0 maximum 127 step 1 textfont 1 textsize 11 | |||
| code0 {o->init("parameter14");} | |||
| class Fl_Osc_Counter | |||
| } | |||
| @@ -223,3 +223,13 @@ void EnvelopeFreeEdit::update(void) | |||
| oscWrite("Penvval"); | |||
| oscWrite("Penvsustain"); | |||
| } | |||
| void EnvelopeFreeEdit::rebase(std::string new_base) | |||
| { | |||
| osc->renameLink(loc+"Penvpoints", new_base+"Penvpoints", this); | |||
| osc->renameLink(loc+"Penvdt", new_base+"Penvdt", this); | |||
| osc->renameLink(loc+"Penvval", new_base+"Penvval", this); | |||
| osc->renameLink(loc+"Penvsustain", new_base+"Penvsustain", this); | |||
| loc = new_base; | |||
| update(); | |||
| } | |||
| @@ -13,17 +13,18 @@ | |||
| #define ENV_ADSR_FILTER 4 | |||
| #define ENV_ADSR_BW 5 | |||
| class EnvelopeFreeEdit : public Fl_Box, Fl_Osc_Widget | |||
| class EnvelopeFreeEdit : public Fl_Box, public Fl_Osc_Widget | |||
| { | |||
| public: | |||
| EnvelopeFreeEdit(int x,int y, int w, int h, const char *label=0); | |||
| void init(void); | |||
| void setpair(Fl_Box *pair_); | |||
| int handle(int event); | |||
| int handle(int event) override; | |||
| void draw(void); | |||
| void draw(void) override; | |||
| void OSC_raw(const char *msg) override; | |||
| void update(void); | |||
| void update(void) override; | |||
| void rebase(std::string new_base) override; | |||
| int lastpoint; | |||
| @@ -24,6 +24,6 @@ class Fl_EQGraph:public Fl_Box, public Fl_Osc_Widget | |||
| float getfreqpos(float freq) const; | |||
| float samplerate; | |||
| float num[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]; | |||
| float dem[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]; | |||
| float num[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]; | |||
| float dem[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]; | |||
| }; | |||
| @@ -32,7 +32,7 @@ void Fl_EQGraph::OSC_raw(const char *msg) | |||
| samplerate = rtosc_argument(msg, 0).f; | |||
| } else { | |||
| memcpy(dem, rtosc_argument(msg, 0).b.data, sizeof(dem)); | |||
| memcpy(num, rtosc_argument(msg, 1).b.data, sizeof(dem)); | |||
| memcpy(num, rtosc_argument(msg, 1).b.data, sizeof(num)); | |||
| redraw(); | |||
| } | |||
| } | |||
| @@ -141,16 +141,24 @@ void Fl_EQGraph::draw(void) | |||
| double Fl_EQGraph::getresponse(int maxy,float freq) const | |||
| { | |||
| const float angle = 2*PI*freq/samplerate; | |||
| std::complex<float> num_res = 0; | |||
| std::complex<float> dem_res = 0; | |||
| float mag = 1; | |||
| //std::complex<float> num_res = 0; | |||
| //std::complex<float> dem_res = 0; | |||
| for(int i = 0; i < MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1; ++i) { | |||
| num_res += FFTpolar<float>(num[i], i*angle); | |||
| dem_res += FFTpolar<float>(dem[i], i*angle); | |||
| for(int i = 0; i < MAX_EQ_BANDS*MAX_FILTER_STAGES; ++i) { | |||
| if(num[3*i] == 0) | |||
| break; | |||
| std::complex<float> num_res= 0; | |||
| std::complex<float> dem_res= 0; | |||
| for(int j=0; j<3; ++j) { | |||
| num_res += FFTpolar<float>(num[3*i+j], j*angle); | |||
| dem_res += FFTpolar<float>(dem[3*i+j], j*angle); | |||
| } | |||
| mag *= abs(num_res/dem_res); | |||
| } | |||
| float dbresp=20*log(abs(num_res/dem_res))/log(10); | |||
| float dbresp=20*log(mag)/log(10); | |||
| //rescale | |||
| return (int) ((dbresp/MAX_DB+1.0)*maxy/2.0); | |||
| @@ -78,7 +78,10 @@ int Fl_Osc_Dial::handle(int ev) | |||
| void Fl_Osc_Dial::OSC_value(int v) | |||
| { | |||
| value(v+minimum()+fmodf(value(), 1)); | |||
| if(64 != (int)minimum()) | |||
| value(v+minimum()+fmodf(value(), 1)); | |||
| else | |||
| value(v+fmodf(value(), 1)); | |||
| } | |||
| void Fl_Osc_Dial::OSC_value(char v) | |||
| @@ -95,11 +98,10 @@ void Fl_Osc_Dial::cb(void) | |||
| { | |||
| assert(osc); | |||
| /* if((maximum()-minimum()) == 127 || (maximum()-minimum()) == 255) { | |||
| oscWrite(ext, "i", (int)(value()-minimum())); | |||
| } | |||
| else*/ | |||
| if(64 != (int)minimum()) | |||
| oscWrite(ext, "i", (int)(value()-minimum())); | |||
| else | |||
| oscWrite(ext, "i", (int)(value())); | |||
| if(cb_data.first) | |||
| cb_data.first(this, cb_data.second); | |||
| @@ -4,7 +4,7 @@ | |||
| #include "Fl_Osc_Widget.H" | |||
| #include <string> | |||
| class Fl_Osc_DialF:public WidgetPDial, Fl_Osc_Widget | |||
| class Fl_Osc_DialF:public WidgetPDial, public Fl_Osc_Widget | |||
| { | |||
| public: | |||
| @@ -4,7 +4,7 @@ | |||
| #include "Fl_Osc_Widget.H" | |||
| //consider merging with Fl_Oscilloscope | |||
| class Fl_OscilSpectrum : public Fl_Box, Fl_Osc_Widget | |||
| class Fl_OscilSpectrum : public Fl_Box, public Fl_Osc_Widget | |||
| { | |||
| public: | |||
| Fl_OscilSpectrum(int x,int y, int w, int h, const char *label=0) | |||
| @@ -6,7 +6,7 @@ | |||
| #include "Fl_Osc_Widget.H" | |||
| #include "Fl_Osc_Interface.h" | |||
| class PADnoteOvertonePosition: public Fl_Box, Fl_Osc_Widget | |||
| class PADnoteOvertonePosition: public Fl_Box, public Fl_Osc_Widget | |||
| { | |||
| public: | |||
| PADnoteOvertonePosition(int x,int y, int w, int h, const char *label=0) | |||
| @@ -13,7 +13,7 @@ | |||
| class FilterParams; | |||
| class FormantFilterGraph : public Fl_Box, Fl_Osc_Widget { | |||
| class FormantFilterGraph : public Fl_Box, public Fl_Osc_Widget { | |||
| public: | |||
| FormantFilterGraph(int x,int y, int w, int h, const char *label=0); | |||
| void init(int *nvowel_, int *nformant_); | |||
| @@ -17,7 +17,7 @@ decl {\#include <stdio.h>} {public local | |||
| decl {\#include <string.h>} {public local | |||
| } | |||
| decl {\#if defined(__linux__) && ! defined(PLUGINVERSION) | |||
| decl {\#if ! defined(PLUGINVERSION) && HAS_X11 | |||
| \#include "zynaddsubfx.xpm" | |||
| \#endif} {public local | |||
| } | |||
| @@ -76,7 +76,7 @@ extern NSM_Client *nsm; | |||
| \#endif} {public local | |||
| } | |||
| decl {\#if defined(__linux__) && ! defined(PLUGINVERSION) | |||
| decl {\#if !defined(PLUGINVERSION) && HAS_X11 | |||
| \#include <X11/xpm.h> | |||
| \#endif} {public local | |||
| } | |||
| @@ -1502,7 +1502,7 @@ configui=new ConfigUI(osc); | |||
| make_window(); | |||
| fl_open_display(); | |||
| \#if defined(__linux__) && ! defined(PLUGINVERSION) | |||
| \#if !defined(PLUGINVERSION) && HAS_X11 | |||
| Pixmap p, mask; | |||
| XCreatePixmapFromData(fl_display, DefaultRootWindow(fl_display), | |||
| (char**)zynaddsubfx_xpm, &p, &mask, NULL); | |||
| @@ -112,13 +112,17 @@ class PartKitItem {open : {public Fl_Osc_Group} | |||
| } | |||
| Fl_Button {} { | |||
| label m | |||
| callback {o->oscWrite("grabMinKey");} | |||
| callback {o->oscWrite("captureMin"); | |||
| minkcounter->update(); | |||
| maxkcounter->update();} | |||
| tooltip {set the minimum key to the last pressed key} xywh {285 3 15 12} box THIN_UP_BOX labelsize 10 | |||
| class Fl_Osc_Button | |||
| } | |||
| Fl_Button {} { | |||
| label M | |||
| callback {o->oscWrite("grabMaxKey");} | |||
| callback {o->oscWrite("captureMax"); | |||
| minkcounter->update(); | |||
| maxkcounter->update();} | |||
| tooltip {set the maximum key to the last pressed key} xywh {315 3 15 12} box THIN_UP_BOX labelsize 10 | |||
| class Fl_Osc_Button | |||
| } | |||
| @@ -124,7 +124,7 @@ if (x==0) o->selection_color(0); | |||
| callback {int x=64; | |||
| if (Fl::event_button1() || Fl::event() == FL_MOUSEWHEEL) x=127-(int)o->value(); | |||
| else o->value(x); | |||
| o->osc->writeValue(o->loc+"Phrelbw"+to_s(n), (char) x);} | |||
| o->osc->writeValue(o->loc + o->ext, (char) x)}; | |||
| tooltip {harmonic's bandwidth} xywh {0 157 10 130} type {Vert Knob} box FLAT_BOX selection_color 222 maximum 127 step 1 value 64 | |||
| class PPSlider | |||
| } | |||
| @@ -153,7 +153,8 @@ make_window(); | |||
| harmonic->show(); | |||
| mag->ext = "Phmag" + to_s(n); | |||
| mag->oscRegister(mag->ext.c_str()); | |||
| osc->createLink(base+"Phrelbw"+to_s(n), bw); | |||
| bw->ext = "Phrelbw" + to_s(n); | |||
| bw->oscRegister(bw->ext.c_str()); | |||
| osc->requestValue(base+"Phrelbw"+to_s(n)); | |||
| end();} {} | |||
| @@ -161,7 +162,7 @@ end();} {} | |||
| Function {refresh()} {} { | |||
| code {// request values for the widgets | |||
| mag->oscWrite(mag->ext); | |||
| osc->requestValue(base+"Phrelbw"+to_s(n));} {} | |||
| bw->oscWrite(bw->ext);} {} | |||
| } | |||
| Function {~SUBnoteharmonic()} {} { | |||
| code {harmonic->hide(); | |||
| @@ -0,0 +1,40 @@ | |||
| /* | |||
| ZynAddSubFX - a software synthesizer | |||
| globals.h - it contains program settings and the program capabilities | |||
| like number of parts, of effects | |||
| Copyright (C) 2002-2005 Nasca Octavian Paul | |||
| Author: Nasca Octavian Paul | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of version 2 of the GNU General Public License | |||
| as published by the Free Software Foundation. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License (version 2 or later) for more details. | |||
| You should have received a copy of the GNU General Public License (version 2) | |||
| along with this program; if not, write to the Free Software Foundation, | |||
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include "Misc/Util.h" | |||
| #include "globals.h" | |||
| void SYNTH_T::alias() | |||
| { | |||
| halfsamplerate_f = (samplerate_f = samplerate) / 2.0f; | |||
| buffersize_f = buffersize; | |||
| bufferbytes = buffersize * sizeof(float); | |||
| oscilsize_f = oscilsize; | |||
| //produce denormal buf | |||
| // note: once there will be more buffers, use a cleanup function | |||
| // for deleting the buffers and also call it in the dtor | |||
| denormalkillbuf.resize(buffersize); | |||
| for(int i = 0; i < buffersize; ++i) | |||
| denormalkillbuf[i] = (RND - 0.5f) * 1e-16; | |||
| } | |||
| @@ -252,22 +252,51 @@ enum LegatoMsg { | |||
| #define O_BINARY 0 | |||
| #endif | |||
| template<class T> | |||
| class m_unique_ptr | |||
| { | |||
| T* ptr = nullptr; | |||
| public: | |||
| m_unique_ptr() = default; | |||
| m_unique_ptr(m_unique_ptr&& other) { | |||
| ptr = other.ptr; | |||
| other.ptr = nullptr; | |||
| } | |||
| m_unique_ptr(const m_unique_ptr& other) = delete; | |||
| ~m_unique_ptr() { ptr = nullptr; } | |||
| void resize(unsigned sz) { | |||
| delete[] ptr; | |||
| ptr = new T[sz]; } | |||
| operator T*() { return ptr; } | |||
| operator const T*() const { return ptr; } | |||
| T& operator[](unsigned idx) { return ptr[idx]; } | |||
| const T& operator[](unsigned idx) const { return ptr[idx]; } | |||
| }; | |||
| //temporary include for synth->{samplerate/buffersize} members | |||
| struct SYNTH_T { | |||
| SYNTH_T(void) | |||
| :samplerate(44100), buffersize(256), oscilsize(1024) | |||
| { | |||
| alias(); | |||
| } | |||
| SYNTH_T(const SYNTH_T& ) = delete; | |||
| SYNTH_T(SYNTH_T&& ) = default; | |||
| /** the buffer to add noise in order to avoid denormalisation */ | |||
| m_unique_ptr<float> denormalkillbuf; | |||
| /**Sampling rate*/ | |||
| unsigned int samplerate; | |||
| /** | |||
| * The size of a sound buffer (or the granularity) | |||
| * All internal transfer of sound data use buffer of this size | |||
| * All parameters are constant during this period of time, exception | |||
| * some parameters(like amplitudes) which are linear interpolated. | |||
| * All internal transfer of sound data use buffer of this size. | |||
| * All parameters are constant during this period of time, except | |||
| * some parameters(like amplitudes) which are linearly interpolated. | |||
| * If you increase this you'll ecounter big latencies, but if you | |||
| * decrease this the CPU requirements gets high. | |||
| */ | |||
| @@ -291,13 +320,7 @@ struct SYNTH_T { | |||
| { | |||
| return buffersize_f / samplerate_f; | |||
| } | |||
| inline void alias(void) | |||
| { | |||
| halfsamplerate_f = (samplerate_f = samplerate) / 2.0f; | |||
| buffersize_f = buffersize; | |||
| bufferbytes = buffersize * sizeof(float); | |||
| oscilsize_f = oscilsize; | |||
| } | |||
| void alias(void); | |||
| static float numRandom(void); //defined in Util.cpp for now | |||
| }; | |||
| #endif | |||
| @@ -76,7 +76,7 @@ NSM_Client *nsm = 0; | |||
| char *instance_name = 0; | |||
| void exitprogram(); | |||
| void exitprogram(const Config &config); | |||
| extern pthread_t main_thread; | |||
| @@ -91,21 +91,21 @@ void sigterm_exit(int /*sig*/) | |||
| /* | |||
| * Program initialisation | |||
| */ | |||
| void initprogram(SYNTH_T synth, int prefered_port) | |||
| void initprogram(SYNTH_T synth, Config* config, int prefered_port) | |||
| { | |||
| middleware = new MiddleWare(synth, prefered_port); | |||
| middleware = new MiddleWare(std::move(synth), config, prefered_port); | |||
| master = middleware->spawnMaster(); | |||
| master->swaplr = swaplr; | |||
| signal(SIGINT, sigterm_exit); | |||
| signal(SIGTERM, sigterm_exit); | |||
| Nio::init(master->synth, master); | |||
| Nio::init(master->synth, config->cfg.oss_devs, master); | |||
| } | |||
| /* | |||
| * Program exit | |||
| */ | |||
| void exitprogram() | |||
| void exitprogram(const Config& config) | |||
| { | |||
| Nio::stop(); | |||
| config.save(); | |||
| @@ -121,7 +121,6 @@ void exitprogram() | |||
| delete nsm; | |||
| #endif | |||
| delete [] denormalkillbuf; | |||
| FFT_cleanup(); | |||
| } | |||
| @@ -129,6 +128,7 @@ int main(int argc, char *argv[]) | |||
| { | |||
| main_thread = pthread_self(); | |||
| SYNTH_T synth; | |||
| Config config; | |||
| config.init(); | |||
| int noui = 0; | |||
| cerr | |||
| @@ -375,12 +375,14 @@ int main(int argc, char *argv[]) | |||
| return 0; | |||
| } | |||
| //produce denormal buf | |||
| denormalkillbuf = new float [synth.buffersize]; | |||
| for(int i = 0; i < synth.buffersize; ++i) | |||
| denormalkillbuf[i] = (RND - 0.5f) * 1e-16; | |||
| cerr.precision(1); | |||
| cerr << std::fixed; | |||
| cerr << "\nSample Rate = \t\t" << synth.samplerate << endl; | |||
| cerr << "Sound Buffer Size = \t" << synth.buffersize << " samples" << endl; | |||
| cerr << "Internal latency = \t" << synth.dt() * 1000.0f << " ms" << endl; | |||
| cerr << "ADsynth Oscil.Size = \t" << synth.oscilsize << " samples" << endl; | |||
| initprogram(synth, prefered_port); | |||
| initprogram(std::move(synth), &config, prefered_port); | |||
| if(!loadfile.empty()) { | |||
| int tmp = master->loadXML(loadfile.c_str()); | |||
| @@ -413,13 +415,6 @@ int main(int argc, char *argv[]) | |||
| //Run the Nio system | |||
| bool ioGood = Nio::start(); | |||
| cerr.precision(1); | |||
| cerr << std::fixed; | |||
| cerr << "\nSample Rate = \t\t" << synth.samplerate << endl; | |||
| cerr << "Sound Buffer Size = \t" << synth.buffersize << " samples" << endl; | |||
| cerr << "Internal latency = \t" << synth.dt() * 1000.0f << " ms" << endl; | |||
| cerr << "ADsynth Oscil.Size = \t" << synth.oscilsize << " samples" << endl; | |||
| if(!execAfterInit.empty()) { | |||
| cout << "Executing user supplied command: " << execAfterInit << endl; | |||
| @@ -519,6 +514,6 @@ done: | |||
| middleware->tick(); | |||
| } | |||
| exitprogram(); | |||
| exitprogram(config); | |||
| return 0; | |||
| } | |||