zynaddsubfx

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

commit 5bd39c2e1d41ad2ddea93e3296eb0b838143cce0
parent 81c307a3e56b2cf285d545fd46c0c1ab3e6b3d60
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Sun,  2 May 2010 13:59:59 -0400

Merge branch 'nio' into niox

Conflicts:
	src/CMakeLists.txt
	src/Nio/InMgr.cpp
	src/Nio/OutMgr.cpp

Diffstat:
MAUTHORS.txt | 2++
MCMakeLists.txt | 4++++
MChangeLog | 14++++++++++++++
MHISTORY.txt | 10++++++++++
Mdoc/build.txt | 15++++++++-------
Adoc/getting.txt | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdoc/zynaddsubfx.txt | 4++++
Msrc/CMakeLists.txt | 21++++++++++++++++++++-
Asrc/Effects/APhaser.cpp | 450+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/APhaser.h | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Effects/Alienwah.cpp | 26+++++++++++++-------------
Msrc/Effects/Alienwah.h | 20++++++++++----------
Msrc/Effects/CMakeLists.txt | 1+
Msrc/Effects/Chorus.cpp | 38++++++++++++--------------------------
Msrc/Effects/Chorus.h | 24+++++++++++-------------
Msrc/Effects/Distorsion.cpp | 22+++++++++++-----------
Msrc/Effects/Distorsion.h | 36++++++++++++++++++------------------
Msrc/Effects/DynamicFilter.cpp | 20++++++++++----------
Msrc/Effects/DynamicFilter.h | 14+++++++-------
Msrc/Effects/EQ.cpp | 20++++++--------------
Msrc/Effects/EQ.h | 8++++----
Msrc/Effects/Echo.cpp | 122++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/Effects/Echo.h | 53++++++++++++++++++++++++++---------------------------
Msrc/Effects/Effect.cpp | 9+++++++--
Msrc/Effects/Effect.h | 13++++++++-----
Msrc/Effects/EffectMgr.cpp | 6++++++
Msrc/Effects/EffectMgr.h | 8++++++++
Msrc/Effects/Makefile | 2+-
Msrc/Effects/Phaser.cpp | 26+++++++++++++-------------
Msrc/Effects/Phaser.h | 31++++++++++++++-----------------
Msrc/Effects/Reverb.cpp | 26+++++++++++++-------------
Msrc/Effects/Reverb.h | 24++++++++++++------------
Msrc/Makefile | 4++--
Msrc/Makefile.inc | 1+
Msrc/Misc/Bank.cpp | 19++++++++++++++-----
Msrc/Misc/Bank.h | 2+-
Msrc/Misc/CMakeLists.txt | 4++++
Msrc/Misc/Master.cpp | 2++
Msrc/Misc/Master.h | 1-
Msrc/Misc/Part.cpp | 6+++++-
Msrc/Misc/Part.h | 3+++
Msrc/Nio/AlsaEngine.cpp | 6+++++-
Msrc/Nio/AlsaEngine.h | 1+
Msrc/Nio/JackEngine.cpp | 4++--
Msrc/Nio/OssEngine.cpp | 4++--
Msrc/Nio/OutMgr.cpp | 1+
Msrc/Nio/WavEngine.h | 4++--
Msrc/Output/DSSIaudiooutput.cpp | 806+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/Output/DSSIaudiooutput.h | 100++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/Params/LFOParams.cpp | 3+--
Msrc/Samples/CMakeLists.txt | 2--
Msrc/Samples/Makefile | 2+-
Msrc/Samples/Sample.cpp | 8++++++++
Msrc/Tests/CMakeLists.txt | 2+-
Msrc/Tests/EchoTest.h | 37+++++++++++++++++++++++++------------
Msrc/Tests/SampleTest.h | 20++++++++++----------
Msrc/UI/BankUI.fl | 17+++++++----------
Msrc/UI/EffUI.fl | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/UI/MasterUI.fl | 14+++++++++++---
Msrc/main.cpp | 22+++++++++++-----------
60 files changed, 1888 insertions(+), 593 deletions(-)

diff --git a/AUTHORS.txt b/AUTHORS.txt @@ -16,4 +16,6 @@ Contributors: Tobias Doerffel (static-instance variables fix, missing include fix) James Morris (Memory leaks in FLTK GUI) Alan Calvert (Portions of New IO) + Stephen Parry (DSSI rebuild) + Ryan Billing (APhaser) diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -5,3 +5,7 @@ project(zynaddsubfx) enable_testing() #Currently the only directory that uses cmake add_subdirectory(src) + +install(FILES AUTHORS.txt COPYING FAQ.txt HISTORY.txt README.txt + DESTINATION share/doc/zynaddsubfx + ) diff --git a/ChangeLog b/ChangeLog @@ -982,3 +982,17 @@ - General Code Cleanup - Adding OpenGL linking for proper compiles +14 Jan 2010 (Mark McCurry) + - Fixed No UI Flag "-U" as it was previously partially initializing + the gui + +14 Feb 2010 (Stephen Parry) + - DSSI Support Repaired + +14 Feb 2010 (Mark McCurry) + - Made the Echo attempt to adjust the delay instead of erasing it + when length is changed + +02 May 2010 (Mark McCurry) + - Merging in cleanup from effects and adding APhaser by Ryan Billing + diff --git a/HISTORY.txt b/HISTORY.txt @@ -1,3 +1,13 @@ +2.4.1 (In Beta) + - Azerty layout + - XML bug fixes + - Vibrato/Unison additions + - Reverb rewrite + - DSSI support enabled + - Adding APhaser + - other bugfixes + - code cleanup + 2.4.0 (21 Jun 2009) - extended mono functionality - legato mode diff --git a/doc/build.txt b/doc/build.txt @@ -1,5 +1,5 @@ -Building ZynAddSubFX -==================== +Appendix B: Building ZynAddSubFX +================================ Introduction to CMake --------------------- @@ -33,6 +33,11 @@ Quick start guide For the impatient ones, here is a quick guide on how to immediately build ZynAddSubFX from source. + +************************************************************** +Note: This assumes that you already have a copy of the source. +************************************************************** + --------------------------------- #enter the source directory cd zynaddsubfx @@ -46,13 +51,9 @@ cd build cmake .. #OPTIONAL: Adjust compile variables in the Cache file: -$EDITOR CMakeCache.txt +ccmake . #And finally, build as usual using make make --------------------------------- -Customizing the build ---------------------- - - diff --git a/doc/getting.txt b/doc/getting.txt @@ -0,0 +1,61 @@ +Appendix C: Getting ZynAddSubFX +=============================== + +Usually there are several methods to obtain a copy of ZynAddSubFX. + +SourceForge:: + http://sourceforge.net/projects/zynaddsubfx/files/ +Distribuition:: + apt/yum/others +Git:: + git://zynaddsubfx.git.sourceforge.net/gitroot/zynaddsubfx/zynaddsubfx + +Introduction to Git +------------------- + +For those who want to live on the bleeding edge or who want to assist with +making sure that the next release has fewer bugs, you will want to get aquanted +with git. +Git is used to manage the source code for this project and can be used to +quickly and easily get an up-to-date copy of the source code. + +Getting the Source Code +~~~~~~~~~~~~~~~~~~~~~~~ + +In order to get a copy of the ZynAddSubFX source code, all that needs to be done is: + +--------------------------------------------- +git clone git://zynaddsubfx.git.sourceforge.net/gitroot/zynaddsubfx/zynaddsubfx + +cd zynaddsubfx +--------------------------------------------- + +You should now be in the directory of the source code. + +For simple steps on building, please see Appendix B of the manual. + +Checking out a branch +~~~~~~~~~~~~~~~~~~~~~ + +Lets say that development has extended into the creation of a new feature that +you want to preview. +For the sake of this guide, lets assume that the name of the branch that the +feature is on is foo. + +----------------------------------------- +#checkout the foo branch from sourceforge +git checkout --track -b foo origin/foo + +#lets checkout the primary branch again +git checkout master + +#hop back to the other branch +git checkout foo +---------------------------------------- + +Now one should be able to change branches and go into the build directory (as +described in Appendix B) and recompile ZynAddSubFX. + +NOTE: When using branches other than the master be aware that stability may + suffer + diff --git a/doc/zynaddsubfx.txt b/doc/zynaddsubfx.txt @@ -18,3 +18,7 @@ include::./controller.txt[] include::./nrpn.txt[] include::./mididefaults.txt[] + +include::./build.txt[] + +include::./getting.txt[] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt @@ -6,6 +6,7 @@ message(STATUS "Checking Library Path" $ENV{CMAKE_LIBRARY_PATH} ${CMAKE_LIBRARY_ find_package(zlib REQUIRED) find_package(fftw REQUIRED) find_package(MXML REQUIRED) +find_package(PkgConfig REQUIRED) #find_package(pthread REQUIRED) #find_package(OSS) find_package(Alsa) @@ -33,6 +34,7 @@ SET (OssEnable ${ALSA_FOUND} CACHE BOOL #TODO perhaps check for /dev/dsp SET (PaEnable ${PORTAUDIO_FOUND} CACHE BOOL "Enable support for Port Audio System") + # Now, handle the incoming settings and set define flags/variables based # on this @@ -48,6 +50,13 @@ else () message(STATUS "GUI module defaulting to off") endif() +if(NOT PKG_CONFIG_FOUND) + message(FATAL_ERROR "pkg-config not found") +endif(NOT PKG_CONFIG_FOUND) + +# lash +pkg_search_module(LASH lash-1.0) +mark_as_advanced(LASH_LIBRARIES) ########### Settings dependant code ########### # From here on, the setting variables have been prepared so concentrate @@ -79,6 +88,13 @@ if (CompileTests) ENABLE_TESTING() endif() +if(LASH_FOUND) + include_directories(${LASH_INCLUDE_DIRS}) + add_definitions(-DUSE_LASH) + set(AUDIO_LIBRARIES ${AUDIO_LIBRARIES} ${LASH_LIBRARIES}) + message(STATUS "Compiling with lash") +endif() + add_definitions(-DFFTW_VERSION_${FFTW_VERSION} -DASM_F2I_YES -g #TODO #todo put in a better location @@ -124,7 +140,7 @@ if(FltkGui) message(STATUS ${MYFLTK_LDFLAGS}) - set(GUI_LIBRARIES ${MYFLTK_LIBRARIES} ${FLTK_LIBRARIES} ${OPENGL_LIBRARIES} zynaddsubfx_gui) + set(GUI_LIBRARIES ${FLTK_LIBRARIES} ${MYFLTK_LIBRARIES} ${OPENGL_LIBRARIES} zynaddsubfx_gui) add_definitions(-DFLTK_GUI) @@ -224,3 +240,6 @@ target_link_libraries(zynaddsubfx ${OS_LIBRARIES} ) +install(TARGETS zynaddsubfx + RUNTIME DESTINATION bin + ) diff --git a/src/Effects/APhaser.cpp b/src/Effects/APhaser.cpp @@ -0,0 +1,450 @@ +/* + + APhaser.C - Approximate digital model of an analog JFET phaser. + Analog modeling implemented by Ryan Billing aka Transmogrifox. + November, 2009 + + Credit to: + /////////////////// + ZynAddSubFX - a software synthesizer + + Phaser.C - Phaser effect + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + Modified for rakarrack by Josep Andreu + + DSP analog modeling theory & practice largely influenced by various CCRMA publications, particularly works by Julius O. Smith. + //////////////////// + + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <cmath> +#include "APhaser.h" +#include <cstdio> +#include <iostream> +using namespace std; +#define PHASER_LFO_SHAPE 2 +#define ONE_ 0.99999f // To prevent LFO ever reaching 1.0 for filter stability purposes +#define ZERO_ 0.00001f // Same idea as above. + +Analog_Phaser::Analog_Phaser(const int & insertion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_) + :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0) +{ + lxn1 = NULL; + lyn1 = NULL; + rxn1 = NULL; + ryn1 = NULL; + + offset = new REALTYPE[12]; //model mismatch between JFET devices + offset[0] = -0.2509303f; + offset[1] = 0.9408924f; + offset[2] = 0.998f; + offset[3] = -0.3486182f; + offset[4] = -0.2762545f; + offset[5] = -0.5215785f; + offset[6] = 0.2509303f; + offset[7] = -0.9408924f; + offset[8] = -0.998f; + offset[9] = 0.3486182f; + offset[10] = 0.2762545f; + offset[11] = 0.5215785f; + + barber = 0; //Deactivate barber pole phasing by default + + mis = 1.0f; + Rmin = 625.0f; // 2N5457 typical on resistance at Vgs = 0 + Rmax = 22000.0f; // Resistor parallel to FET + Rmx = Rmin/Rmax; + Rconst = 1.0f + Rmx; // Handle parallel resistor relationship + C = 0.00000005f; // 50 nF + CFs = (float) 2.0f*(float)SAMPLE_RATE*C; + invperiod = 1.0f / ((float) SOUND_BUFFER_SIZE); + + + Ppreset = 0; + setpreset (Ppreset); + cleanup (); +}; + +Analog_Phaser::~Analog_Phaser() +{ + + if(lxn1 != NULL) + delete[]lxn1; + + if(lyn1 != NULL) + delete[]lyn1; + + if(rxn1 != NULL) + delete[]rxn1; + + if(ryn1 != NULL) + delete[]ryn1; + + if(offset != NULL) + delete[]offset; +}; + + +/* + * Effect output + */ +void Analog_Phaser::out(const Stereo<REALTYPE *> &input) +{ + int i, j; + float lfol, lfor, lgain, rgain, bl, br, gl, gr, rmod, lmod, d, hpfr, hpfl; + lgain = 0.0; + rgain = 0.0; + + //initialize hpf + hpfl = 0.0; + hpfr = 0.0; + + lfo.effectlfoout (&lfol, &lfor); + lmod = lfol*width + depth; + rmod = lfor*width + depth; + + if(lmod > ONE_) + lmod = ONE_; + else if(lmod < ZERO_) + lmod = ZERO_; + if(rmod > ONE_) + rmod = ONE_; + else if(rmod < ZERO_) + rmod = ZERO_; + + if(Phyper != 0) + { + lmod *= lmod; //Triangle wave squared is approximately sin on bottom, tri on top + rmod *= rmod; //Result is exponential sweep more akin to filter in synth with exponential generator circuitry. + }; + + lmod = sqrtf(1.0f - lmod); //gl,gr is Vp - Vgs. Typical FET drain-source resistance follows constant/[1-sqrt(Vp - Vgs)] + rmod = sqrtf(1.0f - rmod); + + rdiff = (rmod - oldrgain) * invperiod; + ldiff = (lmod - oldlgain) * invperiod; + + gl = oldlgain; + gr = oldrgain; + + oldlgain = lmod; + oldrgain = rmod; + + for (i = 0; i < SOUND_BUFFER_SIZE; i++) + { + + gl += ldiff; // Linear interpolation between LFO samples + gr += rdiff; + + float lxn = input.l()[i]; + float rxn = input.r()[i]; + + + if (barber) { + gl = fmodf((gl + 0.25f) , ONE_); + gr = fmodf((gr + 0.25f) , ONE_); + }; + + + //cout << lxn << " vs "; + //Left channel + for (j = 0; j < Pstages; j++) + { //Phasing routine + mis = 1.0f + offsetpct*offset[j]; + d = (1.0f + 2.0f*(0.25f + gl)*hpfl*hpfl*distortion) * mis; //This is symmetrical. FET is not, so this deviates slightly, however sym dist. is better sounding than a real FET. + Rconst = 1.0f + mis*Rmx; + bl = (Rconst - gl )/ (d*Rmin); // This is 1/R. R is being modulated to control filter fc. + lgain = (CFs - bl)/(CFs + bl); + + lyn1[j] = lgain * (lxn + lyn1[j]) - lxn1[j]; + //lyn1[j] += DENORMAL_GUARD; + hpfl = lyn1[j] + (1.0f-lgain)*lxn1[j]; //high pass filter -- Distortion depends on the high-pass part of the AP stage. + + lxn1[j] = lxn; + lxn = lyn1[j]; + if (j==1) lxn += fbl; //Insert feedback after first phase stage + }; + //cout << lxn << endl; + + //Right channel + for (j = 0; j < Pstages; j++) + { //Phasing routine + mis = 1.0f + offsetpct*offset[j]; + d = (1.0f + 2.0f*(0.25f + gr)*hpfr*hpfr*distortion) * mis; // distortion + Rconst = 1.0f + mis*Rmx; + br = (Rconst - gr )/ (d*Rmin); + rgain = (CFs - br)/(CFs + br); + + ryn1[j] = rgain * (rxn + ryn1[j]) - rxn1[j]; + //ryn1[j] += DENORMAL_GUARD; + hpfr = ryn1[j] + (1.0f-rgain)*rxn1[j]; //high pass filter + + rxn1[j] = rxn; + rxn = ryn1[j]; + if (j==1) rxn += fbr; //Insert feedback after first phase stage + } + + //cout << fb << ' ' << input.l()[i] - lxn << endl; + //cout << "input" << input.l()[i] << "output:" << lxn << endl; + + fbl = lxn * fb; + fbr = rxn * fb; + efxoutl[i] = lxn; + efxoutr[i] = rxn; + + } + + if(Poutsub != 0) + for(i = 0; i < SOUND_BUFFER_SIZE; i++) + { + efxoutl[i] *= -1.0f; + efxoutr[i] *= -1.0f; + }; +}; + +/* + * Cleanup the effect + */ +void Analog_Phaser::cleanup() +{ + fbl = 0.0; + fbr = 0.0; + oldlgain = 0.0; + oldrgain = 0.0; + for(int i = 0; i < Pstages; i++) + { + lxn1[i] = 0.0; + + lyn1[i] = 0.0; + + rxn1[i] = 0.0; + + ryn1[i] = 0.0; + + }; +}; + +/* + * Parameter control + */ +void Analog_Phaser::setwidth(unsigned char Pwidth) +{ + this->Pwidth = Pwidth; + width = ((float)Pwidth / 127.0f); +}; + + +void Analog_Phaser::setfb(unsigned char Pfb) +{ + this->Pfb = Pfb; + fb = (float) (Pfb - 64) / 64.2f; +}; + +void Analog_Phaser::setvolume(unsigned char Pvolume) +{ + cout << "setting volume" << (int) Pvolume << endl; + this->Pvolume = Pvolume; + // outvolume is needed in calling program + if(insertion == 0) { + outvolume = pow(0.01, (1.0 - Pvolume / 127.0)) * 4.0; + volume = 1.0; + } + else + volume = outvolume = Pvolume / 127.0; +}; + +void Analog_Phaser::setdistortion(unsigned char Pdistortion) +{ + this->Pdistortion = Pdistortion; + distortion = (float)Pdistortion / 127.0f; +}; + +void Analog_Phaser::setoffset(unsigned char Poffset) +{ + this->Poffset = Poffset; + offsetpct = (float)Poffset / 127.0f; +}; + +void Analog_Phaser::setstages(unsigned char Pstages) +{ + + if(lxn1 != NULL) + delete[]lxn1; + + if(lyn1 != NULL) + delete[]lyn1; + + if(rxn1 != NULL) + delete[]rxn1; + + if(ryn1 != NULL) + delete[]ryn1; + + + if(Pstages >= MAX_PHASER_STAGES) + Pstages = MAX_PHASER_STAGES ; + this->Pstages = Pstages; + + + lxn1 = new REALTYPE[Pstages]; + lyn1 = new REALTYPE[Pstages]; + + rxn1 = new REALTYPE[Pstages]; + ryn1 = new REALTYPE[Pstages]; + + cleanup(); +}; + +void Analog_Phaser::setdepth(unsigned char Pdepth) +{ + this->Pdepth = Pdepth; + depth = (float)(Pdepth - 64) / 127.0f; //Pdepth input should be 0-127. depth shall range 0-0.5 since we don't need to shift the full spectrum. +}; + + +void Analog_Phaser::setpreset(unsigned char npreset) +{ + const int PRESET_SIZE = 13; + const int NUM_PRESETS = 6; + unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { + //Phaser1 + {64, 20, 14, 0, 1, 64, 110, 40, 4, 10, 0, 64, 1}, + //Phaser2 + {64, 20, 14, 5, 1, 64, 110, 40, 6, 10, 0, 70, 1}, + //Phaser3 + {64, 20, 9, 0, 0, 64, 40, 40, 8, 10, 0, 60, 0}, + //Phaser4 + {64, 20, 14, 10, 0, 64, 110, 80, 7, 10, 1, 45, 1}, + //Phaser5 + {25, 20, 240, 10, 0, 64, 25, 16, 8, 100, 0, 25, 0}, + //Phaser6 + {64, 20, 1, 10, 1, 64, 110, 40, 12, 10, 0, 70, 1} + }; + if(npreset >= NUM_PRESETS) + npreset = NUM_PRESETS - 1; + for(int n = 0; n < PRESET_SIZE; n++) + changepar(n, presets[npreset][n]); + Ppreset = npreset; +}; + + +void Analog_Phaser::changepar(int npar, unsigned char value) +{ + switch(npar) + { + case 0: + setvolume(value); + break; + case 1: + setdistortion(value); + break; + case 2: + lfo.Pfreq = value; + lfo.updateparams(); + break; + case 3: + lfo.Prandomness = value; + lfo.updateparams (); + break; + case 4: + lfo.PLFOtype = value; + lfo.updateparams(); + barber = 0; + if (value == 2) barber = 1; + break; + case 5: + lfo.Pstereo = value; + lfo.updateparams(); + break; + case 6: + setwidth(value); + break; + case 7: + setfb(value); + break; + case 8: + setstages(value); + break; + case 9: + setoffset(value); + break; + case 10: + if (value > 1) + value = 1; + Poutsub = value; + break; + case 11: + setdepth(value); + break; + case 12: + if (value > 1) + value = 1; + Phyper = value; + break; + }; +}; + +unsigned char Analog_Phaser::getpar(int npar) const +{ + switch(npar) + { + case 0: + return(Pvolume); + break; + case 1: + return(Pdistortion); + break; + case 2: + return(lfo.Pfreq); + break; + case 3: + return(lfo.Prandomness); + break; + case 4: + return(lfo.PLFOtype); + break; + case 5: + return(lfo.Pstereo); + break; + case 6: + return(Pwidth); + break; + case 7: + return(Pfb); + break; + case 8: + return(Pstages); + break; + case 9: + return(Poffset); + break; + case 10: + return(Poutsub); + break; + case 11: + return(Pdepth); + break; + case 12: + return(Phyper); + break; + + default: + return(0); + } +} diff --git a/src/Effects/APhaser.h b/src/Effects/APhaser.h @@ -0,0 +1,86 @@ +/* + ZynAddSubFX - a software synthesizer + + Phaser.h - Phaser effect + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + Modified for rakarrack by Josep Andreu + + Further modified for rakarrack by Ryan Billing (Transmogrifox) to model Analog Phaser behavior 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef APHASER_H +#define APHASER_H +#include "../globals.h" +#include "Effect.h" +#include "EffectLFO.h" + +#define MAX_PHASER_STAGES 12 + +class Analog_Phaser:public Effect +{ + public: + Analog_Phaser(const int & insertion_, REALTYPE * efxoutl_, REALTYPE * efxoutr_); + ~Analog_Phaser(); + void out(const Stereo<REALTYPE *> &input); + void setpreset(unsigned char npreset); + void changepar(int npar, unsigned char value); + unsigned char getpar(int npar) const; + void cleanup(); + //unsigned char Ppreset; + + private: + //Phaser parameters + EffectLFO lfo; //Phaser modulator + unsigned char Pvolume; //Used in Process.C to set wet/dry mix + unsigned char Pdistortion; //Model distortion added by FET element + unsigned char Pwidth; //Phaser width (LFO amplitude) + unsigned char Pfb; //feedback + unsigned char Poffset; //Model mismatch between variable resistors + unsigned char Pstages; //Number of first-order All-Pass stages + unsigned char Poutsub; //if I wish to subtract the output instead of the adding it + unsigned char Phyper; //lfo^2 -- converts tri into hyper-sine + unsigned char Pdepth; //Depth of phaser sweep + unsigned char Pbarber; //Enable parber pole phasing + + + //Control parameters + void setvolume(unsigned char Pvolume); + void setdistortion(unsigned char Pdistortion); + void setwidth(unsigned char Pwidth); + void setfb(unsigned char Pfb); + void setoffset(unsigned char Poffset); + void setstages(unsigned char Pstages); + void setdepth(unsigned char Pdepth); + + //Internal Variables + bool barber; //Barber pole phasing flag + REALTYPE distortion, fb, width, offsetpct, fbl, fbr, depth; + REALTYPE *lxn1, *lyn1,*rxn1, *ryn1, *offset; + REALTYPE oldlgain, oldrgain, rdiff, ldiff, invperiod; + + float mis; + float Rmin; // 2N5457 typical on resistance at Vgs = 0 + float Rmax; // Resistor parallel to FET + float Rmx; // Rmin/Rmax to avoid division in loop + float Rconst; // Handle parallel resistor relationship + float C; // Capacitor + float CFs; // A constant derived from capacitor and resistor relationships +}; + +#endif diff --git a/src/Effects/Alienwah.cpp b/src/Effects/Alienwah.cpp @@ -46,7 +46,7 @@ Alienwah::~Alienwah() /* * Apply the effect */ -void Alienwah::out(REALTYPE *smpsl, REALTYPE *smpsr) +void Alienwah::out(const Stereo<float *> &smp) { REALTYPE lfol, lfor; //Left/Right LFOs complex<REALTYPE> clfol, clfor, out, tmp; @@ -67,7 +67,7 @@ void Alienwah::out(REALTYPE *smpsl, REALTYPE *smpsr) tmp = clfol * x + oldclfol * x1; out = tmp * oldl[oldk]; - out.real() += (1 - fabs(fb)) * smpsr[i] * (1.0 - panning); + out.real() += (1 - fabs(fb)) * smp.l()[i] * (1.0 - panning); oldl[oldk] = out; REALTYPE l = out.real() * 10.0 * (fb + 0.1); @@ -76,7 +76,7 @@ void Alienwah::out(REALTYPE *smpsl, REALTYPE *smpsr) tmp = clfor * x + oldclfor * x1; out = tmp * oldr[oldk]; - out.real() += (1 - fabs(fb)) * smpsr[i] * (1.0 - panning); + out.real() += (1 - fabs(fb)) * smp.r()[i] * (1.0 - panning); oldr[oldk] = out; REALTYPE r = out.real() * 10.0 * (fb + 0.1); @@ -110,13 +110,13 @@ void Alienwah::cleanup() * Parameter control */ -void Alienwah::setdepth(const unsigned char &Pdepth) +void Alienwah::setdepth(unsigned char Pdepth) { this->Pdepth = Pdepth; depth = (Pdepth / 127.0); } -void Alienwah::setfb(const unsigned char &Pfb) +void Alienwah::setfb(unsigned char Pfb) { this->Pfb = Pfb; fb = fabs((Pfb - 64.0) / 64.1); @@ -127,7 +127,7 @@ void Alienwah::setfb(const unsigned char &Pfb) fb = -fb; } -void Alienwah::setvolume(const unsigned char &Pvolume) +void Alienwah::setvolume(unsigned char Pvolume) { this->Pvolume = Pvolume; outvolume = Pvolume / 127.0; @@ -137,25 +137,25 @@ void Alienwah::setvolume(const unsigned char &Pvolume) volume = outvolume; } -void Alienwah::setpanning(const unsigned char &Ppanning) +void Alienwah::setpanning(unsigned char Ppanning) { this->Ppanning = Ppanning; panning = Ppanning / 127.0; } -void Alienwah::setlrcross(const unsigned char &Plrcross) +void Alienwah::setlrcross(unsigned char Plrcross) { this->Plrcross = Plrcross; lrcross = Plrcross / 127.0; } -void Alienwah::setphase(const unsigned char &Pphase) +void Alienwah::setphase(unsigned char Pphase) { this->Pphase = Pphase; phase = (Pphase - 64.0) / 64.0 * PI; } -void Alienwah::setdelay(const unsigned char &Pdelay) +void Alienwah::setdelay(unsigned char Pdelay) { if(oldl != NULL) delete [] oldl; @@ -190,12 +190,12 @@ void Alienwah::setpreset(unsigned char npreset) for(int n = 0; n < PRESET_SIZE; n++) changepar(n, presets[npreset][n]); if(insertion == 0) - changepar(0, presets[npreset][0] / 2); //lower the volume if this is system effect + changepar(0, presets[npreset][0] / 2); //lower the volume if this is system effect Ppreset = npreset; } -void Alienwah::changepar(const int &npar, const unsigned char &value) +void Alienwah::changepar(int npar, unsigned char value) { switch(npar) { case 0: @@ -238,7 +238,7 @@ void Alienwah::changepar(const int &npar, const unsigned char &value) } } -unsigned char Alienwah::getpar(const int &npar) const +unsigned char Alienwah::getpar(int npar) const { switch(npar) { case 0: diff --git a/src/Effects/Alienwah.h b/src/Effects/Alienwah.h @@ -46,11 +46,11 @@ class Alienwah:public Effect REALTYPE *const efxoutl_, REALTYPE *const efxoutr_); ~Alienwah(); - void out(REALTYPE *const smpsl, REALTYPE *const smpsr); + void out(const Stereo<float *> &smp); void setpreset(unsigned char npreset); - void changepar(const int &npar, const unsigned char &value); - unsigned char getpar(const int &npar) const; + void changepar(int npar, unsigned char value); + unsigned char getpar(int npar) const; void cleanup(); private: @@ -66,13 +66,13 @@ class Alienwah:public Effect //Control Parameters - void setvolume(const unsigned char &Pvolume); - void setpanning(const unsigned char &Ppanning); - void setdepth(const unsigned char &Pdepth); - void setfb(const unsigned char &Pfb); - void setlrcross(const unsigned char &Plrcross); - void setdelay(const unsigned char &Pdelay); - void setphase(const unsigned char &Pphase); + void setvolume(unsigned char Pvolume); + void setpanning(unsigned char Ppanning); + void setdepth(unsigned char Pdepth); + void setfb(unsigned char Pfb); + void setlrcross(unsigned char Plrcross); + void setdelay(unsigned char Pdelay); + void setphase(unsigned char Pphase); //Internal Values REALTYPE panning, fb, depth, lrcross, phase; diff --git a/src/Effects/CMakeLists.txt b/src/Effects/CMakeLists.txt @@ -10,6 +10,7 @@ set(zynaddsubfx_effect_SRCS EQ.cpp Phaser.cpp Reverb.cpp + APhaser.cpp ) add_library(zynaddsubfx_effect STATIC diff --git a/src/Effects/Chorus.cpp b/src/Effects/Chorus.cpp @@ -35,9 +35,6 @@ Chorus::Chorus(const int &insertion_, { dlk = 0; drk = 0; - //maxdelay=(int)(MAX_CHORUS_DELAY/1000.0*SAMPLE_RATE); - //delayl=new REALTYPE[maxdelay]; - //delayr=new REALTYPE[maxdelay]; setpreset(Ppreset); @@ -71,18 +68,7 @@ REALTYPE Chorus::getdelay(REALTYPE xlfo) return result; } -/* - * Apply the effect - */ -void Chorus::out(REALTYPE *smpsl, REALTYPE *smpsr) -{ - const Stereo<AuSample> input(AuSample(SOUND_BUFFER_SIZE, smpsl), AuSample( - SOUND_BUFFER_SIZE, - smpsr)); - out(input); -} - -void Chorus::out(const Stereo<AuSample> &input) +void Chorus::out(const Stereo<float *> &input) { const REALTYPE one = 1.0; dl1 = dl2; @@ -92,7 +78,7 @@ void Chorus::out(const Stereo<AuSample> &input) dl2 = getdelay(lfol); dr2 = getdelay(lfor); - for(int i = 0; i < input.l().size(); i++) { + for(int i = 0; i < SOUND_BUFFER_SIZE; i++) { REALTYPE inl = input.l()[i]; REALTYPE inr = input.r()[i]; //LRcross @@ -137,14 +123,14 @@ void Chorus::out(const Stereo<AuSample> &input) } if(Poutsub != 0) - for(int i = 0; i < input.l().size(); i++) { + for(int i = 0; i < SOUND_BUFFER_SIZE; i++) { efxoutl[i] *= -1.0; efxoutr[i] *= -1.0; } ; - for(int i = 0; i < input.l().size(); i++) { + for(int i = 0; i < SOUND_BUFFER_SIZE; i++) { efxoutl[i] *= panning; efxoutr[i] *= (1.0 - panning); } @@ -162,24 +148,24 @@ void Chorus::cleanup() /* * Parameter control */ -void Chorus::setdepth(const unsigned char &Pdepth) +void Chorus::setdepth(unsigned char Pdepth) { this->Pdepth = Pdepth; depth = (pow(8.0, (Pdepth / 127.0) * 2.0) - 1.0) / 1000.0; //seconds } -void Chorus::setdelay(const unsigned char &Pdelay) +void Chorus::setdelay(unsigned char Pdelay) { this->Pdelay = Pdelay; delay = (pow(10.0, (Pdelay / 127.0) * 2.0) - 1.0) / 1000.0; //seconds } -void Chorus::setfb(const unsigned char &Pfb) +void Chorus::setfb(unsigned char Pfb) { this->Pfb = Pfb; fb = (Pfb - 64.0) / 64.1; } -void Chorus::setvolume(const unsigned char &Pvolume) +void Chorus::setvolume(unsigned char Pvolume) { this->Pvolume = Pvolume; outvolume = Pvolume / 127.0; @@ -189,13 +175,13 @@ void Chorus::setvolume(const unsigned char &Pvolume) volume = outvolume; } -void Chorus::setpanning(const unsigned char &Ppanning) +void Chorus::setpanning(unsigned char Ppanning) { this->Ppanning = Ppanning; panning = Ppanning / 127.0; } -void Chorus::setlrcross(const unsigned char &Plrcross) +void Chorus::setlrcross(unsigned char Plrcross) { this->Plrcross = Plrcross; lrcross = Plrcross / 127.0; @@ -236,7 +222,7 @@ void Chorus::setpreset(unsigned char npreset) } -void Chorus::changepar(const int &npar, const unsigned char &value) +void Chorus::changepar(int npar, unsigned char value) { switch(npar) { case 0: @@ -288,7 +274,7 @@ void Chorus::changepar(const int &npar, const unsigned char &value) } } -unsigned char Chorus::getpar(const int &npar) const +unsigned char Chorus::getpar(int npar) const { switch(npar) { case 0: diff --git a/src/Effects/Chorus.h b/src/Effects/Chorus.h @@ -25,7 +25,7 @@ #include "../globals.h" #include "Effect.h" #include "EffectLFO.h" -#include "../Samples/AuSample.h" +#include "../Samples/Sample.h" #include "../Misc/Stereo.h" #define MAX_CHORUS_DELAY 250.0 //ms @@ -37,8 +37,7 @@ class Chorus:public Effect Chorus(const int &insetion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_); /**Destructor*/ ~Chorus(); - void out(REALTYPE *smpsl, REALTYPE *smpsr); - void out(const Stereo<AuSample> &input); + void out(const Stereo<float *> &input); void setpreset(unsigned char npreset); /** * Sets the value of the chosen variable @@ -58,7 +57,7 @@ class Chorus:public Effect * @param npar number of chosen parameter * @param value the new value */ - void changepar(const int &npar, const unsigned char &value); + void changepar(int npar, unsigned char value); /** * Gets the value of the chosen variable * @@ -77,7 +76,7 @@ class Chorus:public Effect * @param npar number of chosen parameter * @return the value of the parameter */ - unsigned char getpar(const int &npar) const; + unsigned char getpar(int npar) const; void cleanup(); private: @@ -94,19 +93,18 @@ class Chorus:public Effect //Parameter Controls - void setvolume(const unsigned char &Pvolume); - void setpanning(const unsigned char &Ppanning); - void setdepth(const unsigned char &Pdepth); - void setdelay(const unsigned char &Pdelay); - void setfb(const unsigned char &Pfb); - void setlrcross(const unsigned char &Plrcross); + void setvolume(unsigned char Pvolume); + void setpanning(unsigned char Ppanning); + void setdepth(unsigned char Pdepth); + void setdelay(unsigned char Pdelay); + void setfb(unsigned char Pfb); + void setlrcross(unsigned char Plrcross); //Internal Values REALTYPE depth, delay, fb, lrcross, panning; REALTYPE dl1, dl2, dr1, dr2, lfol, lfor; int maxdelay; - Stereo<AuSample> delaySample; - //REALTYPE *delayl,*delayr; + Stereo<Sample> delaySample; int dlk, drk, dlhi, dlhi2; REALTYPE getdelay(REALTYPE xlfo); REALTYPE dllo, mdel; diff --git a/src/Effects/Distorsion.cpp b/src/Effects/Distorsion.cpp @@ -260,7 +260,7 @@ void Distorsion::applyfilters(REALTYPE *efxoutl, REALTYPE *efxoutr) /* * Effect output */ -void Distorsion::out(REALTYPE *smpsl, REALTYPE *smpsr) +void Distorsion::out(const Stereo<float *> &smp) { int i; REALTYPE l, r, lout, rout; @@ -271,14 +271,14 @@ void Distorsion::out(REALTYPE *smpsl, REALTYPE *smpsr) if(Pstereo != 0) { //Stereo for(i = 0; i < SOUND_BUFFER_SIZE; i++) { - efxoutl[i] = smpsl[i] * inputvol * panning; - efxoutr[i] = smpsr[i] * inputvol * (1.0 - panning); + efxoutl[i] = smp.l()[i] * inputvol * panning; + efxoutr[i] = smp.r()[i] * inputvol * (1.0 - panning); } } else { for(i = 0; i < SOUND_BUFFER_SIZE; i++) efxoutl[i] = - (smpsl[i] * panning + smpsr[i] * (1.0 - panning)) * inputvol; + (smp.l()[i] * panning + smp.r()[i] * (1.0 - panning)) * inputvol; ; } @@ -315,7 +315,7 @@ void Distorsion::out(REALTYPE *smpsl, REALTYPE *smpsr) /* * Parameter control */ -void Distorsion::setvolume(const unsigned char &Pvolume) +void Distorsion::setvolume(unsigned char Pvolume) { this->Pvolume = Pvolume; @@ -330,20 +330,20 @@ void Distorsion::setvolume(const unsigned char &Pvolume) cleanup(); } -void Distorsion::setpanning(const unsigned char &Ppanning) +void Distorsion::setpanning(unsigned char Ppanning) { this->Ppanning = Ppanning; panning = (Ppanning + 0.5) / 127.0; } -void Distorsion::setlrcross(const unsigned char &Plrcross) +void Distorsion::setlrcross(unsigned char Plrcross) { this->Plrcross = Plrcross; lrcross = Plrcross / 127.0 * 1.0; } -void Distorsion::setlpf(const unsigned char &Plpf) +void Distorsion::setlpf(unsigned char Plpf) { this->Plpf = Plpf; REALTYPE fr = exp(pow(Plpf / 127.0, 0.5) * log(25000.0)) + 40; @@ -351,7 +351,7 @@ void Distorsion::setlpf(const unsigned char &Plpf) lpfr->setfreq(fr); } -void Distorsion::sethpf(const unsigned char &Phpf) +void Distorsion::sethpf(unsigned char Phpf) { this->Phpf = Phpf; REALTYPE fr = exp(pow(Phpf / 127.0, 0.5) * log(25000.0)) + 20.0; @@ -391,7 +391,7 @@ void Distorsion::setpreset(unsigned char npreset) } -void Distorsion::changepar(const int &npar, const unsigned char &value) +void Distorsion::changepar(int npar, unsigned char value) { switch(npar) { case 0: @@ -439,7 +439,7 @@ void Distorsion::changepar(const int &npar, const unsigned char &value) } } -unsigned char Distorsion::getpar(const int &npar) const +unsigned char Distorsion::getpar(int npar) const { switch(npar) { case 0: diff --git a/src/Effects/Distorsion.h b/src/Effects/Distorsion.h @@ -38,32 +38,32 @@ class Distorsion:public Effect public: Distorsion(const int &insertion, REALTYPE *efxoutl_, REALTYPE *efxoutr_); ~Distorsion(); - void out(REALTYPE *smpsl, REALTYPE *smpr); + void out(const Stereo<float *> &smp); void setpreset(unsigned char npreset); - void changepar(const int &npar, const unsigned char &value); - unsigned char getpar(const int &npar) const; + void changepar(int npar, unsigned char value); + unsigned char getpar(int npar) const; void cleanup(); void applyfilters(REALTYPE *efxoutl, REALTYPE *efxoutr); private: //Parametrii - unsigned char Pvolume; //Volumul or E/R - unsigned char Ppanning; //Panning - unsigned char Plrcross; // L/R Mixing - unsigned char Pdrive; //the input amplification - unsigned char Plevel; //the output amplification - unsigned char Ptype; //Distorsion type - unsigned char Pnegate; //if the input is negated - unsigned char Plpf; //lowpass filter - unsigned char Phpf; //highpass filter - unsigned char Pstereo; //0=mono,1=stereo + unsigned char Pvolume; //Volume or E/R + unsigned char Ppanning; //Panning + unsigned char Plrcross; // L/R Mixing + unsigned char Pdrive; //the input amplification + unsigned char Plevel; //the output amplification + unsigned char Ptype; //Distorsion type + unsigned char Pnegate; //if the input is negated + unsigned char Plpf; //lowpass filter + unsigned char Phpf; //highpass filter + unsigned char Pstereo; //0=mono,1=stereo unsigned char Pprefiltering; //if you want to do the filtering before the distorsion - void setvolume(const unsigned char &Pvolume); - void setpanning(const unsigned char &Ppanning); - void setlrcross(const unsigned char &Plrcross); - void setlpf(const unsigned char &Plpf); - void sethpf(const unsigned char &Phpf); + void setvolume(unsigned char Pvolume); + void setpanning(unsigned char Ppanning); + void setlrcross(unsigned char Plrcross); + void setlpf(unsigned char Plpf); + void sethpf(unsigned char Phpf); //Real Parameters REALTYPE panning, lrcross; diff --git a/src/Effects/DynamicFilter.cpp b/src/Effects/DynamicFilter.cpp @@ -46,7 +46,7 @@ DynamicFilter::~DynamicFilter() /* * Apply the effect */ -void DynamicFilter::out(REALTYPE *smpsl, REALTYPE *smpsr) +void DynamicFilter::out(const Stereo<float *> &smp) { int i; if(filterpars->changed) { @@ -62,10 +62,10 @@ void DynamicFilter::out(REALTYPE *smpsl, REALTYPE *smpsr) REALTYPE q = filterpars->getq(); for(i = 0; i < SOUND_BUFFER_SIZE; i++) { - efxoutl[i] = smpsl[i]; - efxoutr[i] = smpsr[i]; + efxoutl[i] = smp.l()[i]; + efxoutr[i] = smp.r()[i]; - REALTYPE x = (fabs(smpsl[i]) + fabs(smpsr[i])) * 0.5; + REALTYPE x = (fabs(smp.l()[i]) + fabs(smp.l()[i])) * 0.5; ms1 = ms1 * (1.0 - ampsmooth) + x * ampsmooth + 1e-10; } @@ -110,14 +110,14 @@ void DynamicFilter::cleanup() * Parameter control */ -void DynamicFilter::setdepth(const unsigned char &Pdepth) +void DynamicFilter::setdepth(unsigned char Pdepth) { this->Pdepth = Pdepth; depth = pow((Pdepth / 127.0), 2.0); } -void DynamicFilter::setvolume(const unsigned char &Pvolume) +void DynamicFilter::setvolume(unsigned char Pvolume) { this->Pvolume = Pvolume; outvolume = Pvolume / 127.0; @@ -127,14 +127,14 @@ void DynamicFilter::setvolume(const unsigned char &Pvolume) volume = outvolume; } -void DynamicFilter::setpanning(const unsigned char &Ppanning) +void DynamicFilter::setpanning(unsigned char Ppanning) { this->Ppanning = Ppanning; panning = Ppanning / 127.0; } -void DynamicFilter::setampsns(const unsigned char &Pampsns) +void DynamicFilter::setampsns(unsigned char Pampsns) { ampsns = pow(Pampsns / 127.0, 2.5) * 10.0; if(Pampsnsinv != 0) @@ -270,7 +270,7 @@ void DynamicFilter::setpreset(unsigned char npreset) } -void DynamicFilter::changepar(const int &npar, const unsigned char &value) +void DynamicFilter::changepar(int npar, unsigned char value) { switch(npar) { case 0: @@ -312,7 +312,7 @@ void DynamicFilter::changepar(const int &npar, const unsigned char &value) } } -unsigned char DynamicFilter::getpar(const int &npar) const +unsigned char DynamicFilter::getpar(int npar) const { switch(npar) { case 0: diff --git a/src/Effects/DynamicFilter.h b/src/Effects/DynamicFilter.h @@ -33,11 +33,11 @@ class DynamicFilter:public Effect public: DynamicFilter(int insetion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_); ~DynamicFilter(); - void out(REALTYPE *smpsl, REALTYPE *smpsr); + void out(const Stereo<float *> &smp); void setpreset(unsigned char npreset); - void changepar(const int &npar, const unsigned char &value); - unsigned char getpar(const int &npar) const; + void changepar(int npar, unsigned char value); + unsigned char getpar(int npar) const; void cleanup(); // void setdryonly(); @@ -53,10 +53,10 @@ class DynamicFilter:public Effect unsigned char Pampsmooth; //how smooth the input amplitude changes the filter //Parameter Control - void setvolume(const unsigned char &Pvolume); - void setpanning(const unsigned char &Ppanning); - void setdepth(const unsigned char &Pdepth); - void setampsns(const unsigned char &Pampsns); + void setvolume(unsigned char Pvolume); + void setpanning(unsigned char Ppanning); + void setdepth(unsigned char Pdepth); + void setampsns(unsigned char Pampsns); void reinitfilter(); diff --git a/src/Effects/EQ.cpp b/src/Effects/EQ.cpp @@ -45,9 +45,6 @@ EQ::EQ(const int &insertion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_) EQ::~EQ() {} -/* - * Cleanup the effect - */ void EQ::cleanup() { for(int i = 0; i < MAX_EQ_BANDS; i++) { @@ -56,17 +53,12 @@ void EQ::cleanup() } } - - -/* - * Effect output - */ -void EQ::out(REALTYPE *smpsl, REALTYPE *smpsr) +void EQ::out(const Stereo<float *> &smp) { int i; for(i = 0; i < SOUND_BUFFER_SIZE; i++) { - efxoutl[i] = smpsl[i] * volume; - efxoutr[i] = smpsr[i] * volume; + efxoutl[i] = smp.l()[i] * volume; + efxoutr[i] = smp.r()[i] * volume; } for(i = 0; i < MAX_EQ_BANDS; i++) { @@ -81,7 +73,7 @@ void EQ::out(REALTYPE *smpsl, REALTYPE *smpsr) /* * Parameter control */ -void EQ::setvolume(const unsigned char &Pvolume) +void EQ::setvolume(unsigned char Pvolume) { this->Pvolume = Pvolume; @@ -113,7 +105,7 @@ void EQ::setpreset(unsigned char npreset) } -void EQ::changepar(const int &npar, const unsigned char &value) +void EQ::changepar(int npar, unsigned char value) { switch(npar) { case 0: @@ -167,7 +159,7 @@ void EQ::changepar(const int &npar, const unsigned char &value) } } -unsigned char EQ::getpar(const int &npar) const +unsigned char EQ::getpar(int npar) const { switch(npar) { case 0: diff --git a/src/Effects/EQ.h b/src/Effects/EQ.h @@ -33,17 +33,17 @@ class EQ:public Effect public: EQ(const int &insertion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_); ~EQ(); - void out(REALTYPE *smpsl, REALTYPE *smpr); + void out(const Stereo<float *> &smp); void setpreset(unsigned char npreset); - void changepar(const int &npar, const unsigned char &value); - unsigned char getpar(const int &npar) const; + void changepar(int npar, unsigned char value); + unsigned char getpar(int npar) const; void cleanup(); REALTYPE getfreqresponse(REALTYPE freq); private: //Parameters unsigned char Pvolume; /**<Volume*/ - void setvolume(const unsigned char &Pvolume); + void setvolume(unsigned char Pvolume); struct { //parameters diff --git a/src/Effects/Echo.cpp b/src/Effects/Echo.cpp @@ -3,7 +3,9 @@ Echo.C - Echo effect Copyright (C) 2002-2005 Nasca Octavian Paul + Copyright (C) 2009-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 @@ -21,95 +23,93 @@ */ #include <cmath> -#include <iostream> #include "Echo.h" +#define MAX_DELAY 2 + Echo::Echo(const int &insertion_, REALTYPE *const efxoutl_, REALTYPE *const efxoutr_) :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0), Pvolume(50), Ppanning(64), //Pdelay(60), Plrdelay(100), Plrcross(100), Pfb(40), Phidamp(60), - lrdelay(0), delaySample(1), old(0.0) + delayTime(1), lrdelay(0), + delay(new REALTYPE[(int)(MAX_DELAY * SAMPLE_RATE)], + new REALTYPE[(int)(MAX_DELAY * SAMPLE_RATE)]), + old(0.0), pos(0), delta(1), ndelta(1) { + initdelays(); setpreset(Ppreset); } -Echo::~Echo() {} +Echo::~Echo() +{ + delete[] delay.l(); + delete[] delay.r(); +} /* * Cleanup the effect */ void Echo::cleanup() { - delaySample.l().clear(); - delaySample.r().clear(); + memset(delay.l(),0,MAX_DELAY*SAMPLE_RATE*sizeof(REALTYPE)); + memset(delay.r(),0,MAX_DELAY*SAMPLE_RATE*sizeof(REALTYPE)); old = Stereo<REALTYPE>(0.0); } +inline int max(int a, int b) +{ + return a > b ? a : b; +} /* * Initialize the delays */ void Echo::initdelays() { - /**\todo make this adjust insted of destroy old delays*/ - kl = 0; - kr = 0; - dl = (int)(1 + delay.getiVal() * SAMPLE_RATE - lrdelay); - if(dl < 1) - dl = 1; - dr = (int)(1 + delay.getiVal() * SAMPLE_RATE + lrdelay); - if(dr < 1) - dr = 1; - - delaySample.l() = AuSample(dl); - delaySample.r() = AuSample(dr); + cleanup(); + //number of seconds to delay left chan + float dl = delayCtl.getiVal() - lrdelay; - old = Stereo<REALTYPE>(0.0); -} + //number of seconds to delay right chan + float dr = delayCtl.getiVal() + lrdelay; -/* - * Effect output - */ -void Echo::out(REALTYPE *const smpsl, REALTYPE *const smpsr) -{ - Stereo<AuSample> input(AuSample(SOUND_BUFFER_SIZE, smpsl), AuSample( - SOUND_BUFFER_SIZE, - smpsr)); - out(input); + ndelta.l() = max(1,(int) (dl * SAMPLE_RATE)); + ndelta.r() = max(1,(int) (dr * SAMPLE_RATE)); } -void Echo::out(const Stereo<AuSample> &input) +void Echo::out(const Stereo<float *> &input) { -//void Echo::out(const Stereo<AuSample> & input){ //ideal - REALTYPE l, r, ldl, rdl; /**\todo move l+r->? ldl+rdl->?*/ + REALTYPE ldl, rdl; - for(int i = 0; i < input.l().size(); i++) { - ldl = delaySample.l()[kl]; - rdl = delaySample.r()[kr]; - l = ldl * (1.0 - lrcross) + rdl * lrcross; - r = rdl * (1.0 - lrcross) + ldl * lrcross; - ldl = l; - rdl = r; + for(int i = 0; i < SOUND_BUFFER_SIZE; ++i) { + ldl = delay.l()[pos.l()]; + rdl = delay.r()[pos.r()]; + ldl = ldl * (1.0 - lrcross) + rdl * lrcross; + rdl = rdl * (1.0 - lrcross) + ldl * lrcross; efxoutl[i] = ldl * 2.0; efxoutr[i] = rdl * 2.0; - ldl = input.l()[i] * panning - ldl * fb; rdl = input.r()[i] * (1.0 - panning) - rdl * fb; //LowPass Filter - delaySample.l()[kl] = ldl = ldl * hidamp + old.l() * (1.0 - hidamp); - delaySample.r()[kr] = rdl = rdl * hidamp + old.r() * (1.0 - hidamp); - old.l() = ldl; - old.r() = rdl; - - if(++kl >= dl) - kl = 0; - if(++kr >= dr) - kr = 0; + old.l() = delay.l()[(pos.l()+delta.l())%(MAX_DELAY * SAMPLE_RATE)] = ldl * hidamp + old.l() * (1.0 - hidamp); + old.r() = delay.r()[(pos.r()+delta.r())%(MAX_DELAY * SAMPLE_RATE)] = rdl * hidamp + old.r() * (1.0 - hidamp); + + //increment + ++pos.l();// += delta.l(); + ++pos.r();// += delta.r(); + + //ensure that pos is still in bounds + pos.l() %= MAX_DELAY * SAMPLE_RATE; + pos.r() %= MAX_DELAY * SAMPLE_RATE; + + //adjust delay if needed + delta.l() = (15*delta.l() + ndelta.l())/16; + delta.r() = (15*delta.r() + ndelta.r())/16; } } @@ -117,7 +117,7 @@ void Echo::out(const Stereo<AuSample> &input) /* * Parameter control */ -void Echo::setvolume(const unsigned char &Pvolume) +void Echo::setvolume(unsigned char Pvolume) { this->Pvolume = Pvolume; @@ -132,45 +132,45 @@ void Echo::setvolume(const unsigned char &Pvolume) cleanup(); } -void Echo::setpanning(const unsigned char &Ppanning) +void Echo::setpanning(unsigned char Ppanning) { this->Ppanning = Ppanning; panning = (Ppanning + 0.5) / 127.0; } -void Echo::setdelay(const unsigned char &Pdelay) +void Echo::setdelay(unsigned char Pdelay) { - delay.setmVal(Pdelay); + delayCtl.setmVal(Pdelay); //this->Pdelay=Pdelay; //delay=1+(int)(Pdelay/127.0*SAMPLE_RATE*1.5);//0 .. 1.5 sec initdelays(); } -void Echo::setlrdelay(const unsigned char &Plrdelay) +void Echo::setlrdelay(unsigned char Plrdelay) { REALTYPE tmp; this->Plrdelay = Plrdelay; tmp = - (pow(2, fabs(Plrdelay - 64.0) / 64.0 * 9) - 1.0) / 1000.0 * SAMPLE_RATE; + (pow(2, fabs(Plrdelay - 64.0) / 64.0 * 9) - 1.0) / 1000.0; if(Plrdelay < 64.0) tmp = -tmp; - lrdelay = (int) tmp; + lrdelay = tmp; initdelays(); } -void Echo::setlrcross(const unsigned char &Plrcross) +void Echo::setlrcross(unsigned char Plrcross) { this->Plrcross = Plrcross; lrcross = Plrcross / 127.0 * 1.0; } -void Echo::setfb(const unsigned char &Pfb) +void Echo::setfb(unsigned char Pfb) { this->Pfb = Pfb; fb = Pfb / 128.0; } -void Echo::sethidamp(const unsigned char &Phidamp) +void Echo::sethidamp(unsigned char Phidamp) { this->Phidamp = Phidamp; hidamp = 1.0 - Phidamp / 127.0; @@ -213,7 +213,7 @@ void Echo::setpreset(unsigned char npreset) } -void Echo::changepar(const int &npar, const unsigned char &value) +void Echo::changepar(int npar, unsigned char value) { switch(npar) { case 0: @@ -240,7 +240,7 @@ void Echo::changepar(const int &npar, const unsigned char &value) } } -unsigned char Echo::getpar(const int &npar) const +unsigned char Echo::getpar(int npar) const { switch(npar) { case 0: @@ -250,7 +250,7 @@ unsigned char Echo::getpar(const int &npar) const return Ppanning; break; case 2: - return delay.getmVal(); + return delayCtl.getmVal(); break; case 3: return Plrdelay; diff --git a/src/Effects/Echo.h b/src/Effects/Echo.h @@ -25,8 +25,8 @@ #include "../globals.h" #include "Effect.h" -#include "../Samples/AuSample.h" #include "../Misc/Stereo.h" +#include "../Samples/Sample.h" #include "../Controls/DelayCtl.h" /**Echo Effect*/ @@ -51,15 +51,7 @@ class Echo:public Effect */ ~Echo(); - /** - * Outputs the echo to efxoutl and efxoutr - * @param smpsl Sample from Left channel - * @param smpsr Sample from Right channel - * \todo try to figure out if smpsl should be const *const - * or not (It should be) - */ - void out(REALTYPE *const smpsl, REALTYPE *const smpr); - void out(const Stereo<AuSample> &input); + void out(const Stereo<float *> &input); /** * Sets the state of Echo to the specified preset @@ -81,7 +73,7 @@ class Echo:public Effect * @param npar number of chosen parameter * @param value the new value */ - void changepar(const int &npar, const unsigned char &value); + void changepar(int npar, unsigned char value); /** * Gets the specified parameter @@ -97,7 +89,7 @@ class Echo:public Effect * @param npar number of chosen parameter * @return value of parameter */ - unsigned char getpar(const int &npar) const; + unsigned char getpar(int npar) const; int getnumparams(); @@ -108,31 +100,38 @@ class Echo:public Effect void setdryonly(); private: //Parameters - char Pvolume; /**<#1 Volume or Dry/Wetness*/ + char Pvolume; /**<#1 Volume or Dry/Wetness*/ char Ppanning; /**<#2 Panning*/ - DelayCtl delay; /**<#3 Delay of the Echo*/ + DelayCtl delayCtl; /**<#3 Delay of the Echo*/ char Plrdelay; /**<#4 L/R delay difference*/ char Plrcross; /**<#5 L/R Mixing*/ - char Pfb; /**<#6Feedback*/ - char Phidamp; /**<#7Dampening of the Echo*/ + char Pfb; /**<#6Feedback*/ + char Phidamp; /**<#7Dampening of the Echo*/ - void setvolume(const unsigned char &Pvolume); - void setpanning(const unsigned char &Ppanning); - void setdelay(const unsigned char &Pdelay); - void setlrdelay(const unsigned char &Plrdelay); - void setlrcross(const unsigned char &Plrcross); - void setfb(const unsigned char &Pfb); - void sethidamp(const unsigned char &Phidamp); + void setvolume(unsigned char Pvolume); + void setpanning(unsigned char Ppanning); + void setdelay(unsigned char Pdelay); + void setlrdelay(unsigned char Plrdelay); + void setlrcross(unsigned char Plrcross); + void setfb(unsigned char Pfb); + void sethidamp(unsigned char Phidamp); //Real Parameters - REALTYPE panning, lrcross, fb, hidamp; //needs better names - int dl, dr, lrdelay; //needs better names + REALTYPE panning, lrcross, fb, hidamp; + //Left/Right delay lengths + Stereo<int> delayTime; + float lrdelay; void initdelays(); - Stereo<AuSample> delaySample; + //2 channel ring buffer + Stereo<REALTYPE *> delay; Stereo<REALTYPE> old; - int kl, kr; + //position of reading/writing from delaysample + Stereo<int> pos; + //step size for delay buffer + Stereo<int> delta; + Stereo<int> ndelta; }; #endif diff --git a/src/Effects/Effect.cpp b/src/Effects/Effect.cpp @@ -23,10 +23,15 @@ #include "Effect.h" #include "../Params/FilterParams.h" - Effect::Effect(bool insertion_, REALTYPE *const efxoutl_, REALTYPE *const efxoutr_, FilterParams *filterpars_, const unsigned char &Ppreset_) :Ppreset(Ppreset_), efxoutl(efxoutl_), efxoutr(efxoutr_), - filterpars(filterpars_), insertion(insertion_) {} + filterpars(filterpars_), insertion(insertion_) +{} + +void Effect::out(REALTYPE *const smpsl, REALTYPE *const smpsr) +{ + out(Stereo<float *>(smpsl,smpsr)); +}; diff --git a/src/Effects/Effect.h b/src/Effects/Effect.h @@ -25,6 +25,8 @@ #include "../Misc/Util.h" #include "../globals.h" +#include "../Params/FilterParams.h" +#include "../Misc/Stereo.h" class FilterParams; @@ -56,12 +58,12 @@ class Effect /**Change parameter npar to value * @param npar chosen parameter * @param value chosen new value*/ - virtual void changepar(const int &npar, const unsigned char &value) = 0; + virtual void changepar(int npar, unsigned char value) = 0; /**Get the value of parameter npar * @param npar chosen parameter * @return the value of the parameter in an unsigned char or 0 if it * does not exist*/ - virtual unsigned char getpar(const int &npar) const = 0; + virtual unsigned char getpar(int npar) const = 0; /**Output result of effect based on the given buffers * * This method should result in the effect generating its results @@ -71,7 +73,8 @@ class Effect * @param smpsl Input buffer for the Left channel * @param smpsr Input buffer for the Right channel */ - virtual void out(REALTYPE *const smpsl, REALTYPE *const smpsr) = 0; + void out(REALTYPE *const smpsl, REALTYPE *const smpsr); + virtual void out(const Stereo<float *> &smp) = 0; /**Reset the state of the effect*/ virtual void cleanup() {} /**This is only used for EQ (for user interface)*/ @@ -82,7 +85,7 @@ class Effect unsigned char Ppreset; /**<Currently used preset*/ REALTYPE *const efxoutl; /**<Effect out Left Channel*/ REALTYPE *const efxoutr; /**<Effect out Right Channel*/ - /**\todo make efxoutl and efxoutr private and replace them with a StereoSample*/ + /**\todo make efxoutl and efxoutr private and replace them with a Stereo<float*>*/ REALTYPE outvolume;/**<This is the volume of effect and is public because * it is needed in system effects. @@ -96,7 +99,7 @@ class Effect protected: const bool insertion;/**<If Effect is an insertion effect, insertion=1 - *otherwise, it should be insertion=0*/ + *otherwise, it should be insertion=0*/ }; #endif diff --git a/src/Effects/EffectMgr.cpp b/src/Effects/EffectMgr.cpp @@ -31,6 +31,9 @@ #include "../Misc/XMLwrapper.h" #include "../Params/FilterParams.h" +#include <iostream> +using namespace std; +>>>>>>> master:src/Effects/EffectMgr.cpp EffectMgr::EffectMgr(int insertion_, pthread_mutex_t *mutex_) :insertion(insertion_), @@ -111,6 +114,9 @@ void EffectMgr::changeeffect(int nefx_) case 8: efx = new DynamicFilter(insertion, efxoutl, efxoutr); break; + case 9: + efx = new Analog_Phaser(insertion, efxoutl, efxoutr); + break; //put more effect here default: efx = NULL; diff --git a/src/Effects/EffectMgr.h b/src/Effects/EffectMgr.h @@ -32,6 +32,14 @@ class Effect; class FilterParams; class XMLwrapper; +#include "Distorsion.h" +#include "EQ.h" +#include "DynamicFilter.h" +#include "APhaser.h" +#include "../Misc/XMLwrapper.h" +#include "../Params/FilterParams.h" +#include "../Params/Presets.h" + /**Effect manager, an interface betwen the program and effects*/ class EffectMgr:public Presets { diff --git a/src/Effects/Makefile b/src/Effects/Makefile @@ -2,7 +2,7 @@ include ../Makefile.inc objects=Alienwah.o Chorus.o Echo.o Effect.o \ EffectLFO.o EffectMgr.o Phaser.o Reverb.o \ - Distorsion.o EQ.o DynamicFilter.o + Distorsion.o EQ.o DynamicFilter.o APhaser.o all: $(objects) diff --git a/src/Effects/Phaser.cpp b/src/Effects/Phaser.cpp @@ -38,7 +38,7 @@ Phaser::~Phaser() /* * Effect output */ -void Phaser::out(REALTYPE *smpsl, REALTYPE *smpsr) +void Phaser::out(const Stereo<float *> &smp) { int i, j; REALTYPE lfol, lfor, lgain, rgain, tmp; @@ -69,8 +69,8 @@ void Phaser::out(REALTYPE *smpsl, REALTYPE *smpsr) REALTYPE x1 = 1.0 - x; REALTYPE gl = lgain * x + oldgain.left() * x1; REALTYPE gr = rgain * x + oldgain.right() * x1; - REALTYPE inl = smpsl[i] * panning + fbl; - REALTYPE inr = smpsr[i] * (1.0 - panning) + fbr; + REALTYPE inl = smp.l()[i] * panning + fbl; + REALTYPE inr = smp.r()[i] * (1.0 - panning) + fbr; //Left channel for(j = 0; j < Pstages * 2; j++) { //Phasing routine @@ -121,20 +121,20 @@ void Phaser::cleanup() /* * Parameter control */ -void Phaser::setdepth(const unsigned char &Pdepth) +void Phaser::setdepth(unsigned char Pdepth) { this->Pdepth = Pdepth; depth = (Pdepth / 127.0); } -void Phaser::setfb(const unsigned char &Pfb) +void Phaser::setfb(unsigned char Pfb) { this->Pfb = Pfb; fb = (Pfb - 64.0) / 64.1; } -void Phaser::setvolume(const unsigned char &Pvolume) +void Phaser::setvolume(unsigned char Pvolume) { this->Pvolume = Pvolume; outvolume = Pvolume / 127.0; @@ -144,29 +144,29 @@ void Phaser::setvolume(const unsigned char &Pvolume) volume = outvolume; } -void Phaser::setpanning(const unsigned char &Ppanning) +void Phaser::setpanning(unsigned char Ppanning) { this->Ppanning = Ppanning; panning = Ppanning / 127.0; } -void Phaser::setlrcross(const unsigned char &Plrcross) +void Phaser::setlrcross(unsigned char Plrcross) { this->Plrcross = Plrcross; lrcross = Plrcross / 127.0; } -void Phaser::setstages(const unsigned char &Pstages) +void Phaser::setstages(unsigned char Pstages) { if(Pstages >= MAX_PHASER_STAGES) this->Pstages = MAX_PHASER_STAGES - 1; else this->Pstages = Pstages; - old = Stereo<AuSample>(Pstages * 2); + old = Stereo<Sample>(Pstages * 2); cleanup(); } -void Phaser::setphase(const unsigned char &Pphase) +void Phaser::setphase(unsigned char Pphase) { this->Pphase = Pphase; phase = (Pphase / 127.0); @@ -199,7 +199,7 @@ void Phaser::setpreset(unsigned char npreset) } -void Phaser::changepar(const int &npar, const unsigned char &value) +void Phaser::changepar(int npar, unsigned char value) { switch(npar) { case 0: @@ -248,7 +248,7 @@ void Phaser::changepar(const int &npar, const unsigned char &value) } } -unsigned char Phaser::getpar(const int &npar) const +unsigned char Phaser::getpar(int npar) const { switch(npar) { case 0: diff --git a/src/Effects/Phaser.h b/src/Effects/Phaser.h @@ -24,7 +24,7 @@ #define PHASER_H #include "../globals.h" #include "../Misc/Stereo.h" -#include "../Samples/AuSample.h" +#include "../Samples/Sample.h" #include "Effect.h" #include "EffectLFO.h" @@ -35,10 +35,10 @@ class Phaser:public Effect public: Phaser(const int &insetion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_); ~Phaser(); - void out(REALTYPE *smpsl, REALTYPE *smpsr); + void out(const Stereo<float *> &smp); void setpreset(unsigned char npreset); - void changepar(const int &npar, const unsigned char &value); - unsigned char getpar(const int &npar) const; + void changepar(int npar, unsigned char value); + unsigned char getpar(int npar) const; void cleanup(); void setdryonly(); @@ -49,26 +49,23 @@ class Phaser:public Effect unsigned char Ppanning; unsigned char Pdepth; /**<the depth of the Phaser*/ unsigned char Pfb; /**<feedback*/ - unsigned char Plrcross; /**<feedback*/ + unsigned char Plrcross; /**<crossover*/ unsigned char Pstages; unsigned char Poutsub; /**<if I wish to substract the output instead of the adding it*/ unsigned char Pphase; - //Control Parametrii - void setvolume(const unsigned char &Pvolume); - void setpanning(const unsigned char &Ppanning); - void setdepth(const unsigned char &Pdepth); - void setfb(const unsigned char &Pfb); - void setlrcross(const unsigned char &Plrcross); - void setstages(const unsigned char &Pstages); - void setphase(const unsigned char &Pphase); + //Control Parameters + void setvolume(unsigned char Pvolume); + void setpanning(unsigned char Ppanning); + void setdepth(unsigned char Pdepth); + void setfb(unsigned char Pfb); + void setlrcross(unsigned char Plrcross); + void setstages(unsigned char Pstages); + void setphase(unsigned char Pphase); //Internal Values - //int insertion; //inherited from Effect REALTYPE panning, fb, depth, lrcross, fbl, fbr, phase; - //REALTYPE *oldl,*oldr; - Stereo<AuSample> old; - //REALTYPE oldlgain,oldrgain; + Stereo<Sample> old; Stereo<REALTYPE> oldgain; }; diff --git a/src/Effects/Reverb.cpp b/src/Effects/Reverb.cpp @@ -165,14 +165,14 @@ void Reverb::processmono(int ch, REALTYPE *output) /* * Effect output */ -void Reverb::out(REALTYPE *smps_l, REALTYPE *smps_r) +void Reverb::out(const Stereo<float *> &smp) { int i; if((Pvolume == 0) && (insertion != 0)) return; for(i = 0; i < SOUND_BUFFER_SIZE; i++) - inputbuf[i] = (smps_l[i] + smps_r[i]) / 2.0; + inputbuf[i] = (smp.l()[i] + smp.r()[i]) / 2.0; ; if(idelay != NULL) { @@ -215,7 +215,7 @@ void Reverb::out(REALTYPE *smps_l, REALTYPE *smps_r) /* * Parameter control */ -void Reverb::setvolume(const unsigned char &Pvolume) +void Reverb::setvolume(unsigned char Pvolume) { this->Pvolume = Pvolume; if(insertion == 0) { @@ -229,13 +229,13 @@ void Reverb::setvolume(const unsigned char &Pvolume) } } -void Reverb::setpan(const unsigned char &Ppan) +void Reverb::setpan(unsigned char Ppan) { this->Ppan = Ppan; pan = (REALTYPE)Ppan / 127.0; } -void Reverb::settime(const unsigned char &Ptime) +void Reverb::settime(unsigned char Ptime) { int i; REALTYPE t; @@ -271,7 +271,7 @@ void Reverb::setlohidamp(unsigned char Plohidamp) } } -void Reverb::setidelay(const unsigned char &Pidelay) +void Reverb::setidelay(unsigned char Pidelay) { REALTYPE delay; this->Pidelay = Pidelay; @@ -290,13 +290,13 @@ void Reverb::setidelay(const unsigned char &Pidelay) } } -void Reverb::setidelayfb(const unsigned char &Pidelayfb) +void Reverb::setidelayfb(unsigned char Pidelayfb) { this->Pidelayfb = Pidelayfb; idelayfb = Pidelayfb / 128.0; } -void Reverb::sethpf(const unsigned char &Phpf) +void Reverb::sethpf(unsigned char Phpf) { this->Phpf = Phpf; if(Phpf == 0) { //No HighPass @@ -313,7 +313,7 @@ void Reverb::sethpf(const unsigned char &Phpf) } } -void Reverb::setlpf(const unsigned char &Plpf) +void Reverb::setlpf(unsigned char Plpf) { this->Plpf = Plpf; if(Plpf == 127) { //No LowPass @@ -405,7 +405,7 @@ void Reverb::settype(unsigned char Ptype) } } -void Reverb::setroomsize(const unsigned char &Proomsize) +void Reverb::setroomsize(unsigned char Proomsize) { this->Proomsize = Proomsize; if(Proomsize == 0) @@ -418,7 +418,7 @@ void Reverb::setroomsize(const unsigned char &Proomsize) settype(Ptype); } -void Reverb::setbandwidth(const unsigned char &Pbandwidth) { +void Reverb::setbandwidth(unsigned char Pbandwidth) { this->Pbandwidth = Pbandwidth; REALTYPE v = Pbandwidth / 127.0; if(bandwidth) @@ -468,7 +468,7 @@ void Reverb::setpreset(unsigned char npreset) } -void Reverb::changepar(const int &npar, const unsigned char &value) +void Reverb::changepar(int npar, unsigned char value) { switch(npar) { case 0: @@ -511,7 +511,7 @@ void Reverb::changepar(const int &npar, const unsigned char &value) } } -unsigned char Reverb::getpar(const int &npar) const +unsigned char Reverb::getpar(int npar) const { switch(npar) { case 0: diff --git a/src/Effects/Reverb.h b/src/Effects/Reverb.h @@ -40,12 +40,12 @@ class Reverb:public Effect public: Reverb(const int &insertion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_); ~Reverb(); - void out(REALTYPE *smps_l, REALTYPE *smps_r); + void out(const Stereo<float *> &smp); void cleanup(); void setpreset(unsigned char npreset); - void changepar(const int &npar, const unsigned char &value); - unsigned char getpar(const int &npar) const; + void changepar(int npar, unsigned char value); + unsigned char getpar(int npar) const; private: //Parametrii @@ -90,17 +90,17 @@ class Reverb:public Effect unsigned char Pbandwidth; //parameter control - void setvolume(const unsigned char &Pvolume); - void setpan(const unsigned char &Ppan); - void settime(const unsigned char &Ptime); + void setvolume(unsigned char Pvolume); + void setpan(unsigned char Ppan); + void settime(unsigned char Ptime); void setlohidamp(unsigned char Plohidamp); - void setidelay(const unsigned char &Pidelay); - void setidelayfb(const unsigned char &Pidelayfb); - void sethpf(const unsigned char &Phpf); - void setlpf(const unsigned char &Plpf); + void setidelay(unsigned char Pidelay); + void setidelayfb(unsigned char Pidelayfb); + void sethpf(unsigned char Phpf); + void setlpf(unsigned char Plpf); void settype(unsigned char Ptype); - void setroomsize(const unsigned char &Proomsize); - void setbandwidth(const unsigned char &Pbandwidth); + void setroomsize(unsigned char Proomsize); + void setbandwidth(unsigned char Pbandwidth); REALTYPE pan, erbalance; //Parameters diff --git a/src/Makefile b/src/Makefile @@ -1,9 +1,9 @@ include Makefile.inc ifneq ($(MAKECMDGOALS),debug) - CXXFLAGS= -O2 -Wall -g + CXXFLAGS= -O2 -Wall -g -fPIC else - CXXFLAGS= -O2 -Wall -Wpointer-arith + CXXFLAGS= -O2 -Wall -Wpointer-arith -fPIC endif CXXFLAGS += -DOS_$(OS_PORT) -D$(MIDIIN)MIDIIN -DFFTW_VERSION_$(FFTW_VERSION) -DASM_F2I_$(ASM_F2I) -ggdb diff --git a/src/Makefile.inc b/src/Makefile.inc @@ -68,6 +68,7 @@ ifeq ($(OS_PORT),LINUX) AUDIOOUT=$(LINUX_AUDIOOUT) WINDOWS_VST=NO ifeq ($(LINUX_DSSI),YES) + DISABLE_GUI=YES MIDIIN=DSSI AUDIOOUT=DSSI endif diff --git a/src/Misc/Bank.cpp b/src/Misc/Bank.cpp @@ -26,7 +26,9 @@ #include <stdlib.h> #include <dirent.h> #include <sys/stat.h> +#include <algorithm> +#include <pthread.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> @@ -34,6 +36,8 @@ #include "Config.h" +using namespace std; + #define INSTRUMENT_EXTENSION ".xiz" //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 @@ -237,16 +241,21 @@ void Bank::savetoslot(unsigned int ninstrument, Part *part) /* * Loads the instrument from the bank */ -void Bank::loadfromslot(unsigned int ninstrument, Part *part) +void Bank::loadfromslot(unsigned int ninstrument, Part *&part) { if(emptyslot(ninstrument)) return; - part->defaultsinstrument(); - -// printf("load: %s\n",ins[ninstrument].filename); + Part *p = new Part(part->getMicrotonal(), part->getFFT(), part->mutex); + p->loadXMLinstrument(ins[ninstrument].filename); + p->Penabled = true; + p->applyparameters(); - part->loadXMLinstrument(ins[ninstrument].filename); + //swap pointers to greatly reduce locked time + pthread_mutex_lock(part->mutex); + swap(part,p); + delete p; + pthread_mutex_unlock(part->mutex); } diff --git a/src/Misc/Bank.h b/src/Misc/Bank.h @@ -57,7 +57,7 @@ class Bank /**Saves the given Part to slot*/ void savetoslot(unsigned int ninstrument, Part *part); /**Loads the given slot into a Part*/ - void loadfromslot(unsigned int ninstrument, Part *part); + void loadfromslot(unsigned int ninstrument, Part *&part); /**Swaps Slots*/ void swapslot(unsigned int n1, unsigned int n2); diff --git a/src/Misc/CMakeLists.txt b/src/Misc/CMakeLists.txt @@ -13,6 +13,10 @@ set(zynaddsubfx_misc_SRCS WavFile.cpp ) +if (LASH_FOUND) + set(zynaddsubfx_misc_SRCS ${zynaddsubfx_misc_SRCS} LASHClient.cpp) +endif() + add_library(zynaddsubfx_misc STATIC ${zynaddsubfx_misc_SRCS} ) diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -21,6 +21,8 @@ */ +#warning TODO move Sequencer out of master + #include "Master.h" #include "../Params/LFOParams.h" diff --git a/src/Misc/Master.h b/src/Misc/Master.h @@ -148,7 +148,6 @@ class Master int swaplr; //1 if L and R are swapped //Sequencer -#warning TODO move Sequencer out of master Sequencer seq; //other objects diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -178,7 +178,11 @@ void Part::cleanup() Part::~Part() { - cleanup(); + for(int k = 0; k < POLIPHONY; k++) + KillNotePos(k); + for(int nefx = 0; nefx < NUM_PART_EFX; nefx++) + partefx[nefx]->cleanup(); + for(int n = 0; n < NUM_KIT_ITEMS; n++) { if(kit[n].adpars != NULL) delete (kit[n].adpars); diff --git a/src/Misc/Part.h b/src/Misc/Part.h @@ -106,6 +106,9 @@ class Part void setkeylimit(unsigned char Pkeylimit); void setkititemstatus(int kititem, int Penabled_); + Microtonal *getMicrotonal(){return microtonal;}; + FFTwrapper *getFFT(){return fft;}; + unsigned char Penabled; /**<if the part is enabled*/ unsigned char Pvolume; /**<part volume*/ unsigned char Pminkey; /**<the minimum key that the part receives noteon messages*/ diff --git a/src/Nio/AlsaEngine.cpp b/src/Nio/AlsaEngine.cpp @@ -287,10 +287,14 @@ bool AlsaEngine::openAudio() snd_pcm_hw_params_set_rate_near(audio.handle, audio.params, &audio.sampleRate, NULL); - audio.frames = 32; + audio.frames = 512; snd_pcm_hw_params_set_period_size_near(audio.handle, audio.params, &audio.frames, NULL); + audio.periods = 4; + snd_pcm_hw_params_set_periods_near(audio.handle, + audio.params, &audio.periods, NULL); + /* Write the parameters to the driver */ rc = snd_pcm_hw_params(audio.handle, audio.params); if (rc < 0) { diff --git a/src/Nio/AlsaEngine.h b/src/Nio/AlsaEngine.h @@ -71,6 +71,7 @@ class AlsaEngine : public AudioOut, MidiIn snd_pcm_hw_params_t *params; unsigned int sampleRate; snd_pcm_uframes_t frames; + unsigned int periods; const short *buffer; pthread_t pThread; } audio; diff --git a/src/Nio/JackEngine.cpp b/src/Nio/JackEngine.cpp @@ -268,7 +268,7 @@ bool JackEngine::processAudio(jack_nframes_t nframes) } -int JackEngine::_xrunCallback(void *arg) +int JackEngine::_xrunCallback(void * /*/arg*/) { cerr << "Jack reports xrun" << endl; return 0; @@ -304,7 +304,7 @@ void JackEngine::handleMidi(unsigned long frames) jack_midi_event_t jack_midi_event; jack_nframes_t event_index = 0; unsigned char *midi_data; - unsigned char type, chan; + unsigned char type; while(jack_midi_event_get(&jack_midi_event, midi_buf, event_index++) == 0) { diff --git a/src/Nio/OssEngine.cpp b/src/Nio/OssEngine.cpp @@ -98,7 +98,7 @@ void OssEngine::stopAudio() return; audio.handle = -1; - if(!getMidiEn()) + if(!getMidiEn() && engThread) pthread_join(*engThread, NULL); delete engThread; engThread = NULL; @@ -187,7 +187,7 @@ void OssEngine::stopMidi() midi.handle = -1; - if(!getAudioEn()) { + if(!getAudioEn() && engThread) { pthread_join(*engThread, NULL); delete engThread; engThread = NULL; diff --git a/src/Nio/OutMgr.cpp b/src/Nio/OutMgr.cpp @@ -143,6 +143,7 @@ string OutMgr::getSink() const cerr << "BUG: No current output in OutMgr " << __LINE__ << endl; return "ERROR"; } + return "ERROR"; } void OutMgr::addSmps(REALTYPE *l, REALTYPE *r) diff --git a/src/Nio/WavEngine.h b/src/Nio/WavEngine.h @@ -38,8 +38,8 @@ class WavEngine: public AudioOut bool Start(); void Stop(); - void setAudioEn(bool nval){}; - bool getAudioEn() const{}; + void setAudioEn(bool /*nval*/){}; + bool getAudioEn() const{return true;}; protected: void *AudioThread(); diff --git a/src/Output/DSSIaudiooutput.cpp b/src/Output/DSSIaudiooutput.cpp @@ -20,268 +20,666 @@ */ +/* + * Inital working DSSI output code contributed by Stephen G. Parry + */ + //this file contains code used from trivial_synth.c from -//the DSSI (published by Steve Harris under public domain) as a template -//the code is incomplete +//the DSSI (published by Steve Harris under public domain) as a template. + #include <string.h> #include "DSSIaudiooutput.h" +#include "../Misc/Config.h" +#include "../Misc/Bank.h" +#include <limits.h> + +// +// Static stubs for LADSPA member functions +// +// LADSPA is essentially a C handle based API; This plug-in implementation is +// a C++ OO one so we need stub functions to map from C API calls to C++ object +// method calls. +void DSSIaudiooutput::stub_connectPort(LADSPA_Handle instance, unsigned long port, LADSPA_Data * data) +{ + getInstance(instance)->connectPort(port, data); +} -static LADSPA_Descriptor *tsLDescriptor = NULL; -static DSSI_Descriptor *tsDDescriptor = NULL; - -typedef struct { - LADSPA_Data *outl; - LADSPA_Data *outr; -// note_data data[MIDI_NOTES]; -// float omega[MIDI_NOTES]; -} TS; +void DSSIaudiooutput::stub_activate(LADSPA_Handle instance) +{ + getInstance(instance)->activate(); +} +void DSSIaudiooutput::stub_run(LADSPA_Handle instance, unsigned long sample_count) +{ + getInstance(instance)->run(sample_count); +} -static void cleanupTS(LADSPA_Handle instance) +void DSSIaudiooutput::stub_deactivate(LADSPA_Handle instance) { - free(instance); + getInstance(instance)->deactivate(); } -static void connectPortTS(LADSPA_Handle instance, unsigned long port, - LADSPA_Data *data) + + +void DSSIaudiooutput::stub_cleanup(LADSPA_Handle instance) { - TS *plugin; - plugin = (TS *) instance; - switch(port) { - case 0: - plugin->outl = data; - break; - case 1: - plugin->outr = data; - break; - } + DSSIaudiooutput* plugin_instance = getInstance(instance); + plugin_instance->cleanup(); + delete plugin_instance; } + const LADSPA_Descriptor *ladspa_descriptor(unsigned long index) { - switch(index) { - case 0: - return tsLDescriptor; - default: + return DSSIaudiooutput::getLadspaDescriptor(index); +} + +// +// Static stubs for DSSI member functions +// +// DSSI is essentially a C handle based API; This plug-in implementation is +// a C++ OO one so we need stub functions to map from C API calls to C++ object +// method calls. +const DSSI_Program_Descriptor* DSSIaudiooutput::stub_getProgram (LADSPA_Handle instance, unsigned long index) +{ + return getInstance(instance)->getProgram(index); +} + +void DSSIaudiooutput::stub_selectProgram(LADSPA_Handle instance, unsigned long bank, unsigned long program) +{ + getInstance(instance)->selectProgram(bank, program); +} + +int DSSIaudiooutput::stub_getMidiControllerForPort(LADSPA_Handle instance, unsigned long port) +{ + return getInstance(instance)->getMidiControllerForPort(port); +} + +void DSSIaudiooutput::stub_runSynth(LADSPA_Handle instance, unsigned long sample_count, + snd_seq_event_t *events, unsigned long event_count) +{ + getInstance(instance)->runSynth(sample_count, events, event_count); +} + +const DSSI_Descriptor *dssi_descriptor(unsigned long index) +{ + return DSSIaudiooutput::getDssiDescriptor(index); +} + +// +// LADSPA member functions +// + +/** + * Instantiates a plug-in. + * + * This LADSPA member function instantiates a plug-in. + * Note that instance initialisation should generally occur in + * activate() rather than here. + * + * Zyn Implementation + * ------------------ + * This implementation creates a C++ class object and hides its pointer + * in the handle by type casting. + * + * @param descriptor [in] the descriptor for this plug-in + * @param s_rate [in] the sample rate + * @return the plug-in instance handle if successful else NULL + */ +LADSPA_Handle DSSIaudiooutput::instantiate(const LADSPA_Descriptor * descriptor, unsigned long s_rate) +{ + if(descriptor->UniqueID == dssiDescriptor->LADSPA_Plugin->UniqueID) + { + return (LADSPA_Handle)(new DSSIaudiooutput(s_rate)); + } + else + { return NULL; } } -const DSSI_Descriptor *dssi_descriptor(unsigned long index) +/** + * Connects a port on an instantiated plug-in. + * + * This LADSPA member function connects a port on an instantiated plug-in to a + * memory location at which a block of data for the port will be read/written. + * The data location is expected to be an array of LADSPA_Data for audio ports + * or a single LADSPA_Data value for control ports. Memory issues will be + * managed by the host. The plug-in must read/write the data at these locations + * every time run() or run_adding() is called and the data present at the time + * of this connection call should not be considered meaningful. + * + * Zyn Implementation + * ------------------ + * The buffer pointers are stored as member variables + * + * @param port [in] the port to be connected + * @param data [in] the data buffer to write to / read from + */ +void DSSIaudiooutput::connectPort(unsigned long port, LADSPA_Data * data) { -// FILE *a=fopen("/tmp/zzzzz11z","w"); -// fprintf(a,"aaaaaaaaaaa TEST\n"); -// fclose(a); - switch(index) { + switch (port) { case 0: - return tsDDescriptor; - default: - return NULL; + outl = data; + break; + case 1: + outr = data; + break; } } -static LADSPA_Handle instantiateTS(const LADSPA_Descriptor *descriptor, - unsigned long s_rate) +/** + * Initialises a plug-in instance and activates it for use. + * + * This LADSPA member function initialises a plug-in instance and activates it + * for use. This is separated from instantiate() to aid real-time support and + * so that hosts can reinitialise a plug-in instance by calling deactivate() and + * then activate(). In this case the plug-in instance must reset all state + * information dependent on the history of the plug-in instance except for any + * data locations provided by connect_port() and any gain set by + * set_run_adding_gain(). + * + * Zyn Implementation + * ------------------ + * Currently this does nothing; Care must be taken as to code placed here as + * too much code here seems to cause time-out problems in jack-dssi-host. +*/ +void DSSIaudiooutput::activate() { - TS *plugin_data = (TS *) malloc(sizeof(TS)); - /* for (i=0; i<MIDI_NOTES; i++) { - plugin_data->omega[i] = M_PI * 2.0 / (double)s_rate * - pow(2.0, (i-69.0) / 12.0); - } - */ - return (LADSPA_Handle) plugin_data; } -static void activateTS(LADSPA_Handle instance) +/** + * Runs an instance of a plug-in for a block. + * + * This LADSPA member function runs an instance of a plug-in for a block. + * Note that if an activate() function exists then it must be called before + * run() or run_adding(). If deactivate() is called for a plug-in instance then + * the plug-in instance may not be reused until activate() has been called again. + * + * Zyn Implementation + * ------------------ + * This is a LADSPA function that does not process any MIDI events; it is hence + * implemented by simply calling runSynth() with an empty event list. + * + * @param sample_count [in] the block size (in samples) for which the plug-in instance may run + */ +void DSSIaudiooutput::run(unsigned long sample_count) +{ + runSynth(sample_count,NULL,(unsigned long)0); +} + +/** + * Counterpart to activate(). + * + * This LADSPA member function is the counterpart to activate() (see above). + * Deactivation is not similar to pausing as the plug-in instance will be + * reinitialised when activate() is called to reuse it. + * + * Zyn Implementation + * ------------------ + * Currently this function does nothing. + */ +void DSSIaudiooutput::deactivate() { - TS *plugin_data = (TS *) instance; -// for (i=0; i<MIDI_NOTES; i++) { -// plugin_data->data[i].active = 0; -// } } +/** + * Deletes a plug-in instance that is no longer required. + * + * LADSPA member function; once an instance of a plug-in has been finished with + * it can be deleted using this function. The instance handle ceases to be + * valid after this call. + * + * If activate() was called for a plug-in instance then a corresponding call to + * deactivate() must be made before cleanup() is called. + * + * Zyn Implementation + * ------------------ + * Currently cleanup is deferred to the destructor that is invoked after cleanup() + */ +void DSSIaudiooutput::cleanup() +{ +} + +/** + * Initial entry point for the LADSPA plug-in library. + * + * This LADSPA function is the initial entry point for the plug-in library. + * The LADSPA host looks for this entry point in each shared library object it + * finds and then calls the function to enumerate the plug-ins within the + * library. + * + * Zyn Implementation + * ------------------ + * As the Zyn plug-in is a DSSI plug-in, the LADSPA descriptor is embedded inside + * the DSSI descriptor, which is created by DSSIaudiooutput::initDssiDescriptor() + * statically when the library is loaded. This function then merely returns a pointer + * to that embedded descriptor. + * + * @param index [in] the index number of the plug-in within the library. + * @return if index is in range, a pointer to the plug-in descriptor is returned, else NULL + */ +const LADSPA_Descriptor* DSSIaudiooutput::getLadspaDescriptor(unsigned long index) +{ + if(index > 0 || dssiDescriptor == NULL) + return NULL; + else + return dssiDescriptor->LADSPA_Plugin; +} -static void runTS(LADSPA_Handle instance, unsigned long sample_count, - snd_seq_event_t *events, unsigned long event_count) +// +// DSSI member functions +// + +/** + * Provides a description of a program available on this synth. + * + * This DSSI member function pointer provides a description of a program (named + * preset sound) available on this synth. + * + * Zyn Implementation + * ------------------ + * The instruments in all Zyn's bank directories, as shown by the `instrument + * -> show instrument bank` command, are enumerated to the host by this + * function, allowing access to all those instruments. + * The first time an instrument is requested, the bank it is in and any + * unmapped ones preceding that are mapped; all the instruments names and + * filenames from those banks are stored in the programMap member variable for + * later use. This is done on demand in this way, rather than up front in one + * go because loading all the instrument names in one go can lead to timeouts + * and zombies. + * + * @param index [in] index into the plug-in's list of + * programs, not a program number as represented by the Program + * field of the DSSI_Program_Descriptor. (This distinction is + * needed to support synths that use non-contiguous program or + * bank numbers.) + * @return a DSSI_Program_Descriptor pointer that is + * guaranteed to be valid only until the next call to get_program, + * deactivate, or configure, on the same plug-in instance, or NULL if index is out of range. + */ +const DSSI_Program_Descriptor* DSSIaudiooutput::getProgram (unsigned long index) { - TS *plugin_data = (TS *) instance; -// LADSPA_Data *const output = plugin_data->output; -// LADSPA_Data freq = *(plugin_data->freq); -// LADSPA_Data vol = *(plugin_data->vol); -// note_data *data = plugin_data->data; - unsigned long pos; - unsigned long event_pos; - unsigned long note; - - /* if (freq < 1.0) { - freq = 440.0f; - } - if (vol < 0.000001) { - vol = 1.0f; - } + static DSSI_Program_Descriptor retVal; - if (event_count > 0) { - printf("trivial_synth: have %ld events\n", event_count); - } + /* Make sure we have the list of banks loaded */ + initBanks(); + + /* Make sure that the bank containing the instrument has been mapped */ + while (index >= programMap.size() && mapNextBank()) + /* DO NOTHING MORE */; - for (pos = 0, event_pos = 0; pos < sample_count; pos++) { + if(index >= programMap.size()) + { + /* No more instruments */ + return NULL; + } + else + { + /* OK, return the instrument */ + retVal.Name = programMap[index].name.c_str(); + retVal.Program = programMap[index].program; + retVal.Bank = programMap[index].bank; + return &retVal; + } +} - while (event_pos < event_count - && pos == events[event_pos].time.tick) { +/** + * Selects a new program for this synth. + * + * This DSSI member function selects a new program for this synth. The program + * change will take effect immediately at the start of the next run_synth() + * call. An invalid bank / instrument combination is ignored. + * + * Zyn Implementation + * ------------------ + * the banks and instruments are as shown in the `instrument -> show instrument + * bank` command in Zyn. The bank no is a 1-based index into the list of banks + * Zyn loads and shows in the drop down and the program number is the + * instrument within that bank. + * + * @param bank [in] the bank number to select + * @param program [in] the program number within the bank to select + */ +void DSSIaudiooutput::selectProgram(unsigned long bank, unsigned long program) +{ + initBanks(); +// cerr << "selectProgram(" << (bank & 0x7F) << ':' << ((bank >> 7) & 0x7F) << "," << program << ")" << '\n'; + if(bank < MAX_NUM_BANKS && program < BANK_SIZE) + { + char* bankdir = master->bank.banks[ bank ].dir; + if(bankdir != NULL) + { + pthread_mutex_lock(&master->mutex); + + /* We have to turn off the CheckPADsynth functionality, else + * the program change takes way too long and we get timeouts + * and hence zombies (!) */ + int save = config.cfg.CheckPADsynth; + config.cfg.CheckPADsynth = 0; + + /* Load the bank... */ + master->bank.loadbank(bankdir); + + /* restore the CheckPADsynth flag */ + config.cfg.CheckPADsynth = save; + + /* Now load the instrument... */ + master->bank.loadfromslot((unsigned int)program, master->part[0]); + + pthread_mutex_unlock(&master->mutex); + } + } +} - printf("trivial_synth: event type %d\n", events[event_pos].type); +/** + * Returns the MIDI controller number or NRPN for a input control port + * + * This DSSI member function returns the MIDI controller number or NRPN that + * should be mapped to the given input control port. If the given port should + * not have any MIDI controller mapped to it, the function will return DSSI_NONE. + * The behaviour of this function is undefined if the given port + * number does not correspond to an input control port. + * + * Zyn Implementation + * ------------------ + * Currently Zyn does not define any controller ports, but may do in the future. + * + * @param port [in] the input controller port + * @return the CC and NRPN values shifted and ORed together. + */ +int DSSIaudiooutput::getMidiControllerForPort(unsigned long port) +{ + return DSSI_NONE; +} - if (events[event_pos].type == SND_SEQ_EVENT_NOTEON) { - data[events[event_pos].data.note.note].amp = - events[event_pos].data.note.velocity / 512.0f; - data[events[event_pos].data.note.note]. - active = events[event_pos].data.note.velocity > 0; - data[events[event_pos].data.note.note]. - phase = 0.0; - } else if (events[event_pos].type == SND_SEQ_EVENT_NOTEOFF) { - data[events[event_pos].data.note.note]. - active = 0; - } - event_pos++; +/** + * Runs the synth for a block. + * + * This DSSI member function runs the synth for a block. This is identical in + * function to the LADSPA run() function, except that it also supplies events + * to the synth. + * + * Zyn Implementation + * ------------------ + * Zyn implements synthesis in Master::GetAudioOutSamples; runSynth calls this + * function in chunks delimited by the sample_count and the frame indexes in + * the events block, calling the appropriate NoteOn, NoteOff and SetController + * members of Master to process the events supplied between each chunk. + * + * @param sample_count [in] the block size (in samples) for which the synth + * instance may run. + * @param events [in] The Events pointer points to a block of ALSA + * sequencer events, used to communicate MIDI and related events to the synth. + * Each event must be timestamped relative to the start of the block, + * (mis)using the ALSA "tick time" field as a frame count. The host is + * responsible for ensuring that events with differing timestamps are already + * ordered by time. Must not include NOTE (only NOTE_ON / NOTE_OFF), LSB or MSB + * events. + * @param event_count [in] the number of entries in the `events` block + */ +void DSSIaudiooutput::runSynth(unsigned long sample_count, snd_seq_event_t *events, unsigned long event_count) +{ + unsigned long from_frame = 0; + unsigned long event_index = 0; + unsigned long next_event_frame = 0; + unsigned long to_frame = 0; + pthread_mutex_lock(&master->mutex); + + do { + /* Find the time of the next event, if any */ + if(events == NULL || event_index >= event_count) + next_event_frame = ULONG_MAX; + else + next_event_frame = events[event_index].time.tick; + + /* find the end of the sub-sample to be processed this time round... */ + /* if the next event falls within the desired sample interval... */ + if(next_event_frame < sample_count && next_event_frame >= to_frame) + /* set the end to be at that event */ + to_frame = next_event_frame; + else + /* ...else go for the whole remaining sample */ + to_frame = sample_count; + if(from_frame<to_frame) + { + // call master to fill from `from_frame` to `to_frame`: + master->GetAudioOutSamples(to_frame - from_frame, (int)sampleRate, &(outl[from_frame]), &(outr[from_frame])); + // next sub-sample please... + from_frame = to_frame; } - output[pos] = 0.0f; - for (note = 0; note < MIDI_NOTES; note++) { - if (data[note].active) { - output[pos] += sin(data[note].phase) * data[note].amp * vol; - data[note].phase += plugin_data->omega[note] * freq; - if (data[note].phase > M_PI * 2.0) { - data[note].phase -= M_PI * 2.0; + // Now process any event(s) at the current timing point + while(events != NULL && event_index < event_count && events[event_index].time.tick == to_frame) + { + if(events[event_index].type == SND_SEQ_EVENT_NOTEON) + { + master->NoteOn(events[event_index].data.note.channel, events[event_index].data.note.note, events[event_index].data.note.velocity); } + else if(events[event_index].type == SND_SEQ_EVENT_NOTEOFF) + { + master->NoteOff(events[event_index].data.note.channel, events[event_index].data.note.note); } + else if(events[event_index].type == SND_SEQ_EVENT_CONTROLLER) + { + master->SetController(events[event_index].data.control.channel, events[event_index].data.control.param, events[event_index].data.control.value); + } + else + { + } + event_index++; } - } - */ -} + // Keep going until we have the desired total length of sample... + } while(to_frame < sample_count); -static void runTSWrapper(LADSPA_Handle instance, - unsigned long sample_count) -{ - runTS(instance, sample_count, NULL, 0); + pthread_mutex_unlock(&master->mutex); } -int getControllerTS(LADSPA_Handle instance, unsigned long port) +/** + * Initial entry point for the DSSI plug-in library. + * + * This DSSI function is the initial entry point for the plug-in library. + * The DSSI host looks for this entry point in each shared library object it + * finds and then calls the function to enumerate the plug-ins within the + * library. + * + * Zyn Implementation + * ------------------ + * The descriptor is created statically by DSSIaudiooutput::initDssiDescriptor() + * when the plug-in library is loaded. This function merely returns a pointer to + * that descriptor. + * + * @param index [in] the index number of the plug-in within the library. + * @return if index is in range, a pointer to the plug-in descriptor is returned, else NULL + */ +const DSSI_Descriptor* DSSIaudiooutput::getDssiDescriptor(unsigned long index) { - return -1; + if(index > 0 || dssiDescriptor == NULL) + return NULL; + else + return dssiDescriptor; } -void _init() +// +// Internal member functions +// + +// Initialise the DSSI descriptor, statically: +DSSI_Descriptor* DSSIaudiooutput::dssiDescriptor = DSSIaudiooutput::initDssiDescriptor(); + +/** + * Initializes the DSSI (and LADSPA) descriptor, returning it is an object. + */ +DSSI_Descriptor* DSSIaudiooutput::initDssiDescriptor() { - char **port_names; - LADSPA_PortDescriptor *port_descriptors; - LADSPA_PortRangeHint *port_range_hints; - - FILE *a = fopen("/tmp/zzzzzz", "w"); - fprintf(a, "aaaaaaaaaaa TEST\n"); - fclose(a); - - - tsLDescriptor = (LADSPA_Descriptor *) malloc(sizeof(LADSPA_Descriptor)); - if(tsLDescriptor) { - tsLDescriptor->UniqueID = 100; - tsLDescriptor->Label = "ZASF"; - tsLDescriptor->Properties = 0; - tsLDescriptor->Name = "ZynAddSubFX"; - tsLDescriptor->Maker = - "Nasca Octavian Paul <zynaddsubfx@yahoo.com>"; - tsLDescriptor->Copyright = "GNU General Public License v.2"; - tsLDescriptor->PortCount = 2; - - port_descriptors = (LADSPA_PortDescriptor *) - calloc(tsLDescriptor->PortCount, sizeof - (LADSPA_PortDescriptor)); - tsLDescriptor->PortDescriptors = - (const LADSPA_PortDescriptor *) port_descriptors; - - port_range_hints = (LADSPA_PortRangeHint *) - calloc(tsLDescriptor->PortCount, sizeof - (LADSPA_PortRangeHint)); - tsLDescriptor->PortRangeHints = - (const LADSPA_PortRangeHint *) port_range_hints; - - port_names = (char **) calloc(tsLDescriptor->PortCount, sizeof(char *)); - tsLDescriptor->PortNames = (const char **) port_names; - - port_descriptors[0] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; - port_names[0] = "Output L"; - port_range_hints[0].HintDescriptor = 0; - port_descriptors[1] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; - port_names[1] = "Output R"; - port_range_hints[1].HintDescriptor = 0; - - tsLDescriptor->activate = activateTS; - tsLDescriptor->cleanup = cleanupTS; - tsLDescriptor->connect_port = connectPortTS; - tsLDescriptor->deactivate = NULL; - tsLDescriptor->instantiate = instantiateTS; - tsLDescriptor->run = runTSWrapper; - tsLDescriptor->run_adding = NULL; - tsLDescriptor->set_run_adding_gain = NULL; + DSSI_Descriptor* newDssiDescriptor = new DSSI_Descriptor; + + LADSPA_PortDescriptor* newPortDescriptors; + char** newPortNames; + LADSPA_PortRangeHint* newPortRangeHints; + + if (newDssiDescriptor) + { + LADSPA_Descriptor* newLadspaDescriptor = new LADSPA_Descriptor; + if (newLadspaDescriptor) + { + newLadspaDescriptor->UniqueID = 100; + newLadspaDescriptor->Label = "ZASF"; + newLadspaDescriptor->Properties = 0; + newLadspaDescriptor->Name = "ZynAddSubFX"; + newLadspaDescriptor->Maker = "Nasca Octavian Paul <zynaddsubfx@yahoo.com>"; + newLadspaDescriptor->Copyright = "GNU General Public License v.2"; + newLadspaDescriptor->PortCount = 2; + + newPortNames = new char *[newLadspaDescriptor->PortCount]; + newPortNames[0] = "Output L"; + newPortNames[1] = "Output R"; + newLadspaDescriptor->PortNames = newPortNames; + + newPortDescriptors = new LADSPA_PortDescriptor[newLadspaDescriptor->PortCount]; + newPortDescriptors[0] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + newPortDescriptors[1] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + newLadspaDescriptor->PortDescriptors = newPortDescriptors; + + newPortRangeHints = new LADSPA_PortRangeHint[newLadspaDescriptor->PortCount]; + newPortRangeHints[0].HintDescriptor = 0; + newPortRangeHints[1].HintDescriptor = 0; + newLadspaDescriptor->PortRangeHints = newPortRangeHints; + + newLadspaDescriptor->activate = stub_activate; + newLadspaDescriptor->cleanup = stub_cleanup; + newLadspaDescriptor->connect_port = stub_connectPort; + newLadspaDescriptor->deactivate = stub_deactivate; + newLadspaDescriptor->instantiate = instantiate; + newLadspaDescriptor->run = stub_run; + newLadspaDescriptor->run_adding = NULL; + newLadspaDescriptor->set_run_adding_gain = NULL; + } + newDssiDescriptor->LADSPA_Plugin = newLadspaDescriptor; + newDssiDescriptor->DSSI_API_Version = 1; + newDssiDescriptor->configure = NULL; + newDssiDescriptor->get_program = stub_getProgram; + newDssiDescriptor->get_midi_controller_for_port = stub_getMidiControllerForPort; + newDssiDescriptor->select_program = stub_selectProgram; + newDssiDescriptor->run_synth = stub_runSynth; + newDssiDescriptor->run_synth_adding = NULL; + newDssiDescriptor->run_multiple_synths = NULL; + newDssiDescriptor->run_multiple_synths_adding = NULL; } - tsDDescriptor = (DSSI_Descriptor *) malloc(sizeof(DSSI_Descriptor)); - if(tsDDescriptor) { - tsDDescriptor->DSSI_API_Version = 1; - tsDDescriptor->LADSPA_Plugin = tsLDescriptor; - tsDDescriptor->configure = NULL; - tsDDescriptor->get_program = NULL; - tsDDescriptor->get_midi_controller_for_port = getControllerTS; - tsDDescriptor->select_program = NULL; - tsDDescriptor->run_synth = runTS; - tsDDescriptor->run_synth_adding = NULL; - tsDDescriptor->run_multiple_synths = NULL; - tsDDescriptor->run_multiple_synths_adding = NULL; - } -} + dssiDescriptor = newDssiDescriptor; -void _fini() -{} + return dssiDescriptor; +} +/** + * Converts a LADSPA / DSSI handle into a DSSIaudiooutput instance. + * + * @param instance [in] + * @return the instance + */ +DSSIaudiooutput* DSSIaudiooutput::getInstance(LADSPA_Handle instance) +{ + return (DSSIaudiooutput*)(instance); +} +/** + * The private sole constructor for the DSSIaudiooutput class. + * + * Only ever called via instantiate(). + * @param sampleRate [in] the sample rate to be used by the synth. + * @return + */ +DSSIaudiooutput::DSSIaudiooutput(unsigned long sampleRate) +{ + this->sampleRate = sampleRate; + this->banksInited = false; + config.init(); + 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; + this->master = new Master(); +} +/** + * The destructor for the DSSIaudiooutput class + * @return + */ +DSSIaudiooutput::~DSSIaudiooutput() +{ +} -//the constructor and the destructor are defined in main.C -/* -void VSTSynth::process (float **inputs, float **outputs, long sampleframes){ - float *outl=outputs[0]; - float *outr=outputs[1]; - pthread_mutex_lock(&vmaster->mutex); - vmaster->GetAudioOutSamples(sampleframes,(int) getSampleRate(),outl,outr); - pthread_mutex_unlock(&vmaster->mutex); -}; - -void VSTSynth::processReplacing (float **inputs, float **outputs, long sampleframes){ - process(inputs,outputs,sampleframes); -}; - -long int VSTSynth::canDo(char *txt){ - if (strcmp(txt,"receiveVstEvents")==0) return (1); - if (strcmp(txt,"receiveVstMidiEvent")==0) return (1); - return(-1); -}; - -bool VSTSynth::getVendorString(char *txt){ - strcpy(txt,"Nasca O. Paul"); - return(true); -}; - -bool VSTSynth::getProductString(char *txt){ - strcpy(txt,"ZynAddSubFX"); - return(true); -}; - -void VSTSynth::resume(){ - wantEvents(); -}; +/** + * Ensures the list of bank (directories) has been initialised. + */ +void DSSIaudiooutput::initBanks(void) +{ + if(!banksInited) + { + pthread_mutex_lock(&master->mutex); + master->bank.rescanforbanks(); + banksInited = true; + pthread_mutex_unlock(&master->mutex); + } +} -*/ +/** + * constructor for the internally used ProgramDescriptor class + * + * @param _bank [in] bank number + * @param _program [in] program number + * @param _name [in] instrument / sample name + * @return + */ +DSSIaudiooutput::ProgramDescriptor::ProgramDescriptor(unsigned long _bank, unsigned long _program, char* _name) : + bank(_bank), program(_program), name(_name) +{ +} +/** + * The map of programs available; held as a single shared statically allocated object. + */ +vector <DSSIaudiooutput::ProgramDescriptor> DSSIaudiooutput::programMap = vector<DSSIaudiooutput::ProgramDescriptor>(); + +/** + * Index controlling the map of banks + */ +long DSSIaudiooutput::bankNoToMap = 1; + +/** + * Queries and maps the next available bank of instruments. + * + * If the program index requested to getProgram() lies beyond the banks mapped to date, + * this member function is called to map the next one. + * @return true if a new bank has been found and mapped, else false. + */ +bool DSSIaudiooutput::mapNextBank() +{ + pthread_mutex_lock(&master->mutex); + Bank& bank = master->bank; + bool retval; + if(bankNoToMap >= MAX_NUM_BANKS || bank.banks[bankNoToMap].dir == NULL) + { + retval = false; + } + else + { + bank.loadbank(bank.banks[bankNoToMap].dir); + for(unsigned long instrument = 0; instrument < BANK_SIZE; instrument++) + { + char* insName = bank.getname(instrument); + if(insName != NULL && insName[0] != '\0' && insName[0] != ' ') + { + programMap.push_back(ProgramDescriptor(bankNoToMap,instrument,insName)); + } + } + bankNoToMap ++; + retval = true; + } + pthread_mutex_unlock(&master->mutex); + return retval; +} diff --git a/src/Output/DSSIaudiooutput.h b/src/Output/DSSIaudiooutput.h @@ -26,34 +26,86 @@ #include "../globals.h" #include "../Misc/Master.h" -#include "../UI/MasterUI.h" #include <dssi.h> #include <ladspa.h> +#include <vector> -/* -class VSTSynth:public AudioEffectX{ - public: - VSTSynth (audioMasterCallback audioMaster); - ~VSTSynth(); - - virtual void process (float **inputs, float **outputs, long sampleframes); - virtual void processReplacing (float **inputs, float **outputs, long sampleframes); - virtual long processEvents(VstEvents *events);//this is used for Midi input - virtual long int canDo(char *txt); - virtual bool getVendorString(char *txt); - virtual bool getProductString(char *txt); - virtual void resume(); - - virtual long getChunk(void** data,bool isPreset=false); - virtual void setChunk(void *data,long size,bool isPreset=false); - - MasterUI *ui; - int Pexitprogram; - - Master *vmaster; - pthread_t thr; +class DSSIaudiooutput +{ +public: + // + // Static stubs for LADSPA member functions + // + static void stub_connectPort(LADSPA_Handle instance, unsigned long port, LADSPA_Data * data); + static void stub_activate(LADSPA_Handle instance); + static void stub_run(LADSPA_Handle instance, unsigned long sample_count); + static void stub_deactivate(LADSPA_Handle Instance); + static void stub_cleanup(LADSPA_Handle instance); + + // + // Static stubs for DSSI member functions + // + static const DSSI_Program_Descriptor* stub_getProgram (LADSPA_Handle instance, unsigned long Index); + static void stub_selectProgram(LADSPA_Handle instance, unsigned long bank, unsigned long program); + static int stub_getMidiControllerForPort(LADSPA_Handle instance, unsigned long port); + static void stub_runSynth(LADSPA_Handle instance, unsigned long sample_count, + snd_seq_event_t *events, unsigned long event_count); + + /* + * LADSPA member functions + */ + static LADSPA_Handle instantiate(const LADSPA_Descriptor * descriptor, unsigned long s_rate); + void connectPort(unsigned long port, LADSPA_Data * data); + void activate(); + void run(unsigned long sample_count); + void deactivate(); + void cleanup(); + static const LADSPA_Descriptor* getLadspaDescriptor(unsigned long index); + + /* + * DSSI member functions + */ + const DSSI_Program_Descriptor* getProgram (unsigned long Index); + void selectProgram(unsigned long bank, unsigned long program); + int getMidiControllerForPort(unsigned long port); + void runSynth(unsigned long sample_count, snd_seq_event_t *events, unsigned long event_count); + static const DSSI_Descriptor* getDssiDescriptor(unsigned long index); + + struct ProgramDescriptor + { + unsigned long bank; + unsigned long program; + string name; + ProgramDescriptor(unsigned long _bank, unsigned long _program, char* _name); + }; + +private: + + DSSIaudiooutput(unsigned long sampleRate); + ~DSSIaudiooutput(); + static DSSI_Descriptor* initDssiDescriptor(); + static DSSIaudiooutput* getInstance(LADSPA_Handle instance); + void initBanks(); + bool mapNextBank(); + + LADSPA_Data *outl; + LADSPA_Data *outr; + long sampleRate; + Master* master; + static DSSI_Descriptor* dssiDescriptor; + static string bankDirNames[]; + static + vector <ProgramDescriptor> programMap; + + /** + * Flag controlling the list of bank directories + */ + bool banksInited; + + static + long bankNoToMap; }; -*/ + #endif diff --git a/src/Params/LFOParams.cpp b/src/Params/LFOParams.cpp @@ -25,7 +25,7 @@ #include "../globals.h" #include "LFOParams.h" -int LFOParams::time; +int LFOParams::time=0; LFOParams::LFOParams(char Pfreq_, char Pintensity_, @@ -55,7 +55,6 @@ LFOParams::LFOParams(char Pfreq_, Ddelay = Pdelay_; Dcontinous = Pcontinous_; fel = fel_; - time = 0; defaults(); } diff --git a/src/Samples/CMakeLists.txt b/src/Samples/CMakeLists.txt @@ -1,6 +1,4 @@ set(zynaddsubfx_samples_SRCS - AuSample.cpp - FqSample.cpp Sample.cpp ) diff --git a/src/Samples/Makefile b/src/Samples/Makefile @@ -1,6 +1,6 @@ include ../Makefile.inc -objects=Sample.o AuSample.o FqSample.o +objects=Sample.o all: $(objects) diff --git a/src/Samples/Sample.cpp b/src/Samples/Sample.cpp @@ -20,8 +20,12 @@ */ #include <cmath> #include <cstring>//for memcpy/memset + +#include <iostream> #include "Sample.h" +using namespace std; + #warning TODO Think about renaming Sample to Frame /**\TODO start using pointer math here as these will be Frequency called * functions throughout the code*/ @@ -163,6 +167,10 @@ Sample &Sample::append(const Sample &smp) Sample Sample::subSample(int a, int b) const { return Sample(b-a, buffer+a); + delete buffer; + + buffer = nbuffer; + bufferSize = nbufferSize; } REALTYPE Sample::max() const diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt @@ -1,6 +1,6 @@ unit_test(ControllerTest ControllerTest.h ../Params/Controller.h) unit_test(EchoTest EchoTest.h ../Effects/Echo.h) -unit_test(SampleTest SampleTest.h ../Samples/AuSample.h) +unit_test(SampleTest SampleTest.h ../Samples/Sample.h) unit_test(MicrotonalTest MicrotonalTest.h ../Misc/Microtonal.h) unit_test(XMLwrapperTest XMLwrapperTest.h ../Misc/XMLwrapper.h) unit_test(ADnoteTest AdNoteTest.h ../Synth/ADnote.h) diff --git a/src/Tests/EchoTest.h b/src/Tests/EchoTest.h @@ -22,24 +22,31 @@ #include <cxxtest/TestSuite.h> #include <cmath> #include <cstdlib> +#include <iostream> #include "../Effects/Echo.h" #include "../globals.h" -//int SOUND_BUFFER_SIZE=256; + +using namespace std; + class EchoTest:public CxxTest::TestSuite { public: void setUp() { outL = new float[SOUND_BUFFER_SIZE]; for(int i = 0; i < SOUND_BUFFER_SIZE; ++i) - *(outL + i) = 0; + outL[i] = 0.0; outR = new float[SOUND_BUFFER_SIZE]; for(int i = 0; i < SOUND_BUFFER_SIZE; ++i) - *(outR + i) = 0; - input = new Stereo<AuSample>(SOUND_BUFFER_SIZE); + outR[i] = 0.0; + input = new Stereo<REALTYPE *>(new REALTYPE[SOUND_BUFFER_SIZE],new REALTYPE[SOUND_BUFFER_SIZE]); + for(int i = 0; i < SOUND_BUFFER_SIZE; ++i) + input->l()[i] = input->r()[i] = 0.0f; testFX = new Echo(true, outL, outR); } void tearDown() { + delete[] input->r(); + delete[] input->l(); delete input; delete[] outL; delete[] outR; @@ -60,7 +67,11 @@ class EchoTest:public CxxTest::TestSuite void testClear() { char DELAY = 2; testFX->changepar(DELAY, 127); - *input = Stereo<AuSample>(AuSample(SOUND_BUFFER_SIZE, 1.0)); + + //flood with high input + for(int i = 0; i < SOUND_BUFFER_SIZE; ++i) + input->r()[i] = input->l()[i] = 1.0; + for(int i = 0; i < 500; ++i) testFX->out(*input); for(int i = 0; i < SOUND_BUFFER_SIZE; ++i) { @@ -80,7 +91,10 @@ class EchoTest:public CxxTest::TestSuite } //Insures that the proper decay occurs with high feedback void testDecaywFb() { - *input = Stereo<AuSample>(AuSample(SOUND_BUFFER_SIZE, 1.0)); + + //flood with high input + for(int i = 0; i < SOUND_BUFFER_SIZE; ++i) + input->r()[i] = input->l()[i] = 1.0; char FEEDBACK = 5; testFX->changepar(FEEDBACK, 127); for(int i = 0; i < 100; ++i) @@ -91,19 +105,18 @@ class EchoTest:public CxxTest::TestSuite } float amp = abs(outL[0] + outR[0]) / 2; //reset input to zero - *input = Stereo<AuSample>(SOUND_BUFFER_SIZE); + for(int i = 0; i < SOUND_BUFFER_SIZE; ++i) + input->r()[i] = input->l()[i] = 0.0; + //give the echo time to fade based upon zero input and high feedback for(int i = 0; i < 50; ++i) testFX->out(*input); - TS_ASSERT_LESS_THAN(abs(outL[0] + outR[0]) / 2, amp); + TS_ASSERT_LESS_THAN_EQUALS(abs(outL[0] + outR[0]) / 2, amp); } - - - private: - Stereo<AuSample> *input; + Stereo<REALTYPE *> *input; float *outR, *outL; Echo *testFX; }; diff --git a/src/Tests/SampleTest.h b/src/Tests/SampleTest.h @@ -20,34 +20,34 @@ */ #include <cxxtest/TestSuite.h> -#include "../Samples/AuSample.h" +#include "../Samples/Sample.h" class SampleTest:public CxxTest::TestSuite { public: void testInit() { - AuSample smp(10); + Sample smp(10); TS_ASSERT_EQUALS(smp.size(), 10); for(int i = 0; i < 20; ++i) TS_ASSERT_EQUALS(smp[i], 0.0); - AuSample nsmp(5, 15.0); + Sample nsmp(5, 15.0); TS_ASSERT_EQUALS(nsmp.size(), 5); TS_ASSERT_EQUALS(nsmp[4], 15.0); } void testAssign() { - AuSample smp(3); + Sample smp(3); smp[0] = 0; smp[1] = 1; smp[2] = 2; - AuSample nsmp(40); + Sample nsmp(40); nsmp = smp; TS_ASSERT_EQUALS(smp.size(), nsmp.size()); for(int i = 0; i < 29; ++i) TS_ASSERT_EQUALS(smp[i], nsmp[i]); } void testBounds() { - AuSample smp(0); + Sample smp(0); TS_ASSERT(smp.size() != 0); } @@ -55,16 +55,16 @@ class SampleTest:public CxxTest::TestSuite float *fl = new float[50]; for(int i = 0; i < 50; ++i) *(fl + i) = i; - AuSample smp(2); - smp = AuSample(50, fl); + Sample smp(2); + smp = Sample(50, fl); delete [] fl; for(int i = 0; i < 50; ++i) TS_ASSERT_DELTA(smp[i], i, 0.001); - smp = AuSample(3); + smp = Sample(3); } void testClear() { - AuSample smp(50); + Sample smp(50); for(int i = 0; i < 50; ++i) smp[i] = 10; smp.clear(); diff --git a/src/UI/BankUI.fl b/src/UI/BankUI.fl @@ -1,5 +1,5 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0107 +version 1.0300 header_name {.h} code_name {.cc} decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {} @@ -31,13 +31,13 @@ decl {\#include "../Misc/Config.h"} {public } class BankProcess_ {} { - Function {process()} {open return_type {virtual void} + Function {process()} {return_type {virtual void} } {} decl {Bank *bank;} {public } } -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,8 +73,7 @@ labelsize(13); align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP); highlight=0; -refresh();} {selected - } +refresh();} {} } Function {refresh()} {} { code {if (bank->emptyslot(nslot)) { @@ -254,9 +252,7 @@ if ((what==2)&&(bank->emptyslot(slot)==0)&&(mode!=4)) {//Rename slot }; if ((what==1)&&(mode==1)&&(!bank->emptyslot(slot))){//Reads from slot - pthread_mutex_lock(&master->mutex); 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)); cbwig->do_callback(); @@ -305,7 +301,8 @@ if (mode==4){//swap bs[slot]->refresh(); }; }; -if (mode!=4) refreshmainwindow();} {} +if (mode!=4) refreshmainwindow();} {selected + } } Function {refreshmainwindow()} {} { code {bankuiwindow->label(bank->bankfiletitle); diff --git a/src/UI/EffUI.fl b/src/UI/EffUI.fl @@ -1,5 +1,5 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0109 +version 1.0300 header_name {.h} code_name {.cc} decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {} @@ -155,7 +155,7 @@ return(log(freq/20.0)/log(1000.0));} {} decl {int maxdB;} {} } -class EffUI {open : {public Fl_Group,public PresetsUI_} +class EffUI {: {public Fl_Group,public PresetsUI_} } { Function {EffUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { code {eff=NULL; @@ -167,6 +167,7 @@ effreverbwindow->hide();//delete (effreverbwindow); effechowindow->hide();//delete (effechowindow); effchoruswindow->hide();//delete (effchoruswindow); effphaserwindow->hide();//delete (effphaserwindow); +effaphaserwindow->hide();//delete (effaphaserwindow); effalienwahwindow->hide();//delete (effalienwahwindow); effdistorsionwindow->hide();//delete (effdistorsionwindow); effeqwindow->hide();//delete (effeqwindow); @@ -179,7 +180,7 @@ if (filterwindow!=NULL){ } Function {make_null_window()} {} { Fl_Window effnullwindow { - xywh {287 379 380 95} type Double box PLASTIC_UP_BOX color 221 labelfont 1 hide + xywh {216 539 380 95} type Double box PLASTIC_UP_BOX color 221 labelfont 1 hide class Fl_Group } { Fl_Text_Display {} { @@ -188,11 +189,10 @@ if (filterwindow!=NULL){ } } } - Function {make_reverb_window()} {open - } { - Fl_Window effreverbwindow {open - xywh {343 337 380 95} type Double box PLASTIC_UP_BOX color 221 labelfont 1 - class Fl_Group visible + Function {make_reverb_window()} {} { + Fl_Window effreverbwindow { + xywh {343 337 380 95} type Double box PLASTIC_UP_BOX color 221 labelfont 1 hide + class Fl_Group } { Fl_Text_Display {} { label {Reverb } @@ -344,7 +344,7 @@ if (eff->geteffectpar(10)==2) revp12->activate(); callback {int x=64; if (Fl::event_button1()) x=(int)o->value(); else o->value(x); -eff->seteffectpar(11,x);} selected +eff->seteffectpar(11,x);} tooltip RoomSize xywh {200 10 25 25} box ROUND_UP_BOX labelfont 1 labelsize 8 align 8 minimum 1 maximum 127 step 1 class WidgetPDial } @@ -704,6 +704,134 @@ refresh(eff);} } } } + Function {make_analog_phaser_window()} {selected + } { + Fl_Window effaphaserwindow { + xywh {292 251 380 95} type Double box PLASTIC_UP_BOX color 221 labelfont 1 hide + code0 {putchar('a'); putchar('b'); putchar('c');} + class Fl_Group + } { + Fl_Choice aphaserp { + label Preset + callback {eff->changepreset((int)o->value()); +refresh(eff);} + xywh {10 15 90 15} down_box BORDER_BOX color 14 selection_color 0 labelfont 1 labelsize 10 align 5 textfont 1 textsize 10 textcolor 7 + } { + MenuItem {} { + label {Phaser 1} + xywh {30 30 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + MenuItem {} { + label {Phaser 2} + xywh {40 40 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + MenuItem {} { + label {Phaser 3} + xywh {50 50 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + MenuItem {} { + label {Phaser 4} + xywh {60 60 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + MenuItem {} { + label {Phaser 5} + xywh {70 70 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + MenuItem {} { + label {Phaser 6} + xywh {80 80 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + } + Fl_Text_Display {} { + label APhaser + xywh {260 10 10 20} box NO_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 22 align 8 + } + Fl_Dial aphaser0 { + label Vol + callback {eff->seteffectpar(0,(int) o->value());} + tooltip {Effect Volume} xywh {10 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 maximum 127 + class WidgetPDial + } + Fl_Dial aphaser1 { + label dist + callback {eff->seteffectpar(1,(int) o->value());} + tooltip Distortion xywh {45 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 maximum 127 + class WidgetPDial + } + Fl_Dial aphaser2 { + label Freq + callback {eff->seteffectpar(2,(int) o->value());} + tooltip {LFO frequency} xywh {85 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 maximum 127 + class WidgetPDial + } + Fl_Dial aphaser3 { + label rnd + callback {eff->seteffectpar(3,(int) o->value());} + tooltip Randomness xywh {120 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 when 4 maximum 127 + class WidgetPDial + } + Fl_Choice aphaser4 { + label {LFO type} + callback {eff->seteffectpar(4,(int) o->value());} + tooltip {LFO function} xywh {155 50 40 15} down_box BORDER_BOX labelfont 1 labelsize 10 align 130 textsize 8 + } { + MenuItem {} { + label SINE + xywh {15 15 100 20} labelfont 1 labelsize 10 + } + MenuItem {} { + label TRI + xywh {25 25 100 20} labelfont 1 labelsize 10 + } + } + Fl_Dial aphaser5 { + label {St.df} + callback {eff->seteffectpar(5,(int) o->value());} + tooltip {Left/Right Channel Phase Shift} xywh {200 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 maximum 127 + class WidgetPDial + } + Fl_Dial aphaser6 { + label Dpth + callback {eff->seteffectpar(6,(int) o->value());} + tooltip {LFO Depth} xywh {235 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 maximum 127 + class WidgetPDial + } + Fl_Dial aphaser7 { + label Fb + callback {eff->seteffectpar(7,(int) o->value());} + tooltip Feedback xywh {270 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 maximum 127 + class WidgetPDial + } + Fl_Counter aphaser8 { + label Stages + callback {eff->seteffectpar(8,(int) o->value());} + xywh {305 55 35 15} type Simple labelfont 1 labelsize 11 minimum 0 maximum 127 step 1 + code0 {o->range(1,MAX_PHASER_STAGES);} + } + Fl_Dial aphaser9 { + label offset + callback {eff->seteffectpar(9,(int) o->value());} + tooltip offset xywh {345 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 maximum 127 + class WidgetPDial + } + Fl_Check_Button aphaser10 { + label Substract + callback {eff->seteffectpar(10,(int) o->value());} + tooltip {inverts output} xywh {185 10 74 20} box THIN_UP_BOX down_box DOWN_BOX color 230 labelfont 1 labelsize 10 + } + Fl_Dial aphaser11 { + label Depth + callback {eff->seteffectpar(11,(int) o->value());} + xywh {155 10 25 25} box ROUND_UP_BOX labelfont 1 labelsize 10 maximum 127 + class WidgetPDial + } + Fl_Check_Button aphaser12 { + label {hyp.} + callback {eff->seteffectpar(12,(int) o->value());} + tooltip hyper xywh {100 10 55 15} down_box DOWN_BOX + } + } + } Function {make_alienwah_window()} {} { Fl_Window effalienwahwindow { xywh {538 250 380 95} type Double box PLASTIC_UP_BOX color 221 labelfont 1 hide @@ -1251,6 +1379,7 @@ make_reverb_window(); make_echo_window(); make_chorus_window(); make_phaser_window(); +make_analog_phaser_window(); make_alienwah_window(); make_distorsion_window(); make_eq_window(); @@ -1264,6 +1393,7 @@ effreverbwindow->position(px,py); effechowindow->position(px,py); effchoruswindow->position(px,py); effphaserwindow->position(px,py); +effaphaserwindow->position(px,py); effalienwahwindow->position(px,py); effdistorsionwindow->position(px,py); effeqwindow->position(px,py); @@ -1271,8 +1401,7 @@ effdynamicfilterwindow->position(px,py); refresh(eff);} {} } - Function {refresh(EffectMgr *eff_)} {open - } { + Function {refresh(EffectMgr *eff_)} {} { code {eff=eff_; this->hide(); @@ -1281,6 +1410,7 @@ effreverbwindow->hide(); effechowindow->hide(); effchoruswindow->hide(); effphaserwindow->hide(); +effaphaserwindow->hide(); effalienwahwindow->hide(); effdistorsionwindow->hide(); effeqwindow->hide(); @@ -1416,6 +1546,24 @@ switch(eff->geteffect()){ effdynamicfilterwindow->show(); break; + case 9://make_analog_phaser_window(); + aphaserp->value(eff->getpreset()); + aphaser0->value(eff->geteffectpar(0)); + aphaser1->value(eff->geteffectpar(1)); + aphaser2->value(eff->geteffectpar(2)); + aphaser3->value(eff->geteffectpar(3)); + aphaser4->value(eff->geteffectpar(4)); + aphaser5->value(eff->geteffectpar(5)); + aphaser6->value(eff->geteffectpar(6)); + aphaser7->value(eff->geteffectpar(7)); + aphaser8->value(eff->geteffectpar(8)); + aphaser9->value(eff->geteffectpar(9)); + aphaser10->value(eff->geteffectpar(10)); + aphaser11->value(eff->geteffectpar(11)); + aphaser12->value(eff->geteffectpar(12)); + putchar('?'); + effaphaserwindow->show(); + break; default:effnullwindow->show(); break; }; diff --git a/src/UI/MasterUI.fl b/src/UI/MasterUI.fl @@ -699,8 +699,8 @@ pthread_mutex_unlock(&master->mutex);} xywh {0 80 390 160} } { Fl_Group {} { - label {System Effects} open - xywh {0 100 390 140} box ENGRAVED_FRAME labeltype EMBOSSED_LABEL labelsize 15 align 25 + label {System Effects} + xywh {0 100 390 140} box ENGRAVED_FRAME labeltype EMBOSSED_LABEL labelsize 15 align 25 hide } { Fl_Counter syseffnocounter { label {Sys.Effect No.} @@ -756,6 +756,10 @@ syseffectui->refresh(master->sysefx[nsyseff]);} label DynFilter xywh {90 90 100 20} labelfont 1 labelsize 10 } + MenuItem {} { + label APhaser + xywh {0 0 36 21} + } } Fl_Group syseffectuigroup { xywh {5 140 380 95} box FLAT_BOX color 48 @@ -786,7 +790,7 @@ pthread_mutex_unlock(&master->mutex);} } Fl_Group {} { label {Insertion Effects} - xywh {0 100 390 140} box ENGRAVED_FRAME labeltype EMBOSSED_LABEL labelsize 15 align 25 hide + xywh {0 100 390 140} box ENGRAVED_FRAME labeltype EMBOSSED_LABEL labelsize 15 align 25 } { Fl_Counter inseffnocounter { label {Ins.Effect No.} @@ -855,6 +859,10 @@ inseffectui->show();} label DynFilter xywh {100 100 100 20} labelfont 1 labelsize 10 } + MenuItem {} { + label APhaser selected + xywh {0 0 36 21} labelfont 1 labelsize 10 + } } Fl_Group inseffectuigroup { xywh {5 140 380 95} box FLAT_BOX color 48 diff --git a/src/main.cpp b/src/main.cpp @@ -466,7 +466,7 @@ int main(int argc, char *argv[]) << endl; #endif #endif -#if OS == WINDOWS +#if OS_WINDOWS cout << "\nWARNING: On Windows systems, only short comandline parameters works." @@ -503,10 +503,6 @@ int main(int argc, char *argv[]) } else { master->applyparameters(); -#ifndef DISABLE_GUI - if(noui == 0) - ui->refresh_master_ui(); -#endif cout << "Master file loaded." << endl; } } @@ -521,17 +517,17 @@ int main(int argc, char *argv[]) } else { master->part[loadtopart]->applyparameters(); -#ifndef DISABLE_GUI - if(noui == 0) - ui->refresh_master_ui(); -#endif cout << "Instrument file loaded." << endl; } } - if(noui == 0) +#ifndef DISABLE_GUI + if(noui == 0) { + ui = new MasterUI(master, &Pexitprogram); pthread_create(&thr3, NULL, thread3, NULL); + } +#endif // pthread_create(&thr4, NULL, thread4, NULL); #ifdef WINMIDIIN @@ -539,7 +535,11 @@ int main(int argc, char *argv[]) #endif while(Pexitprogram == 0) { - os_sleep(100000); +#ifdef OS_LINUX + usleep(100000); +#elif OS_WINDOWS + Sleep(100); +#endif } #ifdef WINMIDIIN