zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit 21e395b14cf8d08e63e144222e10ca1a172ece10
parent e85dd19254df52b18d4d53554d4a60c8d61a16a4
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Sat, 22 May 2010 07:36:01 -0400

Merge branch 'nio'

Diffstat:
Mdoc/gen/Makefile | 7+++++++
Adoc/gen/echo.tex | 48++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/DSP/FFTwrapper.cpp | 5+++++
Msrc/DSP/FFTwrapper.h | 1+
Msrc/Misc/Bank.cpp | 399+++++++++++++++++++++++--------------------------------------------------------
Msrc/Misc/Bank.h | 49+++++++++++++++++++++++--------------------------
Msrc/Misc/Config.cpp | 165+++++++++++++++++++++++++++----------------------------------------------------
Msrc/Misc/Config.h | 6+++---
Msrc/Misc/Dump.cpp | 4++--
Msrc/Misc/Master.cpp | 14+++++++++-----
Msrc/Misc/Master.h | 6++++--
Msrc/Misc/Part.cpp | 19+++++++++----------
Msrc/Misc/Part.h | 6+++---
Msrc/Misc/Recorder.cpp | 11++++++-----
Msrc/Misc/Util.cpp | 12+++++++++++-
Msrc/Misc/Util.h | 2++
Msrc/Misc/WavFile.cpp | 6+++++-
Msrc/Misc/XMLwrapper.cpp | 23++++++++++++++---------
Msrc/Nio/AlsaEngine.cpp | 28+++++++++++++++-------------
Msrc/Nio/AlsaEngine.h | 4++--
Msrc/Nio/AudioOut.cpp | 36+++++++++---------------------------
Msrc/Nio/AudioOut.h | 7+++----
Msrc/Nio/CMakeLists.txt | 1+
Msrc/Nio/EngineMgr.cpp | 38+++++++++++++++++++++-----------------
Msrc/Nio/EngineMgr.h | 6+++---
Msrc/Nio/InMgr.cpp | 42+++++++++++++++++++++++++-----------------
Msrc/Nio/InMgr.h | 11+++++------
Msrc/Nio/JackEngine.cpp | 13+++++++------
Msrc/Nio/JackEngine.h | 2+-
Msrc/Nio/MidiIn.cpp | 8++++----
Asrc/Nio/Nio.cpp | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Nio/Nio.h | 39+++++++++++++++++++++++++++++++++++++++
Msrc/Nio/NulEngine.cpp | 6+++---
Msrc/Nio/NulEngine.h | 2+-
Msrc/Nio/OssEngine.cpp | 4++--
Msrc/Nio/OssEngine.h | 2+-
Msrc/Nio/OutMgr.cpp | 41+++++++++++++++++++++++++++--------------
Msrc/Nio/OutMgr.h | 10++++------
Msrc/Nio/PaEngine.h | 1-
Msrc/Nio/SafeQueue.cpp | 45++++++++++++++++++++++-----------------------
Msrc/Nio/SafeQueue.h | 12+++++++++---
Msrc/Nio/WavEngine.cpp | 32+++++++++++++++++++++-----------
Msrc/Nio/WavEngine.h | 2+-
Msrc/Params/PresetsStore.cpp | 10+++-------
Msrc/Synth/Envelope.cpp | 27+++++++++++++--------------
Msrc/Synth/Envelope.h | 8+++-----
Msrc/Synth/OscilGen.cpp | 657+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/Synth/OscilGen.h | 26++++++++------------------
Msrc/Tests/XMLwrapperTest.h | 20++++++++++++++++++++
Msrc/UI/BankUI.fl | 54++++++++++++++++++++++++++++--------------------------
Msrc/UI/ConfigUI.fl | 71+++++++++++++++++++++++++++++++++++------------------------------------
Msrc/UI/MasterUI.fl | 2+-
Msrc/UI/NioUI.cpp | 55++++++++++++++++++++++++++++++++-----------------------
Msrc/UI/NioUI.h | 2--
Msrc/main.cpp | 80+++++++++++++++++++++++++++++++++++--------------------------------------------
55 files changed, 1168 insertions(+), 1119 deletions(-)

diff --git a/doc/gen/Makefile b/doc/gen/Makefile @@ -1,4 +1,11 @@ +all:echo.png ad-note.png + ad-note.png: ad-note.tex pslatex ad-note.tex convert ad-note.dvi -trim ad-note.png rm ad-note.dvi ad-note.log ad-note.aux + +echo.png: echo.tex + pslatex echo.tex + convert echo.dvi -trim echo.png + rm echo.dvi echo.log echo.aux diff --git a/doc/gen/echo.tex b/doc/gen/echo.tex @@ -0,0 +1,48 @@ +\documentclass[11pt]{report} +\pagestyle{empty} +\usepackage{pst-sigsys} +\begin{document} +\begin{pspicture}[showgrid=true](0,0)(10,10) + %Style + \psset{framesize=1 .65} + \psset{style=Arrow} + + %In/Out + \rput(0,7){\rnode{in}{$x[n]$}} + \rput(10,5){\rnode{out}{$y[n]$}} + + %Panning + \psfblock[framesize=1.3 .65](1.5,7){pan}{Panning} + \ncline{in}{pan} + + %Crossover + \psfblock[framesize=1.8 .65](5,5){cross}{Crossover} + + %Gain + \psfblock(7,5){gain}{Gain} + + %Feedback + \psfblock[framesize=1.6 .65](5,7){fb}{Feedback} + \ncline{cross}{fb} + \pscircleop(3,7){combine} + \ncline{pan}{combine} + \ncline{fb}{combine} + + %Dampining + \psfblock[framesize=1.6 .65](3,6){hidamp}{Dampening} + \ncline{combine}{hidamp} + + %Delay + \psfblock(3,5){delay}{$z^{-n}$} + \pscircleop(1,5){delayp} + + \nclist{ncline}{delayp,delay,cross,gain,out} + %\ncline{in}{delayp} + + %Filter Unit + \psfblock(1,6){fildelay}{$z^{-1}$} + \ncline[arrows=<->]{fildelay}{hidamp} + \ncline{fildelay}{delayp} + +\end{pspicture} +\end{document} diff --git a/src/DSP/FFTwrapper.cpp b/src/DSP/FFTwrapper.cpp @@ -134,3 +134,8 @@ void deleteFFTFREQS(FFTFREQS *f) f->c = f->s = NULL; } +void FFT_cleanup() +{ + fftw_cleanup(); +} + diff --git a/src/DSP/FFTwrapper.h b/src/DSP/FFTwrapper.h @@ -66,5 +66,6 @@ class FFTwrapper void newFFTFREQS(FFTFREQS *f, int size); void deleteFFTFREQS(FFTFREQS *f); +void FFT_cleanup(); #endif diff --git a/src/Misc/Bank.cpp b/src/Misc/Bank.cpp @@ -1,9 +1,11 @@ /* ZynAddSubFX - a software synthesizer - Bank.h - Instrument Bank + Bank.cpp - Instrument Bank Copyright (C) 2002-2005 Nasca Octavian Paul + Copyright (C) 2010-2010 Mark McCurry Author: Nasca Octavian Paul + Mark McCurry 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 @@ -26,6 +28,8 @@ #include <stdlib.h> #include <dirent.h> #include <sys/stat.h> +#include <algorithm> +#include <iostream> #include <sys/types.h> #include <fcntl.h> @@ -39,47 +43,25 @@ //if this file exists into a directory, this make the directory to be considered as a bank, even if it not contains a instrument file #define FORCE_BANK_DIR_FILE ".bankdir" +using namespace std; + Bank::Bank() + :defaultinsname(" ") { - ZERO(defaultinsname, PART_MAX_NAME_LEN); - snprintf(defaultinsname, PART_MAX_NAME_LEN, "%s", " "); - - for(int i = 0; i < BANK_SIZE; i++) { - ins[i].used = false; - ins[i].filename = NULL; - ins[i].info.PADsynth_used = false; - } - dirname = NULL; clearbank(); - - - - for(int i = 0; i < MAX_NUM_BANKS; i++) { - banks[i].dir = NULL; - banks[i].name = NULL; - } - bankfiletitle = dirname; - loadbank(config.cfg.currentBankDir); } Bank::~Bank() { - for(int i = 0; i < MAX_NUM_BANKS; i++) { - if(banks[i].dir != NULL) - delete [] banks[i].dir; - if(banks[i].name != NULL) - delete [] banks[i].name; - } - clearbank(); } /* * Get the name of an instrument from the bank */ -char *Bank::getname(unsigned int ninstrument) +string Bank::getname(unsigned int ninstrument) { if(emptyslot(ninstrument)) return defaultinsname; @@ -89,82 +71,57 @@ char *Bank::getname(unsigned int ninstrument) /* * Get the numbered name of an instrument from the bank */ -char *Bank::getnamenumbered(unsigned int ninstrument) +string Bank::getnamenumbered(unsigned int ninstrument) { if(emptyslot(ninstrument)) return defaultinsname; - snprintf(tmpinsname[ninstrument], - PART_MAX_NAME_LEN + 15, - "%d. %s", - ninstrument + 1, - getname(ninstrument)); - return tmpinsname[ninstrument]; + + return stringFrom(ninstrument + 1) + ". " + getname(ninstrument); } /* * Changes the name of an instrument (and the filename) */ -void Bank::setname(unsigned int ninstrument, const char *newname, int newslot) +void Bank::setname(unsigned int ninstrument, string newname, int newslot) { if(emptyslot(ninstrument)) return; - char newfilename[1000 + 1], tmpfilename[100 + 1]; + string newfilename; + char tmpfilename[100 + 1]; - ZERO(newfilename, 1001); - ZERO(tmpfilename, 101); if(newslot >= 0) - snprintf(tmpfilename, 100, "%4d-%s", newslot + 1, newname); + snprintf(tmpfilename, 100, "%4d-%s", newslot + 1, newname.c_str()); else - snprintf(tmpfilename, 100, "%4d-%s", ninstrument + 1, newname); + snprintf(tmpfilename, 100, "%4d-%s", ninstrument + 1, newname.c_str()); //add the zeroes at the start of filename for(int i = 0; i < 4; i++) if(tmpfilename[i] == ' ') tmpfilename[i] = '0'; - //make the filenames legal - for(int i = 0; i < (int) strlen(tmpfilename); i++) { - char c = tmpfilename[i]; - if((c >= '0') && (c <= '9')) - continue; - if((c >= 'A') && (c <= 'Z')) - continue; - if((c >= 'a') && (c <= 'z')) - continue; - if((c == '-') || (c == ' ')) - continue; + newfilename = dirname + '/' + legalizeFilename(tmpfilename) + ".xiz"; - tmpfilename[i] = '_'; - } + rename(ins[ninstrument].filename.c_str(), newfilename.c_str()); - snprintf(newfilename, 1000, "%s/%s.xiz", dirname, tmpfilename); - -// printf("rename %s -> %s\n",ins[ninstrument].filename,newfilename);////////////// - - rename(ins[ninstrument].filename, newfilename); - if(ins[ninstrument].filename) - delete [] ins[ninstrument].filename; - ins[ninstrument].filename = new char[strlen(newfilename) + 5]; - snprintf(ins[ninstrument].filename, strlen( - newfilename) + 1, "%s", newfilename); - snprintf(ins[ninstrument].name, PART_MAX_NAME_LEN, "%s", &tmpfilename[5]); + ins[ninstrument].filename = newfilename; + ins[ninstrument].name = legalizeFilename(tmpfilename); //TODO limit name to PART_MAX_NAME_LEN } /* * Check if there is no instrument on a slot from the bank */ -int Bank::emptyslot(unsigned int ninstrument) +bool Bank::emptyslot(unsigned int ninstrument) { if(ninstrument >= BANK_SIZE) - return 1; - if(ins[ninstrument].filename == NULL) - return 1; + return true; + if(ins[ninstrument].filename.empty()) + return true; if(ins[ninstrument].used) - return 0; + return false; else - return 1; + return true; } /* @@ -175,10 +132,7 @@ void Bank::clearslot(unsigned int ninstrument) if(emptyslot(ninstrument)) return; -// printf("remove %s \n",ins[ninstrument].filename);//////////////////////// - - - remove(ins[ninstrument].filename); + remove(ins[ninstrument].filename.c_str()); deletefrombank(ninstrument); } @@ -204,34 +158,11 @@ void Bank::savetoslot(unsigned int ninstrument, Part *part) if(tmpfilename[i] == ' ') tmpfilename[i] = '0'; - //make the filenames legal - for(int i = 0; i < (int)strlen(tmpfilename); i++) { - char c = tmpfilename[i]; - if((c >= '0') && (c <= '9')) - continue; - if((c >= 'A') && (c <= 'Z')) - continue; - if((c >= 'a') && (c <= 'z')) - continue; - if((c == '-') || (c == ' ')) - continue; + string filename = dirname + '/' + legalizeFilename(tmpfilename) + ".xiz"; - tmpfilename[i] = '_'; - } - - strncat(tmpfilename, ".xiz", maxfilename + 10); - - int fnsize = strlen(dirname) + strlen(tmpfilename) + 10; - char *filename = new char[fnsize + 4]; - ZERO(filename, fnsize + 2); - - snprintf(filename, fnsize, "%s/%s", dirname, tmpfilename); - - remove(filename); - part->saveXML(filename); - addtobank(ninstrument, tmpfilename, (char *) part->Pname); - - delete[] filename; + remove(filename.c_str()); + part->saveXML(filename.c_str()); + addtobank(ninstrument, legalizeFilename(tmpfilename), (char *) part->Pname); } /* @@ -244,37 +175,30 @@ void Bank::loadfromslot(unsigned int ninstrument, Part *part) part->defaultsinstrument(); -// printf("load: %s\n",ins[ninstrument].filename); - - part->loadXMLinstrument(ins[ninstrument].filename); + part->loadXMLinstrument(ins[ninstrument].filename.c_str()); } - /* * Makes current a bank directory */ -int Bank::loadbank(const char *bankdirname) +int Bank::loadbank(string bankdirname) { - DIR *dir = opendir(bankdirname); + DIR *dir = opendir(bankdirname.c_str()); clearbank(); if(dir == NULL) return -1; - if(dirname != NULL) - delete[] dirname; - dirname = new char[strlen(bankdirname) + 1]; - snprintf(dirname, strlen(bankdirname) + 1, "%s", bankdirname); + dirname = bankdirname; bankfiletitle = dirname; - // printf("loadbank %s/\n",bankdirname); struct dirent *fn; while((fn = readdir(dir))) { const char *filename = fn->d_name; - //sa verific daca e si extensia dorita + //check for extension if(strstr(filename, INSTRUMENT_EXTENSION) == NULL) continue; @@ -292,35 +216,29 @@ int Bank::loadbank(const char *bankdirname) } } - if((startname + 1) < strlen(filename)) - startname++; //to take out the "-" + startname++; //to take out the "-" - char name[PART_MAX_NAME_LEN + 1]; - ZERO(name, PART_MAX_NAME_LEN + 1); - snprintf(name, PART_MAX_NAME_LEN, "%s", filename); + string name = filename; //remove the file extension - for(int i = strlen(name) - 1; i >= 2; i--) { + for(int i = name.size() - 1; i >= 2; i--) { if(name[i] == '.') { - name[i] = '\0'; + name = name.substr(0,i); break; } } if(no != 0) //the instrument position in the bank is found - addtobank(no - 1, filename, &name[startname]); + addtobank(no - 1, filename, name.substr(startname)); else addtobank(-1, filename, name); - ; } - closedir(dir); - if(dirname != NULL) - sprintf(config.cfg.currentBankDir, "%s", dirname); - ; + if(!dirname.empty()) + config.cfg.currentBankDir = dirname; return 0; } @@ -328,35 +246,30 @@ int Bank::loadbank(const char *bankdirname) /* * Makes a new bank, put it on a file and makes it current bank */ -int Bank::newbank(const char *newbankdirname) +int Bank::newbank(string newbankdirname) { int result; - char tmpfilename[MAX_STRING_SIZE]; - char bankdir[MAX_STRING_SIZE]; - snprintf(bankdir, MAX_STRING_SIZE, "%s", config.cfg.bankRootDirList[0]); - - if(((bankdir[strlen(bankdir) - 1]) != '/') - && ((bankdir[strlen(bankdir) - 1]) != '\\')) - strncat(bankdir, "/", MAX_STRING_SIZE); - ; - strncat(bankdir, newbankdirname, MAX_STRING_SIZE); + string bankdir; + bankdir = config.cfg.bankRootDirList[0]; + + if(((bankdir[bankdir.size() - 1]) != '/') + && ((bankdir[bankdir.size() - 1]) != '\\')) + bankdir += "/"; + + bankdir += newbankdirname; #if OS_WINDOWS - result = mkdir(bankdir); + result = mkdir(bankdir.c_str()); #elif OS_LINUX || OS_CYGWIN - result = mkdir(bankdir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + result = mkdir(bankdir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); #else #warning Undefined OS #endif if(result < 0) return -1; - snprintf(tmpfilename, - MAX_STRING_SIZE, - "%s/%s", - bankdir, - FORCE_BANK_DIR_FILE); -// printf("%s\n",tmpfilename); - FILE *tmpfile = fopen(tmpfilename, "w+"); + string tmpfilename = bankdir + '/' + FORCE_BANK_DIR_FILE; + + FILE *tmpfile = fopen(tmpfilename.c_str(), "w+"); fclose(tmpfile); return loadbank(bankdir); @@ -367,7 +280,7 @@ int Bank::newbank(const char *newbankdirname) */ int Bank::locked() { - return dirname == NULL; + return dirname.empty(); } /* @@ -379,106 +292,55 @@ void Bank::swapslot(unsigned int n1, unsigned int n2) return; if(emptyslot(n1) && (emptyslot(n2))) return; - if(emptyslot(n1)) { //change n1 to n2 in order to make - int tmp = n2; - n2 = n1; - n1 = tmp; - } + if(emptyslot(n1)) //change n1 to n2 in order to make + swap(n1, n2); if(emptyslot(n2)) { //this is just a movement from slot1 to slot2 setname(n1, getname(n1), n2); ins[n2] = ins[n1]; - ins[n1].used = false; - ins[n1].name[0] = '\0'; - ins[n1].filename = NULL; - ins[n1].info.PADsynth_used = 0; + ins[n1] = ins_t(); } else { //if both slots are used - if(strcmp(ins[n1].name, ins[n2].name) == 0) //change the name of the second instrument if the name are equal - strncat(ins[n2].name, "2", PART_MAX_NAME_LEN); - ; + if(ins[n1].name == ins[n2].name) //change the name of the second instrument if the name are equal + ins[n2].name += "2"; + setname(n1, getname(n1), n2); setname(n2, getname(n2), n1); - ins_t tmp; - tmp.used = true; - strcpy(tmp.name, ins[n2].name); - char *tmpfilename = ins[n2].filename; - bool padsynth_used = ins[n2].info.PADsynth_used; - - ins[n2] = ins[n1]; - strcpy(ins[n1].name, tmp.name); - ins[n1].filename = tmpfilename; - ins[n1].info.PADsynth_used = padsynth_used; + swap(ins[n2],ins[n1]); } } -//a helper function that compares 2 banks[] arrays -int Bank_compar(const void *a, const void *b) +bool Bank::bankstruct::operator<(const bankstruct &b) const { - struct Bank::bankstruct *bank1 = (Bank::bankstruct *)a; - struct Bank::bankstruct *bank2 = (Bank::bankstruct *)b; - if(((bank1->name) == NULL) || ((bank2->name) == NULL)) - return 0; - - int result = strcasecmp(bank1->name, bank2->name); - return result < 0; + return name < b.name; } - /* * Re-scan for directories containing instrument banks */ void Bank::rescanforbanks() { - for(int i = 0; i < MAX_NUM_BANKS; i++) { - if(banks[i].dir != NULL) - delete [] banks[i].dir; - if(banks[i].name != NULL) - delete [] banks[i].name; - banks[i].dir = NULL; - banks[i].name = NULL; - } + //remove old banks + banks.clear(); for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) - if(config.cfg.bankRootDirList[i] != NULL) + if(!config.cfg.bankRootDirList[i].empty()) scanrootdir(config.cfg.bankRootDirList[i]); //sort the banks - for(int j = 0; j < MAX_NUM_BANKS - 1; j++) { - for(int i = j + 1; i < MAX_NUM_BANKS; i++) { - if(Bank_compar(&banks[i], &banks[j])) { - char *tmpname = banks[i].name; - char *tmpdir = banks[i].dir; - - banks[i].name = banks[j].name; - banks[i].dir = banks[j].dir; - - banks[j].name = tmpname; - banks[j].dir = tmpdir; - } - } - } + sort(banks.begin(), banks.end()); //remove duplicate bank names int dupl = 0; - for(int j = 0; j < MAX_NUM_BANKS - 1; j++) { - for(int i = j + 1; i < MAX_NUM_BANKS; i++) { - if((banks[i].name == NULL) || (banks[j].name == NULL)) - continue; - if(strcmp(banks[i].name, banks[j].name) == 0) { //add a [1] to the first bankname and [n] to others - char *tmpname = banks[i].name; - banks[i].name = new char[strlen(tmpname) + 100]; - sprintf(banks[i].name, "%s[%d]", tmpname, dupl + 2); - delete[] tmpname; - - if(dupl == 0) { - char *tmpname = banks[j].name; - banks[j].name = new char[strlen(tmpname) + 100]; - sprintf(banks[j].name, "%s[1]", tmpname); - delete[] tmpname; - } + for(unsigned int j = 0; j < banks.size() - 1; j++) { + for(unsigned int i = j + 1; i < banks.size(); i++) { + if(banks[i].name == banks[j].name) { + //add a [1] to the first bankname and [n] to others + banks[i].name = banks[i].name + '[' + stringFrom(dupl +2) + ']'; + if(dupl == 0) + banks[j].name += "[1]"; dupl++; } @@ -489,25 +351,19 @@ void Bank::rescanforbanks() } - // private stuff -void Bank::scanrootdir(char *rootdir) +void Bank::scanrootdir(string rootdir) { -// printf("Scanning root dir:%s\n",rootdir); - DIR *dir = opendir(rootdir); + DIR *dir = opendir(rootdir.c_str()); if(dir == NULL) return; - const int maxdirsize = 1000; - struct { - char dir[maxdirsize]; - char name[maxdirsize]; - } bank; + bankstruct bank; const char *separator = "/"; - if(strlen(rootdir)) { - char tmp = rootdir[strlen(rootdir) - 1]; + if(rootdir.size()) { + char tmp = rootdir[rootdir.size() - 1]; if((tmp == '/') || (tmp == '\\')) separator = ""; } @@ -518,12 +374,12 @@ void Bank::scanrootdir(char *rootdir) if(dirname[0] == '.') continue; - snprintf(bank.dir, maxdirsize, "%s%s%s/", rootdir, separator, dirname); - snprintf(bank.name, maxdirsize, "%s", dirname); + bank.dir = rootdir + separator + dirname + '/'; + bank.name = dirname; //find out if the directory contains at least 1 instrument bool isbank = false; - DIR *d = opendir(bank.dir); + DIR *d = opendir(bank.dir.c_str()); if(d == NULL) continue; @@ -533,28 +389,14 @@ void Bank::scanrootdir(char *rootdir) if((strstr(fname->d_name, INSTRUMENT_EXTENSION) != NULL) || (strstr(fname->d_name, FORCE_BANK_DIR_FILE) != NULL)) { isbank = true; - break; //aici as putea pune in loc de break un update la un counter care imi arata nr. de instrumente din bank + break; //could put a #instrument counter here instead } } - closedir(d); + if(isbank) + banks.push_back(bank); - if(isbank) { - int pos = -1; - for(int i = 1; i < MAX_NUM_BANKS; i++) { //banks[0] e liber intotdeauna - if(banks[i].name == NULL) { - pos = i; - break; - } - } - - if(pos >= 0) { - banks[pos].name = new char[maxdirsize]; - banks[pos].dir = new char[maxdirsize]; - snprintf(banks[pos].name, maxdirsize, "%s", bank.name); - snprintf(banks[pos].dir, maxdirsize, "%s", bank.dir); - } - } + closedir(d); } closedir(dir); @@ -562,58 +404,48 @@ void Bank::scanrootdir(char *rootdir) void Bank::clearbank() { - for(int i = 0; i < BANK_SIZE; i++) - deletefrombank(i); - if(dirname != NULL) - delete[] dirname; - bankfiletitle = NULL; - dirname = NULL; + for(int i = 0; i < BANK_SIZE; ++i) + ins[i] = ins_t(); + + bankfiletitle.clear(); + dirname.clear(); } -int Bank::addtobank(int pos, const char *filename, const char *name) +int Bank::addtobank(int pos, string filename, string name) { if((pos >= 0) && (pos < BANK_SIZE)) { if(ins[pos].used) - pos = -1; //force it to find a new free position + pos = -1; //force it to find a new free position } else - if(pos >= BANK_SIZE) - pos = -1; + if(pos >= BANK_SIZE) + pos = -1; if(pos < 0) { //find a free position - for(int i = BANK_SIZE - 1; i >= 0; i--) + for(int i = BANK_SIZE - 1; i >= 0; i--) { if(!ins[i].used) { pos = i; break; } - ; + } } if(pos < 0) - return -1; //the bank is full - - // printf("%s %d\n",filename,pos); + return -1;//the bank is full deletefrombank(pos); ins[pos].used = true; - snprintf(ins[pos].name, PART_MAX_NAME_LEN, "%s", name); - - snprintf(tmpinsname[pos], PART_MAX_NAME_LEN + 10, " "); - - int len = strlen(filename) + 1 + strlen(dirname); - ins[pos].filename = new char[len + 2]; - ins[pos].filename[len + 1] = 0; - snprintf(ins[pos].filename, len + 1, "%s/%s", dirname, filename); + ins[pos].name = name; + ins[pos].filename = dirname + '/' + filename; //see if PADsynth is used if(config.cfg.CheckPADsynth) { - XMLwrapper *xml = new XMLwrapper(); - xml->loadXMLfile(ins[pos].filename); + XMLwrapper xml; + xml.loadXMLfile(ins[pos].filename); - ins[pos].info.PADsynth_used = xml->hasPadSynth(); - delete xml; + ins[pos].info.PADsynth_used = xml.hasPadSynth(); } else ins[pos].info.PADsynth_used = false; @@ -632,15 +464,14 @@ bool Bank::isPADsynth_used(unsigned int ninstrument) void Bank::deletefrombank(int pos) { - if((pos < 0) || (pos >= BANK_SIZE)) + if((pos < 0) || (pos >= (int) banks.size())) return; - ins[pos].used = false; - ZERO(ins[pos].name, PART_MAX_NAME_LEN + 1); - if(ins[pos].filename != NULL) { - delete [] ins[pos].filename; - ins[pos].filename = NULL; - } + ins[pos] = ins_t(); +} - ZERO(tmpinsname[pos], PART_MAX_NAME_LEN + 20); +Bank::ins_t::ins_t() + :used(false), name(""), filename("") +{ + info.PADsynth_used = false; } diff --git a/src/Misc/Bank.h b/src/Misc/Bank.h @@ -23,34 +23,30 @@ #ifndef BANK_H #define BANK_H +#include <string> +#include <vector> #include "../globals.h" #include "Util.h" #include "XMLwrapper.h" #include "Part.h" +//entries in a bank #define BANK_SIZE 160 -/** - * The max. number of banks that are used - */ -#define MAX_NUM_BANKS 400 - -/**The instrument Bank - * \todo add in strings to replace char* */ +/**The instrument Bank*/ class Bank { public: /**Constructor*/ Bank(); ~Bank(); - char *getname(unsigned int ninstrument); - char *getnamenumbered(unsigned int ninstrument); - void setname(unsigned int ninstrument, const char *newname, int newslot); //if newslot==-1 then this is ignored, else it will be put on that slot + std::string getname(unsigned int ninstrument); + std::string getnamenumbered(unsigned int ninstrument); + void setname(unsigned int ninstrument, const std::string newname, int newslot); //if newslot==-1 then this is ignored, else it will be put on that slot bool isPADsynth_used(unsigned int ninstrument); - /**returns 0 if the slot is not empty or 1 if the slot is empty - * \todo start using bool before facepalm*/ - int emptyslot(unsigned int ninstrument); + /**returns true when slot is empty*/ + bool emptyslot(unsigned int ninstrument); /**Empties out the selected slot*/ void clearslot(unsigned int ninstrument); @@ -62,47 +58,48 @@ class Bank /**Swaps Slots*/ void swapslot(unsigned int n1, unsigned int n2); - int loadbank(const char *bankdirname); - int newbank(const char *newbankdirname); + int loadbank(std::string bankdirname); + int newbank(std::string newbankdirname); - char *bankfiletitle; //this is shown on the UI of the bank (the title of the window) + std::string bankfiletitle; //this is shown on the UI of the bank (the title of the window) int locked(); void rescanforbanks(); struct bankstruct { - char *dir; - char *name; + bool operator<(const bankstruct &b) const; + std::string dir; + std::string name; }; - bankstruct banks[MAX_NUM_BANKS]; + std::vector<bankstruct> banks; private: //it adds a filename to the bank //if pos is -1 it try to find a position //returns -1 if the bank is full, or 0 if the instrument was added - int addtobank(int pos, const char *filename, const char *name); + int addtobank(int pos, std::string filename, std::string name); void deletefrombank(int pos); void clearbank(); - char defaultinsname[PART_MAX_NAME_LEN]; - char tmpinsname[BANK_SIZE][PART_MAX_NAME_LEN + 20]; //this keeps the numbered names + std::string defaultinsname; struct ins_t { + ins_t(); bool used; - char name[PART_MAX_NAME_LEN + 1]; - char *filename; + std::string name; + std::string filename; struct { bool PADsynth_used; } info; } ins[BANK_SIZE]; - char *dirname; + std::string dirname; - void scanrootdir(char *rootdir); //scans a root dir for banks + void scanrootdir(std::string rootdir); //scans a root dir for banks }; #endif diff --git a/src/Misc/Config.cpp b/src/Misc/Config.cpp @@ -50,8 +50,7 @@ void Config::init() cfg.LinuxOSSSeqInDev = new char[MAX_STRING_SIZE]; snprintf(cfg.LinuxOSSSeqInDev, MAX_STRING_SIZE, "/dev/sequencer"); - cfg.DumpFile = new char[MAX_STRING_SIZE]; - snprintf(cfg.DumpFile, MAX_STRING_SIZE, "zynaddsubfx_dump.txt"); + cfg.DumpFile = "zynaddsubfx_dump.txt"; cfg.WindowsWaveOutId = 0; cfg.WindowsMidiInId = 0; @@ -94,90 +93,56 @@ void Config::init() midiincaps.szPname); ; #endif - for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) - cfg.bankRootDirList[i] = NULL; - cfg.currentBankDir = new char[MAX_STRING_SIZE]; - sprintf(cfg.currentBankDir, "./testbnk"); - - for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) - cfg.presetsDirList[i] = NULL; + cfg.currentBankDir = "./testbnk"; char filename[MAX_STRING_SIZE]; getConfigFileName(filename, MAX_STRING_SIZE); readConfig(filename); - if(cfg.bankRootDirList[0] == NULL) { + if(cfg.bankRootDirList[0].empty()) { #if OS_LINUX //banks - cfg.bankRootDirList[0] = new char[MAX_STRING_SIZE]; - sprintf(cfg.bankRootDirList[0], "~/banks"); - - cfg.bankRootDirList[1] = new char[MAX_STRING_SIZE]; - sprintf(cfg.bankRootDirList[1], "./"); - - cfg.bankRootDirList[2] = new char[MAX_STRING_SIZE]; - sprintf(cfg.bankRootDirList[2], "/usr/share/zynaddsubfx/banks"); - - cfg.bankRootDirList[3] = new char[MAX_STRING_SIZE]; - sprintf(cfg.bankRootDirList[3], "/usr/local/share/zynaddsubfx/banks"); - - cfg.bankRootDirList[4] = new char[MAX_STRING_SIZE]; - sprintf(cfg.bankRootDirList[4], "../banks"); - - cfg.bankRootDirList[5] = new char[MAX_STRING_SIZE]; - sprintf(cfg.bankRootDirList[5], "banks"); + cfg.bankRootDirList[0] = "~/banks"; + cfg.bankRootDirList[1] = "./"; + cfg.bankRootDirList[2] = "/usr/share/zynaddsubfx/banks"; + cfg.bankRootDirList[3] = "/usr/local/share/zynaddsubfx/banks"; + cfg.bankRootDirList[4] = "../banks"; + cfg.bankRootDirList[5] = "banks"; #else //banks - cfg.bankRootDirList[0] = new char[MAX_STRING_SIZE]; - sprintf(cfg.bankRootDirList[0], "./"); + cfg.bankRootDirList[0] = "./"; #ifdef VSTAUDIOOUT - cfg.bankRootDirList[1] = new char[MAX_STRING_SIZE]; - sprintf(cfg.bankRootDirList[1], "c:/Program Files/ZynAddSubFX/banks"); + cfg.bankRootDirList[1] = "c:/Program Files/ZynAddSubFX/banks"; #else - cfg.bankRootDirList[1] = new char[MAX_STRING_SIZE]; - sprintf(cfg.bankRootDirList[1], "../banks"); + cfg.bankRootDirList[1] = "../banks"; #endif - cfg.bankRootDirList[2] = new char[MAX_STRING_SIZE]; - sprintf(cfg.bankRootDirList[2], "banks"); + cfg.bankRootDirList[2] = "banks"; #endif } - if(cfg.presetsDirList[0] == NULL) { + if(cfg.presetsDirList[0].empty()) { #if OS_LINUX || OS_CYGWIN //presets - cfg.presetsDirList[0] = new char[MAX_STRING_SIZE]; - sprintf(cfg.presetsDirList[0], "./"); - - cfg.presetsDirList[1] = new char[MAX_STRING_SIZE]; - sprintf(cfg.presetsDirList[1], "../presets"); - - cfg.presetsDirList[2] = new char[MAX_STRING_SIZE]; - sprintf(cfg.presetsDirList[2], "presets"); - - cfg.presetsDirList[3] = new char[MAX_STRING_SIZE]; - sprintf(cfg.presetsDirList[3], "/usr/share/zynaddsubfx/presets"); - - cfg.presetsDirList[4] = new char[MAX_STRING_SIZE]; - sprintf(cfg.presetsDirList[4], "/usr/local/share/zynaddsubfx/presets"); + cfg.presetsDirList[0] = "./"; + cfg.presetsDirList[1] = "../presets"; + cfg.presetsDirList[2] = "presets"; + cfg.presetsDirList[3] = "/usr/share/zynaddsubfx/presets"; + cfg.presetsDirList[4] = "/usr/local/share/zynaddsubfx/presets"; #elif OS_WINDOWS //presets - cfg.presetsDirList[0] = new char[MAX_STRING_SIZE]; - sprintf(cfg.presetsDirList[0], "./"); + cfg.presetsDirList[0] = "./"; #ifdef VSTAUDIOOUT - cfg.presetsDirList[1] = new char[MAX_STRING_SIZE]; - sprintf(cfg.presetsDirList[1], "c:/Program Files/ZynAddSubFX/presets"); + cfg.presetsDirList[1] = "c:/Program Files/ZynAddSubFX/presets"; #else - cfg.presetsDirList[1] = new char[MAX_STRING_SIZE]; - sprintf(cfg.presetsDirList[1], "../presets"); + cfg.presetsDirList[1] = "../presets"; #endif //end vst - cfg.presetsDirList[2] = new char[MAX_STRING_SIZE]; - sprintf(cfg.presetsDirList[2], "presets"); + cfg.presetsDirList[2] = "presets"; #else #error Undefined OS #endif //end OS @@ -190,7 +155,6 @@ Config::~Config() { delete [] cfg.LinuxOSSWaveOutDev; delete [] cfg.LinuxOSSSeqInDev; - delete [] cfg.DumpFile; for(int i = 0; i < winmidimax; i++) delete [] winmididevices[i].name; @@ -207,128 +171,115 @@ void Config::save() void Config::clearbankrootdirlist() { - for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) { - if(cfg.bankRootDirList[i] == NULL) - delete (cfg.bankRootDirList[i]); - cfg.bankRootDirList[i] = NULL; - } + for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) + cfg.bankRootDirList[i].clear(); } void Config::clearpresetsdirlist() { - for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) { - if(cfg.presetsDirList[i] == NULL) - delete (cfg.presetsDirList[i]); - cfg.presetsDirList[i] = NULL; - } + for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) + cfg.presetsDirList[i].clear(); } void Config::readConfig(const char *filename) { - XMLwrapper *xmlcfg = new XMLwrapper(); - if(xmlcfg->loadXMLfile(filename) < 0) + XMLwrapper xmlcfg; + if(xmlcfg.loadXMLfile(filename) < 0) return; - if(xmlcfg->enterbranch("CONFIGURATION")) { - cfg.SampleRate = xmlcfg->getpar("sample_rate", + if(xmlcfg.enterbranch("CONFIGURATION")) { + cfg.SampleRate = xmlcfg.getpar("sample_rate", cfg.SampleRate, 4000, 1024000); - cfg.SoundBufferSize = xmlcfg->getpar("sound_buffer_size", + cfg.SoundBufferSize = xmlcfg.getpar("sound_buffer_size", cfg.SoundBufferSize, 16, 8192); - cfg.OscilSize = xmlcfg->getpar("oscil_size", + cfg.OscilSize = xmlcfg.getpar("oscil_size", cfg.OscilSize, MAX_AD_HARMONICS * 2, 131072); - cfg.SwapStereo = xmlcfg->getpar("swap_stereo", + cfg.SwapStereo = xmlcfg.getpar("swap_stereo", cfg.SwapStereo, 0, 1); - cfg.BankUIAutoClose = xmlcfg->getpar("bank_window_auto_close", + cfg.BankUIAutoClose = xmlcfg.getpar("bank_window_auto_close", cfg.BankUIAutoClose, 0, 1); - cfg.DumpNotesToFile = xmlcfg->getpar("dump_notes_to_file", + cfg.DumpNotesToFile = xmlcfg.getpar("dump_notes_to_file", cfg.DumpNotesToFile, 0, 1); - cfg.DumpAppend = xmlcfg->getpar("dump_append", + cfg.DumpAppend = xmlcfg.getpar("dump_append", cfg.DumpAppend, 0, 1); - xmlcfg->getparstr("dump_file", cfg.DumpFile, MAX_STRING_SIZE); + cfg.DumpFile = xmlcfg.getparstr("dump_file", ""); - cfg.GzipCompression = xmlcfg->getpar("gzip_compression", + cfg.GzipCompression = xmlcfg.getpar("gzip_compression", cfg.GzipCompression, 0, 9); - xmlcfg->getparstr("bank_current", cfg.currentBankDir, MAX_STRING_SIZE); - cfg.Interpolation = xmlcfg->getpar("interpolation", + cfg.currentBankDir = xmlcfg.getparstr("bank_current", ""); + cfg.Interpolation = xmlcfg.getpar("interpolation", cfg.Interpolation, 0, 1); - cfg.CheckPADsynth = xmlcfg->getpar("check_pad_synth", + cfg.CheckPADsynth = xmlcfg.getpar("check_pad_synth", cfg.CheckPADsynth, 0, 1); - cfg.UserInterfaceMode = xmlcfg->getpar("user_interface_mode", + cfg.UserInterfaceMode = xmlcfg.getpar("user_interface_mode", cfg.UserInterfaceMode, 0, 2); - cfg.VirKeybLayout = xmlcfg->getpar("virtual_keyboard_layout", + cfg.VirKeybLayout = xmlcfg.getpar("virtual_keyboard_layout", cfg.VirKeybLayout, 0, 10); //get bankroot dirs for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) { - if(xmlcfg->enterbranch("BANKROOT", i)) { - cfg.bankRootDirList[i] = new char[MAX_STRING_SIZE]; - xmlcfg->getparstr("bank_root", - cfg.bankRootDirList[i], - MAX_STRING_SIZE); - xmlcfg->exitbranch(); + if(xmlcfg.enterbranch("BANKROOT", i)) { + cfg.bankRootDirList[i] = xmlcfg.getparstr("bank_root", ""); + xmlcfg.exitbranch(); } } //get preset root dirs for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) { - if(xmlcfg->enterbranch("PRESETSROOT", i)) { - cfg.presetsDirList[i] = new char[MAX_STRING_SIZE]; - xmlcfg->getparstr("presets_root", - cfg.presetsDirList[i], - MAX_STRING_SIZE); - xmlcfg->exitbranch(); + if(xmlcfg.enterbranch("PRESETSROOT", i)) { + cfg.presetsDirList[i] = xmlcfg.getparstr("presets_root", ""); + xmlcfg.exitbranch(); } } //linux stuff - xmlcfg->getparstr("linux_oss_wave_out_dev", + xmlcfg.getparstr("linux_oss_wave_out_dev", cfg.LinuxOSSWaveOutDev, MAX_STRING_SIZE); - xmlcfg->getparstr("linux_oss_seq_in_dev", + xmlcfg.getparstr("linux_oss_seq_in_dev", cfg.LinuxOSSSeqInDev, MAX_STRING_SIZE); //windows stuff - cfg.WindowsWaveOutId = xmlcfg->getpar("windows_wave_out_id", + cfg.WindowsWaveOutId = xmlcfg.getpar("windows_wave_out_id", cfg.WindowsWaveOutId, 0, winwavemax); - cfg.WindowsMidiInId = xmlcfg->getpar("windows_midi_in_id", + cfg.WindowsMidiInId = xmlcfg.getpar("windows_midi_in_id", cfg.WindowsMidiInId, 0, winmidimax); - xmlcfg->exitbranch(); + xmlcfg.exitbranch(); } - delete (xmlcfg); cfg.OscilSize = (int) pow(2, ceil(log(cfg.OscilSize - 1.0) / log(2.0))); } @@ -360,20 +311,18 @@ void Config::saveConfig(const char *filename) for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) - if(cfg.bankRootDirList[i] != NULL) { + if(!cfg.bankRootDirList[i].empty()) { xmlcfg->beginbranch("BANKROOT", i); xmlcfg->addparstr("bank_root", cfg.bankRootDirList[i]); xmlcfg->endbranch(); } - ; for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) - if(cfg.presetsDirList[i] != NULL) { + if(!cfg.presetsDirList[i].empty()) { xmlcfg->beginbranch("PRESETSROOT", i); xmlcfg->addparstr("presets_root", cfg.presetsDirList[i]); xmlcfg->endbranch(); } - ; xmlcfg->addpar("interpolation", cfg.Interpolation); diff --git a/src/Misc/Config.h b/src/Misc/Config.h @@ -43,9 +43,9 @@ class Config int DumpNotesToFile, DumpAppend; int GzipCompression; int Interpolation; - char *DumpFile; - char *bankRootDirList[MAX_BANK_ROOT_DIRS], *currentBankDir; - char *presetsDirList[MAX_BANK_ROOT_DIRS]; + std::string DumpFile; + std::string bankRootDirList[MAX_BANK_ROOT_DIRS], currentBankDir; + std::string presetsDirList[MAX_BANK_ROOT_DIRS]; int CheckPADsynth; int UserInterfaceMode; int VirKeybLayout; diff --git a/src/Misc/Dump.cpp b/src/Misc/Dump.cpp @@ -55,9 +55,9 @@ void Dump::startnow() if(config.cfg.DumpNotesToFile != 0) { if(config.cfg.DumpAppend != 0) - file = fopen(config.cfg.DumpFile, "a"); + file = fopen(config.cfg.DumpFile.c_str(), "a"); else - file = fopen(config.cfg.DumpFile, "w"); + file = fopen(config.cfg.DumpFile.c_str(), "w"); if(file == NULL) return; if(config.cfg.DumpAppend != 0) diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -64,7 +64,6 @@ Master::Master() //System Effects init for(int nefx = 0; nefx < NUM_SYS_EFX; nefx++) sysefx[nefx] = new EffectMgr(0, &mutex); - ; defaults(); @@ -119,6 +118,11 @@ bool Master::mutexLock(lockset request) return false; } +Master &Master::getInstance() +{ + static Master instance; + return instance; +} /* * Note On Messages (velocity=0 for NoteOff) @@ -468,7 +472,8 @@ Master::~Master() delete [] tmpmixl; delete [] tmpmixr; - delete (fft); + delete fft; + FFT_cleanup(); pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&vumutex); @@ -551,11 +556,10 @@ vuData Master::getVuData() return tmp; } -void Master::applyparameters() +void Master::applyparameters(bool lockmutex) { for(int npart = 0; npart < NUM_MIDI_PARTS; npart++) - part[npart]->applyparameters(); - ; + part[npart]->applyparameters(lockmutex); } void Master::add2XML(XMLwrapper *xml) diff --git a/src/Misc/Master.h b/src/Misc/Master.h @@ -50,11 +50,13 @@ typedef struct vuData_t { class Master { public: - /** Constructor*/ + /** Constructor TODO make private*/ Master(); /** Destructor*/ ~Master(); + static Master &getInstance(); + /**Saves all settings to a XML file * @return 0 for ok or <0 if there is an error*/ int saveXML(const char *filename); @@ -68,7 +70,7 @@ class Master /**loads all settings from a XML file * @return 0 for ok or -1 if there is an error*/ int loadXML(const char *filename); - void applyparameters(); + void applyparameters(bool lockmutex = true); void getfromXML(XMLwrapper *xml); diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -155,13 +155,13 @@ void Part::defaultsinstrument() /* * Cleanup the part */ -void Part::cleanup() +void Part::cleanup(bool final) { for(int k = 0; k < POLIPHONY; k++) KillNotePos(k); for(int i = 0; i < SOUND_BUFFER_SIZE; i++) { - partoutl[i] = denormalkillbuf[i]; - partoutr[i] = denormalkillbuf[i]; + partoutl[i] = final ? 0.0 : denormalkillbuf[i]; + partoutr[i] = final ? 0.0 : denormalkillbuf[i]; tmpoutl[i] = 0.0; tmpoutr[i] = 0.0; } @@ -170,15 +170,15 @@ void Part::cleanup() partefx[nefx]->cleanup(); for(int n = 0; n < NUM_PART_EFX + 1; n++) { for(int i = 0; i < SOUND_BUFFER_SIZE; i++) { - partfxinputl[n][i] = denormalkillbuf[i]; - partfxinputr[n][i] = denormalkillbuf[i]; + partfxinputl[n][i] = final ? 0.0 : denormalkillbuf[i]; + partfxinputr[n][i] = final ? 0.0 : denormalkillbuf[i]; } } } Part::~Part() { - cleanup(); + cleanup(true); for(int n = 0; n < NUM_KIT_ITEMS; n++) { if(kit[n].adpars != NULL) delete (kit[n].adpars); @@ -1217,7 +1217,7 @@ void Part::add2XML(XMLwrapper *xml) xml->endbranch(); } -int Part::saveXML(char *filename) +int Part::saveXML(const char *filename) { XMLwrapper *xml; xml = new XMLwrapper(); @@ -1249,12 +1249,11 @@ int Part::loadXMLinstrument(const char *filename) } -void Part::applyparameters() +void Part::applyparameters(bool lockmutex) { for(int n = 0; n < NUM_KIT_ITEMS; n++) if((kit[n].padpars != NULL) && (kit[n].Ppadenabled != 0)) - kit[n].padpars->applyparameters(true); - ; + kit[n].padpars->applyparameters(lockmutex); } void Part::getfromXMLinstrument(XMLwrapper *xml) diff --git a/src/Misc/Part.h b/src/Misc/Part.h @@ -71,7 +71,7 @@ class Part //saves the instrument settings to a XML file //returns 0 for ok or <0 if there is an error - int saveXML(char *filename); + int saveXML(const char *filename); int loadXMLinstrument(const char *filename); void add2XML(XMLwrapper *xml); @@ -80,12 +80,12 @@ class Part void defaults(); void defaultsinstrument(); - void applyparameters(); + void applyparameters(bool lockmutex = true); void getfromXML(XMLwrapper *xml); void getfromXMLinstrument(XMLwrapper *xml); - void cleanup(); + void cleanup(bool final = false); // ADnoteParameters *ADPartParameters; // SUBnoteParameters *SUBPartParameters; diff --git a/src/Misc/Recorder.cpp b/src/Misc/Recorder.cpp @@ -46,7 +46,7 @@ int Recorder::preparefile(std::string filename_, int overwrite) return 1; } - sysOut->wave->newFile(new WavFile(filename_, SAMPLE_RATE, 2)); + OutMgr::getInstance().wave->newFile(new WavFile(filename_, SAMPLE_RATE, 2)); status = 1; //ready @@ -61,15 +61,15 @@ void Recorder::start() void Recorder::stop() { - sysOut->wave->Stop(); - sysOut->wave->destroyFile(); + OutMgr::getInstance().wave->Stop(); + OutMgr::getInstance().wave->destroyFile(); status = 0; } void Recorder::pause() { status = 0; - sysOut->wave->Stop(); + OutMgr::getInstance().wave->Stop(); } int Recorder::recording() @@ -84,9 +84,10 @@ void Recorder::triggernow() { if(status == 2) { if(notetrigger!=1) { - sysOut->wave->Start(); + OutMgr::getInstance().wave->Start(); } notetrigger = 1; } } +#warning todo move recorder inside nio system diff --git a/src/Misc/Util.cpp b/src/Misc/Util.cpp @@ -142,4 +142,14 @@ void os_sleep(long length) Sleep((long)length/1000); #endif } - + +std::string legalizeFilename(std::string filename) +{ + for(int i = 0; i < (int) filename.size(); i++) { + char c = filename[i]; + if(!(isdigit(c) || isalpha(c) || (c == '-') || (c == ' '))) + filename[i] = '_'; + } + return filename; +} + diff --git a/src/Misc/Util.h b/src/Misc/Util.h @@ -47,6 +47,8 @@ void set_realtime(); /**Os independent sleep in microsecond*/ void os_sleep(long length); +std::string legalizeFilename(std::string filename); + extern REALTYPE *denormalkillbuf; /**<the buffer to add noise in order to avoid denormalisation*/ extern Config config; diff --git a/src/Misc/WavFile.cpp b/src/Misc/WavFile.cpp @@ -20,6 +20,7 @@ #include <cstdio> #include <cstring> #include <cstdlib> +#include <iostream> #include "WavFile.h" using namespace std; @@ -29,6 +30,7 @@ WavFile::WavFile(string filename, int samplerate, int channels) { if(file) { + cout << "INFO: Making space for wave file header" << endl; //making space for the header written at destruction char tmp[44]; memset(tmp, 0, 44*sizeof(char)); @@ -39,6 +41,8 @@ WavFile::WavFile(string filename, int samplerate, int channels) WavFile::~WavFile() { if(file) { + cout << "INFO: Writing wave file header" << endl; + unsigned int chunksize; rewind(file); @@ -73,7 +77,7 @@ WavFile::~WavFile() bool WavFile::good() const { - return NULL != file; + return file; } void WavFile::writeStereoSamples(int nsmps, short int *smps) diff --git a/src/Misc/XMLwrapper.cpp b/src/Misc/XMLwrapper.cpp @@ -140,7 +140,7 @@ XMLwrapper::XMLwrapper() XMLwrapper::~XMLwrapper() { - if(tree != NULL) + if(tree) mxmlDelete(tree); } @@ -295,6 +295,13 @@ void XMLwrapper::endbranch() } +//workaround for memory leak +const char *trimLeadingWhite(const char *c) +{ + while(isspace(*c)) + ++c; + return c; +} /* LOAD XML members */ @@ -306,15 +313,14 @@ int XMLwrapper::loadXMLfile(const string &filename) const char *xmldata = doloadfile(filename.c_str()); if(xmldata == NULL) - return -1; //the file could not be loaded or uncompressed + return -1; //the file could not be loaded or uncompressed - root = tree = mxmlLoadString(NULL, xmldata, MXML_OPAQUE_CALLBACK); + root = tree = mxmlLoadString(NULL, trimLeadingWhite(xmldata), MXML_OPAQUE_CALLBACK); - delete [] xmldata; + delete[] xmldata; if(tree == NULL) - return -2; //this is not XML - + return -2; //this is not XML node = root = mxmlFindElement(tree, tree, @@ -323,7 +329,7 @@ int XMLwrapper::loadXMLfile(const string &filename) NULL, MXML_DESCEND); if(root == NULL) - return -3; //the XML doesnt embbed zynaddsubfx data + return -3; //the XML doesnt embbed zynaddsubfx data //fetch version information version.Major = stringTo<int>(mxmlElementGetAttr(root, "version-major")); @@ -335,7 +341,6 @@ int XMLwrapper::loadXMLfile(const string &filename) cout << "loadXMLfile() version: " << version.Major << '.' << version.Minor << '.' << version.Revision << endl; - return 0; } @@ -379,7 +384,7 @@ bool XMLwrapper::putXMLdata(const char *xmldata) if(xmldata == NULL) return false; - root = tree = mxmlLoadString(NULL, xmldata, MXML_OPAQUE_CALLBACK); + root = tree = mxmlLoadString(NULL, trimLeadingWhite(xmldata), MXML_OPAQUE_CALLBACK); if(tree == NULL) return false; diff --git a/src/Nio/AlsaEngine.cpp b/src/Nio/AlsaEngine.cpp @@ -28,8 +28,8 @@ using namespace std; #include "InMgr.h" #include "AlsaEngine.h" -AlsaEngine::AlsaEngine(OutMgr *out) - :AudioOut(out) +AlsaEngine::AlsaEngine() + :AudioOut() { name = "ALSA"; audio.handle = NULL; @@ -53,8 +53,7 @@ void *AlsaEngine::_AudioThread(void *arg) void *AlsaEngine::AudioThread() { set_realtime(); - processAudio(); - return NULL; + return processAudio(); } bool AlsaEngine::Start() @@ -68,6 +67,7 @@ void AlsaEngine::Stop() setMidiEn(false); if(getAudioEn()) setAudioEn(false); + snd_config_update_free_global(); } void AlsaEngine::setMidiEn(bool nval) @@ -107,7 +107,7 @@ void *AlsaEngine::MidiThread(void) snd_seq_event_t *event; MidiEvent ev; set_realtime(); - while (snd_seq_event_input(midi.handle, &event) > 0) + while(snd_seq_event_input(midi.handle, &event) > 0) { //ensure ev is empty ev.channel = 0; @@ -126,7 +126,7 @@ void *AlsaEngine::MidiThread(void) ev.channel = event->data.note.channel; ev.num = event->data.note.note; ev.value = event->data.note.velocity; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); } break; @@ -135,7 +135,7 @@ void *AlsaEngine::MidiThread(void) ev.channel = event->data.note.channel; ev.num = event->data.note.note; ev.value = 0; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; case SND_SEQ_EVENT_PITCHBEND: @@ -143,7 +143,7 @@ void *AlsaEngine::MidiThread(void) ev.channel = event->data.control.channel; ev.num = C_pitchwheel; ev.value = event->data.control.value; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; case SND_SEQ_EVENT_CONTROLLER: @@ -151,7 +151,7 @@ void *AlsaEngine::MidiThread(void) ev.channel = event->data.control.channel; ev.num = event->data.control.param; ev.value = event->data.control.value; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; case SND_SEQ_EVENT_RESET: // reset to power-on state @@ -159,7 +159,7 @@ void *AlsaEngine::MidiThread(void) ev.channel = event->data.control.channel; ev.num = C_resetallcontrollers; ev.value = 0; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; case SND_SEQ_EVENT_PORT_SUBSCRIBED: // ports connected @@ -311,6 +311,7 @@ bool AlsaEngine::openAudio() //snd_pcm_hw_params_get_period_size(audio.params, &audio.frames, NULL); //snd_pcm_hw_params_get_period_time(audio.params, &val, NULL); + pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); @@ -327,10 +328,11 @@ void AlsaEngine::stopAudio() audio.handle = NULL; pthread_join(audio.pThread, NULL); snd_pcm_drain(handle); - snd_pcm_close(handle); + if(snd_pcm_close(handle)) + cout << "Error: in snd_pcm_close " << __LINE__ << ' ' << __FILE__ << endl; } -void AlsaEngine::processAudio() +void *AlsaEngine::processAudio() { int rc; while (audio.handle) { @@ -347,5 +349,5 @@ void AlsaEngine::processAudio() else if (rc < 0) cerr << "error from writei: " << snd_strerror(rc) << endl; } - pthread_exit(NULL); + return NULL; } diff --git a/src/Nio/AlsaEngine.h b/src/Nio/AlsaEngine.h @@ -34,7 +34,7 @@ class AlsaEngine : public AudioOut, MidiIn { public: - AlsaEngine(OutMgr *out); + AlsaEngine(); ~AlsaEngine(); bool Start(); @@ -76,7 +76,7 @@ class AlsaEngine : public AudioOut, MidiIn pthread_t pThread; } audio; - void processAudio(); + void *processAudio(); }; #endif diff --git a/src/Nio/AudioOut.cpp b/src/Nio/AudioOut.cpp @@ -30,63 +30,45 @@ using namespace std; #include "../Misc/Master.h" #include "AudioOut.h" -struct AudioOut::Data -{ - Data(OutMgr *out); - - int samplerate; - int bufferSize; - - Stereo<Sample> current;/**<used for xrun defence*/ - - OutMgr *manager; -}; - -AudioOut::Data::Data(OutMgr *out) - :samplerate(SAMPLE_RATE),bufferSize(SOUND_BUFFER_SIZE), - current(Sample(SOUND_BUFFER_SIZE,0.0)),manager(out) -{} - -AudioOut::AudioOut(OutMgr *out) - :dat(new Data(out)) +AudioOut::AudioOut() + :samplerate(SAMPLE_RATE),bufferSize(SOUND_BUFFER_SIZE) {} AudioOut::~AudioOut() { - delete dat; } void AudioOut::setSamplerate(int _samplerate) { - dat->samplerate = _samplerate; + samplerate = _samplerate; } int AudioOut::getSampleRate() { - return dat->samplerate; + return samplerate; } void AudioOut::setBufferSize(int _bufferSize) { - dat->bufferSize = _bufferSize; + bufferSize = _bufferSize; } //delete me void AudioOut::bufferingSize(int nBuffering) { - //dat->buffering = nBuffering; + //buffering = nBuffering; } //delete me int AudioOut::bufferingSize() { - //return dat->buffering; + //return buffering; } const Stereo<Sample> AudioOut::getNext(bool wait) { - Stereo<REALTYPE *> tmp = sysOut->tick(dat->bufferSize); + Stereo<REALTYPE *> tmp = OutMgr::getInstance().tick(bufferSize); //stop the samples - return Stereo<Sample>(Sample(dat->bufferSize, tmp.l()), Sample(dat->bufferSize, tmp.r())); + return Stereo<Sample>(Sample(bufferSize, tmp.l()), Sample(bufferSize, tmp.r())); } diff --git a/src/Nio/AudioOut.h b/src/Nio/AudioOut.h @@ -30,7 +30,7 @@ class AudioOut : public virtual Engine { public: - AudioOut(class OutMgr *out); + AudioOut(); virtual ~AudioOut(); /**Sets the Sample Rate of this Output @@ -54,9 +54,8 @@ class AudioOut : public virtual Engine * (has nsamples sampled at a rate of samplerate)*/ const Stereo<Sample> getNext(bool wait = false); - //using opaque pointer to reduce compile times - struct Data; - Data *dat; + int samplerate; + int bufferSize; }; #endif diff --git a/src/Nio/CMakeLists.txt b/src/Nio/CMakeLists.txt @@ -12,6 +12,7 @@ set(zynaddsubfx_nio_SRCS InMgr.cpp Engine.cpp EngineMgr.cpp + Nio.cpp ) set(zynaddsubfx_nio_lib ) diff --git a/src/Nio/EngineMgr.cpp b/src/Nio/EngineMgr.cpp @@ -21,46 +21,50 @@ using namespace std; -EngineMgr *sysEngine; +EngineMgr &EngineMgr::getInstance() +{ + static EngineMgr instance; + return instance; +} EngineMgr::EngineMgr() { Engine *defaultEng = NULL; //conditional compiling mess (but contained) - engines.push_back(defaultEng = new NulEngine(sysOut)); + engines.push_back(defaultEng = new NulEngine()); #if OSS #if OSS_DEFAULT - engines.push_back(defaultEng = new OssEngine(sysOut)); + engines.push_back(defaultEng = new OssEngine()); #else - engines.push_back(new OssEngine(sysOut)); + engines.push_back(new OssEngine()); #endif #endif #if ALSA #if ALSA_DEFAULT - engines.push_back(defaultEng = new AlsaEngine(sysOut)); + engines.push_back(defaultEng = new AlsaEngine()); #else - engines.push_back(new AlsaEngine(sysOut)); + engines.push_back(new AlsaEngine()); #endif #endif #if JACK #if JACK_DEFAULT - engines.push_back(defaultEng = new JackEngine(sysOut)); + engines.push_back(defaultEng = new JackEngine()); #else - engines.push_back(new JackEngine(sysOut)); + engines.push_back(new JackEngine()); #endif #endif #if PORTAUDIO #if PORTAUDIO_DEFAULT - engines.push_back(defaultEng = new PaEngine(sysOut)); + engines.push_back(defaultEng = new PaEngine()); #else - engines.push_back(new PaEngine(sysOut)); + engines.push_back(new PaEngine()); #endif #endif defaultOut = dynamic_cast<AudioOut *>(defaultEng); - defaultIn = dynamic_cast<MidiIn *>(defaultEng); + defaultIn = dynamic_cast<MidiIn *>(defaultEng); }; EngineMgr::~EngineMgr() @@ -93,8 +97,8 @@ void EngineMgr::start() defaultIn = dynamic_cast<MidiIn *>(getEng("NULL")); } - sysOut->currentOut = defaultOut; - sysIn->current = defaultIn; + OutMgr::getInstance().currentOut = defaultOut; + InMgr::getInstance().current = defaultIn; //open up the default output(s) cout << "Starting Audio: " << defaultOut->name << endl; @@ -104,8 +108,8 @@ void EngineMgr::start() } else { cerr << "ERROR: The default audio output failed to open!" << endl; - sysOut->currentOut = dynamic_cast<AudioOut *>(sysEngine->getEng("NULL")); - sysOut->currentOut->setAudioEn(true); + OutMgr::getInstance().currentOut = dynamic_cast<AudioOut *>(getEng("NULL")); + OutMgr::getInstance().currentOut->setAudioEn(true); } cout << "Starting MIDI: " << defaultIn->name << endl; @@ -115,8 +119,8 @@ void EngineMgr::start() } else { //recover cerr << "ERROR: The default MIDI input failed to open!" << endl; - sysIn->current = dynamic_cast<MidiIn *>(sysEngine->getEng("NULL")); - sysIn->current->setMidiEn(true); + InMgr::getInstance().current = dynamic_cast<MidiIn *>(getEng("NULL")); + InMgr::getInstance().current->setMidiEn(true); } } diff --git a/src/Nio/EngineMgr.h b/src/Nio/EngineMgr.h @@ -12,7 +12,7 @@ class OutMgr; /**Container/Owner of the long lived Engines*/ struct EngineMgr { - EngineMgr(); + static EngineMgr &getInstance(); ~EngineMgr(); /**Gets requested engine @@ -36,8 +36,8 @@ struct EngineMgr //default I/O AudioOut *defaultOut; MidiIn *defaultIn; + private: + EngineMgr(); }; - -extern EngineMgr *sysEngine; #endif diff --git a/src/Nio/InMgr.cpp b/src/Nio/InMgr.cpp @@ -6,8 +6,6 @@ using namespace std; -InMgr *sysIn; - ostream &operator<<(ostream &out, const MidiEvent& ev) { if(ev.type == M_NOTE) @@ -25,8 +23,14 @@ MidiEvent::MidiEvent() :channel(0),type(0),num(0),value(0) {} -InMgr::InMgr(Master *_master) - :queue(100), master(_master) +InMgr &InMgr::getInstance() +{ + static InMgr instance; + return instance; +} + +InMgr::InMgr() + :queue(100), master(Master::getInstance()) { current = NULL; sem_init(&work, PTHREAD_PROCESS_PRIVATE, 0); @@ -57,28 +61,20 @@ void InMgr::flush() dump.dumpnote(ev.channel, ev.num, ev.value); if(ev.value) - master->noteOn(ev.channel, ev.num, ev.value); + master.noteOn(ev.channel, ev.num, ev.value); else - master->noteOff(ev.channel, ev.num); + master.noteOff(ev.channel, ev.num); } else { dump.dumpcontroller(ev.channel, ev.num, ev.value); - master->setController(ev.channel, ev.num, ev.value); + master.setController(ev.channel, ev.num, ev.value); } } } bool InMgr::setSource(string name) { - MidiIn *src = NULL; - for(list<Engine*>::iterator itr = sysEngine->engines.begin(); - itr != sysEngine->engines.end(); ++itr) { - MidiIn *in = dynamic_cast<MidiIn *>(*itr); - if(in && in->name == name) { - src = in; - break; - } - } + MidiIn *src = getIn(name); if(!src) return false; @@ -88,7 +84,13 @@ bool InMgr::setSource(string name) current = src; current->setMidiEn(true); - return current->getMidiEn(); + bool success = current->getMidiEn(); + + //Keep system in a valid state (aka with a running driver) + if(!success) + (current = getIn("NULL"))->setMidiEn(true); + + return success; } string InMgr::getSource() const @@ -99,3 +101,9 @@ string InMgr::getSource() const return "ERROR"; } +MidiIn *InMgr::getIn(string name) +{ + EngineMgr &eng = EngineMgr::getInstance(); + return dynamic_cast<MidiIn *>(eng.getEng(name)); +} + diff --git a/src/Nio/InMgr.h b/src/Nio/InMgr.h @@ -19,13 +19,11 @@ struct MidiEvent int value; //velocity or controller value }; -class Master; -class MidiIn; //super simple class to manage the inputs class InMgr { public: - InMgr(Master *nmaster); + static InMgr &getInstance(); ~InMgr(); void putEvent(MidiEvent ev); @@ -39,14 +37,15 @@ class InMgr friend class EngineMgr; private: + InMgr(); + class MidiIn *getIn(std::string name); SafeQueue<MidiEvent> queue; sem_t work; - MidiIn *current; + class MidiIn *current; /**the link to the rest of zyn*/ - Master *master; + class Master &master; }; -extern InMgr *sysIn; #endif diff --git a/src/Nio/JackEngine.cpp b/src/Nio/JackEngine.cpp @@ -30,8 +30,8 @@ using namespace std; -JackEngine::JackEngine(OutMgr *out) - :AudioOut(out), jackClient(NULL) +JackEngine::JackEngine() + :AudioOut(), jackClient(NULL) { name = "JACK"; audio.jackSamplerate = 0; @@ -41,6 +41,7 @@ JackEngine::JackEngine(OutMgr *out) audio.ports[i] = NULL; audio.portBuffs[i] = NULL; } + midi.inport = NULL; } bool JackEngine::connectServer(string server) @@ -318,28 +319,28 @@ void JackEngine::handleMidi(unsigned long frames) ev.type = M_NOTE; ev.num = midi_data[1]; ev.value = 0; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; case 0x90: /* note-on */ ev.type = M_NOTE; ev.num = midi_data[1]; ev.value = midi_data[2]; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; case 0xB0: /* controller */ ev.type = M_CONTROLLER; ev.num = midi_data[1]; ev.value = midi_data[2]; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; case 0xE0: /* pitch bend */ ev.type = M_CONTROLLER; ev.num = C_pitchwheel; ev.value = ((midi_data[2] << 7) | midi_data[1]); - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; /* XXX TODO: handle MSB/LSB controllers and RPNs and NRPNs */ diff --git a/src/Nio/JackEngine.h b/src/Nio/JackEngine.h @@ -34,7 +34,7 @@ typedef jack_default_audio_sample_t jsample_t; class JackEngine : public AudioOut, MidiIn { public: - JackEngine(OutMgr *out); + JackEngine(); ~JackEngine() { }; bool Start(); diff --git a/src/Nio/MidiIn.cpp b/src/Nio/MidiIn.cpp @@ -35,28 +35,28 @@ void MidiIn::midiProcess(unsigned char head, unsigned char num, unsigned char va ev.channel = chan; ev.num = num; ev.value = 0; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; case 0x90: //Note On ev.type = M_NOTE; ev.channel = chan; ev.num = num; ev.value = value; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; case 0xb0: //Controller ev.type = M_CONTROLLER; ev.channel = chan; ev.num = num; ev.value = value; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; case 0xe0: //Pitch Wheel ev.type = M_CONTROLLER; ev.channel = chan; ev.num = C_pitchwheel; ev.value = (num + value * (int) 128) - 8192; - sysIn->putEvent(ev); + InMgr::getInstance().putEvent(ev); break; } } diff --git a/src/Nio/Nio.cpp b/src/Nio/Nio.cpp @@ -0,0 +1,100 @@ +#include "Nio.h" +#include "OutMgr.h" +#include "InMgr.h" +#include "EngineMgr.h" +#include "MidiIn.h" +#include "AudioOut.h" +#include <iostream> +using namespace std; + +Nio &Nio::getInstance() +{ + static Nio instance; + return instance; +} + +Nio::Nio() +:in(InMgr::getInstance()),//Enable input wrapper + out(OutMgr::getInstance()),//Initialize the Output Systems + eng(EngineMgr::getInstance())//Initialize The Engines +{} + +Nio::~Nio() +{ + stop(); +} + +void Nio::start() +{ + eng.start();//Drivers start your engines! +} + +void Nio::stop() +{ + eng.stop(); +} + +int Nio::setDefaultSource(string name) +{ + if(name.empty()) + return 0; + + if(!eng.setInDefault(name)) { + cerr << "There is no input for " << name << endl; + return false; + } + return 0; +} + + +int Nio::setDefaultSink(string name) +{ + if(name.empty()) + return 0; + + if(!eng.setOutDefault(name)) { + cerr << "There is no output for " << name << endl; + } + return 0; +} + +bool Nio::setSource(string name) +{ + return in.setSource(name); +} + +bool Nio::setSink(string name) +{ + return out.setSink(name); +} + +set<string> Nio::getSources() const +{ + set<string> sources; + for(list<Engine *>::iterator itr = eng.engines.begin(); + itr != eng.engines.end(); ++itr) + if(dynamic_cast<MidiIn *>(*itr)) + sources.insert((*itr)->name); + return sources; +} + +set<string> Nio::getSinks() const +{ + set<string> sinks; + for(list<Engine *>::iterator itr = eng.engines.begin(); + itr != eng.engines.end(); ++itr) + if(dynamic_cast<AudioOut *>(*itr)) + sinks.insert((*itr)->name); + return sinks; +} + +string Nio::getSource() const +{ + return in.getSource(); +} + +string Nio::getSink() const +{ + return out.getSink(); +} + diff --git a/src/Nio/Nio.h b/src/Nio/Nio.h @@ -0,0 +1,39 @@ +#ifndef NIO_H +#define NIO_H +#include <string> +#include <set> + +/**Interface to Nio Subsystem + * + * Should be only externally included header */ +class Nio +{ + public: + static Nio &getInstance(); + ~Nio(); + + void start(); + void stop(); + + int setDefaultSource(std::string name); + int setDefaultSink(std::string name); + + bool setSource(std::string name); + bool setSink(std::string name); + + std::set<std::string> getSources() const; + std::set<std::string> getSinks() const; + + std::string getSource() const; + std::string getSink() const; + + private: + Nio(); + + class InMgr &in; + class OutMgr &out; + class EngineMgr &eng; +}; + +#endif + diff --git a/src/Nio/NulEngine.cpp b/src/Nio/NulEngine.cpp @@ -27,8 +27,8 @@ using namespace std; -NulEngine::NulEngine(OutMgr *out) - :AudioOut(out), pThread(NULL) +NulEngine::NulEngine() + :AudioOut(), pThread(NULL) { name = "NULL"; playing_until.tv_sec = 0; @@ -68,7 +68,7 @@ void *NulEngine::AudioThread() playing_until.tv_sec += playing_until.tv_usec / 1000000; playing_until.tv_usec %= 1000000; } - pthread_exit(NULL); + return NULL; } NulEngine::~NulEngine() diff --git a/src/Nio/NulEngine.h b/src/Nio/NulEngine.h @@ -32,7 +32,7 @@ class NulEngine: public AudioOut, MidiIn { public: - NulEngine(OutMgr *out); + NulEngine(); ~NulEngine(); bool Start(); diff --git a/src/Nio/OssEngine.cpp b/src/Nio/OssEngine.cpp @@ -38,8 +38,8 @@ using namespace std; -OssEngine::OssEngine(OutMgr *out) - :AudioOut(out), engThread(NULL) +OssEngine::OssEngine() + :AudioOut(), engThread(NULL) { name = "OSS"; diff --git a/src/Nio/OssEngine.h b/src/Nio/OssEngine.h @@ -31,7 +31,7 @@ class OssEngine: public AudioOut, MidiIn { public: - OssEngine(OutMgr *out); + OssEngine(); ~OssEngine(); bool Start(); diff --git a/src/Nio/OutMgr.cpp b/src/Nio/OutMgr.cpp @@ -11,15 +11,19 @@ using namespace std; -OutMgr *sysOut; +OutMgr &OutMgr::getInstance() +{ + static OutMgr instance; + return instance; +} -OutMgr::OutMgr(Master *nmaster) - :wave(new WavEngine(this)), - priBuf(new REALTYPE[4096],new REALTYPE[4096]),priBuffCurrent(priBuf) +OutMgr::OutMgr() + :wave(new WavEngine()), + priBuf(new REALTYPE[4096],new REALTYPE[4096]),priBuffCurrent(priBuf),master(Master::getInstance()) { currentOut = NULL; stales = 0; - master = nmaster; + master = Master::getInstance(); //init samples outr = new REALTYPE[SOUND_BUFFER_SIZE]; @@ -28,6 +32,9 @@ OutMgr::OutMgr(Master *nmaster) OutMgr::~OutMgr() { + delete wave; + delete [] priBuf.l(); + delete [] priBuf.r(); delete [] outr; delete [] outl; } @@ -45,15 +52,15 @@ OutMgr::~OutMgr() */ const Stereo<REALTYPE *> OutMgr::tick(unsigned int frameSize) { - pthread_mutex_lock(&(master->mutex)); - sysIn->flush(); - pthread_mutex_unlock(&(master->mutex)); + pthread_mutex_lock(&(master.mutex)); + InMgr::getInstance().flush(); + pthread_mutex_unlock(&(master.mutex)); //SysEv->execute(); removeStaleSmps(); while(frameSize > storedSmps()) { - pthread_mutex_lock(&(master->mutex)); - master->AudioOut(outl, outr); - pthread_mutex_unlock(&(master->mutex)); + pthread_mutex_lock(&(master.mutex)); + master.AudioOut(outl, outr); + pthread_mutex_unlock(&(master.mutex)); addSmps(outl,outr); } Stereo<REALTYPE *> ans = priBuffCurrent; @@ -65,7 +72,7 @@ const Stereo<REALTYPE *> OutMgr::tick(unsigned int frameSize) AudioOut *OutMgr::getOut(string name) { - return dynamic_cast<AudioOut *>(sysEngine->getEng(name)); + return dynamic_cast<AudioOut *>(EngineMgr::getInstance().getEng(name)); } string OutMgr::getDriver() const @@ -85,7 +92,14 @@ bool OutMgr::setSink(string name) currentOut = sink; currentOut->setAudioEn(true); - return currentOut->getAudioEn(); + + bool success = currentOut->getAudioEn(); + + //Keep system in a valid state (aka with a running driver) + if(!success) + (currentOut = getOut("NULL"))->setAudioEn(true); + + return success; } string OutMgr::getSink() const @@ -122,7 +136,6 @@ void OutMgr::addSmps(REALTYPE *l, REALTYPE *r) void OutMgr::removeStaleSmps() { int toShift = storedSmps() - stales; - //cout << "toShift: " << toShift << endl << "stales: " << stales << endl << priBuf.l() << ' ' << priBuffCurrent.l() << endl; if(!stales) return; diff --git a/src/Nio/OutMgr.h b/src/Nio/OutMgr.h @@ -10,12 +10,10 @@ class AudioOut; -class WavEngine; -class Master; class OutMgr { public: - OutMgr(Master *nmaster); + static OutMgr &getInstance(); ~OutMgr(); /**Execute a tick*/ @@ -42,9 +40,10 @@ class OutMgr std::string getSink() const; - WavEngine *wave; /**<The Wave Recorder*/ + class WavEngine *wave; /**<The Wave Recorder*/ friend class EngineMgr; private: + OutMgr(); void addSmps(REALTYPE *l, REALTYPE *r); int storedSmps() const {return priBuffCurrent.l() - priBuf.l();}; void removeStaleSmps(); @@ -60,11 +59,10 @@ class OutMgr REALTYPE *outl; REALTYPE *outr; - Master *master; + class Master &master; int stales; }; -extern OutMgr *sysOut; #endif diff --git a/src/Nio/PaEngine.h b/src/Nio/PaEngine.h @@ -47,7 +47,6 @@ class PaEngine: public AudioOut }; -void PAaudiooutputinit(Master *master_); void PAfinish(); #endif diff --git a/src/Nio/SafeQueue.cpp b/src/Nio/SafeQueue.cpp @@ -3,13 +3,17 @@ template<class T> SafeQueue<T>::SafeQueue(size_t maxlen) :writePtr(0),readPtr(0),bufSize(maxlen) { + sem_init(&w_space, PTHREAD_PROCESS_PRIVATE, maxlen-1); + sem_init(&r_space, PTHREAD_PROCESS_PRIVATE, 0); buffer = new T[maxlen]; } template<class T> SafeQueue<T>::~SafeQueue() { - delete[] buffer; + sem_destroy(&w_space); + sem_destroy(&r_space); + delete [] buffer; } template<class T> @@ -21,33 +25,17 @@ unsigned int SafeQueue<T>::size() const template<class T> unsigned int SafeQueue<T>::rSpace() const { - size_t w, r; - - w = writePtr; - r = readPtr; - - if (w > r) { - return w - r; - } - else { - return (w - r + bufSize) % bufSize; - } + int space = 0; + sem_getvalue(&r_space, &space); + return space; } template<class T> unsigned int SafeQueue<T>::wSpace() const { - size_t w, r; - - w = writePtr; - r = readPtr - 1; - - if (r > w) { - return r - w; - } - else { - return (r - w + bufSize) % bufSize; - } + int space = 0; + sem_getvalue(&w_space, &space); + return space; } template<class T> @@ -60,6 +48,10 @@ int SafeQueue<T>::push(const T &in) size_t w = (writePtr + 1) % bufSize; buffer[w] = in; writePtr = w; + + //adjust ranges + sem_wait(&w_space);//guaranteed not to wait + sem_post(&r_space); return 0; } @@ -73,11 +65,18 @@ int SafeQueue<T>::pop(T &out) size_t r = (readPtr + 1) % bufSize; out = buffer[r]; readPtr = r; + + //adjust ranges + sem_wait(&r_space);//guaranteed not to wait + sem_post(&w_space); return 0; } template<class T> void SafeQueue<T>::clear() { + //thread unsafe + while(!sem_trywait(&r_space)) + sem_post(&w_space); readPtr = writePtr; } diff --git a/src/Nio/SafeQueue.h b/src/Nio/SafeQueue.h @@ -2,6 +2,7 @@ #ifndef SAFEQUEUE_H #define SAFEQUEUE_H #include <cstdlib> +#include <semaphore.h> /** * C++ thread safe lockless queue @@ -28,10 +29,15 @@ class SafeQueue unsigned int wSpace() const; unsigned int rSpace() const; - //next writting spot - volatile size_t writePtr; + //write space + mutable sem_t w_space; + //read space + mutable sem_t r_space; + + //next writing spot + size_t writePtr; //next reading spot - volatile size_t readPtr; + size_t readPtr; const size_t bufSize; T *buffer; }; diff --git a/src/Nio/WavEngine.cpp b/src/Nio/WavEngine.cpp @@ -25,8 +25,8 @@ using namespace std; -WavEngine::WavEngine(OutMgr *out) - :AudioOut(out), file(NULL), buffer(SAMPLE_RATE*2), pThread(NULL) +WavEngine::WavEngine() + :AudioOut(), file(NULL), buffer(SAMPLE_RATE*4), pThread(NULL) { sem_init(&work, PTHREAD_PROCESS_PRIVATE, 0); } @@ -80,8 +80,8 @@ void WavEngine::push(Stereo<REALTYPE *> smps, size_t len) for(size_t i = 0; i < len; ++i) { buffer.push(*smps.l()++); buffer.push(*smps.r()++); - sem_post(&work); } + sem_post(&work); } void WavEngine::newFile(WavFile *_file) @@ -89,12 +89,17 @@ void WavEngine::newFile(WavFile *_file) //ensure system is clean destroyFile(); file = _file; + + //check state + if(!file->good()) + cerr << "ERROR: WavEngine handed bad file output WavEngine::newFile()" << endl; } void WavEngine::destroyFile() { if(file) delete file; + file = NULL; } void *WavEngine::_AudioThread(void *arg) @@ -104,17 +109,22 @@ void *WavEngine::_AudioThread(void *arg) void *WavEngine::AudioThread() { - short int recordbuf_16bit[2]; + short *recordbuf_16bit = new short[2*SOUND_BUFFER_SIZE]; while(!sem_wait(&work) && pThread) { - float left=0.0f, right=0.0f; - buffer.pop(left); - buffer.pop(right); - recordbuf_16bit[0] = limit((int)(left * 32767.0), -32768, 32767); - recordbuf_16bit[1] = limit((int)(right * 32767.0), -32768, 32767); - file->writeStereoSamples(1, recordbuf_16bit); + for(int i = 0; i < SOUND_BUFFER_SIZE; ++i) { + float left=0.0f, right=0.0f; + buffer.pop(left); + buffer.pop(right); + recordbuf_16bit[2*i] = limit((int)(left * 32767.0), -32768, 32767); + recordbuf_16bit[2*i+1] = limit((int)(right * 32767.0), -32768, 32767); + } + file->writeStereoSamples(SOUND_BUFFER_SIZE, recordbuf_16bit); } - pthread_exit(NULL); + + delete[] recordbuf_16bit; + + return NULL; } diff --git a/src/Nio/WavEngine.h b/src/Nio/WavEngine.h @@ -32,7 +32,7 @@ class WavFile; class WavEngine: public AudioOut { public: - WavEngine(OutMgr *out); + WavEngine(); ~WavEngine(); bool openAudio(); diff --git a/src/Params/PresetsStore.cpp b/src/Params/PresetsStore.cpp @@ -97,7 +97,7 @@ void PresetsStore::rescanforpresets(string type) string ftype = "." + type + ".xpz"; for(int i = 0; i < MAX_BANK_ROOT_DIRS; i++) { - if(config.cfg.presetsDirList[i] == NULL) + if(config.cfg.presetsDirList[i].empty()) continue; //open directory @@ -140,15 +140,11 @@ void PresetsStore::rescanforpresets(string type) void PresetsStore::copypreset(XMLwrapper *xml, char *type, string name) { - if(config.cfg.presetsDirList[0] == NULL) + if(config.cfg.presetsDirList[0].empty()) return; //make the filenames legal - for(int i = 0; i < (int) name.size(); i++) { - char c = name[i]; - if(!(isdigit(c) || isalpha(c) || (c == '-') || (c == ' '))) - name[i] = '_'; - } + name = legalizeFilename(name); //make path legal const string dirname = config.cfg.presetsDirList[0]; diff --git a/src/Synth/Envelope.cpp b/src/Synth/Envelope.cpp @@ -79,9 +79,9 @@ Envelope::Envelope(EnvelopeParams *envpars, REALTYPE basefreq) envdt[0] = 1.0; currentpoint = 1; //the envelope starts from 1 - keyreleased = 0; + keyreleased = false; t = 0.0; - envfinish = 0; + envfinish = false; inct = envdt[1]; envoutval = 0.0; } @@ -95,9 +95,9 @@ Envelope::~Envelope() */ void Envelope::relasekey() { - if(keyreleased == 1) + if(keyreleased) return; - keyreleased = 1; + keyreleased = true; if(forcedrelase != 0) t = 0.0; } @@ -109,16 +109,16 @@ REALTYPE Envelope::envout() { REALTYPE out; - if(envfinish != 0) { //if the envelope is finished + if(envfinish) { //if the envelope is finished envoutval = envval[envpoints - 1]; return envoutval; } - if((currentpoint == envsustain + 1) && (keyreleased == 0)) { //if it is sustaining now + if((currentpoint == envsustain + 1) && !keyreleased) { //if it is sustaining now envoutval = envval[envsustain]; return envoutval; } - if((keyreleased != 0) && (forcedrelase != 0)) { //do the forced release + if(keyreleased && (forcedrelase != 0)) { //do the forced release int tmp = (envsustain < 0) ? (envpoints - 1) : (envsustain + 1); //if there is no sustain point, use the last point for release if(envdt[tmp] < 0.00000001) @@ -133,21 +133,20 @@ REALTYPE Envelope::envout() t = 0.0; inct = envdt[currentpoint]; if((currentpoint >= envpoints) || (envsustain < 0)) - envfinish = 1; + envfinish = true; } return out; } if(inct >= 1.0) out = envval[currentpoint]; else - out = - envval[currentpoint - - 1] + (envval[currentpoint] - envval[currentpoint - 1]) * t; + out = envval[currentpoint - 1] + + (envval[currentpoint] - envval[currentpoint - 1]) * t; t += inct; if(t >= 1.0) { if(currentpoint >= envpoints - 1) - envfinish = 1; + envfinish = true; else currentpoint++; t = 0.0; @@ -167,7 +166,7 @@ REALTYPE Envelope::envout_dB() if(linearenvelope != 0) return envout(); - if((currentpoint == 1) && ((keyreleased == 0) || (forcedrelase == 0))) { //first point is always lineary interpolated + if((currentpoint == 1) && (!keyreleased || (forcedrelase == 0))) { //first point is always lineary interpolated REALTYPE v1 = dB2rap(envval[0]); REALTYPE v2 = dB2rap(envval[1]); out = v1 + (v2 - v1) * t; @@ -191,7 +190,7 @@ REALTYPE Envelope::envout_dB() return out; } -int Envelope::finished() +bool Envelope::finished() const { return envfinish; } diff --git a/src/Synth/Envelope.h b/src/Synth/Envelope.h @@ -40,10 +40,8 @@ class Envelope REALTYPE envout(); REALTYPE envout_dB(); /**Determines the status of the Envelope - * - *\todo see if this can be changed to use a boolean * @return returns 1 if the envelope is finished*/ - int finished(); + bool finished() const; private: int envpoints; int envsustain; //"-1" means disabled @@ -54,8 +52,8 @@ class Envelope int currentpoint; //current envelope point (starts from 1) int forcedrelase; - char keyreleased; //if the key was released /** \todo figure out WHY IS THIS A CHAR*/ - char envfinish; /** \todo figure out WHY IS THIS A CHAR*/ + bool keyreleased; //if the key was released + bool envfinish; REALTYPE t; // the time from the last point REALTYPE inct; // the time increment REALTYPE envoutval; //used to do the forced release diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp @@ -20,6 +20,7 @@ */ +#include <cassert> #include <stdlib.h> #include <math.h> #include <stdio.h> @@ -27,6 +28,7 @@ #include "OscilGen.h" #include "../Effects/Distorsion.h" + OscilGen::OscilGen(FFTwrapper *fft_, Resonance *res_):Presets() { setpresettype("Poscilgen"); @@ -173,154 +175,6 @@ void OscilGen::convert2sine(int magtype) } /* - * Base Functions - START - */ -REALTYPE OscilGen::basefunc_pulse(REALTYPE x, REALTYPE a) -{ - return (fmod(x, 1.0) < a) ? -1.0 : 1.0; -} - -REALTYPE OscilGen::basefunc_saw(REALTYPE x, REALTYPE a) -{ - if(a < 0.00001) - a = 0.00001; - else - if(a > 0.99999) - a = 0.99999; - x = fmod(x, 1); - if(x < a) - return x / a * 2.0 - 1.0; - else - return (1.0 - x) / (1.0 - a) * 2.0 - 1.0; -} - -REALTYPE OscilGen::basefunc_triangle(REALTYPE x, REALTYPE a) -{ - x = fmod(x + 0.25, 1); - a = 1 - a; - if(a < 0.00001) - a = 0.00001; - if(x < 0.5) - x = x * 4 - 1.0; - else - x = (1.0 - x) * 4 - 1.0; - x /= -a; - if(x < -1.0) - x = -1.0; - if(x > 1.0) - x = 1.0; - return x; -} - -REALTYPE OscilGen::basefunc_power(REALTYPE x, REALTYPE a) -{ - x = fmod(x, 1); - if(a < 0.00001) - a = 0.00001; - else - if(a > 0.99999) - a = 0.99999; - return pow(x, exp((a - 0.5) * 10.0)) * 2.0 - 1.0; -} - -REALTYPE OscilGen::basefunc_gauss(REALTYPE x, REALTYPE a) -{ - x = fmod(x, 1) * 2.0 - 1.0; - if(a < 0.00001) - a = 0.00001; - return exp(-x * x * (exp(a * 8) + 5.0)) * 2.0 - 1.0; -} - -REALTYPE OscilGen::basefunc_diode(REALTYPE x, REALTYPE a) -{ - if(a < 0.00001) - a = 0.00001; - else - if(a > 0.99999) - a = 0.99999; - a = a * 2.0 - 1.0; - x = cos((x + 0.5) * 2.0 * PI) - a; - if(x < 0.0) - x = 0.0; - return x / (1.0 - a) * 2 - 1.0; -} - -REALTYPE OscilGen::basefunc_abssine(REALTYPE x, REALTYPE a) -{ - x = fmod(x, 1); - if(a < 0.00001) - a = 0.00001; - else - if(a > 0.99999) - a = 0.99999; - return sin(pow(x, exp((a - 0.5) * 5.0)) * PI) * 2.0 - 1.0; -} - -REALTYPE OscilGen::basefunc_pulsesine(REALTYPE x, REALTYPE a) -{ - if(a < 0.00001) - a = 0.00001; - x = (fmod(x, 1) - 0.5) * exp((a - 0.5) * log(128)); - if(x < -0.5) - x = -0.5; - else - if(x > 0.5) - x = 0.5; - x = sin(x * PI * 2.0); - return x; -} - -REALTYPE OscilGen::basefunc_stretchsine(REALTYPE x, REALTYPE a) -{ - x = fmod(x + 0.5, 1) * 2.0 - 1.0; - a = (a - 0.5) * 4; - if(a > 0.0) - a *= 2; - a = pow(3.0, a); - REALTYPE b = pow(fabs(x), a); - if(x < 0) - b = -b; - return -sin(b * PI); -} - -REALTYPE OscilGen::basefunc_chirp(REALTYPE x, REALTYPE a) -{ - x = fmod(x, 1.0) * 2.0 * PI; - a = (a - 0.5) * 4; - if(a < 0.0) - a *= 2.0; - a = pow(3.0, a); - return sin(x / 2.0) * sin(a * x * x); -} - -REALTYPE OscilGen::basefunc_absstretchsine(REALTYPE x, REALTYPE a) -{ - x = fmod(x + 0.5, 1) * 2.0 - 1.0; - a = (a - 0.5) * 9; - a = pow(3.0, a); - REALTYPE b = pow(fabs(x), a); - if(x < 0) - b = -b; - return -pow(sin(b * PI), 2); -} - -REALTYPE OscilGen::basefunc_chebyshev(REALTYPE x, REALTYPE a) -{ - a = a * a * a * 30.0 + 1.0; - return cos(acos(x * 2.0 - 1.0) * a); -} - -REALTYPE OscilGen::basefunc_sqr(REALTYPE x, REALTYPE a) -{ - a = a * a * a * a * 160.0 + 0.001; - return -atan(sin(x * 2.0 * PI) * a); -} -/* - * Base Functions - END - */ - - -/* * Get the base function */ void OscilGen::getbasefunction(REALTYPE *smps) @@ -359,7 +213,7 @@ void OscilGen::getbasefunction(REALTYPE *smps) break; } -// printf("%.5f %.5f\n",basefuncmodulationpar1,basefuncmodulationpar3); + base_func func = getBaseFunction(Pcurrentbasefunc); for(i = 0; i < OSCIL_SIZE; i++) { REALTYPE t = i * 1.0 / OSCIL_SIZE; @@ -368,65 +222,26 @@ void OscilGen::getbasefunction(REALTYPE *smps) case 1: t = t * basefuncmodulationpar3 + sin( (t - + basefuncmodulationpar2) * 2.0 * PI) * basefuncmodulationpar1; //rev + + basefuncmodulationpar2) * 2.0 * PI) * basefuncmodulationpar1;//rev break; case 2: t = t + sin( (t * basefuncmodulationpar3 - + basefuncmodulationpar2) * 2.0 * PI) * basefuncmodulationpar1; //sine + + basefuncmodulationpar2) * 2.0 * PI) * basefuncmodulationpar1;//sine break; case 3: t = t + pow((1.0 - cos( (t + basefuncmodulationpar2) * 2.0 * PI)) * 0.5, - basefuncmodulationpar3) * basefuncmodulationpar1; //power + basefuncmodulationpar3) * basefuncmodulationpar1;//power break; } t = t - floor(t); - switch(Pcurrentbasefunc) { - case 1: - smps[i] = basefunc_triangle(t, par); - break; - case 2: - smps[i] = basefunc_pulse(t, par); - break; - case 3: - smps[i] = basefunc_saw(t, par); - break; - case 4: - smps[i] = basefunc_power(t, par); - break; - case 5: - smps[i] = basefunc_gauss(t, par); - break; - case 6: - smps[i] = basefunc_diode(t, par); - break; - case 7: - smps[i] = basefunc_abssine(t, par); - break; - case 8: - smps[i] = basefunc_pulsesine(t, par); - break; - case 9: - smps[i] = basefunc_stretchsine(t, par); - break; - case 10: - smps[i] = basefunc_chirp(t, par); - break; - case 11: - smps[i] = basefunc_absstretchsine(t, par); - break; - case 12: - smps[i] = basefunc_chebyshev(t, par); - break; - case 13: - smps[i] = basefunc_sqr(t, par); - break; - default: + if(func) + smps[i] = func(t, par); + else smps[i] = -sin(2.0 * PI * i / OSCIL_SIZE); - } } } @@ -437,129 +252,37 @@ void OscilGen::oscilfilter() { if(Pfiltertype == 0) return; - REALTYPE par = 1.0 - Pfilterpar1 / 128.0; - REALTYPE par2 = Pfilterpar2 / 127.0; - REALTYPE max = 0.0, tmp = 0.0, p2, x; - for(int i = 1; i < OSCIL_SIZE / 2; i++) { - REALTYPE gain = 1.0; - switch(Pfiltertype) { - case 1: - gain = pow(1.0 - par * par * par * 0.99, i); //lp - tmp = par2 * par2 * par2 * par2 * 0.5 + 0.0001; - if(gain < tmp) - gain = pow(gain, 10.0) / pow(tmp, 9.0); - break; - case 2: - gain = 1.0 - pow(1.0 - par * par, i + 1); //hp1 - gain = pow(gain, par2 * 2.0 + 0.1); - break; - case 3: - if(par < 0.2) - par = par * 0.25 + 0.15; - gain = 1.0 - pow(1.0 - par * par * 0.999 + 0.001, - i * 0.05 * i + 1.0); //hp1b - tmp = pow(5.0, par2 * 2.0); - gain = pow(gain, tmp); - break; - case 4: - gain = i + 1 - pow(2, (1.0 - par) * 7.5); //bp1 - gain = 1.0 / (1.0 + gain * gain / (i + 1.0)); - tmp = pow(5.0, par2 * 2.0); - gain = pow(gain, tmp); - if(gain < 1e-5) - gain = 1e-5; - break; - case 5: - gain = i + 1 - pow(2, (1.0 - par) * 7.5); //bs1 - gain = pow(atan(gain / (i / 10.0 + 1)) / 1.57, 6); - gain = pow(gain, par2 * par2 * 3.9 + 0.1); - break; - case 6: - tmp = pow(par2, 0.33); - gain = - (i + 1 > - pow(2, (1.0 - par) * 10) ? 0.0 : 1.0) * par2 + (1.0 - par2); //lp2 - break; - case 7: - tmp = pow(par2, 0.33); - //tmp=1.0-(1.0-par2)*(1.0-par2); - gain = - (i + 1 > - pow(2, (1.0 - par) * 7) ? 1.0 : 0.0) * par2 + (1.0 - par2); //hp2 - if(Pfilterpar1 == 0) - gain = 1.0; - break; - case 8: - tmp = pow(par2, 0.33); - //tmp=1.0-(1.0-par2)*(1.0-par2); - gain = - (fabs(pow(2, - (1.0 - - par) - * 7) - i) > i / 2 + 1 ? 0.0 : 1.0) * par2 + (1.0 - par2); //bp2 - break; - case 9: - tmp = pow(par2, 0.33); - gain = - (fabs(pow(2, - (1.0 - - par) - * 7) - i) < i / 2 + 1 ? 0.0 : 1.0) * par2 + (1.0 - par2); //bs2 - break; - case 10: - tmp = pow(5.0, par2 * 2.0 - 1.0); - tmp = pow(i / 32.0, tmp) * 32.0; - if(Pfilterpar2 == 64) - tmp = i; - gain = cos(par * par * PI / 2.0 * tmp); //cos - gain *= gain; - break; - case 11: - tmp = pow(5.0, par2 * 2.0 - 1.0); - tmp = pow(i / 32.0, tmp) * 32.0; - if(Pfilterpar2 == 64) - tmp = i; - gain = sin(par * par * PI / 2.0 * tmp); //sin - gain *= gain; - break; - case 12: - p2 = 1.0 - par + 0.2; - x = i / (64.0 * p2 * p2); - if(x < 0.0) - x = 0.0; - else - if(x > 1.0) - x = 1.0; - tmp = pow(1.0 - par2, 2.0); - gain = cos(x * PI) * (1.0 - tmp) + 1.01 + tmp; //low shelf - break; - case 13: - tmp = (int) (pow(2.0, (1.0 - par) * 7.2)); - gain = 1.0; - if(i == (int) (tmp)) - gain = pow(2.0, par2 * par2 * 8.0); - break; - } + const REALTYPE par = 1.0 - Pfilterpar1 / 128.0; + const REALTYPE par2 = Pfilterpar2 / 127.0; + REALTYPE max = 0.0; + filter_func filter = getFilter(Pfiltertype); + + for(int i = 1; i < OSCIL_SIZE / 2; i++) { + REALTYPE gain = filter(i,par,par2); oscilFFTfreqs.s[i] *= gain; oscilFFTfreqs.c[i] *= gain; - REALTYPE tmp = oscilFFTfreqs.s[i] * oscilFFTfreqs.s[i] - + oscilFFTfreqs.c[i] * oscilFFTfreqs.c[i]; - if(max < tmp) - max = tmp; + REALTYPE magnitude = oscilFFTfreqs.s[i] * oscilFFTfreqs.s[i] + + oscilFFTfreqs.c[i] * oscilFFTfreqs.c[i]; + if(max < magnitude) + max = magnitude; } + //Finish RMS calculation max = sqrt(max); if(max < 1e-10) max = 1.0; REALTYPE imax = 1.0 / max; + + //Normalize signal for(int i = 1; i < OSCIL_SIZE / 2; i++) { oscilFFTfreqs.s[i] *= imax; oscilFFTfreqs.c[i] *= imax; } } + /* * Change the base function */ @@ -692,17 +415,17 @@ void OscilGen::modulation() switch(Pmodulation) { case 1: t = t * modulationpar3 - + sin((t + modulationpar2) * 2.0 * PI) * modulationpar1; //rev + + sin((t + modulationpar2) * 2.0 * PI) * modulationpar1; //rev break; case 2: t = t + sin((t * modulationpar3 - + modulationpar2) * 2.0 * PI) * modulationpar1; //sine + + modulationpar2) * 2.0 * PI) * modulationpar1; //sine break; case 3: t = t + pow((1.0 - cos( (t + modulationpar2) * 2.0 * PI)) * 0.5, - modulationpar3) * modulationpar1; //power + modulationpar3) * modulationpar1; //power break; } @@ -907,8 +630,6 @@ void OscilGen::prepare() if(Pharmonicshiftfirst != 0) shiftharmonics(); - - if(Pfilterbeforews == 0) { waveshape(); oscilfilter(); @@ -1021,7 +742,7 @@ void OscilGen::adaptiveharmonicpostprocess(REALTYPE *f, int size) if(Padaptiveharmonics == 2) { //2n+1 for(int i = 0; i < size; i++) if((i % 2) == 0) - f[i] += inf[i]; //i=0 pt prima armonica,etc. + f[i] += inf[i]; //i=0 pt prima armonica,etc. } else { //celelalte moduri int nh = (Padaptiveharmonics - 3) / 2 + 2; @@ -1043,16 +764,6 @@ void OscilGen::adaptiveharmonicpostprocess(REALTYPE *f, int size) delete (inf); } - - -/* - * Get the oscillator function - */ -short int OscilGen::get(REALTYPE *smps, REALTYPE freqHz) -{ - return this->get(smps, freqHz, 0); -} - void OscilGen::newrandseed(unsigned int randseed) { this->randseed = randseed; @@ -1473,3 +1184,315 @@ void OscilGen::getfromXML(XMLwrapper *xml) } } +//Define basic functions +#define FUNC(b) REALTYPE basefunc_##b(REALTYPE x, REALTYPE a) + +FUNC(pulse) +{ + return (fmod(x, 1.0) < a) ? -1.0 : 1.0; +} + +FUNC(saw) +{ + if(a < 0.00001) + a = 0.00001; + else + if(a > 0.99999) + a = 0.99999; + x = fmod(x, 1); + if(x < a) + return x / a * 2.0 - 1.0; + else + return (1.0 - x) / (1.0 - a) * 2.0 - 1.0; +} + +FUNC(triangle) +{ + x = fmod(x + 0.25, 1); + a = 1 - a; + if(a < 0.00001) + a = 0.00001; + if(x < 0.5) + x = x * 4 - 1.0; + else + x = (1.0 - x) * 4 - 1.0; + x /= -a; + if(x < -1.0) + x = -1.0; + if(x > 1.0) + x = 1.0; + return x; +} + +FUNC(power) +{ + x = fmod(x, 1); + if(a < 0.00001) + a = 0.00001; + else + if(a > 0.99999) + a = 0.99999; + return pow(x, exp((a - 0.5) * 10.0)) * 2.0 - 1.0; +} + +FUNC(gauss) +{ + x = fmod(x, 1) * 2.0 - 1.0; + if(a < 0.00001) + a = 0.00001; + return exp(-x * x * (exp(a * 8) + 5.0)) * 2.0 - 1.0; +} + +FUNC(diode) +{ + if(a < 0.00001) + a = 0.00001; + else + if(a > 0.99999) + a = 0.99999; + a = a * 2.0 - 1.0; + x = cos((x + 0.5) * 2.0 * PI) - a; + if(x < 0.0) + x = 0.0; + return x / (1.0 - a) * 2 - 1.0; +} + +FUNC(abssine) +{ + x = fmod(x, 1); + if(a < 0.00001) + a = 0.00001; + else + if(a > 0.99999) + a = 0.99999; + return sin(pow(x, exp((a - 0.5) * 5.0)) * PI) * 2.0 - 1.0; +} + +FUNC(pulsesine) +{ + if(a < 0.00001) + a = 0.00001; + x = (fmod(x, 1) - 0.5) * exp((a - 0.5) * log(128)); + if(x < -0.5) + x = -0.5; + else + if(x > 0.5) + x = 0.5; + x = sin(x * PI * 2.0); + return x; +} + +FUNC(stretchsine) +{ + x = fmod(x + 0.5, 1) * 2.0 - 1.0; + a = (a - 0.5) * 4; + if(a > 0.0) + a *= 2; + a = pow(3.0, a); + REALTYPE b = pow(fabs(x), a); + if(x < 0) + b = -b; + return -sin(b * PI); +} + +FUNC(chirp) +{ + x = fmod(x, 1.0) * 2.0 * PI; + a = (a - 0.5) * 4; + if(a < 0.0) + a *= 2.0; + a = pow(3.0, a); + return sin(x / 2.0) * sin(a * x * x); +} + +FUNC(absstretchsine) +{ + x = fmod(x + 0.5, 1) * 2.0 - 1.0; + a = (a - 0.5) * 9; + a = pow(3.0, a); + REALTYPE b = pow(fabs(x), a); + if(x < 0) + b = -b; + return -pow(sin(b * PI), 2); +} + +FUNC(chebyshev) +{ + a = a * a * a * 30.0 + 1.0; + return cos(acos(x * 2.0 - 1.0) * a); +} + +FUNC(sqr) +{ + a = a * a * a * a * 160.0 + 0.001; + return -atan(sin(x * 2.0 * PI) * a); +} + +typedef REALTYPE(*base_func)(REALTYPE,REALTYPE); +base_func getBaseFunction(unsigned char func) +{ + if(!func) + return NULL; + + func--; + assert(func < 13); + base_func functions[] = { + basefunc_triangle, + basefunc_pulse, + basefunc_saw, + basefunc_power, + basefunc_gauss, + basefunc_diode, + basefunc_abssine, + basefunc_pulsesine, + basefunc_stretchsine, + basefunc_chirp, + basefunc_absstretchsine, + basefunc_chebyshev, + basefunc_sqr,}; + return functions[func]; +} + +//And filters + +#define FILTER(x) REALTYPE osc_##x(unsigned int i, REALTYPE par, REALTYPE par2) +FILTER(lp) +{ + REALTYPE gain = pow(1.0 - par * par * par * 0.99, i); + REALTYPE tmp = par2 * par2 * par2 * par2 * 0.5 + 0.0001; + if(gain < tmp) + gain = pow(gain, 10.0) / pow(tmp, 9.0); + return gain; +} + +FILTER(hp1) +{ + REALTYPE gain = 1.0 - pow(1.0 - par * par, i + 1); + return pow(gain, par2 * 2.0 + 0.1); +} + +FILTER(hp1b) +{ + if(par < 0.2) + par = par * 0.25 + 0.15; + REALTYPE gain = 1.0 - pow(1.0 - par * par * 0.999 + 0.001, i * 0.05 * i + 1.0); + REALTYPE tmp = pow(5.0, par2 * 2.0); + return pow(gain, tmp); +} + +FILTER(bp1) +{ + REALTYPE gain = i + 1 - pow(2, (1.0 - par) * 7.5); + gain = 1.0 / (1.0 + gain * gain / (i + 1.0)); + REALTYPE tmp = pow(5.0, par2 * 2.0); + gain = pow(gain, tmp); + if(gain < 1e-5) + gain = 1e-5; + return gain; +} + +FILTER(bs1) +{ + REALTYPE gain = i + 1 - pow(2, (1.0 - par) * 7.5); + gain = pow(atan(gain / (i / 10.0 + 1)) / 1.57, 6); + return pow(gain, par2 * par2 * 3.9 + 0.1); +} + +FILTER(lp2) +{ + return (i + 1 > pow(2, (1.0 - par) * 10) ? 0.0 : 1.0) * par2 + (1.0 - par2); +} + +FILTER(hp2) +{ + if(par == 1) + return 1.0; + return (i + 1 > pow(2, (1.0 - par) * 7) ? 1.0 : 0.0) * par2 + (1.0 - par2); +} + +FILTER(bp2) +{ + return (fabs(pow(2, (1.0 - par) * 7) - i) > i / 2 + 1 ? 0.0 : 1.0) * par2 + (1.0 - par2); +} + +FILTER(bs2) +{ + return (fabs(pow(2, (1.0 - par) * 7) - i) < i / 2 + 1 ? 0.0 : 1.0) * par2 + (1.0 - par2); +} + +bool floatEq(float a, float b) +{ + const float fudge = .01; + return a + fudge > b && a - fudge < b; +} + +FILTER(cos) +{ + REALTYPE tmp = pow(5.0, par2 * 2.0 - 1.0); + tmp = pow(i / 32.0, tmp) * 32.0; + if(floatEq(par2 * 127.0, 64.0)) + tmp = i; + REALTYPE gain = cos(par * par * PI / 2.0 * tmp); + gain *= gain; + return gain; +} + +FILTER(sin) +{ + REALTYPE tmp = pow(5.0, par2 * 2.0 - 1.0); + tmp = pow(i / 32.0, tmp) * 32.0; + if(floatEq(par2 * 127.0, 64.0)) + tmp = i; + REALTYPE gain = sin(par * par * PI / 2.0 * tmp); + gain *= gain; + return gain; +} + +FILTER(low_shelf) +{ + REALTYPE p2 = 1.0 - par + 0.2; + REALTYPE x = i / (64.0 * p2 * p2); + if(x < 0.0) + x = 0.0; + else + if(x > 1.0) + x = 1.0; + REALTYPE tmp = pow(1.0 - par2, 2.0); + return cos(x * PI) * (1.0 - tmp) + 1.01 + tmp; +} + +FILTER(s) +{ + unsigned int tmp = (int) (pow(2.0, (1.0 - par) * 7.2)); + REALTYPE gain = 1.0; + if(i == tmp) + gain = pow(2.0, par2 * par2 * 8.0); + return gain; +} +#undef FILTER + +typedef REALTYPE(*filter_func)(unsigned int, REALTYPE, REALTYPE); +filter_func getFilter(unsigned char func) +{ + if(!func) + return NULL; + + func--; + assert(func < 13); + filter_func functions[] = { + osc_lp, + osc_hp1, + osc_hp1b, + osc_bp1, + osc_bs1, + osc_lp2, + osc_hp2, + osc_bp2, + osc_bs2, + osc_cos, + osc_sin, + osc_low_shelf, + osc_s}; + return functions[func]; +} + diff --git a/src/Synth/OscilGen.h b/src/Synth/OscilGen.h @@ -39,8 +39,8 @@ class OscilGen:public Presets void prepare(); /**do the antialiasing(cut off higher freqs.),apply randomness and do a IFFT*/ - short get(REALTYPE *smps, REALTYPE freqHz); //returns where should I start getting samples, used in block type randomness - short get(REALTYPE *smps, REALTYPE freqHz, int resonance); + //returns where should I start getting samples, used in block type randomness + short get(REALTYPE *smps, REALTYPE freqHz, int resonance=0); //if freqHz is smaller than 0, return the "un-randomized" sample for UI void getbasefunction(REALTYPE *smps); @@ -79,7 +79,7 @@ class OscilGen:public Presets unsigned char Pbasefuncmodulation; //what modulation is applied to the basefunc unsigned char Pbasefuncmodulationpar1, Pbasefuncmodulationpar2, - Pbasefuncmodulationpar3; //the parameter of the base function modulation + Pbasefuncmodulationpar3;//the parameter of the base function modulation /*the Randomness: 64=no randomness @@ -144,21 +144,6 @@ class OscilGen:public Presets //(that's why the sine and cosine components should be processed with a separate call) void adaptiveharmonicpostprocess(REALTYPE *f, int size); - //Basic/base functions (Functiile De Baza) - REALTYPE basefunc_pulse(REALTYPE x, REALTYPE a); - REALTYPE basefunc_saw(REALTYPE x, REALTYPE a); - REALTYPE basefunc_triangle(REALTYPE x, REALTYPE a); - REALTYPE basefunc_power(REALTYPE x, REALTYPE a); - REALTYPE basefunc_gauss(REALTYPE x, REALTYPE a); - REALTYPE basefunc_diode(REALTYPE x, REALTYPE a); - REALTYPE basefunc_abssine(REALTYPE x, REALTYPE a); - REALTYPE basefunc_pulsesine(REALTYPE x, REALTYPE a); - REALTYPE basefunc_stretchsine(REALTYPE x, REALTYPE a); - REALTYPE basefunc_chirp(REALTYPE x, REALTYPE a); - REALTYPE basefunc_absstretchsine(REALTYPE x, REALTYPE a); - REALTYPE basefunc_chebyshev(REALTYPE x, REALTYPE a); - REALTYPE basefunc_sqr(REALTYPE x, REALTYPE a); - //Internal Data unsigned char oldbasefunc, oldbasepar, oldhmagtype, oldwaveshapingfunction, oldwaveshaping; @@ -178,6 +163,11 @@ class OscilGen:public Presets unsigned int randseed; }; +typedef REALTYPE(*filter_func)(unsigned int, REALTYPE, REALTYPE); +filter_func getFilter(unsigned char func); +typedef REALTYPE(*base_func)(REALTYPE,REALTYPE); +base_func getBaseFunction(unsigned char func); + #endif diff --git a/src/Tests/XMLwrapperTest.h b/src/Tests/XMLwrapperTest.h @@ -21,6 +21,8 @@ */ #include <cxxtest/TestSuite.h> #include "../Misc/XMLwrapper.h" +#include <string> +using namespace std; class XMLwrapperTest:public CxxTest::TestSuite { @@ -36,6 +38,24 @@ class XMLwrapperTest:public CxxTest::TestSuite TS_ASSERT_EQUALS(xmla->getpar("my Pa*_ramet@er", 0, -200, 200), 75); } + //here to verify that no leaks occur + void testLoad() { + string location = string(SOURCE_DIR) + string("/Tests/guitar-adnote.xmz"); + xmla->loadXMLfile(location); + } + + void testAnotherLoad() + { + string dat = "\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ +<!DOCTYPE ZynAddSubFX-data>\n\ +<ZynAddSubFX-data version-major=\"2\" version-minor=\"4\"\n\ +version-revision=\"1\" ZynAddSubFX-author=\"Nasca Octavian Paul\">\n\ +</ZynAddSubFX-data>\n"; + xmlb->putXMLdata(dat.c_str()); +#warning todo contact mxml people about possible memoryleak when +#warning mxmlLoadString is giving something starting with a newline + } + void tearDown() { delete xmla; delete xmlb; diff --git a/src/UI/BankUI.fl b/src/UI/BankUI.fl @@ -37,7 +37,7 @@ class BankProcess_ {} { } } -class BankSlot {open : {public Fl_Button,BankProcess_} +class BankSlot {: {public Fl_Button,BankProcess_} } { Function {BankSlot(int x,int y, int w, int h, const char *label=0):Fl_Button(x,y,w,h,label)} {} { code {what=NULL; @@ -59,8 +59,7 @@ int tmp=Fl_Button::handle(event); if ((*what!=0) && Fl::event_inside(this)) (bp->*fnc)(); return(tmp);} {} } - Function {init(int nslot_, int *what_, int *whatslot_,void (BankProcess_:: *fnc_)(void),BankProcess_ *bp_,Bank *bank_,int *nselected_)} {open - } { + Function {init(int nslot_, int *what_, int *whatslot_,void (BankProcess_:: *fnc_)(void),BankProcess_ *bp_,Bank *bank_,int *nselected_)} {} { code {nslot=nslot_; what=what_; whatslot=whatslot_; @@ -74,21 +73,23 @@ labelsize(13); align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP); highlight=0; -refresh();} {selected - } +refresh();} {} } Function {refresh()} {} { - code {if (bank->emptyslot(nslot)) { - color(46); -} else { - if (bank->isPADsynth_used(nslot)) color(26); - else color(51); -}; + code {if (bank->emptyslot(nslot)) + color(46); +else if (bank->isPADsynth_used(nslot)) + color(26); +else + color(51); -if (*nselected==nslot) color(6); +if (*nselected==nslot) + color(6); -label(bank->getnamenumbered(nslot));} {} + +copy_label(bank->getnamenumbered(nslot).c_str());} {selected + } } decl {int *what,*whatslot,nslot,highlight, *nselected;} {} decl {void (BankProcess_:: *fnc)(void);} {} @@ -100,9 +101,9 @@ class BankUI {: {public BankProcess_} Function {make_window()} {} { Fl_Window bankuiwindow { label Bank - xywh {4 64 785 575} type Double hide - code0 {o->label(bank->bankfiletitle);} - code1 {if (bank->bankfiletitle==NULL) o->label ("Choose a bank from the bank list on the left (or go to settings if to configure the bank location) or choose 'New Bank...' to make a new bank.");} + xywh {5 64 785 575} type Double hide + code0 {o->label(bank->bankfiletitle.c_str());} + code1 {if (bank->bankfiletitle.empty()) o->label ("Choose a bank from the bank list on the left (or go to settings if to configure the bank location) or choose 'New Bank...' to make a new bank.");} } { Fl_Button {} { label Close @@ -193,13 +194,13 @@ refreshmainwindow();} } Fl_Choice banklist { callback {int n=o->value(); -char *dirname=bank->banks[n].dir; -if (dirname==NULL) return; +std::string dirname=bank->banks[n].dir; +if (dirname.empty()) return; if (bank->loadbank(dirname)==2) - fl_alert("Error: Could not load the bank from the directory\\n%s.",dirname); + fl_alert("Error: Could not load the bank from the directory\\n%s.",dirname.c_str()); for (int i=0;i<BANK_SIZE;i++) bs[i]->refresh(); -refreshmainwindow();} open +refreshmainwindow();} xywh {5 8 220 20} down_box BORDER_BOX labelfont 1 align 0 textfont 1 textsize 11 } {} Fl_Button {} { @@ -248,7 +249,7 @@ rescan_for_banks();} {} code {int slot=this->slot; if ((what==2)&&(bank->emptyslot(slot)==0)&&(mode!=4)) {//Rename slot - const char *tmp=fl_input("Slot (instrument) name:",(const char *)bank->getname(slot)); + const char *tmp=fl_input("Slot (instrument) name:",bank->getname(slot).c_str()); if (tmp!=NULL) bank->setname(slot,tmp,-1); bs[slot]->refresh(); }; @@ -258,7 +259,7 @@ if ((what==1)&&(mode==1)&&(!bank->emptyslot(slot))){//Reads from slot bank->loadfromslot(slot,master->part[*npart]); pthread_mutex_unlock(&master->mutex); master->part[*npart]->applyparameters(); - snprintf((char *)master->part[*npart]->Pname,PART_MAX_NAME_LEN,"%s",bank->getname(slot)); + snprintf((char *)master->part[*npart]->Pname,PART_MAX_NAME_LEN,"%s",bank->getname(slot).c_str()); cbwig->do_callback(); if (config.cfg.BankUIAutoClose!=0) @@ -308,7 +309,7 @@ if (mode==4){//swap if (mode!=4) refreshmainwindow();} {} } Function {refreshmainwindow()} {} { - code {bankuiwindow->label(bank->bankfiletitle); + code {bankuiwindow->label(bank->bankfiletitle.c_str()); mode=1;readbutton->value(1);writebutton->value(0);clearbutton->value(0);swapbutton->value(0); nselected=-1; if (bank->locked()){ @@ -320,7 +321,8 @@ if (bank->locked()){ clearbutton->activate(); swapbutton->activate(); }; -for (int i=0;i<BANK_SIZE;i++) bs[i]->refresh();} {} +for (int i=0;i<BANK_SIZE;i++) + bs[i]->refresh();} {} } Function {removeselection()} {} { code {if (nselected>=0) { @@ -334,8 +336,8 @@ for (int i=0;i<BANK_SIZE;i++) bs[i]->refresh();} {} banklist->add(" "); bank->rescanforbanks(); -for (int i=1;i<MAX_NUM_BANKS;i++) { - if (bank->banks[i].name!=NULL) banklist->add(bank->banks[i].name); +for (unsigned int i=1;i<bank->banks.size();i++) { + banklist->add(bank->banks[i].name.c_str()); };} {} } Function {simplesetmode(bool beginnerui)} {} { diff --git a/src/UI/ConfigUI.fl b/src/UI/ConfigUI.fl @@ -1,5 +1,5 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0106 +version 1.0107 header_name {.h} code_name {.cc} decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {} @@ -60,35 +60,35 @@ setsamplerateinput();} xywh {20 50 85 20} down_box BORDER_BOX textsize 10 code0 {o->value(getsamplerateorder());} } { - menuitem {} { + MenuItem {} { label Custom xywh {10 10 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 16000Hz xywh {30 30 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 22050Hz xywh {20 20 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 32000Hz xywh {30 30 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 44100Hz xywh {40 40 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 48000Hz xywh {50 50 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 88200Hz xywh {60 60 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 96000Hz xywh {70 70 100 20} labelfont 1 } @@ -122,35 +122,35 @@ config.cfg.SoundBufferSize=strtoul(o->value(),&tmp,10);} tooltip {ADSynth Oscillator Size (samples)} xywh {175 80 75 20} down_box BORDER_BOX labelfont 1 labelsize 11 textsize 10 code0 {o->value( (int) (log(config.cfg.OscilSize/128.0-1.0)/log(2)) +1);} } { - menuitem {} { + MenuItem {} { label 128 xywh {25 25 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 256 xywh {35 35 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 512 xywh {45 45 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 1024 xywh {45 45 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 2048 xywh {55 55 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 4096 xywh {55 55 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 8192 xywh {65 65 100 20} labelfont 1 } - menuitem {} { + MenuItem {} { label 16384 xywh {75 75 100 20} labelfont 1 } @@ -168,9 +168,9 @@ config.cfg.SoundBufferSize=strtoul(o->value(),&tmp,10);} } { Fl_File_Input {} { label {Dump File} - callback {snprintf(config.cfg.DumpFile,config.maxstringsize,"%s",o->value());} + callback {config.cfg.DumpFile = o->value();} selected xywh {20 170 220 35} align 5 - code0 {o->insert(config.cfg.DumpFile);} + code0 {o->insert(config.cfg.DumpFile.c_str());} } Fl_Check_Button {} { label {Dump notes} @@ -241,38 +241,38 @@ midiinputnamebox->label(config.winmididevices[config.cfg.WindowsMidiInId].name); xywh {175 105 75 15} down_box BORDER_BOX labelsize 10 textsize 11 code0 {o->value(config.cfg.Interpolation);} } { - menuitem {} { + MenuItem {} { label {Linear(fast)} xywh {0 0 100 20} labelfont 1 labelsize 10 } - menuitem {} { + MenuItem {} { label {Cubic(slow)} xywh {10 10 100 20} labelfont 1 labelsize 10 } } Fl_Choice {} { label {Virtual Keyboard Layout} - callback {config.cfg.VirKeybLayout=(int) o->value();;} open selected + callback {config.cfg.VirKeybLayout=(int) o->value();;} xywh {155 235 85 20} down_box BORDER_BOX labelsize 12 textfont 1 textsize 11 code0 {o->value(config.cfg.VirKeybLayout);} } { - menuitem {} { + MenuItem {} { label { } xywh {5 5 100 20} labelfont 1 labelsize 11 deactivate } - menuitem {} { + MenuItem {} { label QWERTY xywh {15 15 100 20} labelfont 1 labelsize 11 } - menuitem {} { + MenuItem {} { label Dvorak xywh {25 25 100 20} labelfont 1 labelsize 11 } - menuitem {} { + MenuItem {} { label QWERTZ xywh {35 35 100 20} labelfont 1 labelsize 11 } - menuitem {} { + MenuItem {} { label AZERTY xywh {45 45 100 20} labelfont 1 labelsize 11 } @@ -395,31 +395,30 @@ readpresetcfg();} {} code {rootsbrowse->clear(); for (int i=0;i<MAX_BANK_ROOT_DIRS;i++){ - if (config.cfg.bankRootDirList[i]!=NULL) rootsbrowse->add(config.cfg.bankRootDirList[i]); + if (!config.cfg.bankRootDirList[i].empty()) + rootsbrowse->add(config.cfg.bankRootDirList[i].c_str()); };} {} } Function {writebankcfg()} {} { code {config.clearbankrootdirlist(); for (int n=0;n<rootsbrowse->size();n++){ - config.cfg.bankRootDirList[n]=new char [MAX_STRING_SIZE]; - strncpy(config.cfg.bankRootDirList[n],rootsbrowse->text(n+1),MAX_STRING_SIZE); + config.cfg.bankRootDirList[n] = rootsbrowse->text(n+1); };} {} } Function {readpresetcfg()} {} { code {presetbrowse->clear(); -for (int i=0;i<MAX_BANK_ROOT_DIRS;i++){ - if (config.cfg.presetsDirList[i]!=NULL) presetbrowse->add(config.cfg.presetsDirList[i]); +for(int i=0;i<MAX_BANK_ROOT_DIRS;i++){ + if(!config.cfg.presetsDirList[i].empty()) + presetbrowse->add(config.cfg.presetsDirList[i].c_str()); };} {} } Function {writepresetcfg()} {} { code {config.clearpresetsdirlist(); -for (int n=0;n<presetbrowse->size();n++){ - config.cfg.presetsDirList[n]=new char [MAX_STRING_SIZE]; - strncpy(config.cfg.presetsDirList[n],presetbrowse->text(n+1),MAX_STRING_SIZE); -};} {} +for (int n=0;n<presetbrowse->size();n++) + config.cfg.presetsDirList[n] = presetbrowse->text(n+1);} {} } Function {getsamplerateorder()} {return_type int } { diff --git a/src/UI/MasterUI.fl b/src/UI/MasterUI.fl @@ -1750,7 +1750,7 @@ pthread_mutex_lock(&master->mutex); //load the data int result=master->loadXML(filename); -master->applyparameters(); +master->applyparameters(false); pthread_mutex_unlock(&master->mutex); npartcounter->value(1); diff --git a/src/UI/NioUI.cpp b/src/UI/NioUI.cpp @@ -1,9 +1,5 @@ #include "NioUI.h" -#include "../Nio/EngineMgr.h" -#include "../Nio/OutMgr.h" -#include "../Nio/InMgr.h" -#include "../Nio/AudioOut.h" -#include "../Nio/MidiIn.h" +#include "../Nio/Nio.h" #include <cstdio> #include <FL/Fl_Tabs.H> #include <FL/Fl_Group.H> @@ -40,23 +36,36 @@ NioUI::NioUI() midi->callback(midiCallback); } settings->end(); - - int audioval = 0; - int midival = 0; - for(list<Engine *>::iterator itr = sysEngine->engines.begin(); - itr != sysEngine->engines.end(); ++itr) { - Engine *eng = *itr; - if(dynamic_cast<MidiIn *>(eng)) - midi->add(eng->name.c_str()); - if(dynamic_cast<AudioOut *>(eng)) - audio->add(eng->name.c_str()); - if(eng->name == sysOut->getSink()) - audioval = audio->size() - 2; - if(eng->name == sysIn->getSource()) - midival = midi->size() - 2; + + Nio &nio = Nio::getInstance(); + + //initialize midi list + { + set<string> midiList = nio.getSources(); + string source = nio.getSource(); + int midival = 0; + for(set<string>::iterator itr = midiList.begin(); + itr != midiList.end(); ++itr) { + midi->add(itr->c_str()); + if(*itr == source) + midival = midi->size() - 2; + } + midi->value(midival); + } + + //initialize audio list + { + set<string> audioList = nio.getSinks(); + string sink = nio.getInstance().getSink(); + int audioval = 0; + for(set<string>::iterator itr = audioList.begin(); + itr != audioList.end(); ++itr) { + audio->add(itr->c_str()); + if(*itr == sink) + audioval = audio->size() - 2; + } + audio->value(audioval); } - audio->value(audioval); - midi->value(midival); } wintabs->end(); @@ -70,13 +79,13 @@ void NioUI::refresh() void NioUI::midiCallback(Fl_Widget *c) { - bool good = sysIn->setSource(static_cast<Fl_Choice *>(c)->text()); + bool good = Nio::getInstance().setSource(static_cast<Fl_Choice *>(c)->text()); static_cast<Fl_Choice *>(c)->textcolor(fl_rgb_color(255*!good,0,0)); } void NioUI::audioCallback(Fl_Widget *c) { - bool good = sysOut->setSink(static_cast<Fl_Choice *>(c)->text()); + bool good = Nio::getInstance().setSink(static_cast<Fl_Choice *>(c)->text()); static_cast<Fl_Choice *>(c)->textcolor(fl_rgb_color(255*!good,0,0)); } diff --git a/src/UI/NioUI.h b/src/UI/NioUI.h @@ -17,8 +17,6 @@ class NioUI : public Fl_Window NioUI(); void refresh(); private: - //std::list<NioTab *> tabs; - Fl_Choice *midi; Fl_Choice *audio; static void midiCallback(Fl_Widget *c); diff --git a/src/main.cpp b/src/main.cpp @@ -24,6 +24,7 @@ #include <cmath> #include <cctype> #include <algorithm> +#include <signal.h> #include <unistd.h> #include <pthread.h> @@ -41,11 +42,7 @@ extern Dump dump; //Nio System -#include "Nio/MidiIn.h" -#include "Nio/AudioOut.h" -#include "Nio/OutMgr.h" -#include "Nio/InMgr.h" -#include "Nio/EngineMgr.h" +#include "Nio/Nio.h" #ifndef DISABLE_GUI #ifdef QT_GUI @@ -167,6 +164,18 @@ void *thread4(void *arg) } #endif +void exitprogram(); + +//cleanup on signaled exit +void sigterm_exit(int sig) +{ + Pexitprogram = 1; + sleep(1); + exitprogram(); + exit(0); +} + + /* * Program initialisation */ @@ -180,24 +189,12 @@ void initprogram() / SAMPLE_RATE << " ms" << endl; cerr << "ADsynth Oscil.Size = \t" << OSCIL_SIZE << " samples" << endl; - srand(time(NULL)); - denormalkillbuf = new REALTYPE [SOUND_BUFFER_SIZE]; - for(int i = 0; i < SOUND_BUFFER_SIZE; i++) - denormalkillbuf[i] = (RND - 0.5) * 1e-16; - master = new Master(); + master = &Master::getInstance(); master->swaplr = swaplr; - //Nio Initialization - - //Enable input wrapper - sysIn = new InMgr(master); - - //Initialize the Output Systems - sysOut = new OutMgr(master); - - //Initialize The Engines - sysEngine = new EngineMgr(); + signal(SIGINT, sigterm_exit); + signal(SIGTERM, sigterm_exit); } /* @@ -205,17 +202,15 @@ void initprogram() */ void exitprogram() { + //ensure that everything has stopped with the mutex wait pthread_mutex_lock(&master->mutex); pthread_mutex_unlock(&master->mutex); - sysEngine->stop(); - delete sysOut; - delete sysIn; - delete sysEngine; + + Nio::getInstance().stop(); #ifndef DISABLE_GUI delete ui; #endif - delete master; #ifdef USE_LASH delete lash; @@ -278,6 +273,11 @@ int main(int argc, char *argv[]) OSCIL_SIZE = config.cfg.OscilSize; swaplr = config.cfg.SwapStereo; + srand(time(NULL)); + //produce denormal buf + denormalkillbuf = new REALTYPE [SOUND_BUFFER_SIZE]; + for(int i = 0; i < SOUND_BUFFER_SIZE; i++) + denormalkillbuf[i] = (RND - 0.5) * 1e-16; /* Parse command-line options */ #if OS_LINUX || OS_CYGWIN @@ -300,7 +300,7 @@ int main(int argc, char *argv[]) opterr = 0; int option_index = 0, opt, exitwithhelp = 0; - string loadfile, loadinstrument, input, output; + string loadfile, loadinstrument; while(1) { /**\todo check this process for a small memory leak*/ @@ -374,10 +374,16 @@ int main(int argc, char *argv[]) dump.startnow(); break; case 'I': - GETOP(input); + if(optarguments) { + if(Nio::getInstance().setDefaultSource(optarguments)) + exit(1); + } break; case 'O': - GETOP(output); + if(optarguments) { + if(Nio::getInstance().setDefaultSink(optarguments)) + exit(1); + } break; case '?': cerr << "ERROR:Bad option or parameter.\n" << endl; @@ -450,24 +456,8 @@ int main(int argc, char *argv[]) } } - - if(!input.empty()) { - if(!sysEngine->setInDefault(input)) { - cerr << "There is no input for " << input << endl; - exit(1); - } - cout << input << " selected." << endl; - } - if(!output.empty()) { - if(!sysEngine->setOutDefault(output)) { - cerr << "There is no output for " << output << endl; - exit(1); - } - cout << output << " selected." << endl; - } - //Run the Nio system - sysEngine->start(); //Drivers start your engines! + Nio::getInstance().start(); #warning remove welcome message when system is out of beta cout << "\nThanks for using the Nio system :)" << endl;