zynaddsubfx

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

commit b8075712de243bee774f8e7ebe94b00c035b4246
parent ab53e7a651ccbea9069ca23a1846f664acdc4a44
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Sun, 25 Apr 2021 16:26:07 -0400

Remove Cxxtest dependency

Looks like upstream is now a dead project.
Rather than try to revive that in any way, let's remove one dependency.

Diffstat:
M.github/workflows/ccpp.yml | 2--
M.travis.yml | 1-
MREADME.adoc | 4+---
Msrc/CMakeLists.txt | 5-----
Asrc/Tests/AdNoteTest.cpp | 258+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/AdNoteTest.h | 248-------------------------------------------------------------------------------
Asrc/Tests/AllocatorTest.cpp | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/AllocatorTest.h | 108-------------------------------------------------------------------------------
Msrc/Tests/CMakeLists.txt | 96++++++++++++++++++++++++++++++-------------------------------------------------
Asrc/Tests/ControllerTest.cpp | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/ControllerTest.h | 70----------------------------------------------------------------------
Asrc/Tests/EchoTest.cpp | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/EchoTest.h | 122-------------------------------------------------------------------------------
Asrc/Tests/EffectTest.cpp | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/EffectTest.h | 79-------------------------------------------------------------------------------
Asrc/Tests/KitTest.cpp | 795+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/KitTest.h | 768-------------------------------------------------------------------------------
Asrc/Tests/MemoryStressTest.cpp | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/MemoryStressTest.h | 111-------------------------------------------------------------------------------
Asrc/Tests/MessageTest.cpp | 367+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/MessageTest.h | 352-------------------------------------------------------------------------------
Asrc/Tests/MicrotonalTest.cpp | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/MicrotonalTest.h | 131-------------------------------------------------------------------------------
Asrc/Tests/MiddlewareTest.cpp | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/MiddlewareTest.h | 146-------------------------------------------------------------------------------
Asrc/Tests/MqTest.cpp | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/MqTest.h | 124-------------------------------------------------------------------------------
Asrc/Tests/MsgParseTest.cpp | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/MsgParseTest.h | 59-----------------------------------------------------------
Asrc/Tests/OscilGenTest.cpp | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/OscilGenTest.h | 128-------------------------------------------------------------------------------
Asrc/Tests/PadNoteTest.cpp | 299+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/PadNoteTest.h | 289------------------------------------------------------------------------------
Asrc/Tests/PluginTest.cpp | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/PluginTest.h | 244-------------------------------------------------------------------------------
Asrc/Tests/RandTest.cpp | 26++++++++++++++++++++++++++
Dsrc/Tests/RandTest.h | 31-------------------------------
Rsrc/Tests/RtAllocTest.h -> src/Tests/RtAllocTest.cpp | 0
Asrc/Tests/SubNoteTest.cpp | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/SubNoteTest.h | 185-------------------------------------------------------------------------------
Asrc/Tests/TriggerTest.cpp | 265+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/TriggerTest.h | 258-------------------------------------------------------------------------------
Asrc/Tests/UnisonTest.cpp | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/UnisonTest.h | 180-------------------------------------------------------------------------------
Asrc/Tests/WatchTest.cpp | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/WatchTest.h | 83-------------------------------------------------------------------------------
Asrc/Tests/XMLwrapperTest.cpp | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/Tests/XMLwrapperTest.h | 63---------------------------------------------------------------
Asrc/Tests/common.h | 250+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Tests/test-suite.h | 26++++++++++++++++++++++++++
50 files changed, 4284 insertions(+), 3850 deletions(-)

diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml @@ -16,8 +16,6 @@ jobs: - name: install_deps2 run: sudo apt-get install liblo-dev - name: install_test_deps1 - run: sudo apt-get install --force-yes cxxtest python3 - - name: install_test_deps2 run: sudo apt-get install ruby - name: submodule run: git submodule update --init diff --git a/.travis.yml b/.travis.yml @@ -9,7 +9,6 @@ before_install: - sudo apt-get install zlib1g-dev libmxml-dev libfftw3-dev dssi-dev libfltk1.3-dev fluid libxpm-dev - sudo apt-get install liblo-dev - sudo apt-get install libsndio-dev - - sudo apt-get install --force-yes cxxtest script: diff --git a/README.adoc b/README.adoc @@ -58,7 +58,6 @@ Optional: - ALSA - LASH - DSSI -- CxxTest (for unit tests) Sibling projects ~~~~~~~~~~~~~~~~ @@ -74,4 +73,4 @@ ZynAddSubFX is available under the GPL-2.0-or-later license. Have fun! :-) ---The ZynAddSubFX team -\ No newline at end of file +--The ZynAddSubFX team diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt @@ -18,10 +18,6 @@ find_package(Alsa) find_package(Sndio) find_package(FLTK) find_package(OpenGL) #for FLTK -find_package(CxxTest) -if(CXXTEST_FOUND) - set(CXXTEST_USE_PYTHON TRUE) -endif() # lash if(PKG_CONFIG_FOUND AND NOT (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")) message("Looking For pkg config modules") @@ -680,7 +676,6 @@ package_status(PORTAUDIO_FOUND "PA " "found" ${Yellow}) package_status(SNDIO_FOUND "SNDIO " "found" ${Yellow}) package_status(LASH_FOUND "Lash " "found" ${Yellow}) package_status(DSSI_FOUND "DSSI " "found" ${Yellow}) -package_status(CXXTEST_FOUND "CxxTest " "found" ${Yellow}) package_status(LashEnable "Lash " "enabled" ${Yellow}) package_status(DssiEnable "DSSI " "enabled" ${Yellow}) package_status(CompileTests "tests " "enabled" ${Yellow}) diff --git a/src/Tests/AdNoteTest.cpp b/src/Tests/AdNoteTest.cpp @@ -0,0 +1,258 @@ +/* + ZynAddSubFX - a software synthesizer + AdNoteTest.h - CxxTest for Synth/ADnote + Copyright (C) 2009-2011 Mark McCurry + Copyright (C) 2009 Harald Hvaal + Authors: Mark McCurry, Harald Hvaal + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ + + +#include "test-suite.h" +#include <iostream> +#include <fstream> +#include <ctime> +#include <string> +#include "../Misc/Master.h" +#include "../Misc/Util.h" +#include "../Misc/Allocator.h" +#include "../Synth/ADnote.h" +#include "../Params/Presets.h" +#include "../DSP/FFTwrapper.h" +#include "../Synth/LFO.h" +#include "../Params/LFOParams.h" +#include "../globals.h" +#include <rtosc/thread-link.h> + +using namespace std; +using namespace zyn; + +SYNTH_T *synth; + + +class AdNoteTest +{ + public: + rtosc::ThreadLink *tr; + ADnote *note; + AbsTime *time; + FFTwrapper *fft; + ADnoteParameters *defaultPreset; + Controller *controller; + Alloc memory; + float test_freq_log2; + WatchManager *w; + float *outR, *outL; + + LFO *lfo; + LFOParams *lfop; + int randval(int min, int max) + { + int ret = rand()%(1+max-min)+min; + //printf("ret = %d (%d..%d)\n",ret, min,max); + return ret; + } + + void randomize_params(void) { + lfop->Pintensity = randval(0,255); + lfop->Pstartphase = randval(0,255); + lfop->Pcutoff = randval(0,127); + lfop->PLFOtype = randval(0,6); + lfop->Prandomness = randval(0,255); + lfop->Pfreqrand = randval(0,255); + lfop->Pcontinous = randval(0,1); + lfop->Pstretch = randval(0,255); + lfop->fel = (consumer_location_type_t) randval(1,2); + + } + + void run_lfo_randomtest(void) + { + lfo = new LFO(*lfop, 440.0f, *time); + for(int i=0; i<100; ++i) { + float out = lfo->lfoout(); + switch(lfop->fel) + { + case consumer_location_type_t::amp: + TS_ASSERT((-2.0f < out && out < 2.0f)); + break; + case consumer_location_type_t::filter: + TS_ASSERT((-8.0f < out && out < 8.0f)); + break; + case consumer_location_type_t::freq: + case consumer_location_type_t::unspecified: + default: + break; + } + } + } + + + + void setUp() { + //First the sensible settings and variables that have to be set: + synth = new SYNTH_T; + synth->buffersize = 256; + //synth->alias(); + time = new AbsTime(*synth); + + outL = new float[synth->buffersize]; + for(int i = 0; i < synth->buffersize; ++i) + *(outL + i) = 0; + outR = new float[synth->buffersize]; + for(int i = 0; i < synth->buffersize; ++i) + *(outR + i) = 0; + + tr = new rtosc::ThreadLink(1024,3); + w = new WatchManager(tr); + + fft = new FFTwrapper(synth->oscilsize); + //prepare the default settings + defaultPreset = new ADnoteParameters(*synth, fft, time); + + //Assert defaults + TS_ASSERT(!defaultPreset->VoicePar[1].Enabled); + + XMLwrapper wrap; + cout << string(SOURCE_DIR) + string("/guitar-adnote.xmz") + << endl; + wrap.loadXMLfile(string(SOURCE_DIR) + + string("/guitar-adnote.xmz")); + TS_ASSERT(wrap.enterbranch("MASTER")); + TS_ASSERT(wrap.enterbranch("PART", 0)); + TS_ASSERT(wrap.enterbranch("INSTRUMENT")); + TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT")); + TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT_ITEM", 0)); + TS_ASSERT(wrap.enterbranch("ADD_SYNTH_PARAMETERS")); + defaultPreset->getfromXML(wrap); + //defaultPreset->defaults(); + + //verify xml was loaded + TS_ASSERT(defaultPreset->VoicePar[1].Enabled); + + + + controller = new Controller(*synth, time); + + //lets go with.... 50! as a nice note + test_freq_log2 = log2f(440.0f) + (50.0 - 69.0f) / 12.0f; + SynthParams pars{memory, *controller, *synth, *time, 120, 0, test_freq_log2, false, prng()}; + + note = new ADnote(defaultPreset, pars,w); + + } + + void tearDown() { + delete note; + delete controller; + delete defaultPreset; + delete fft; + delete [] outL; + delete [] outR; + FFT_cleanup(); + delete synth; + } + + void testDefaults() { + int sampleCount = 0; + +//#define WRITE_OUTPUT + +#ifdef WRITE_OUTPUT + ofstream file("adnoteout", ios::out); +#endif + note->noteout(outL, outR); +#ifdef WRITE_OUTPUT + for(int i = 0; i < synth->buffersize; ++i) + file << outL[i] << std::endl; + +#endif + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], 0.1924f, 0.0001f); + note->releasekey(); + + TS_ASSERT(!tr->hasNext()); + w->add_watch("noteout/be4_mix"); + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], -0.4717f, 0.0001f); + w->tick(); + TS_ASSERT(tr->hasNext()); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + w->tick(); + TS_ASSERT_DELTA(outL[255], 0.0646f, 0.0001f); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], 0.1183f, 0.0001f); + w->tick(); + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], -0.1169f, 0.0001f); + w->tick(); + + TS_ASSERT(tr->hasNext()); + TS_ASSERT_EQUAL_STR("noteout/be4_mix", tr->read()); + TS_ASSERT(!tr->hasNext()); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + + + while(!note->finished()) { + note->noteout(outL, outR); +#ifdef WRITE_OUTPUT + for(int i = 0; i < synth->buffersize; ++i) + file << outL[i] << std::endl; + +#endif + sampleCount += synth->buffersize; + } +#ifdef WRITE_OUTPUT + file.close(); +#endif + + TS_ASSERT_EQUAL_INT(sampleCount, 30208); + + lfop = new LFOParams(); + lfop->fel = zyn::consumer_location_type_t::amp; + lfop->freq = 2.0f; + lfop->delay = 0.0f; + for(int i=0; i<10000; ++i) { + randomize_params(); + run_lfo_randomtest(); + } + + + } + +#define OUTPUT_PROFILE +#ifdef OUTPUT_PROFILE + void testSpeed() { + const int samps = 15000; + + int t_on = clock(); // timer before calling func + for(int i = 0; i < samps; ++i) + note->noteout(outL, outR); + int t_off = clock(); // timer when func returns + + printf("AdNoteTest: %f seconds for %d Samples to be generated.\n", + (static_cast<float>(t_off - t_on)) / CLOCKS_PER_SEC, samps); + } +#endif +}; + +int main() +{ + tap_quiet = 1; + AdNoteTest test; + test.setUp(); + test.testDefaults(); + test.tearDown(); + return test_summary(); +} diff --git a/src/Tests/AdNoteTest.h b/src/Tests/AdNoteTest.h @@ -1,248 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - AdNoteTest.h - CxxTest for Synth/ADnote - Copyright (C) 2009-2011 Mark McCurry - Copyright (C) 2009 Harald Hvaal - Authors: Mark McCurry, Harald Hvaal - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ - - -#include <cxxtest/TestSuite.h> -#include <iostream> -#include <fstream> -#include <ctime> -#include <string> -#include "../Misc/Master.h" -#include "../Misc/Util.h" -#include "../Misc/Allocator.h" -#include "../Synth/ADnote.h" -#include "../Params/Presets.h" -#include "../DSP/FFTwrapper.h" -#include "../Synth/LFO.h" -#include "../Params/LFOParams.h" -#include "../globals.h" -#include <rtosc/thread-link.h> - -using namespace std; -using namespace zyn; - -SYNTH_T *synth; - - -class AdNoteTest:public CxxTest::TestSuite -{ - public: - rtosc::ThreadLink *tr; - ADnote *note; - AbsTime *time; - FFTwrapper *fft; - ADnoteParameters *defaultPreset; - Controller *controller; - Alloc memory; - float test_freq_log2; - WatchManager *w; - float *outR, *outL; - - LFO *lfo; - LFOParams *lfop; - int randval(int min, int max) - { - int ret = rand()%(1+max-min)+min; - //printf("ret = %d (%d..%d)\n",ret, min,max); - return ret; - } - - void randomize_params(void) { - lfop->Pintensity = randval(0,255); - lfop->Pstartphase = randval(0,255); - lfop->Pcutoff = randval(0,127); - lfop->PLFOtype = randval(0,6); - lfop->Prandomness = randval(0,255); - lfop->Pfreqrand = randval(0,255); - lfop->Pcontinous = randval(0,1); - lfop->Pstretch = randval(0,255); - lfop->fel = (consumer_location_type_t) randval(1,2); - - } - - void run_lfo_randomtest(void) - { - lfo = new LFO(*lfop, 440.0f, *time); - for(int i=0; i<100; ++i) { - float out = lfo->lfoout(); - switch(lfop->fel) - { - case consumer_location_type_t::amp: - TS_ASSERT((-2.0f < out && out < 2.0f)); - break; - case consumer_location_type_t::filter: - TS_ASSERT((-8.0f < out && out < 8.0f)); - break; - case consumer_location_type_t::freq: - case consumer_location_type_t::unspecified: - default: - break; - } - } - } - - - - void setUp() { - //First the sensible settings and variables that have to be set: - synth = new SYNTH_T; - synth->buffersize = 256; - //synth->alias(); - time = new AbsTime(*synth); - - outL = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - *(outL + i) = 0; - outR = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - *(outR + i) = 0; - - tr = new rtosc::ThreadLink(1024,3); - w = new WatchManager(tr); - - fft = new FFTwrapper(synth->oscilsize); - //prepare the default settings - defaultPreset = new ADnoteParameters(*synth, fft, time); - - //Assert defaults - TS_ASSERT(!defaultPreset->VoicePar[1].Enabled); - - XMLwrapper wrap; - cout << string(SOURCE_DIR) + string("/guitar-adnote.xmz") - << endl; - wrap.loadXMLfile(string(SOURCE_DIR) - + string("/guitar-adnote.xmz")); - TS_ASSERT(wrap.enterbranch("MASTER")); - TS_ASSERT(wrap.enterbranch("PART", 0)); - TS_ASSERT(wrap.enterbranch("INSTRUMENT")); - TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT")); - TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT_ITEM", 0)); - TS_ASSERT(wrap.enterbranch("ADD_SYNTH_PARAMETERS")); - defaultPreset->getfromXML(wrap); - //defaultPreset->defaults(); - - //verify xml was loaded - TS_ASSERT(defaultPreset->VoicePar[1].Enabled); - - - - controller = new Controller(*synth, time); - - //lets go with.... 50! as a nice note - test_freq_log2 = log2f(440.0f) + (50.0 - 69.0f) / 12.0f; - SynthParams pars{memory, *controller, *synth, *time, 120, 0, test_freq_log2, false, prng()}; - - note = new ADnote(defaultPreset, pars,w); - - } - - void tearDown() { - delete note; - delete controller; - delete defaultPreset; - delete fft; - delete [] outL; - delete [] outR; - FFT_cleanup(); - delete synth; - } - - void testDefaults() { - int sampleCount = 0; - -//#define WRITE_OUTPUT - -#ifdef WRITE_OUTPUT - ofstream file("adnoteout", ios::out); -#endif - note->noteout(outL, outR); -#ifdef WRITE_OUTPUT - for(int i = 0; i < synth->buffersize; ++i) - file << outL[i] << std::endl; - -#endif - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.1924f, 0.0001f); - note->releasekey(); - - TS_ASSERT(!tr->hasNext()); - w->add_watch("noteout/be4_mix"); - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.4717f, 0.0001f); - w->tick(); - TS_ASSERT(tr->hasNext()); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - w->tick(); - TS_ASSERT_DELTA(outL[255], 0.0646f, 0.0001f); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.1183f, 0.0001f); - w->tick(); - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.1169f, 0.0001f); - w->tick(); - - TS_ASSERT(tr->hasNext()); - TS_ASSERT_EQUALS(string("noteout/be4_mix"), tr->read()); - TS_ASSERT(!tr->hasNext()); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - - - while(!note->finished()) { - note->noteout(outL, outR); -#ifdef WRITE_OUTPUT - for(int i = 0; i < synth->buffersize; ++i) - file << outL[i] << std::endl; - -#endif - sampleCount += synth->buffersize; - } -#ifdef WRITE_OUTPUT - file.close(); -#endif - - TS_ASSERT_EQUALS(sampleCount, 30208); - - lfop = new LFOParams(); - lfop->fel = zyn::consumer_location_type_t::amp; - lfop->freq = 2.0f; - lfop->delay = 0.0f; - for(int i=0; i<10000; ++i) { - randomize_params(); - run_lfo_randomtest(); - } - - - } - -#define OUTPUT_PROFILE -#ifdef OUTPUT_PROFILE - void testSpeed() { - const int samps = 15000; - - int t_on = clock(); // timer before calling func - for(int i = 0; i < samps; ++i) - note->noteout(outL, outR); - int t_off = clock(); // timer when func returns - - printf("AdNoteTest: %f seconds for %d Samples to be generated.\n", - (static_cast<float>(t_off - t_on)) / CLOCKS_PER_SEC, samps); - } -#endif -}; diff --git a/src/Tests/AllocatorTest.cpp b/src/Tests/AllocatorTest.cpp @@ -0,0 +1,116 @@ +/* + ZynAddSubFX - a software synthesizer + + AllocatorTest.h - CxxTest for RT Memory Allocator + Copyright (C) 2014-2014 Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ + + +#include "test-suite.h" +#include <iostream> +#include <fstream> +#include <ctime> +#include <cstring> +#include <string> +#include <vector> +#include "../Misc/Allocator.h" +//using namespace std; +using std::vector; +using namespace zyn; + +class AllocatorTest +{ + public: + Allocator *memory_; + vector<void*> data; + + void setUp() { + memory_ = new AllocatorClass(); + } + + void tearDown() { + delete memory_; + } + + void testBasic() { + Allocator &memory = *memory_; + char *d = (char*)memory.alloc_mem(128); + TS_NON_NULL(d); + d[0] = 0; + d[127] = 0; + memory.dealloc_mem(d); + } + + void testTooBig() { + Allocator &memory = *memory_; + //Try to allocate a gig + char *d = (char*)memory.alloc_mem(1024*1024*1024); + TS_ASSERT(d==nullptr); + } + + void testEnlarge() + { + Allocator &memory = *memory_; + //Additional Buffers + size_t N = 50*1024*1024; + char *bufA = (char*)malloc(N); + char *bufB = (char*)malloc(N); + memset(bufA,0xff, N); + memset(bufB,0xff, N); + + + //By default 25MBi is too large + //Therefore this allocation should fail + bool low = memory.lowMemory(5,5*1024*1024); + TS_ASSERT(low); + TS_ASSERT(memory.memPools() == 1); + + + //Try to add a buffer + //This provides enough for the low memory check to pass + memory.addMemory(bufA, N); + TS_ASSERT(memory.memPools() == 2); + TS_ASSERT(memory.memFree(bufA)); + bool low2 = memory.lowMemory(5,5*1024*1024); + TS_ASSERT(!low2); + TS_ASSERT(memory.memFree(bufA)); + + //We should be able to see that a chunk enters and exits the free + //state + char *mem2 = (char*)memory.alloc_mem(10*1024*1024); + TS_NON_NULL(mem2); + TS_ASSERT(!memory.memFree(bufA)); + memory.dealloc_mem(mem2); + TS_ASSERT(memory.memFree(bufA)); + mem2 = (char*)memory.alloc_mem(10*1024*1024); + char *mem3 = (char*)memory.alloc_mem(10*1024*1024); + TS_NON_NULL(mem3); + memory.dealloc_mem(mem2); + TS_ASSERT(!memory.memFree(bufA)); + TS_ASSERT(memory.freePools() == 0); + memory.dealloc_mem(mem3); + TS_ASSERT(memory.memFree(bufA)); + TS_ASSERT(memory.freePools() == 1); + + //Observe that adding another pool superficially works + memory.addMemory(bufB, N); + TS_ASSERT(memory.freePools() == 2); + + //delete [] bufA; + //delete [] bufB; + } + +}; + +int main() +{ + AllocatorTest test; + RUN_TEST(testBasic); + RUN_TEST(testTooBig); + RUN_TEST(testEnlarge); +} diff --git a/src/Tests/AllocatorTest.h b/src/Tests/AllocatorTest.h @@ -1,108 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - AllocatorTest.h - CxxTest for RT Memory Allocator - Copyright (C) 2014-2014 Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ - - -#include <cxxtest/TestSuite.h> -#include <iostream> -#include <fstream> -#include <ctime> -#include <cstring> -#include <string> -#include <vector> -#include "../Misc/Allocator.h" -//using namespace std; -using std::vector; -using namespace zyn; - -class AllocatorTest:public CxxTest::TestSuite -{ - public: - Allocator *memory_; - vector<void*> data; - - void setUp() { - memory_ = new AllocatorClass(); - } - - void tearDown() { - delete memory_; - } - - void testBasic() { - Allocator &memory = *memory_; - char *d = (char*)memory.alloc_mem(128); - TS_ASSERT(d); - d[0] = 0; - d[127] = 0; - memory.dealloc_mem(d); - } - - void testTooBig() { - Allocator &memory = *memory_; - //Try to allocate a gig - char *d = (char*)memory.alloc_mem(1024*1024*1024); - TS_ASSERT(d==nullptr); - } - - void testEnlarge() - { - Allocator &memory = *memory_; - //Additional Buffers - size_t N = 50*1024*1024; - char *bufA = (char*)malloc(N); - char *bufB = (char*)malloc(N); - memset(bufA,0xff, N); - memset(bufB,0xff, N); - - - //By default 25MBi is too large - //Therefore this allocation should fail - bool low = memory.lowMemory(5,5*1024*1024); - TS_ASSERT(low); - TS_ASSERT(memory.memPools() == 1); - - - //Try to add a buffer - //This provides enough for the low memory check to pass - memory.addMemory(bufA, N); - TS_ASSERT(memory.memPools() == 2); - TS_ASSERT(memory.memFree(bufA)); - bool low2 = memory.lowMemory(5,5*1024*1024); - TS_ASSERT(!low2); - TS_ASSERT(memory.memFree(bufA)); - - //We should be able to see that a chunk enters and exits the free - //state - char *mem2 = (char*)memory.alloc_mem(10*1024*1024); - TS_ASSERT(mem2); - TS_ASSERT(!memory.memFree(bufA)); - memory.dealloc_mem(mem2); - TS_ASSERT(memory.memFree(bufA)); - mem2 = (char*)memory.alloc_mem(10*1024*1024); - char *mem3 = (char*)memory.alloc_mem(10*1024*1024); - TS_ASSERT(mem3); - memory.dealloc_mem(mem2); - TS_ASSERT(!memory.memFree(bufA)); - TS_ASSERT(memory.freePools() == 0); - memory.dealloc_mem(mem3); - TS_ASSERT(memory.memFree(bufA)); - TS_ASSERT(memory.freePools() == 1); - - //Observe that adding another pool superficially works - memory.addMemory(bufB, N); - TS_ASSERT(memory.freePools() == 2); - - //delete [] bufA; - //delete [] bufB; - } - -}; diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt @@ -3,72 +3,51 @@ function(cp_script script_name) ${CMAKE_CURRENT_BINARY_DIR}/${script_name} COPYONLY) endfunction() +function(quick_test test_name link) + add_executable(${test_name} "${test_name}.cpp") + add_test(NAME ${test_name} + COMMAND ${test_name}) + target_link_libraries(${test_name} ${link} ${ARGN}) +endfunction() + #for tests looking for files stored in the source dir add_definitions(-DSOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") -CXXTEST_ADD_TEST(ControllerTest ControllerTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ControllerTest.h) -CXXTEST_ADD_TEST(EchoTest EchoTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/EchoTest.h) -#CXXTEST_ADD_TEST(SampleTest SampleTest.h) -CXXTEST_ADD_TEST(MicrotonalTest MicrotonalTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MicrotonalTest.h) -CXXTEST_ADD_TEST(XMLwrapperTest XMLwrapper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/XMLwrapperTest.h) -CXXTEST_ADD_TEST(ADnoteTest AdNoteTest.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/AdNoteTest.h) -CXXTEST_ADD_TEST(SUBnoteTest SubNoteTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/SubNoteTest.h) -CXXTEST_ADD_TEST(OscilGenTest OscilGenTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/OscilGenTest.h) -CXXTEST_ADD_TEST(RandTest RandTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RandTest.h) -CXXTEST_ADD_TEST(PADnoteTest PadNoteTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/PadNoteTest.h) -CXXTEST_ADD_TEST(PluginTest PluginTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/PluginTest.h) -CXXTEST_ADD_TEST(MsgParseTest MsgParseTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MsgParseTest.h) -CXXTEST_ADD_TEST(MiddlewareTest MiddlewareTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MiddlewareTest.h) -CXXTEST_ADD_TEST(MessageTest MessageTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MessageTest.h) -CXXTEST_ADD_TEST(UnisonTest UnisonTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/UnisonTest.h) -CXXTEST_ADD_TEST(MqTest MqTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MqTest.h) -CXXTEST_ADD_TEST(WatchTest WatchTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/WatchTest.h) -#CXXTEST_ADD_TEST(RtAllocTest RtAllocTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RtAllocTest.h) -CXXTEST_ADD_TEST(AllocatorTest AllocatorTest.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/AllocatorTest.h) -CXXTEST_ADD_TEST(EffectTest EffectTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/EffectTest.h) -CXXTEST_ADD_TEST(KitTest KitTest.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/KitTest.h) -CXXTEST_ADD_TEST(MemoryStressTest MemoryStressTest.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/MemoryStressTest.h) -CXXTEST_ADD_TEST(TriggerTest TriggerTest.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/TriggerTest.h) - #Extra libraries added to make test and full compilation use the same library #links for quirky compilers set(test_lib zynaddsubfx_core ${GUI_LIBRARIES} ${ZLIB_LIBRARY} ${FFTW_LIBRARIES} ${MXML_LIBRARIES} pthread "-Wl,--no-as-needed -lpthread") message(STATUS "Linking tests with: ${test_lib}") -target_link_libraries(ADnoteTest ${test_lib}) -target_link_libraries(SUBnoteTest ${test_lib}) -target_link_libraries(ControllerTest ${test_lib}) -target_link_libraries(EchoTest ${test_lib}) -target_link_libraries(MicrotonalTest ${test_lib}) -target_link_libraries(OscilGenTest ${test_lib}) -target_link_libraries(XMLwrapperTest ${test_lib}) -target_link_libraries(RandTest ${test_lib}) -target_link_libraries(PADnoteTest ${test_lib}) -target_link_libraries(MqTest ${test_lib}) -target_link_libraries(WatchTest ${test_lib}) -target_link_libraries(TriggerTest ${test_lib}) -target_link_libraries(PluginTest zynaddsubfx_core zynaddsubfx_nio - zynaddsubfx_gui_bridge - ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}) -target_link_libraries(MsgParseTest ${test_lib}) -target_link_libraries(MiddlewareTest zynaddsubfx_core zynaddsubfx_nio - zynaddsubfx_gui_bridge - ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}) -target_link_libraries(MessageTest zynaddsubfx_core zynaddsubfx_nio - zynaddsubfx_gui_bridge - ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}) -target_link_libraries(UnisonTest ${test_lib}) -#target_link_libraries(RtAllocTest ${test_lib}) -target_link_libraries(AllocatorTest ${test_lib}) -target_link_libraries(KitTest ${test_lib}) -target_link_libraries(MemoryStressTest ${test_lib}) -target_link_libraries(EffectTest ${test_lib}) + +quick_test(AdNoteTest ${test_lib}) +quick_test(AllocatorTest ${test_lib}) +quick_test(ControllerTest ${test_lib}) +quick_test(EchoTest ${test_lib}) +quick_test(EffectTest ${test_lib}) +quick_test(KitTest ${test_lib}) +quick_test(MemoryStressTest ${test_lib}) +quick_test(MicrotonalTest ${test_lib}) +quick_test(MsgParseTest ${test_lib}) +quick_test(MqTest ${test_lib}) +quick_test(OscilGenTest ${test_lib}) +quick_test(PadNoteTest ${test_lib}) +quick_test(RandTest ${test_lib}) +quick_test(SubNoteTest ${test_lib}) +quick_test(TriggerTest ${test_lib}) +quick_test(UnisonTest ${test_lib}) +quick_test(WatchTest ${test_lib}) +quick_test(XMLwrapperTest ${test_lib}) + +quick_test(PluginTest zynaddsubfx_core zynaddsubfx_nio + zynaddsubfx_gui_bridge + ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}) +quick_test(MiddlewareTest zynaddsubfx_core zynaddsubfx_nio + zynaddsubfx_gui_bridge + ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}) +quick_test(MessageTest zynaddsubfx_core zynaddsubfx_nio + zynaddsubfx_gui_bridge + ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}) #Testbed app add_executable(ins-test InstrumentStats.cpp) @@ -86,6 +65,3 @@ target_link_libraries(save-osc ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}) #this will be replaced with a for loop when the code will get more stable: add_test(SaveOsc save-osc ${CMAKE_CURRENT_SOURCE_DIR}/../../instruments/examples/Arpeggio\ 1.xmz) - -#message(STATUS "Plugin Test ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}") - diff --git a/src/Tests/ControllerTest.cpp b/src/Tests/ControllerTest.cpp @@ -0,0 +1,79 @@ +/* + ZynAddSubFX - a software synthesizer + + ControllerTest.h - CxxTest for Params/Controller + Copyright (C) 2009-2011 Mark McCurry + Author: Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ +#include "test-suite.h" +#include <cmath> +#include <iostream> +#include "../Params/Controller.h" +#include "../globals.h" +#include "../Misc/Time.h" +using namespace zyn; + +SYNTH_T *synth; + +class ControllerTest +{ + public: + void setUp() { + synth = new SYNTH_T; + AbsTime time(*synth); + testCtl = new Controller(*synth, &time); + } + + void tearDown() { + delete testCtl; + delete synth; + } + + + void testPortamentoRange() { + //Initialize portamento + testCtl->setportamento(127); + testCtl->portamento.time = 127; + testCtl->initportamento(log2f(40.0f), log2f(400.0f), false); + //Bounds Check + while(testCtl->portamento.used) { + TS_ASSERT((0.0f <= testCtl->portamento.x) + && (testCtl->portamento.x <= 1.0f)); + TS_ASSERT((log2f(0.1f) <= testCtl->portamento.freqdelta_log2) + && (testCtl->portamento.freqdelta_log2 <= log2f(1.0f))); + testCtl->updateportamento(); + } + TS_ASSERT((0.0f <= testCtl->portamento.x) + && (testCtl->portamento.x <= 1.0f)); + TS_ASSERT((log2f(0.1f) <= testCtl->portamento.freqdelta_log2) + && (testCtl->portamento.freqdelta_log2 <= log2f(1.0f))); + } + + void testPortamentoValue() { + testCtl->setportamento(127); + testCtl->portamento.time = 127; + testCtl->initportamento(log2f(40.0f), log2f(400.0f), false); + int i; + for(i = 0; i < 10; ++i) + testCtl->updateportamento(); + //Assert that the numbers are the same as they were at release + TS_ASSERT_DELTA(testCtl->portamento.x, 0.0290249f, 0.000001f); + TS_ASSERT_DELTA(testCtl->portamento.freqdelta_log2, -3.2255092, 0.000001f); + } + + private: + Controller *testCtl; +}; + +int main() +{ + ControllerTest test; + RUN_TEST(testPortamentoRange); + RUN_TEST(testPortamentoValue); + return test_summary(); +} diff --git a/src/Tests/ControllerTest.h b/src/Tests/ControllerTest.h @@ -1,70 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - ControllerTest.h - CxxTest for Params/Controller - Copyright (C) 2009-2011 Mark McCurry - Author: Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ -#include <cxxtest/TestSuite.h> -#include <iostream> -#include "../Params/Controller.h" -#include "../globals.h" -#include "../Misc/Time.h" -using namespace zyn; - -SYNTH_T *synth; - -class ControllerTest:public CxxTest::TestSuite -{ - public: - void setUp() { - synth = new SYNTH_T; - AbsTime time(*synth); - testCtl = new Controller(*synth, &time); - } - - void tearDown() { - delete testCtl; - delete synth; - } - - - void testPortamentoRange() { - //Initialize portamento - testCtl->setportamento(127); - testCtl->portamento.time = 127; - testCtl->initportamento(log2f(40.0f), log2f(400.0f), false); - //Bounds Check - while(testCtl->portamento.used) { - TS_ASSERT((0.0f <= testCtl->portamento.x) - && (testCtl->portamento.x <= 1.0f)); - TS_ASSERT((log2f(0.1f) <= testCtl->portamento.freqdelta_log2) - && (testCtl->portamento.freqdelta_log2 <= log2f(1.0f))); - testCtl->updateportamento(); - } - TS_ASSERT((0.0f <= testCtl->portamento.x) - && (testCtl->portamento.x <= 1.0f)); - TS_ASSERT((log2f(0.1f) <= testCtl->portamento.freqdelta_log2) - && (testCtl->portamento.freqdelta_log2 <= log2f(1.0f))); - } - - void testPortamentoValue() { - testCtl->setportamento(127); - testCtl->portamento.time = 127; - testCtl->initportamento(log2f(40.0f), log2f(400.0f), false); - int i; - for(i = 0; i < 10; ++i) - testCtl->updateportamento(); - //Assert that the numbers are the same as they were at release - TS_ASSERT_DELTA(testCtl->portamento.x, 0.0290249f, 0.000001f) - TS_ASSERT_DELTA(testCtl->portamento.freqdelta_log2, -3.2255092, 0.000001f) - } - - private: - Controller *testCtl; -}; diff --git a/src/Tests/EchoTest.cpp b/src/Tests/EchoTest.cpp @@ -0,0 +1,132 @@ +/* + ZynAddSubFX - a software synthesizer + + EchoTest.h - CxxTest for Effect/Echo + Copyright (C) 2009-2011 Mark McCurry + Copyright (C) 2009 Harald Hvaal + Authors: Mark McCurry, Harald Hvaal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ +#include "test-suite.h" +#include <cmath> +#include <cstdlib> +#include <iostream> +#include "../Effects/Echo.h" +#include "../Misc/Allocator.h" +#include "../globals.h" + +using namespace std; +using namespace zyn; + +SYNTH_T *synth; + +class EchoTest +{ + public: + void setUp() { + synth = new SYNTH_T; + outL = new float[synth->buffersize]; + for(int i = 0; i < synth->buffersize; ++i) + outL[i] = 0.0f; + outR = new float[synth->buffersize]; + for(int i = 0; i < synth->buffersize; ++i) + outR[i] = 0.0f; + input = new Stereo<float *>(new float[synth->buffersize], + new float[synth->buffersize]); + for(int i = 0; i < synth->buffersize; ++i) + input->l[i] = input->r[i] = 0.0f; + EffectParams pars{alloc,true, outL, outR, 0, 44100, 256, nullptr}; + testFX = new Echo(pars); + } + + void tearDown() { + delete[] input->r; + delete[] input->l; + delete input; + delete[] outL; + delete[] outR; + delete testFX; + delete synth; + } + + + void testInit() { + //Make sure that the output will be zero at start + //(given a zero input) + testFX->out(*input); + for(int i = 0; i < synth->buffersize; ++i) { + TS_ASSERT_DELTA(outL[i], 0.0f, 0.0001f); + TS_ASSERT_DELTA(outR[i], 0.0f, 0.0001f); + } + } + + void testClear() { + char DELAY = 2; + testFX->changepar(DELAY, 127); + + //flood with high input + for(int i = 0; i < synth->buffersize; ++i) + input->r[i] = input->l[i] = 1.0f; + + for(int i = 0; i < 500; ++i) + testFX->out(*input); + for(int i = 0; i < synth->buffersize; ++i) { + TS_ASSERT(outL[i] != 0.0f); + TS_ASSERT(outR[i] != 0.0f); + } + //After making sure the internal buffer has a nonzero value + //cleanup + //Then get the next output, which should be zereoed out if DELAY + //is large enough + testFX->cleanup(); + testFX->out(*input); + for(int i = 0; i < synth->buffersize; ++i) { + TS_ASSERT_DELTA(outL[i], 0.0f, 0.0001f); + TS_ASSERT_DELTA(outR[i], 0.0f, 0.0001f); + } + } + //Insures that the proper decay occurs with high feedback + void testDecaywFb() { + //flood with high input + for(int i = 0; i < synth->buffersize; ++i) + input->r[i] = input->l[i] = 1.0f; + char FEEDBACK = 5; + testFX->changepar(FEEDBACK, 127); + for(int i = 0; i < 100; ++i) + testFX->out(*input); + for(int i = 0; i < synth->buffersize; ++i) { + TS_ASSERT(outL[i] != 0.0f); + TS_ASSERT(outR[i] != 0.0f); + } + float amp = abs(outL[0] + outR[0]) / 2; + //reset input to zero + for(int i = 0; i < synth->buffersize; ++i) + input->r[i] = input->l[i] = 0.0f; + + //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(abs(outL[0] + outR[0]) / 2 <= amp); + } + + + private: + Stereo<float *> *input; + float *outR, *outL; + Echo *testFX; + Alloc alloc; +}; + +int main() +{ + tap_quiet = 1; + EchoTest test; + RUN_TEST(testInit); + RUN_TEST(testClear); + RUN_TEST(testDecaywFb); + return test_summary(); +} diff --git a/src/Tests/EchoTest.h b/src/Tests/EchoTest.h @@ -1,122 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - EchoTest.h - CxxTest for Effect/Echo - Copyright (C) 2009-2011 Mark McCurry - Copyright (C) 2009 Harald Hvaal - Authors: Mark McCurry, Harald Hvaal - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ -#include <cxxtest/TestSuite.h> -#include <cmath> -#include <cstdlib> -#include <iostream> -#include "../Effects/Echo.h" -#include "../Misc/Allocator.h" -#include "../globals.h" - -using namespace std; -using namespace zyn; - -SYNTH_T *synth; - -class EchoTest:public CxxTest::TestSuite -{ - public: - void setUp() { - synth = new SYNTH_T; - outL = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - outL[i] = 0.0f; - outR = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - outR[i] = 0.0f; - input = new Stereo<float *>(new float[synth->buffersize], - new float[synth->buffersize]); - for(int i = 0; i < synth->buffersize; ++i) - input->l[i] = input->r[i] = 0.0f; - EffectParams pars{alloc,true, outL, outR, 0, 44100, 256, nullptr}; - testFX = new Echo(pars); - } - - void tearDown() { - delete[] input->r; - delete[] input->l; - delete input; - delete[] outL; - delete[] outR; - delete testFX; - delete synth; - } - - - void testInit() { - //Make sure that the output will be zero at start - //(given a zero input) - testFX->out(*input); - for(int i = 0; i < synth->buffersize; ++i) { - TS_ASSERT_DELTA(outL[i], 0.0f, 0.0001f); - TS_ASSERT_DELTA(outR[i], 0.0f, 0.0001f); - } - } - - void testClear() { - char DELAY = 2; - testFX->changepar(DELAY, 127); - - //flood with high input - for(int i = 0; i < synth->buffersize; ++i) - input->r[i] = input->l[i] = 1.0f; - - for(int i = 0; i < 500; ++i) - testFX->out(*input); - for(int i = 0; i < synth->buffersize; ++i) { - TS_ASSERT_DIFFERS(outL[i], 0.0f); - TS_ASSERT_DIFFERS(outR[i], 0.0f) - } - //After making sure the internal buffer has a nonzero value - //cleanup - //Then get the next output, which should be zereoed out if DELAY - //is large enough - testFX->cleanup(); - testFX->out(*input); - for(int i = 0; i < synth->buffersize; ++i) { - TS_ASSERT_DELTA(outL[i], 0.0f, 0.0001f); - TS_ASSERT_DELTA(outR[i], 0.0f, 0.0001f); - } - } - //Insures that the proper decay occurs with high feedback - void testDecaywFb() { - //flood with high input - for(int i = 0; i < synth->buffersize; ++i) - input->r[i] = input->l[i] = 1.0f; - char FEEDBACK = 5; - testFX->changepar(FEEDBACK, 127); - for(int i = 0; i < 100; ++i) - testFX->out(*input); - for(int i = 0; i < synth->buffersize; ++i) { - TS_ASSERT_DIFFERS(outL[i], 0.0f); - TS_ASSERT_DIFFERS(outR[i], 0.0f) - } - float amp = abs(outL[0] + outR[0]) / 2; - //reset input to zero - for(int i = 0; i < synth->buffersize; ++i) - input->r[i] = input->l[i] = 0.0f; - - //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_EQUALS(abs(outL[0] + outR[0]) / 2, amp); - } - - - private: - Stereo<float *> *input; - float *outR, *outL; - Echo *testFX; - Alloc alloc; -}; diff --git a/src/Tests/EffectTest.cpp b/src/Tests/EffectTest.cpp @@ -0,0 +1,95 @@ +/* + ZynAddSubFX - a software synthesizer + + EffectTest.h - CxxTest for General Effect Stuff + Copyright (C) 2015 Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ +#include "test-suite.h" +#include <cmath> +#include <cstdio> +#include "../Misc/Allocator.h" +#include "../Misc/Stereo.h" +#include "../Effects/EffectMgr.h" +#include "../Effects/Reverb.h" +#include "../Effects/Echo.h" +#include "../globals.h" +using namespace zyn; + +SYNTH_T *synth; + +class EffectTest +{ + public: + void setUp() { + synth = new SYNTH_T; + alloc = new AllocatorClass; + mgr = new EffectMgr(*alloc, *synth, true); + } + + void tearDown() { + delete mgr; + delete alloc; + delete synth; + } + + void testInit() { + TS_ASSERT_EQUAL_INT(mgr->nefx, 0); + mgr->changeeffect(1); + TS_ASSERT_EQUAL_INT(mgr->nefx, 1); + assert_ptr_eq(mgr->efx, nullptr, + "nothing before init", __LINE__); + mgr->init(); + TS_NON_NULL(mgr->efx); + } + + void testClear() { + mgr->changeeffect(1); + mgr->init(); + TS_NON_NULL(mgr->efx); + mgr->changeeffect(0); + mgr->init(); + assert_ptr_eq(mgr->efx, nullptr, + "nothing after clearing", __LINE__); + } + + void testSwap() { + //Initially the effect is NULL + assert_ptr_eq(mgr->efx, nullptr, + "initially null", __LINE__); + + //A Reverb is selected + mgr->changeeffect(1); + mgr->init(); + TS_NON_NULL(dynamic_cast<Reverb*>(mgr->efx)); + assert_ptr_eq(dynamic_cast<Echo*>(mgr->efx), + nullptr, + "not an echo", __LINE__); + + //An Echo is selected + mgr->changeeffect(2); + mgr->init(); + assert_ptr_eq(dynamic_cast<Reverb*>(mgr->efx), + nullptr, + "not a reverb", __LINE__); + TS_NON_NULL(dynamic_cast<Echo*>(mgr->efx)); + } + + private: + EffectMgr *mgr; + Allocator *alloc; + SYNTH_T *synth; +}; + +int main() +{ + EffectTest test; + RUN_TEST(testInit); + RUN_TEST(testClear); + RUN_TEST(testSwap); + return test_summary(); +} diff --git a/src/Tests/EffectTest.h b/src/Tests/EffectTest.h @@ -1,79 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - EffectTest.h - CxxTest for General Effect Stuff - Copyright (C) 2015 Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ -#include <cxxtest/TestSuite.h> -#include <cmath> -#include <cstdio> -#include "../Misc/Allocator.h" -#include "../Misc/Stereo.h" -#include "../Effects/EffectMgr.h" -#include "../Effects/Reverb.h" -#include "../Effects/Echo.h" -#include "../globals.h" -using namespace zyn; - -SYNTH_T *synth; - -class EchoTest:public CxxTest::TestSuite -{ - public: - void setUp() { - synth = new SYNTH_T; - alloc = new AllocatorClass; - mgr = new EffectMgr(*alloc, *synth, true); - } - - void tearDown() { - delete mgr; - delete alloc; - delete synth; - } - - void testInit() { - TS_ASSERT_EQUALS(mgr->nefx, 0); - mgr->changeeffect(1); - TS_ASSERT_EQUALS(mgr->nefx, 1); - TS_ASSERT_EQUALS(mgr->efx, nullptr); - mgr->init(); - TS_ASSERT_DIFFERS(mgr->efx, nullptr); - } - - void testClear() { - mgr->changeeffect(1); - mgr->init(); - TS_ASSERT_DIFFERS(mgr->efx, nullptr); - mgr->changeeffect(0); - mgr->init(); - TS_ASSERT_EQUALS(mgr->efx, nullptr); - } - - void testSwap() { - //Initially the effect is NULL - TS_ASSERT_EQUALS(mgr->efx, nullptr); - - //A Reverb is selected - mgr->changeeffect(1); - mgr->init(); - TS_ASSERT_DIFFERS(dynamic_cast<Reverb*>(mgr->efx), nullptr); - TS_ASSERT_EQUALS(dynamic_cast<Echo*>(mgr->efx), nullptr); - - //An Echo is selected - mgr->changeeffect(2); - mgr->init(); - TS_ASSERT_EQUALS(dynamic_cast<Reverb*>(mgr->efx), nullptr); - TS_ASSERT_DIFFERS(dynamic_cast<Echo*>(mgr->efx), nullptr); - } - - private: - EffectMgr *mgr; - Allocator *alloc; - SYNTH_T *synth; -}; diff --git a/src/Tests/KitTest.cpp b/src/Tests/KitTest.cpp @@ -0,0 +1,795 @@ +/* + ZynAddSubFX - a software synthesizer + + KitTest.h - Test For Note Allocation Under Kits + Copyright (C) 2016 Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ +#include "test-suite.h" +#include <cmath> +#include <cstring> +#include <cstdlib> +#include <iostream> +#include "../Misc/Time.h" +#include "../Misc/Allocator.h" +#include "../DSP/FFTwrapper.h" +#include "../Misc/Microtonal.h" +#define private public +#define protected public +#include "../Synth/SynthNote.h" +#include "../Misc/Part.h" +#include "../globals.h" + +using namespace std; +using namespace zyn; + +SYNTH_T *synth; +int dummy=0; + +#define SUSTAIN_BIT 0x04 +enum PrivateNoteStatus { + KEY_OFF = 0x00, + KEY_PLAYING = 0x01, + KEY_RELEASED_AND_SUSTAINED = 0x02, + KEY_RELEASED = 0x03 +}; + + +class KitTest +{ + private: + Alloc alloc; + FFTwrapper fft; + Microtonal microtonal; + Part *part; + AbsTime *time; + float *outL, *outR; + public: + KitTest() + :fft(512), microtonal(dummy) + {} + void setUp() { + synth = new SYNTH_T; + time = new AbsTime(*synth); + outL = new float[synth->buffersize]; + outR = new float[synth->buffersize]; + memset(outL, 0, synth->bufferbytes); + memset(outR, 0, synth->bufferbytes); + + + part = new Part(alloc, *synth, *time, dummy, dummy, &microtonal, &fft); + } + + //Standard poly mode with sustain + void testSustainCase1() { + //enable sustain + part->ctl.setsustain(127); + + part->NoteOn(64, 127, 0); + part->NoteOn(64, 127, 0); + part->NoteOff(64); + + //first note has moved to release state + //second note has moved to sustain state + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=64, + .sendto=0, + .size=1, + .status=KEY_RELEASED|SUSTAIN_BIT, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=64, + .sendto=0, + .size=1, + .status=KEY_RELEASED_AND_SUSTAINED, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + } + + void testSustainCase2() { + //enable sustain + part->ctl.setsustain(127); + + part->NoteOn(64, 127, 0); + part->NoteOff(64); + part->NoteOn(64, 127, 0); + + //first note has moved to release state + //second note has stayed in playing state + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=64, + .sendto=0, + .size=1, + .status=KEY_RELEASED|SUSTAIN_BIT, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=64, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + } + + void testMonoSustain() { + //enable sustain + part->ctl.setsustain(127); + part->Ppolymode = false; + + part->NoteOn(64, 127, 0); + part->NoteOff(64); + part->NoteOn(65, 127, 0); + + part->notePool.dump(); + + //first note has moved to release state + //second note has stayed in playing state + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=64, + .sendto=0, + .size=1, + .status=KEY_RELEASED, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + } + + //Enumerate cases of: + //Legato = {disabled,enabled} + //Mono = {disabled, enabled} + //Kit = {off, normal, single} + //ignore legato=enabled, mono=enabled + + //No Kit + void testNoKitNoLegatoNoMono() { + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=64, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + } + + void testNoKitYesLegatoNoMono() { + part->Ppolymode = false; + part->Plegatomode = true; + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + + TS_NON_NULL(part->notePool.sdesc[0].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].kit, 0); + + TS_NON_NULL(part->notePool.sdesc[1].note); + if(part->notePool.sdesc[1].note) + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].note->legato.silent, true); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].kit, 0); + } + + void testNoKitNoLegatoYesMono() { + part->Ppolymode = false; + part->Plegatomode = false; + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=64, + .sendto=0, + .size=1, + .status=KEY_RELEASED, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + + TS_NON_NULL(part->notePool.sdesc[0].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].kit, 0); + + TS_NON_NULL(part->notePool.sdesc[1].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].kit, 0); + } + + //Normal Kit + //Three patches that overlap give an overlapping response + void testYesKitNoLegatoNoMono() { + part->setkititemstatus(1, true); + part->setkititemstatus(2, true); + part->kit[1].Padenabled = true; + part->kit[2].Padenabled = true; + part->kit[2].Pmaxkey = 32; + part->Pkitmode = 1; + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + + part->notePool.dump(); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=64, + .sendto=0, + .size=2, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=2, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + + TS_NON_NULL(part->notePool.sdesc[0].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].kit, 0); + + TS_NON_NULL(part->notePool.sdesc[1].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].kit, 1); + + TS_NON_NULL(part->notePool.sdesc[2].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[2].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[2].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[2].kit, 0); + + TS_NON_NULL(part->notePool.sdesc[3].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[3].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[3].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[3].kit, 1); + + assert_ptr_eq(part->notePool.sdesc[4].note, + nullptr, + "note free", __LINE__); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[4].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[4].kit, 0); + } + + void testYesKitYesLegatoNoMono() { + part->setkititemstatus(1, true); + part->setkititemstatus(2, true); + part->kit[1].Padenabled = true; + part->kit[2].Padenabled = true; + part->kit[2].Pmaxkey = 32; + part->Pkitmode = 1; + part->Ppolymode = false; + part->Plegatomode = true; + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + + part->notePool.dump(); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=2, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=2, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + + TS_NON_NULL(part->notePool.sdesc[0].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].kit, 0); + + TS_NON_NULL(part->notePool.sdesc[1].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].kit, 1); + + TS_NON_NULL(part->notePool.sdesc[2].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[2].note->legato.silent, true); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[2].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[2].kit, 0); + + TS_NON_NULL(part->notePool.sdesc[3].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[3].note->legato.silent, true); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[3].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[3].kit, 1); + + assert_ptr_eq(part->notePool.sdesc[4].note, + nullptr, + "note free", __LINE__); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[4].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[4].kit, 0); + } + + void testYesKitNoLegatoYesMono() { + part->setkititemstatus(1, true); + part->setkititemstatus(2, true); + part->kit[1].Padenabled = true; + part->kit[2].Padenabled = true; + part->kit[2].Pmaxkey = 32; + part->Pkitmode = 1; + part->Ppolymode = false; + part->Plegatomode = false; + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + + part->notePool.dump(); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=64, + .sendto=0, + .size=2, + .status=KEY_RELEASED, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=2, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + + TS_NON_NULL(part->notePool.sdesc[0].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].kit, 0); + + TS_NON_NULL(part->notePool.sdesc[1].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].kit, 1); + + TS_NON_NULL(part->notePool.sdesc[2].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[2].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[2].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[2].kit, 0); + + TS_NON_NULL(part->notePool.sdesc[3].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[3].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[3].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[3].kit, 1); + + assert_ptr_eq(part->notePool.sdesc[4].note, + nullptr, + "note free", __LINE__); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[4].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[4].kit, 0); + } + + //Single Kit + void testSingleKitNoLegatoNoMono() { + part->setkititemstatus(1, true); + part->setkititemstatus(2, true); + part->kit[1].Padenabled = true; + part->kit[2].Padenabled = true; + part->kit[2].Pmaxkey = 32; + part->Pkitmode = 2; + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + + part->notePool.dump(); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=64, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + + TS_NON_NULL(part->notePool.sdesc[0].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].kit, 0); + + TS_NON_NULL(part->notePool.sdesc[1].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].kit, 0); + + assert_ptr_eq(part->notePool.sdesc[2].note, + nullptr, + "note free", __LINE__); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[2].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[2].kit, 0); + } + + void testSingleKitYesLegatoNoMono() { + part->setkititemstatus(1, true); + part->setkititemstatus(2, true); + part->kit[1].Padenabled = true; + part->kit[2].Padenabled = true; + part->kit[2].Pmaxkey = 32; + part->Pkitmode = 2; + part->Ppolymode = false; + part->Plegatomode = true; + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + + TS_NON_NULL(part->notePool.sdesc[0].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].kit, 0); + + TS_NON_NULL(part->notePool.sdesc[1].note); + if(part->notePool.sdesc[1].note) + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].note->legato.silent, true); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].kit, 0); + } + + void testSingleKitNoLegatoYesMono() { + part->setkititemstatus(1, true); + part->setkititemstatus(2, true); + part->kit[1].Padenabled = true; + part->kit[2].Padenabled = true; + part->kit[2].Pmaxkey = 32; + part->Pkitmode = 2; + part->Ppolymode = false; + part->Plegatomode = false; + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + + + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[0], + (NotePool::NoteDescriptor{ + .age=0, + .note=64, + .sendto=0, + .size=1, + .status=KEY_RELEASED, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[1], + (NotePool::NoteDescriptor{ + .age=0, + .note=65, + .sendto=0, + .size=1, + .status=KEY_PLAYING, + .legatoMirror=false})); + + TS_ASSERT_EQUAL_CPP(part->notePool.ndesc[2], + (NotePool::NoteDescriptor{ + .age=0, + .note=0, + .sendto=0, + .size=0, + .status=0, + .legatoMirror=false})); + + TS_NON_NULL(part->notePool.sdesc[0].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[0].kit, 0); + + TS_NON_NULL(part->notePool.sdesc[1].note); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].note->legato.silent, false); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].type, 0); + TS_ASSERT_EQUAL_INT(part->notePool.sdesc[1].kit, 0); + } + + void testKeyLimit(void) + { + auto &pool = part->notePool; + //Verify that without a key limit, several notes can be run + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + part->NoteOn(66, 127, 0); + part->NoteOn(67, 127, 0); + part->NoteOn(68, 127, 0); + + //Verify that notes are spawned as expected + TS_ASSERT_EQUAL_INT(pool.usedNoteDesc(), 5); + TS_ASSERT_EQUAL_INT(pool.usedSynthDesc(), 5); + + //Reset the part + part->monomemClear(); + pool.killAllNotes(); + + //Verify that notes are despawned + TS_ASSERT_EQUAL_INT(pool.usedNoteDesc(), 0); + TS_ASSERT_EQUAL_INT(pool.usedSynthDesc(), 0); + + //Enable keylimit + part->setkeylimit(3); + + //Replay notes + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + part->NoteOn(66, 127, 0); + part->NoteOn(67, 127, 0); + part->NoteOn(68, 127, 0); + + //Verify that notes are spawned as expected with limit + TS_ASSERT_EQUAL_INT(pool.getRunningNotes(), 3);//2 entombed + TS_ASSERT_EQUAL_INT(pool.usedNoteDesc(), 5); + TS_ASSERT_EQUAL_INT(pool.usedSynthDesc(), 5); + + //Reset the part + part->monomemClear(); + pool.killAllNotes(); + + //Verify that notes are despawned + TS_ASSERT_EQUAL_INT(pool.usedNoteDesc(), 0); + TS_ASSERT_EQUAL_INT(pool.usedSynthDesc(), 0); + + //Now to test note stealing + + //Replay notes + part->NoteOn(64, 127, 0); + part->NoteOn(65, 127, 0); + part->NoteOn(66, 127, 0); + + //Verify that note pool is full + TS_ASSERT_EQUAL_INT(pool.usedNoteDesc(), 3); + TS_ASSERT_EQUAL_INT(pool.usedSynthDesc(), 3); + + //Age the notes + pool.ndesc[1].age = 50; + pool.ndesc[2].age = 500; + + printf("-------------------------------------\n"); + + //Inject two more notes which should steal the note + //descriptors for #66 and #65 + part->NoteOn(67, 127, 0); + pool.cleanup(); + TS_ASSERT_EQUAL_INT(pool.ndesc[0].note, 64); + TS_ASSERT_EQUAL_INT(pool.ndesc[1].note, 65); + TS_ASSERT_EQUAL_INT(pool.ndesc[2].note, 66); + TS_ASSERT_EQUAL_INT(pool.ndesc[2].status, KEY_RELEASED); + TS_ASSERT_EQUAL_INT(pool.ndesc[3].note, 67); + + part->NoteOn(68, 127, 0); + + //Verify that note pool is still full and entombed + TS_ASSERT_EQUAL_INT(pool.usedNoteDesc(), 5); + TS_ASSERT_EQUAL_INT(pool.usedSynthDesc(), 5); + + //Check that the result is {64, 68, 67} + TS_ASSERT_EQUAL_INT(pool.ndesc[0].note, 64); + TS_ASSERT_EQUAL_INT(pool.ndesc[1].note, 65); + TS_ASSERT_EQUAL_INT(pool.ndesc[1].status, KEY_RELEASED); + TS_ASSERT_EQUAL_INT(pool.ndesc[2].note, 66); + TS_ASSERT_EQUAL_INT(pool.ndesc[2].status, KEY_RELEASED); + TS_ASSERT_EQUAL_INT(pool.ndesc[3].note, 67); + TS_ASSERT_EQUAL_INT(pool.ndesc[4].note, 68); + } + + void tearDown() { + delete part; + delete[] outL; + delete[] outR; + delete time; + delete synth; + } +}; + +int main() +{ + KitTest test; + RUN_TEST(testSustainCase1); + RUN_TEST(testSustainCase2); + RUN_TEST(testMonoSustain); + RUN_TEST(testNoKitNoLegatoNoMono); + RUN_TEST(testNoKitYesLegatoNoMono); + RUN_TEST(testNoKitNoLegatoYesMono); + RUN_TEST(testYesKitNoLegatoNoMono); + RUN_TEST(testYesKitYesLegatoNoMono); + RUN_TEST(testYesKitNoLegatoYesMono); + RUN_TEST(testSingleKitNoLegatoNoMono); + RUN_TEST(testSingleKitYesLegatoNoMono); + RUN_TEST(testSingleKitNoLegatoYesMono); + RUN_TEST(testKeyLimit); + return test_summary(); +} diff --git a/src/Tests/KitTest.h b/src/Tests/KitTest.h @@ -1,768 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - KitTest.h - Test For Note Allocation Under Kits - Copyright (C) 2016 Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ -#include <cxxtest/TestSuite.h> -#include <cmath> -#include <cstring> -#include <cstdlib> -#include <iostream> -#include "../Misc/Time.h" -#include "../Misc/Allocator.h" -#include "../DSP/FFTwrapper.h" -#include "../Misc/Microtonal.h" -#define private public -#define protected public -#include "../Synth/SynthNote.h" -#include "../Misc/Part.h" -#include "../globals.h" - -using namespace std; -using namespace zyn; - -SYNTH_T *synth; -int dummy=0; - -#define SUSTAIN_BIT 0x04 -enum PrivateNoteStatus { - KEY_OFF = 0x00, - KEY_PLAYING = 0x01, - KEY_RELEASED_AND_SUSTAINED = 0x02, - KEY_RELEASED = 0x03 -}; - - -class KitTest:public CxxTest::TestSuite -{ - private: - Alloc alloc; - FFTwrapper fft; - Microtonal microtonal; - Part *part; - AbsTime *time; - float *outL, *outR; - public: - KitTest() - :fft(512), microtonal(dummy) - {} - void setUp() { - synth = new SYNTH_T; - time = new AbsTime(*synth); - outL = new float[synth->buffersize]; - outR = new float[synth->buffersize]; - memset(outL, 0, synth->bufferbytes); - memset(outR, 0, synth->bufferbytes); - - - part = new Part(alloc, *synth, *time, dummy, dummy, &microtonal, &fft); - } - - //Standard poly mode with sustain - void testSustainCase1() { - //enable sustain - part->ctl.setsustain(127); - - part->NoteOn(64, 127, 0); - part->NoteOn(64, 127, 0); - part->NoteOff(64); - - //first note has moved to release state - //second note has moved to sustain state - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=64, - .sendto=0, - .size=1, - .status=KEY_RELEASED|SUSTAIN_BIT, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=64, - .sendto=0, - .size=1, - .status=KEY_RELEASED_AND_SUSTAINED, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - } - - void testSustainCase2() { - //enable sustain - part->ctl.setsustain(127); - - part->NoteOn(64, 127, 0); - part->NoteOff(64); - part->NoteOn(64, 127, 0); - - //first note has moved to release state - //second note has stayed in playing state - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=64, - .sendto=0, - .size=1, - .status=KEY_RELEASED|SUSTAIN_BIT, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=64, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - } - - void testMonoSustain() { - //enable sustain - part->ctl.setsustain(127); - part->Ppolymode = false; - - part->NoteOn(64, 127, 0); - part->NoteOff(64); - part->NoteOn(65, 127, 0); - - part->notePool.dump(); - - //first note has moved to release state - //second note has stayed in playing state - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=64, - .sendto=0, - .size=1, - .status=KEY_RELEASED, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - } - - //Enumerate cases of: - //Legato = {disabled,enabled} - //Mono = {disabled, enabled} - //Kit = {off, normal, single} - //ignore legato=enabled, mono=enabled - - //No Kit - void testNoKitNoLegatoNoMono() { - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=64, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - } - - void testNoKitYesLegatoNoMono() { - part->Ppolymode = false; - part->Plegatomode = true; - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - - TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr); - if(part->notePool.sdesc[1].note) - TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, true); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 0) - } - - void testNoKitNoLegatoYesMono() { - part->Ppolymode = false; - part->Plegatomode = false; - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=64, - .sendto=0, - .size=1, - .status=KEY_RELEASED, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - - TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 0) - } - - //Normal Kit - //Three patches that overlap give an overlapping response - void testYesKitNoLegatoNoMono() { - part->setkititemstatus(1, true); - part->setkititemstatus(2, true); - part->kit[1].Padenabled = true; - part->kit[2].Padenabled = true; - part->kit[2].Pmaxkey = 32; - part->Pkitmode = 1; - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - - part->notePool.dump(); - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=64, - .sendto=0, - .size=2, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=2, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - - TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 1) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[2].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[2].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[2].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[2].kit, 0) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[3].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[3].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[3].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[3].kit, 1) - - TS_ASSERT_EQUALS(part->notePool.sdesc[4].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[4].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[4].kit, 0) - } - - void testYesKitYesLegatoNoMono() { - part->setkititemstatus(1, true); - part->setkititemstatus(2, true); - part->kit[1].Padenabled = true; - part->kit[2].Padenabled = true; - part->kit[2].Pmaxkey = 32; - part->Pkitmode = 1; - part->Ppolymode = false; - part->Plegatomode = true; - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - - part->notePool.dump(); - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=2, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=2, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - - TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 1) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[2].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[2].note->legato.silent, true); - TS_ASSERT_EQUALS(part->notePool.sdesc[2].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[2].kit, 0) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[3].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[3].note->legato.silent, true); - TS_ASSERT_EQUALS(part->notePool.sdesc[3].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[3].kit, 1) - - TS_ASSERT_EQUALS(part->notePool.sdesc[4].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[4].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[4].kit, 0) - } - - void testYesKitNoLegatoYesMono() { - part->setkititemstatus(1, true); - part->setkititemstatus(2, true); - part->kit[1].Padenabled = true; - part->kit[2].Padenabled = true; - part->kit[2].Pmaxkey = 32; - part->Pkitmode = 1; - part->Ppolymode = false; - part->Plegatomode = false; - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - - part->notePool.dump(); - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=64, - .sendto=0, - .size=2, - .status=KEY_RELEASED, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=2, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - - TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 1) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[2].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[2].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[2].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[2].kit, 0) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[3].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[3].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[3].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[3].kit, 1) - - TS_ASSERT_EQUALS(part->notePool.sdesc[4].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[4].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[4].kit, 0) - } - - //Single Kit - void testSingleKitNoLegatoNoMono() { - part->setkititemstatus(1, true); - part->setkititemstatus(2, true); - part->kit[1].Padenabled = true; - part->kit[2].Padenabled = true; - part->kit[2].Pmaxkey = 32; - part->Pkitmode = 2; - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - - part->notePool.dump(); - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=64, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - - TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 0) - - TS_ASSERT_EQUALS(part->notePool.sdesc[2].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[2].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[2].kit, 0) - } - - void testSingleKitYesLegatoNoMono() { - part->setkititemstatus(1, true); - part->setkititemstatus(2, true); - part->kit[1].Padenabled = true; - part->kit[2].Padenabled = true; - part->kit[2].Pmaxkey = 32; - part->Pkitmode = 2; - part->Ppolymode = false; - part->Plegatomode = true; - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - - TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr); - if(part->notePool.sdesc[1].note) - TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, true); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 0) - } - - void testSingleKitNoLegatoYesMono() { - part->setkititemstatus(1, true); - part->setkititemstatus(2, true); - part->kit[1].Padenabled = true; - part->kit[2].Padenabled = true; - part->kit[2].Pmaxkey = 32; - part->Pkitmode = 2; - part->Ppolymode = false; - part->Plegatomode = false; - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - - - - TS_ASSERT_EQUALS(part->notePool.ndesc[0], - (NotePool::NoteDescriptor{ - .age=0, - .note=64, - .sendto=0, - .size=1, - .status=KEY_RELEASED, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[1], - (NotePool::NoteDescriptor{ - .age=0, - .note=65, - .sendto=0, - .size=1, - .status=KEY_PLAYING, - .legatoMirror=false})); - - TS_ASSERT_EQUALS(part->notePool.ndesc[2], - (NotePool::NoteDescriptor{ - .age=0, - .note=0, - .sendto=0, - .size=0, - .status=0, - .legatoMirror=false})); - - TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0) - - TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false); - TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0) - TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 0) - } - - void testKeyLimit(void) - { - auto &pool = part->notePool; - //Verify that without a key limit, several notes can be run - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - part->NoteOn(66, 127, 0); - part->NoteOn(67, 127, 0); - part->NoteOn(68, 127, 0); - - //Verify that notes are spawned as expected - TS_ASSERT_EQUALS(pool.usedNoteDesc(), 5); - TS_ASSERT_EQUALS(pool.usedSynthDesc(), 5); - - //Reset the part - part->monomemClear(); - pool.killAllNotes(); - - //Verify that notes are despawned - TS_ASSERT_EQUALS(pool.usedNoteDesc(), 0); - TS_ASSERT_EQUALS(pool.usedSynthDesc(), 0); - - //Enable keylimit - part->setkeylimit(3); - - //Replay notes - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - part->NoteOn(66, 127, 0); - part->NoteOn(67, 127, 0); - part->NoteOn(68, 127, 0); - - //Verify that notes are spawned as expected with limit - TS_ASSERT_EQUALS(pool.getRunningNotes(), 3);//2 entombed - TS_ASSERT_EQUALS(pool.usedNoteDesc(), 5); - TS_ASSERT_EQUALS(pool.usedSynthDesc(), 5); - - //Reset the part - part->monomemClear(); - pool.killAllNotes(); - - //Verify that notes are despawned - TS_ASSERT_EQUALS(pool.usedNoteDesc(), 0); - TS_ASSERT_EQUALS(pool.usedSynthDesc(), 0); - - //Now to test note stealing - - //Replay notes - part->NoteOn(64, 127, 0); - part->NoteOn(65, 127, 0); - part->NoteOn(66, 127, 0); - - //Verify that note pool is full - TS_ASSERT_EQUALS(pool.usedNoteDesc(), 3); - TS_ASSERT_EQUALS(pool.usedSynthDesc(), 3); - - //Age the notes - pool.ndesc[1].age = 50; - pool.ndesc[2].age = 500; - - printf("-------------------------------------\n"); - - //Inject two more notes which should steal the note - //descriptors for #66 and #65 - part->NoteOn(67, 127, 0); - pool.cleanup(); - TS_ASSERT_EQUALS(pool.ndesc[0].note, 64); - TS_ASSERT_EQUALS(pool.ndesc[1].note, 65); - TS_ASSERT_EQUALS(pool.ndesc[2].note, 66); - TS_ASSERT_EQUALS(pool.ndesc[2].status, KEY_RELEASED); - TS_ASSERT_EQUALS(pool.ndesc[3].note, 67); - - part->NoteOn(68, 127, 0); - - //Verify that note pool is still full and entombed - TS_ASSERT_EQUALS(pool.usedNoteDesc(), 5); - TS_ASSERT_EQUALS(pool.usedSynthDesc(), 5); - - //Check that the result is {64, 68, 67} - TS_ASSERT_EQUALS(pool.ndesc[0].note, 64); - TS_ASSERT_EQUALS(pool.ndesc[1].note, 65); - TS_ASSERT_EQUALS(pool.ndesc[1].status, KEY_RELEASED); - TS_ASSERT_EQUALS(pool.ndesc[2].note, 66); - TS_ASSERT_EQUALS(pool.ndesc[2].status, KEY_RELEASED); - TS_ASSERT_EQUALS(pool.ndesc[3].note, 67); - TS_ASSERT_EQUALS(pool.ndesc[4].note, 68); - } - - void tearDown() { - delete part; - delete[] outL; - delete[] outR; - delete time; - delete synth; - } -}; diff --git a/src/Tests/MemoryStressTest.cpp b/src/Tests/MemoryStressTest.cpp @@ -0,0 +1,116 @@ +/* + ZynAddSubFX - a software synthesizer + + AdNoteTest.h - CxxTest for Synth/ADnote + Copyright (C) 2009-2011 Mark McCurry + Copyright (C) 2009 Harald Hvaal + Authors: Mark McCurry, Harald Hvaal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ + + +#include "test-suite.h" +#include <iostream> +#include <fstream> +#include <ctime> +#include <string> +#include "../Misc/Master.h" +#include "../Misc/Util.h" +#include "../Misc/Allocator.h" +#include "../Synth/ADnote.h" +#include "../Params/Presets.h" +#include "../DSP/FFTwrapper.h" +#include "../globals.h" +using namespace zyn; + +SYNTH_T *synth; + +class MemoryStressTest +{ + public: + AbsTime *time; + FFTwrapper *fft; + ADnoteParameters *defaultPreset; + Controller *controller; + Alloc memory; + + void setUp() { + //First the sensible settings and variables that have to be set: + synth = new SYNTH_T; + synth->buffersize = 256; + //synth->alias(); + time = new AbsTime(*synth); + + fft = new FFTwrapper(synth->oscilsize); + //prepare the default settings + defaultPreset = new ADnoteParameters(*synth, fft, time); + + //Assert defaults + TS_ASSERT(!defaultPreset->VoicePar[1].Enabled); + + std::string instrument_filename = std::string(SOURCE_DIR) + "/guitar-adnote.xmz"; + std::cout << instrument_filename << std::endl; + + XMLwrapper wrap; + wrap.loadXMLfile(instrument_filename); + TS_ASSERT(wrap.enterbranch("MASTER")); + TS_ASSERT(wrap.enterbranch("PART", 0)); + TS_ASSERT(wrap.enterbranch("INSTRUMENT")); + TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT")); + TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT_ITEM", 0)); + TS_ASSERT(wrap.enterbranch("ADD_SYNTH_PARAMETERS")); + defaultPreset->getfromXML(wrap); + + //verify xml was loaded + TS_ASSERT(defaultPreset->VoicePar[1].Enabled); + + controller = new Controller(*synth, time); + + } + + void tearDown() { + delete controller; + delete defaultPreset; + delete fft; + FFT_cleanup(); + delete synth; + } + + void testManySimultaneousNotes() { + + unsigned char testnote = 42; + SynthParams pars{memory, *controller, *synth, *time, 120, 0, testnote / 12.0f, false, prng()}; + + std::vector<ADnote*> notes; + + for ( size_t note_idx = 0; note_idx < 1000; ++ note_idx ) { + try { + notes.push_back(new ADnote(defaultPreset, pars)); + } catch (std::exception & e) { +#if defined(DEBUG) + std::cerr << "couldn't push note #" << note_idx << std::endl; +#endif + } + } + + // If we made it that far, we managed to create many ADnotewithout sigsev + + for (auto note_ptr: notes) { + delete note_ptr; + } + + + } + +}; + +int main() +{ + MemoryStressTest test; + RUN_TEST(testManySimultaneousNotes); + return test_summary(); +} diff --git a/src/Tests/MemoryStressTest.h b/src/Tests/MemoryStressTest.h @@ -1,111 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - AdNoteTest.h - CxxTest for Synth/ADnote - Copyright (C) 2009-2011 Mark McCurry - Copyright (C) 2009 Harald Hvaal - Authors: Mark McCurry, Harald Hvaal - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ - - -#include <cxxtest/TestSuite.h> -#include <iostream> -#include <fstream> -#include <ctime> -#include <string> -#include "../Misc/Master.h" -#include "../Misc/Util.h" -#include "../Misc/Allocator.h" -#include "../Synth/ADnote.h" -#include "../Params/Presets.h" -#include "../DSP/FFTwrapper.h" -#include "../globals.h" -using namespace zyn; - -SYNTH_T *synth; - -class AdNoteTest:public CxxTest::TestSuite -{ - public: - ADnote *note; - AbsTime *time; - FFTwrapper *fft; - ADnoteParameters *defaultPreset; - Controller *controller; - Alloc memory; - - void setUp() { - //First the sensible settings and variables that have to be set: - synth = new SYNTH_T; - synth->buffersize = 256; - //synth->alias(); - time = new AbsTime(*synth); - - fft = new FFTwrapper(synth->oscilsize); - //prepare the default settings - defaultPreset = new ADnoteParameters(*synth, fft, time); - - //Assert defaults - TS_ASSERT(!defaultPreset->VoicePar[1].Enabled); - - std::string instrument_filename = std::string(SOURCE_DIR) + "/guitar-adnote.xmz"; - std::cout << instrument_filename << std::endl; - - XMLwrapper wrap; - wrap.loadXMLfile(instrument_filename); - TS_ASSERT(wrap.enterbranch("MASTER")); - TS_ASSERT(wrap.enterbranch("PART", 0)); - TS_ASSERT(wrap.enterbranch("INSTRUMENT")); - TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT")); - TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT_ITEM", 0)); - TS_ASSERT(wrap.enterbranch("ADD_SYNTH_PARAMETERS")); - defaultPreset->getfromXML(wrap); - - //verify xml was loaded - TS_ASSERT(defaultPreset->VoicePar[1].Enabled); - - controller = new Controller(*synth, time); - - } - - void tearDown() { - delete note; - delete controller; - delete defaultPreset; - delete fft; - FFT_cleanup(); - delete synth; - } - - void testManySimultaneousNotes() { - - unsigned char testnote = 42; - SynthParams pars{memory, *controller, *synth, *time, 120, 0, testnote / 12.0f, false, prng()}; - - std::vector<ADnote*> notes; - - for ( size_t note_idx = 0; note_idx < 1000; ++ note_idx ) { - try { - notes.push_back(new ADnote(defaultPreset, pars)); - } catch (std::exception & e) { -#if defined(DEBUG) - std::cerr << "couldn't push note #" << note_idx << std::endl; -#endif - } - } - - // If we made it that far, we managed to create many ADnotewithout sigsev - - for (auto note_ptr: notes) { - delete note_ptr; - } - - - } - -}; diff --git a/src/Tests/MessageTest.cpp b/src/Tests/MessageTest.cpp @@ -0,0 +1,367 @@ +/* + ZynAddSubFX - a software synthesizer + + PluginTest.h - CxxTest for embedding zyn + Copyright (C) 2013-2013 Mark McCurry + Authors: Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ +#include "test-suite.h" +#include <cmath> +#include <cstdlib> +#include <iostream> +#include <fstream> +#include <string> +#include <thread> +#include <rtosc/thread-link.h> +#include <unistd.h> +#include "../Misc/MiddleWare.h" +#include "../Misc/Master.h" +#include "../Misc/Part.h" +#include "../Misc/PresetExtractor.h" +#include "../Misc/PresetExtractor.cpp" +#include "../Misc/Util.h" +#include "../globals.h" +#include "../UI/NSM.H" +using namespace std; +using namespace zyn; + +class NSM_Client *nsm = 0; +MiddleWare *middleware = 0; + +char *instance_name=(char*)""; + +#define NUM_MIDDLEWARE 3 + +class MessageTest +{ + public: + Config config; + void setUp() { + synth = new SYNTH_T; + mw = new MiddleWare(std::move(*synth), &config); + ms = mw->spawnMaster(); + realtime = NULL; + } + + void tearDown() { + delete mw; + delete synth; + } + + void testKitEnable(void) + { + const char *msg = NULL; + mw->transmitMsg("/part0/kit0/Psubenabled", "T"); + TS_ASSERT(ms->uToB->hasNext()); + msg = ms->uToB->read(); + TS_ASSERT_EQUAL_STR("/part0/kit0/subpars-data", msg); + TS_ASSERT(ms->uToB->hasNext()); + msg = ms->uToB->read(); + TS_ASSERT_EQUAL_STR("/part0/kit0/Psubenabled", msg); + } + + void testBankCapture(void) + { + mw->transmitMsg("/bank/slot23", ""); + TS_ASSERT(!ms->uToB->hasNext()); + mw->transmitMsg("/bank/fake", ""); + TS_ASSERT(ms->uToB->hasNext()); + const char *msg = ms->uToB->read(); + TS_ASSERT_EQUAL_STR("/bank/fake", msg); + } + + void testOscCopyPaste(void) + { + //Enable pad synth + mw->transmitMsg("/part0/kit0/Ppadenabled", "T"); + + TS_ASSERT(ms->uToB->hasNext()); + ms->applyOscEvent(ms->uToB->read()); + TS_ASSERT(ms->uToB->hasNext()); + ms->applyOscEvent(ms->uToB->read()); + TS_ASSERT(!ms->uToB->hasNext()); + + auto &osc_src = *ms->part[0]->kit[0].adpars->VoicePar[0].FmGn; + auto &osc_dst = *ms->part[0]->kit[0].padpars->oscilgen; + auto &osc_oth = *ms->part[0]->kit[0].adpars->VoicePar[1].OscilGn; + + TS_ASSERT_EQUAL_INT(osc_src.Pbasefuncpar, 64); + osc_src.Pbasefuncpar = 32; + TS_ASSERT_EQUAL_INT(osc_src.Pbasefuncpar, 32); + + //Copy From ADsynth modulator + printf("====Copy From ADsynth modulator\n"); + start_realtime(); + mw->transmitMsg("/presets/copy", "s", "/part0/kit0/adpars/VoicePar0/FMSmp/"); + + TS_ASSERT_EQUAL_STR("Poscilgen", mw->getPresetsStore().clipboard.type.c_str()); + // a regex would be better here... + // hopefully, mxml will not change its whitespace behavior + assert_non_null(strstr(mw->getPresetsStore().clipboard.data.c_str(), "<par name=\"base_function_par\" value=\"32\" />"), + "base_function_par at right value", __LINE__); + + /* // better test this without string comparison: + { + XMLwrapper xml; + bool couldPutXml = xml.putXMLdata(mw->getPresetsStore().clipboard.data.c_str()); + TS_ASSERT(couldPutXml); + unsigned char copiedBasefuncPar = xml.getpar127("base_function_par", 0); + TS_ASSERT_EQUALS(copiedBasefuncPar, 32); + }*/ + + //printf("clipboard type: %s\n",mw->getPresetsStore().clipboard.type.c_str()); + //printf("clipboard data:\n%s\n",mw->getPresetsStore().clipboard.data.c_str()); + + TS_ASSERT_EQUAL_INT(osc_dst.Pbasefuncpar, 64); + TS_ASSERT_EQUAL_INT(osc_oth.Pbasefuncpar, 64); + + //Paste to PADsynth + printf("====Paste to PADsynth\n"); + mw->transmitMsg("/presets/paste", "s", "/part0/kit0/padpars/oscilgen/"); + + printf("====Paste to ADsynth\n"); + mw->transmitMsg("/presets/paste", "s", "/part0/kit0/adpars/VoicePar1/OscilSmp/"); + + stop_realtime(); + TS_ASSERT_EQUAL_INT(osc_dst.Pbasefuncpar, 32); + TS_ASSERT_EQUAL_INT(osc_oth.Pbasefuncpar, 32); + } + + + void start_realtime(void) + { + do_exit = false; + realtime = new std::thread([this](){ + int tries = 0; + while(tries < 10000) { + if(!ms->uToB->hasNext()) { + if(do_exit) + break; + + usleep(500); + continue; + } + const char *msg = ms->uToB->read(); + printf("RT: handling <%s>\n", msg); + ms->applyOscEvent(msg); + }}); + } + + void stop_realtime(void) + { + do_exit = true; + realtime->join(); + delete realtime; + realtime = NULL; + } + + void run_realtime(void) + { + start_realtime(); + stop_realtime(); + } + + void testMidiLearn(void) + { + mw->transmitMsg("/learn", "s", "/Pkeyshift"); + mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 108); + TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 64); + + //Perform a learning operation + + run_realtime(); //1. runs learning and identifies a CC to bind + mw->tick(); //2. produces new binding table + run_realtime(); //3. applies new binding table + + + //Verify that the learning actually worked + mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 13); + run_realtime(); + TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 13); + + mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 2); + run_realtime(); + TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 2); + + mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 0); + run_realtime(); + TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 0); + + mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 127); + run_realtime(); + TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 127); + } + + void testMidiLearnSave(void) + { + mw->transmitMsg("/learn", "s", "/Pkeyshift"); + mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 108); + + //param is at default until rt-thread is run + TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 64); + + + //Perform a learning operation + run_realtime(); + + //Verify binding affects control + TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 108); + + + printf("# Trying to save automations\n"); + start_realtime(); + mw->transmitMsg("/save_xlz", "s", "test-midi-learn.xlz"); + stop_realtime(); + + //Verify that some file exists + printf("# Verifying file exists\n"); + FILE *f = fopen("test-midi-learn.xlz", "r"); + assert_non_null(f, "test file exists", __LINE__); + + if(f) + fclose(f); + + printf("# Clearing automation\n"); + //Clear out state + mw->transmitMsg("/clear_xlz", ""); + //Send dummy message + mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 27); + run_realtime(); + + //Verify automation table is clear + TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 108); + + printf("# Loading automation\n"); + mw->transmitMsg("/load_xlz", "s", "test-midi-learn.xlz"); + //Send message + mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 28); + run_realtime(); + + //Verify automation table is restored + TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 28); + } + + void testLfoPaste(void) + { + start_realtime(); + ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand = 32; + TS_ASSERT_EQUAL_INT(ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand, 32); + + //Copy + mw->transmitMsg("/presets/copy", "s", "/part0/kit0/adpars/GlobalPar/FreqLfo/"); + + ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand = 99; + TS_ASSERT_EQUAL_INT(ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand, 99); + + //Paste + mw->transmitMsg("/presets/paste", "s", "/part0/kit0/adpars/GlobalPar/FreqLfo/"); + stop_realtime(); + + TS_ASSERT_EQUAL_INT(ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand, 32); + } + + void testPadPaste(void) + { + mw->transmitMsg("/part0/kit0/Ppadenabled", "T"); + run_realtime(); + + start_realtime(); + + auto &field1 = ms->part[0]->kit[0].padpars->PVolume; + auto &field2 = ms->part[0]->kit[0].padpars->oscilgen->Pfilterpar1; + field1 = 32; + TS_ASSERT_EQUAL_INT(field1, 32); + field2 = 35; + TS_ASSERT_EQUAL_INT(field2, 35); + + //Copy + mw->transmitMsg("/presets/copy", "s", "/part0/kit0/padpars/"); + + field1 = 99; + TS_ASSERT_EQUAL_INT(field1, 99); + field2 = 95; + TS_ASSERT_EQUAL_INT(field2, 95); + + //Paste + mw->transmitMsg("/presets/paste", "s", "/part0/kit0/padpars/"); + stop_realtime(); + + TS_ASSERT_EQUAL_INT(field1, 32); + TS_ASSERT_EQUAL_INT(field2, 35); + } + + void testFilterDepricated(void) + { + vector<string> v = {"Pfreq", "Pfreqtrack", "Pgain", "Pq"}; + for(size_t i=0; i<v.size(); ++i) { + string path = "/part0/kit0/adpars/GlobalPar/GlobalFilter/"+v[i]; + for(int j=0; j<128; ++j) { + mw->transmitMsg(path.c_str(), "i", j); //Set + mw->transmitMsg(path.c_str(), ""); //Get + } + + } + while(ms->uToB->hasNext()) { + const char *msg = ms->uToB->read(); + //printf("RT: handling <%s>\n", msg); + ms->applyOscEvent(msg); + } + + int id = 0; + int state = 0; + int value = 0; + // 0 - broadcast + // 1 - true value (set) + // 2 - expected value (get) + while(ms->bToU->hasNext()) { + const char *msg = ms->bToU->read(); + if(state == 0) { + TS_ASSERT_EQUAL_INT(rtosc_narguments(msg), 0U); + state = 1; + } else if(state == 1) { + TS_ASSERT_EQUAL_INT(rtosc_narguments(msg), 1U); + value = rtosc_argument(msg, 0).i; + state = 2; + } else if(state == 2) { + int val = rtosc_argument(msg, 0).i; + if(value != val) { + printf("%s - %d should equal %d\n", msg, value, val); + TS_ASSERT(0); + } + state = 0; + } + + (void) id; + //printf("Message #%d %s:%s\n", id++, msg, rtosc_argument_string(msg)); + //if(rtosc_narguments(msg)) + // printf(" %d\n", rtosc_argument(msg, 0).i); + } + } + + + private: + SYNTH_T *synth; + MiddleWare *mw; + Master *ms; + std::thread *realtime; + bool do_exit; +}; + +int main() +{ + MessageTest test; + RUN_TEST(testKitEnable); + RUN_TEST(testBankCapture); + RUN_TEST(testOscCopyPaste); + RUN_TEST(testMidiLearn); + RUN_TEST(testMidiLearnSave); + RUN_TEST(testLfoPaste); + RUN_TEST(testPadPaste); + RUN_TEST(testFilterDepricated); + return test_summary(); +} diff --git a/src/Tests/MessageTest.h b/src/Tests/MessageTest.h @@ -1,352 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - PluginTest.h - CxxTest for embedding zyn - Copyright (C) 2013-2013 Mark McCurry - Authors: Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ -#include <cxxtest/TestSuite.h> -#include <cmath> -#include <cstdlib> -#include <iostream> -#include <fstream> -#include <string> -#include <thread> -#include <rtosc/thread-link.h> -#include <unistd.h> -#include "../Misc/MiddleWare.h" -#include "../Misc/Master.h" -#include "../Misc/Part.h" -#include "../Misc/PresetExtractor.h" -#include "../Misc/PresetExtractor.cpp" -#include "../Misc/Util.h" -#include "../globals.h" -#include "../UI/NSM.H" -using namespace std; -using namespace zyn; - -class NSM_Client *nsm = 0; -MiddleWare *middleware = 0; - -char *instance_name=(char*)""; - -#define NUM_MIDDLEWARE 3 - -class MessageTest:public CxxTest::TestSuite -{ - public: - Config config; - void setUp() { - synth = new SYNTH_T; - mw = new MiddleWare(std::move(*synth), &config); - ms = mw->spawnMaster(); - realtime = NULL; - } - - void tearDown() { - delete mw; - delete synth; - } - - void testKitEnable(void) - { - const char *msg = NULL; - mw->transmitMsg("/part0/kit0/Psubenabled", "T"); - TS_ASSERT(ms->uToB->hasNext()); - msg = ms->uToB->read(); - TS_ASSERT_EQUALS(string("/part0/kit0/subpars-data"), msg); - TS_ASSERT(ms->uToB->hasNext()); - msg = ms->uToB->read(); - TS_ASSERT_EQUALS(string("/part0/kit0/Psubenabled"), msg); - } - - void testBankCapture(void) - { - mw->transmitMsg("/bank/slot23", ""); - TS_ASSERT(!ms->uToB->hasNext()); - mw->transmitMsg("/bank/fake", ""); - TS_ASSERT(ms->uToB->hasNext()); - const char *msg = ms->uToB->read(); - TS_ASSERT_EQUALS(string("/bank/fake"), msg); - } - - void testOscCopyPaste(void) - { - //Enable pad synth - mw->transmitMsg("/part0/kit0/Ppadenabled", "T"); - - TS_ASSERT(ms->uToB->hasNext()); - ms->applyOscEvent(ms->uToB->read()); - TS_ASSERT(ms->uToB->hasNext()); - ms->applyOscEvent(ms->uToB->read()); - TS_ASSERT(!ms->uToB->hasNext()); - - auto &osc_src = *ms->part[0]->kit[0].adpars->VoicePar[0].FmGn; - auto &osc_dst = *ms->part[0]->kit[0].padpars->oscilgen; - auto &osc_oth = *ms->part[0]->kit[0].adpars->VoicePar[1].OscilGn; - - TS_ASSERT_EQUALS(osc_src.Pbasefuncpar, 64); - osc_src.Pbasefuncpar = 32; - TS_ASSERT_EQUALS(osc_src.Pbasefuncpar, 32); - - //Copy From ADsynth modulator - printf("====Copy From ADsynth modulator\n"); - start_realtime(); - mw->transmitMsg("/presets/copy", "s", "/part0/kit0/adpars/VoicePar0/FMSmp/"); - - TS_ASSERT_EQUALS(mw->getPresetsStore().clipboard.type.c_str(), string("Poscilgen")); - // a regex would be better here... - // hopefully, mxml will not change its whitespace behavior - TS_ASSERT(strstr(mw->getPresetsStore().clipboard.data.c_str(), "<par name=\"base_function_par\" value=\"32\" />")); - - /* // better test this without string comparison: - { - XMLwrapper xml; - bool couldPutXml = xml.putXMLdata(mw->getPresetsStore().clipboard.data.c_str()); - TS_ASSERT(couldPutXml); - unsigned char copiedBasefuncPar = xml.getpar127("base_function_par", 0); - TS_ASSERT_EQUALS(copiedBasefuncPar, 32); - }*/ - - //printf("clipboard type: %s\n",mw->getPresetsStore().clipboard.type.c_str()); - //printf("clipboard data:\n%s\n",mw->getPresetsStore().clipboard.data.c_str()); - - TS_ASSERT_EQUALS(osc_dst.Pbasefuncpar, 64); - TS_ASSERT_EQUALS(osc_oth.Pbasefuncpar, 64); - - //Paste to PADsynth - printf("====Paste to PADsynth\n"); - mw->transmitMsg("/presets/paste", "s", "/part0/kit0/padpars/oscilgen/"); - - printf("====Paste to ADsynth\n"); - mw->transmitMsg("/presets/paste", "s", "/part0/kit0/adpars/VoicePar1/OscilSmp/"); - - stop_realtime(); - TS_ASSERT_EQUALS(osc_dst.Pbasefuncpar, 32); - TS_ASSERT_EQUALS(osc_oth.Pbasefuncpar, 32); - } - - - void start_realtime(void) - { - do_exit = false; - realtime = new std::thread([this](){ - int tries = 0; - while(tries < 10000) { - if(!ms->uToB->hasNext()) { - if(do_exit) - break; - - usleep(500); - continue; - } - const char *msg = ms->uToB->read(); - printf("RT: handling <%s>\n", msg); - ms->applyOscEvent(msg); - }}); - } - - void stop_realtime(void) - { - do_exit = true; - realtime->join(); - delete realtime; - realtime = NULL; - } - - void run_realtime(void) - { - start_realtime(); - stop_realtime(); - } - - void testMidiLearn(void) - { - mw->transmitMsg("/learn", "s", "/Pkeyshift"); - mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 108); - TS_ASSERT_EQUALS(ms->Pkeyshift, 64); - - //Perform a learning operation - - run_realtime(); //1. runs learning and identifies a CC to bind - mw->tick(); //2. produces new binding table - run_realtime(); //3. applies new binding table - - - //Verify that the learning actually worked - mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 13); - run_realtime(); - TS_ASSERT_EQUALS(ms->Pkeyshift, 13); - - mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 2); - run_realtime(); - TS_ASSERT_EQUALS(ms->Pkeyshift, 2); - - mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 0); - run_realtime(); - TS_ASSERT_EQUALS(ms->Pkeyshift, 0); - - mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 127); - run_realtime(); - TS_ASSERT_EQUALS(ms->Pkeyshift, 127); - } - - void testMidiLearnSave(void) - { - mw->transmitMsg("/learn", "s", "/Pkeyshift"); - mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 108); - - //param is at default until rt-thread is run - TS_ASSERT_EQUALS(ms->Pkeyshift, 64); - - - //Perform a learning operation - run_realtime(); - - //Verify binding affects control - TS_ASSERT_EQUALS(ms->Pkeyshift, 108); - - - printf("# Trying to save automations\n"); - start_realtime(); - mw->transmitMsg("/save_xlz", "s", "test-midi-learn.xlz"); - stop_realtime(); - - //Verify that some file exists - printf("# Verifying file exists\n"); - FILE *f = fopen("test-midi-learn.xlz", "r"); - TS_ASSERT(f); - - if(f) - fclose(f); - - printf("# Clearing automation\n"); - //Clear out state - mw->transmitMsg("/clear_xlz", ""); - //Send dummy message - mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 27); - run_realtime(); - - //Verify automation table is clear - TS_ASSERT_EQUALS(ms->Pkeyshift, 108); - - printf("# Loading automation\n"); - mw->transmitMsg("/load_xlz", "s", "test-midi-learn.xlz"); - //Send message - mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 28); - run_realtime(); - - //Verify automation table is restored - TS_ASSERT_EQUALS(ms->Pkeyshift, 28); - } - - void testLfoPaste(void) - { - start_realtime(); - ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand = 32; - TS_ASSERT_EQUALS(ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand, 32); - - //Copy - mw->transmitMsg("/presets/copy", "s", "/part0/kit0/adpars/GlobalPar/FreqLfo/"); - - ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand = 99; - TS_ASSERT_EQUALS(ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand, 99); - - //Paste - mw->transmitMsg("/presets/paste", "s", "/part0/kit0/adpars/GlobalPar/FreqLfo/"); - stop_realtime(); - - TS_ASSERT_EQUALS(ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand, 32); - } - - void testPadPaste(void) - { - mw->transmitMsg("/part0/kit0/Ppadenabled", "T"); - run_realtime(); - - start_realtime(); - - auto &field1 = ms->part[0]->kit[0].padpars->PVolume; - auto &field2 = ms->part[0]->kit[0].padpars->oscilgen->Pfilterpar1; - field1 = 32; - TS_ASSERT_EQUALS(field1, 32); - field2 = 35; - TS_ASSERT_EQUALS(field2, 35); - - //Copy - mw->transmitMsg("/presets/copy", "s", "/part0/kit0/padpars/"); - - field1 = 99; - TS_ASSERT_EQUALS(field1, 99); - field2 = 95; - TS_ASSERT_EQUALS(field2, 95); - - //Paste - mw->transmitMsg("/presets/paste", "s", "/part0/kit0/padpars/"); - stop_realtime(); - - TS_ASSERT_EQUALS(field1, 32); - TS_ASSERT_EQUALS(field2, 35); - } - - void testFilterDepricated(void) - { - vector<string> v = {"Pfreq", "Pfreqtrack", "Pgain", "Pq"}; - for(size_t i=0; i<v.size(); ++i) { - string path = "/part0/kit0/adpars/GlobalPar/GlobalFilter/"+v[i]; - for(int j=0; j<128; ++j) { - mw->transmitMsg(path.c_str(), "i", j); //Set - mw->transmitMsg(path.c_str(), ""); //Get - } - - } - while(ms->uToB->hasNext()) { - const char *msg = ms->uToB->read(); - //printf("RT: handling <%s>\n", msg); - ms->applyOscEvent(msg); - } - - int id = 0; - int state = 0; - int value = 0; - // 0 - broadcast - // 1 - true value (set) - // 2 - expected value (get) - while(ms->bToU->hasNext()) { - const char *msg = ms->bToU->read(); - if(state == 0) { - TS_ASSERT_EQUALS(rtosc_narguments(msg), 0U); - state = 1; - } else if(state == 1) { - TS_ASSERT_EQUALS(rtosc_narguments(msg), 1U); - value = rtosc_argument(msg, 0).i; - state = 2; - } else if(state == 2) { - int val = rtosc_argument(msg, 0).i; - if(value != val) { - printf("%s - %d should equal %d\n", msg, value, val); - TS_ASSERT(0); - } - state = 0; - } - - (void) id; - //printf("Message #%d %s:%s\n", id++, msg, rtosc_argument_string(msg)); - //if(rtosc_narguments(msg)) - // printf(" %d\n", rtosc_argument(msg, 0).i); - } - } - - - private: - SYNTH_T *synth; - MiddleWare *mw; - Master *ms; - std::thread *realtime; - bool do_exit; -}; diff --git a/src/Tests/MicrotonalTest.cpp b/src/Tests/MicrotonalTest.cpp @@ -0,0 +1,138 @@ +/* + ZynAddSubFX - a software synthesizer + + MicrotonalTest.h - CxxTest for Misc/Microtonal + Copyright (C) 2009-2012 Mark McCurry + Author: Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ +#include "test-suite.h" +#include <iostream> +#include "../Misc/Microtonal.h" +#include "../Misc/XMLwrapper.h" +#include <cstring> +#include <string> +#include <cstdio> +#include "../globals.h" +using namespace std; +using namespace zyn; + +SYNTH_T *synth; + +class MicrotonalTest +{ + public: + int compression; + void setUp() { + compression = 0; + synth = new SYNTH_T; + testMicro = new Microtonal(compression); + } + + void tearDown() { + delete testMicro; + delete synth; + } + + //Verifies that the object is initialized correctly + void testinit() { + TS_ASSERT_EQUAL_INT(testMicro->Pinvertupdown, 0); + TS_ASSERT_EQUAL_INT(testMicro->Pinvertupdowncenter, 60); + TS_ASSERT_EQUAL_INT(testMicro->getoctavesize(), 12); + TS_ASSERT_EQUAL_INT(testMicro->Penabled, 0); + TS_ASSERT_EQUAL_INT(testMicro->PAnote, 69); + TS_ASSERT_EQUAL_INT(testMicro->PAfreq, 440.0f); + TS_ASSERT_EQUAL_INT(testMicro->Pscaleshift, 64); + TS_ASSERT_EQUAL_INT(testMicro->Pfirstkey, 0); + TS_ASSERT_EQUAL_INT(testMicro->Plastkey, 127); + TS_ASSERT_EQUAL_INT(testMicro->Pmiddlenote, 60); + TS_ASSERT_EQUAL_INT(testMicro->Pmapsize, 12); + TS_ASSERT_EQUAL_INT(testMicro->Pmappingenabled, 0); + TS_ASSERT_EQUAL_INT(testMicro->Pglobalfinedetune, 64); + + TS_ASSERT_EQUAL_STR("12tET", (const char *)testMicro->Pname); + TS_ASSERT_EQUAL_STR("Equal Temperament 12 notes per octave", + testMicro->Pcomment); + + for(int i = 0; i < 128; ++i) + TS_ASSERT_EQUAL_INT(i, testMicro->Pmapping[i]); + + TS_ASSERT_DELTA(testMicro->getnotefreq(19 / 12.0f, 0), 24.4997f, 0.0001f); + } + + //Tests saving/loading to XML + void testXML() { + //Gah, the XMLwrapper is a twisted maze + testMicro->Penabled = 1; + XMLwrapper xml; + xml.beginbranch("Dummy"); //this should not be needed, but odd behavior + //seems to exist from MICROTONAL being on the + //top of the stack + xml.beginbranch("MICROTONAL"); + testMicro->add2XML(xml); + xml.endbranch(); + xml.endbranch(); + + char *tmp = xml.getXMLdata(); + Microtonal other(compression); + + other.Penabled = 1; + strcpy((char *)other.Pname, "Myname"); //will be nicer with strings + + TS_ASSERT(*testMicro != other); //sanity check + + TS_ASSERT(xml.enterbranch("Dummy")); + TS_ASSERT(xml.enterbranch("MICROTONAL")); + + other.getfromXML(xml); + xml.exitbranch(); + xml.exitbranch(); + char *tmpo = xml.getXMLdata(); + + TS_ASSERT(!strcmp(tmp, tmpo)); + free(tmp); + free(tmpo); + } + +#if 0 + /**\todo Test Saving/loading from file*/ + + //Test texttomapping TODO finish + void _testTextToMapping() { + //the mapping is from old documentation for "Intense Diatonic" scale + const char *mapping[12] = + {"0", "x", "1", "x", "2", "3", "x", "4", "x", "5", "x", "6"}; + //for(int i=0;i<20;++i) + // cout << i << ':' << testMicro->getnotefreq(i,0) << endl; + // + // octave size == 7 + // find dead notes + } + //Test texttotunings TODO finish + void _testTextToTunings() { + //the tuning is from old documentation for "Intense Diatonic" scale + const char *tuning[7] = + {"9/8", "5/4", "4/3", "3/2", "5/3", "15/8", "2/1"}; + const int numTunings = 7; + //for(int i=0;i<20;++i) + // cout << i << ':' << testMicro->getnotefreq(i,0) << endl; + // go to middle key and verify the proportions + } + /**\TODO test loading from scl and kbm files*/ +#endif + + private: + Microtonal *testMicro; +}; + +int main() +{ + MicrotonalTest test; + RUN_TEST(testinit); + RUN_TEST(testXML); + return test_summary(); +} diff --git a/src/Tests/MicrotonalTest.h b/src/Tests/MicrotonalTest.h @@ -1,131 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - MicrotonalTest.h - CxxTest for Misc/Microtonal - Copyright (C) 2009-2012 Mark McCurry - Author: Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ -#include <cxxtest/TestSuite.h> -#include <iostream> -#include "../Misc/Microtonal.h" -#include "../Misc/XMLwrapper.h" -#include <cstring> -#include <string> -#include <cstdio> -#include "../globals.h" -using namespace std; -using namespace zyn; - -SYNTH_T *synth; - -class MicrotonalTest:public CxxTest::TestSuite -{ - public: - int compression; - void setUp() { - compression = 0; - synth = new SYNTH_T; - testMicro = new Microtonal(compression); - } - - void tearDown() { - delete testMicro; - delete synth; - } - - //Verifies that the object is initialized correctly - void testinit() { - TS_ASSERT_EQUALS(testMicro->Pinvertupdown, 0); - TS_ASSERT_EQUALS(testMicro->Pinvertupdowncenter, 60); - TS_ASSERT_EQUALS(testMicro->getoctavesize(), 12); - TS_ASSERT_EQUALS(testMicro->Penabled, 0); - TS_ASSERT_EQUALS(testMicro->PAnote, 69); - TS_ASSERT_EQUALS(testMicro->PAfreq, 440.0f); - TS_ASSERT_EQUALS(testMicro->Pscaleshift, 64); - TS_ASSERT_EQUALS(testMicro->Pfirstkey, 0); - TS_ASSERT_EQUALS(testMicro->Plastkey, 127); - TS_ASSERT_EQUALS(testMicro->Pmiddlenote, 60); - TS_ASSERT_EQUALS(testMicro->Pmapsize, 12); - TS_ASSERT_EQUALS(testMicro->Pmappingenabled, 0); - TS_ASSERT_EQUALS(testMicro->Pglobalfinedetune, 64); - - TS_ASSERT_EQUALS(string((const char *)testMicro->Pname), "12tET"); - TS_ASSERT_EQUALS(string( - (const char *)testMicro->Pcomment), - "Equal Temperament 12 notes per octave"); - - for(int i = 0; i < 128; ++i) - TS_ASSERT_EQUALS(testMicro->Pmapping[i], i); - - TS_ASSERT_DELTA(testMicro->getnotefreq(19 / 12.0f, 0), 24.4997f, 0.0001f); - } - - //Tests saving/loading to XML - void testXML() { - //Gah, the XMLwrapper is a twisted maze - testMicro->Penabled = 1; - XMLwrapper xml; - xml.beginbranch("Dummy"); //this should not be needed, but odd behavior - //seems to exist from MICROTONAL being on the - //top of the stack - xml.beginbranch("MICROTONAL"); - testMicro->add2XML(xml); - xml.endbranch(); - xml.endbranch(); - - char *tmp = xml.getXMLdata(); - Microtonal other(compression); - - other.Penabled = 1; - strcpy((char *)other.Pname, "Myname"); //will be nicer with strings - - TS_ASSERT(*testMicro != other); //sanity check - - TS_ASSERT(xml.enterbranch("Dummy")); - TS_ASSERT(xml.enterbranch("MICROTONAL")); - - other.getfromXML(xml); - xml.exitbranch(); - xml.exitbranch(); - char *tmpo = xml.getXMLdata(); - - TS_ASSERT(!strcmp(tmp, tmpo)); - free(tmp); - free(tmpo); - } - -#if 0 - /**\todo Test Saving/loading from file*/ - - //Test texttomapping TODO finish - void _testTextToMapping() { - //the mapping is from old documentation for "Intense Diatonic" scale - const char *mapping[12] = - {"0", "x", "1", "x", "2", "3", "x", "4", "x", "5", "x", "6"}; - //for(int i=0;i<20;++i) - // cout << i << ':' << testMicro->getnotefreq(i,0) << endl; - // - // octave size == 7 - // find dead notes - } - //Test texttotunings TODO finish - void _testTextToTunings() { - //the tuning is from old documentation for "Intense Diatonic" scale - const char *tuning[7] = - {"9/8", "5/4", "4/3", "3/2", "5/3", "15/8", "2/1"}; - const int numTunings = 7; - //for(int i=0;i<20;++i) - // cout << i << ':' << testMicro->getnotefreq(i,0) << endl; - // go to middle key and verify the proportions - } - /**\TODO test loading from scl and kbm files*/ -#endif - - private: - Microtonal *testMicro; -}; diff --git a/src/Tests/MiddlewareTest.cpp b/src/Tests/MiddlewareTest.cpp @@ -0,0 +1,156 @@ +/* + ZynAddSubFX - a software synthesizer + + PluginTest.h - CxxTest for embedding zyn + Copyright (C) 2013-2013 Mark McCurry + Authors: Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ +#include "test-suite.h" +#include <cmath> +#include <cstdlib> +#include <iostream> +#include <fstream> +#include <string> +#include "../Misc/MiddleWare.h" +#include "../Misc/Master.h" +#include "../Misc/PresetExtractor.h" +#include "../Misc/PresetExtractor.cpp" +#include "../Misc/Util.h" +#include "../globals.h" +#include "../UI/NSM.H" +using namespace std; +using namespace zyn; + +NSM_Client *nsm = 0; +MiddleWare *middleware = 0; + +char *instance_name=(char*)""; + +#define NUM_MIDDLEWARE 3 + +class PluginTest +{ + public: + Config config; + void setUp() { + synth = new SYNTH_T; + synth->buffersize = 256; + synth->samplerate = 48000; + //synth->alias(); + + outL = new float[1024]; + for(int i = 0; i < synth->buffersize; ++i) + outL[i] = 0.0f; + outR = new float[1024]; + for(int i = 0; i < synth->buffersize; ++i) + outR[i] = 0.0f; + + delete synth; + synth = NULL; + for(int i = 0; i < NUM_MIDDLEWARE; ++i) { + synth = new SYNTH_T; + synth->buffersize = 256; + synth->samplerate = 48000; + //synth->alias(); + middleware[i] = new MiddleWare(std::move(*synth), &config); + master[i] = middleware[i]->spawnMaster(); + //printf("Octave size = %d\n", master[i]->microtonal.getoctavesize()); + } + } + + void tearDown() { + for(int i = 0; i < NUM_MIDDLEWARE; ++i) + delete middleware[i]; + + delete[] outL; + delete[] outR; + delete synth; + } + + + void testInit() { + + for(int x=0; x<100; ++x) { + for(int i=0; i<NUM_MIDDLEWARE; ++i) { + middleware[i]->tick(); + master[i]->GetAudioOutSamples(rand()%1025, + synth->samplerate, outL, outR); + } + } + } + + void testPanic() + { + master[0]->setController(0, 0x64, 0); + master[0]->noteOn(0,64,64); + master[0]->AudioOut(outL, outR); + + float sum = 0.0f; + for(int i = 0; i < synth->buffersize; ++i) + sum += fabsf(outL[i]); + + TS_ASSERT(0.1f < sum); + } + + string loadfile(string fname) const + { + std::ifstream t(fname.c_str()); + std::string str((std::istreambuf_iterator<char>(t)), + std::istreambuf_iterator<char>()); + return str; + } + + void testLoad(void) + { + for(int i=0; i<NUM_MIDDLEWARE; ++i) { + middleware[i]->transmitMsg("/load-part", "is", 0, (string(SOURCE_DIR) + "/../../instruments/banks/Organ/0037-Church Organ 1.xiz").c_str()); + middleware[i]->tick(); + master[i]->GetAudioOutSamples(synth->buffersize, synth->samplerate, outL, outR); + middleware[i]->tick(); + master[i]->GetAudioOutSamples(synth->buffersize, synth->samplerate, outL, outR); + middleware[i]->tick(); + master[i]->GetAudioOutSamples(synth->buffersize, synth->samplerate, outL, outR); + middleware[i]->tick(); + master[i]->GetAudioOutSamples(synth->buffersize, synth->samplerate, outL, outR); + middleware[i]->tick(); + } + //const string fname = string(SOURCE_DIR) + "/../../instruments/banks/Organ/0037-Church Organ 1.xiz"; + //const string fdata = loadfile(fname); + } + + void testChangeToOutOfRangeProgram() + { + middleware[0]->transmitMsg("/bank/msb", "i", 0); + middleware[0]->tick(); + middleware[0]->transmitMsg("/bank/lsb", "i", 1); + middleware[0]->tick(); + middleware[0]->pendingSetProgram(0, 32); + middleware[0]->tick(); + master[0]->GetAudioOutSamples(synth->buffersize, synth->samplerate, outL, outR); + // We should ideally be checking to verify that the part change + // didn't happen, but it's not clear how to do that. We're + // currently relying on the assert(filename) in loadPart() failing + // if this logic gets broken. + } + + private: + SYNTH_T *synth; + float *outR, *outL; + MiddleWare *middleware[NUM_MIDDLEWARE]; + Master *master[NUM_MIDDLEWARE]; +}; + +int main() +{ + PluginTest test; + RUN_TEST(testInit); + RUN_TEST(testPanic); + RUN_TEST(testLoad); + RUN_TEST(testChangeToOutOfRangeProgram); + return test_summary(); +} diff --git a/src/Tests/MiddlewareTest.h b/src/Tests/MiddlewareTest.h @@ -1,146 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - PluginTest.h - CxxTest for embedding zyn - Copyright (C) 2013-2013 Mark McCurry - Authors: Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ -#include <cxxtest/TestSuite.h> -#include <cmath> -#include <cstdlib> -#include <iostream> -#include <fstream> -#include <string> -#include "../Misc/MiddleWare.h" -#include "../Misc/Master.h" -#include "../Misc/PresetExtractor.h" -#include "../Misc/PresetExtractor.cpp" -#include "../Misc/Util.h" -#include "../globals.h" -#include "../UI/NSM.H" -using namespace std; -using namespace zyn; - -NSM_Client *nsm = 0; -MiddleWare *middleware = 0; - -char *instance_name=(char*)""; - -#define NUM_MIDDLEWARE 3 - -class PluginTest:public CxxTest::TestSuite -{ - public: - Config config; - void setUp() { - synth = new SYNTH_T; - synth->buffersize = 256; - synth->samplerate = 48000; - //synth->alias(); - - outL = new float[1024]; - for(int i = 0; i < synth->buffersize; ++i) - outL[i] = 0.0f; - outR = new float[1024]; - for(int i = 0; i < synth->buffersize; ++i) - outR[i] = 0.0f; - - delete synth; - synth = NULL; - for(int i = 0; i < NUM_MIDDLEWARE; ++i) { - synth = new SYNTH_T; - synth->buffersize = 256; - synth->samplerate = 48000; - //synth->alias(); - middleware[i] = new MiddleWare(std::move(*synth), &config); - master[i] = middleware[i]->spawnMaster(); - //printf("Octave size = %d\n", master[i]->microtonal.getoctavesize()); - } - } - - void tearDown() { - for(int i = 0; i < NUM_MIDDLEWARE; ++i) - delete middleware[i]; - - delete[] outL; - delete[] outR; - delete synth; - } - - - void testInit() { - - for(int x=0; x<100; ++x) { - for(int i=0; i<NUM_MIDDLEWARE; ++i) { - middleware[i]->tick(); - master[i]->GetAudioOutSamples(rand()%1025, - synth->samplerate, outL, outR); - } - } - } - - void testPanic() - { - master[0]->setController(0, 0x64, 0); - master[0]->noteOn(0,64,64); - master[0]->AudioOut(outL, outR); - - float sum = 0.0f; - for(int i = 0; i < synth->buffersize; ++i) - sum += fabsf(outL[i]); - - TS_ASSERT_LESS_THAN(0.1f, sum); - } - - string loadfile(string fname) const - { - std::ifstream t(fname.c_str()); - std::string str((std::istreambuf_iterator<char>(t)), - std::istreambuf_iterator<char>()); - return str; - } - - void testLoad(void) - { - for(int i=0; i<NUM_MIDDLEWARE; ++i) { - middleware[i]->transmitMsg("/load-part", "is", 0, (string(SOURCE_DIR) + "/../../instruments/banks/Organ/0037-Church Organ 1.xiz").c_str()); - middleware[i]->tick(); - master[i]->GetAudioOutSamples(synth->buffersize, synth->samplerate, outL, outR); - middleware[i]->tick(); - master[i]->GetAudioOutSamples(synth->buffersize, synth->samplerate, outL, outR); - middleware[i]->tick(); - master[i]->GetAudioOutSamples(synth->buffersize, synth->samplerate, outL, outR); - middleware[i]->tick(); - master[i]->GetAudioOutSamples(synth->buffersize, synth->samplerate, outL, outR); - middleware[i]->tick(); - } - //const string fname = string(SOURCE_DIR) + "/../../instruments/banks/Organ/0037-Church Organ 1.xiz"; - //const string fdata = loadfile(fname); - } - - void testChangeToOutOfRangeProgram() - { - middleware[0]->transmitMsg("/bank/msb", "i", 0); - middleware[0]->tick(); - middleware[0]->transmitMsg("/bank/lsb", "i", 1); - middleware[0]->tick(); - middleware[0]->pendingSetProgram(0, 32); - middleware[0]->tick(); - master[0]->GetAudioOutSamples(synth->buffersize, synth->samplerate, outL, outR); - // We should ideally be checking to verify that the part change - // didn't happen, but it's not clear how to do that. We're - // currently relying on the assert(filename) in loadPart() failing - // if this logic gets broken. - } - - private: - SYNTH_T *synth; - float *outR, *outL; - MiddleWare *middleware[NUM_MIDDLEWARE]; - Master *master[NUM_MIDDLEWARE]; -}; diff --git a/src/Tests/MqTest.cpp b/src/Tests/MqTest.cpp @@ -0,0 +1,135 @@ +/* + ZynAddSubFX - a software synthesizer + + PluginTest.h - CxxTest for embedding zyn + Copyright (C) 2013-2013 Mark McCurry + Authors: Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ +#include "test-suite.h" +#include <cmath> +#include <cstdlib> +#include <iostream> +#include <fstream> +#include <string> +#include <thread> +#include <rtosc/thread-link.h> +#include <unistd.h> +#include "../Containers/MultiPseudoStack.h" +using namespace std; +using namespace zyn; + +char *instance_name=(char*)""; + +class MessageTest +{ + public: + MultiQueue *s; + void setUp() { + s = new MultiQueue; + } + + void tearDown() { + delete s; + } + + void testBasic(void) + { + auto *mem = s->alloc(); + TS_NON_NULL(mem); + TS_NON_NULL(mem->memory); + TS_ASSERT(!s->read()); + s->write(mem); + auto *mem2 = s->read(); + assert_ptr_eq(mem, mem2, + "both locations are the same", __LINE__); + s->free(mem2); + } + void testMed(void) + { + for(int i=0; i<100; ++i) { + auto *mem = s->alloc(); + TS_NON_NULL(mem); + TS_NON_NULL(mem->memory); + TS_ASSERT(!s->read()); + s->write(mem); + auto *mem2 = s->read(); + assert_ptr_eq(mem, mem2, + "both locations are the same", __LINE__); + s->free(mem2); + } + } + +#define OPS 1000 +#define THREADS 8 + void testThreads(void) + { + uint8_t messages[OPS*THREADS]; + memset(messages, 0, sizeof(messages)); + std::thread *t[THREADS]; + for(int i=0; i<THREADS; ++i) { + t[i] = new std::thread([this,i,&messages](){ + int op=0; + while(op<OPS) { + int read = rand()%2; + if(read) { + auto *mem = s->read(); + if(mem) { + //printf("r%d",i%10); + //printf("got: <%s>\n", mem->memory); + messages[atoi(mem->memory)]++; + } + s->free(mem); + } else { + auto *mem = s->alloc(); + if(mem) { + sprintf(mem->memory,"%d written by %d@op%d", i*OPS+op,i,op); + //printf("w%d",i%10); + op++; + } + s->write(mem); + } + } + }); + } + + printf("thread started...\n"); + for(int i=0; i<THREADS; ++i) { + t[i]->join(); + delete t[i]; + } + printf("thread stopped...\n"); + //read the last few + while(1) { + auto *mem = s->read(); + if(mem) { + printf("got: <%s>\n", mem->memory); + messages[atoi(mem->memory)]++; + } else + break; + s->free(mem); + } + + int good = 1; + for(int i=0; i<OPS*THREADS; ++i) { + if(messages[i] != 1) { + assert(false); + good = 0; + } + } + TS_ASSERT(good); + } +}; + +int main() +{ + MessageTest test; + RUN_TEST(testBasic); + RUN_TEST(testMed); + RUN_TEST(testThreads); + return test_summary(); +} diff --git a/src/Tests/MqTest.h b/src/Tests/MqTest.h @@ -1,124 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - PluginTest.h - CxxTest for embedding zyn - Copyright (C) 2013-2013 Mark McCurry - Authors: Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ -#include <cxxtest/TestSuite.h> -#include <cmath> -#include <cstdlib> -#include <iostream> -#include <fstream> -#include <string> -#include <thread> -#include <rtosc/thread-link.h> -#include <unistd.h> -#include "../Containers/MultiPseudoStack.h" -using namespace std; -using namespace zyn; - -char *instance_name=(char*)""; - -class MessageTest:public CxxTest::TestSuite -{ - public: - MultiQueue *s; - void setUp() { - s = new MultiQueue; - } - - void tearDown() { - delete s; - } - - void testBasic(void) - { - auto *mem = s->alloc(); - TS_ASSERT(mem); - TS_ASSERT(mem->memory); - TS_ASSERT(!s->read()); - s->write(mem); - auto *mem2 = s->read(); - TS_ASSERT_EQUALS(mem, mem2); - s->free(mem2); - } - void testMed(void) - { - for(int i=0; i<100; ++i) { - auto *mem = s->alloc(); - TS_ASSERT(mem); - TS_ASSERT(mem->memory); - TS_ASSERT(!s->read()); - s->write(mem); - auto *mem2 = s->read(); - TS_ASSERT_EQUALS(mem, mem2); - s->free(mem2); - } - } - -#define OPS 1000 -#define THREADS 8 - void testThreads(void) - { - uint8_t messages[OPS*THREADS]; - memset(messages, 0, sizeof(messages)); - std::thread *t[THREADS]; - for(int i=0; i<THREADS; ++i) { - t[i] = new std::thread([this,i,&messages](){ - int op=0; - while(op<OPS) { - int read = rand()%2; - if(read) { - auto *mem = s->read(); - if(mem) { - //printf("r%d",i%10); - //printf("got: <%s>\n", mem->memory); - messages[atoi(mem->memory)]++; - } - s->free(mem); - } else { - auto *mem = s->alloc(); - if(mem) { - sprintf(mem->memory,"%d written by %d@op%d", i*OPS+op,i,op); - //printf("w%d",i%10); - op++; - } - s->write(mem); - } - } - }); - } - - printf("thread started...\n"); - for(int i=0; i<THREADS; ++i) { - t[i]->join(); - delete t[i]; - } - printf("thread stopped...\n"); - //read the last few - while(1) { - auto *mem = s->read(); - if(mem) { - printf("got: <%s>\n", mem->memory); - messages[atoi(mem->memory)]++; - } else - break; - s->free(mem); - } - - int good = 1; - for(int i=0; i<OPS*THREADS; ++i) { - if(messages[i] != 1) { - assert(false); - good = 0; - } - } - TS_ASSERT(good); - } -}; diff --git a/src/Tests/MsgParseTest.cpp b/src/Tests/MsgParseTest.cpp @@ -0,0 +1,61 @@ +#include "test-suite.h" +#include "../Misc/MsgParsing.h" + +class PluginTest +{ + public: + void setUp() {} + + void tearDown() {} + + void testExtracting() { + std::size_t res; + int part, kit, vc; + bool isFm; + + // test a full string with OscilSmp + res = zyn::idsFromMsg("/part1/kit2/adpars/VoicePar3/OscilSmp", &part, &kit, &vc, &isFm); + TS_ASSERT(res); + TS_ASSERT_EQUAL_INT(part, 1); + TS_ASSERT_EQUAL_INT(kit, 2); + TS_ASSERT_EQUAL_INT(vc, 3); + TS_ASSERT(!isFm); + // translate back into string + std::string str = zyn::buildVoiceParMsg(&part, &kit, &vc, &isFm); + TS_ASSERT_EQUAL_STR("/part1/kit2/adpars/VoicePar3/OscilSmp", str.c_str()); + + // same with FMSmp + res = zyn::idsFromMsg("/part11/kit12/adpars/VoicePar13/FMSmp", &part, &kit, &vc, &isFm); + TS_ASSERT(res); + TS_ASSERT_EQUAL_INT(part, 11); + TS_ASSERT_EQUAL_INT(kit, 12); + TS_ASSERT_EQUAL_INT(vc, 13); + TS_ASSERT(isFm); + // translate back into string + str = zyn::buildVoiceParMsg(&part, &kit, &vc, &isFm); + TS_ASSERT_EQUAL_STR("/part11/kit12/adpars/VoicePar13/FMSmp", str.c_str()); + + // check return values + TS_ASSERT(!zyn::idsFromMsg("/part", &part, &kit, nullptr)); + TS_ASSERT(!zyn::idsFromMsg("/part1", &part, &kit, nullptr)); + TS_ASSERT(!zyn::idsFromMsg("/part1/kit", &part, &kit, nullptr)); + TS_ASSERT(zyn::idsFromMsg("/part1/kit2", &part, &kit, nullptr)); + TS_ASSERT(!zyn::idsFromMsg("/part1/kit2", &part, &kit, &vc)); + TS_ASSERT(!zyn::idsFromMsg("/part1/kit2/adpars/", &part, &kit, &vc)); + TS_ASSERT(!zyn::idsFromMsg("/part1/kit2/adpars/", &part, &kit, &vc)); + TS_ASSERT(!zyn::idsFromMsg("/part1/kit2/adpars/VoicePar", &part, &kit, &vc)); + TS_ASSERT(!zyn::idsFromMsg("/part1/kit2/adpars/VoicePar/", &part, &kit, &vc)); + TS_ASSERT(zyn::idsFromMsg("/part1/kit2/adpars/VoicePar0/", &part, &kit, &vc)); + TS_ASSERT(zyn::idsFromMsg("/part1/kit2/adpars/VoicePar0/XXX", &part, &kit, &vc)); + TS_ASSERT(!zyn::idsFromMsg("/part1/kit2/adpars/VoicePar0/XXX", &part, &kit, &vc, &isFm)); + TS_ASSERT(zyn::idsFromMsg("/part1/kit2/adpars/VoicePar0/OscilSmp", &part, &kit, &vc, &isFm)); + TS_ASSERT(zyn::idsFromMsg("/part1/kit2/adpars/VoicePar0/FMSmp", &part, &kit, &vc, &isFm)); + } +}; + +int main() +{ + PluginTest test; + RUN_TEST(testExtracting); + return test_summary(); +} diff --git a/src/Tests/MsgParseTest.h b/src/Tests/MsgParseTest.h @@ -1,59 +0,0 @@ -#ifndef MSGPARSETEST_H -#define MSGPARSETEST_H - -#include <cxxtest/TestSuite.h> -#include "../Misc/MsgParsing.h" - -class PluginTest:public CxxTest::TestSuite -{ - public: - void setUp() {} - - void tearDown() {} - - void testExtracting() { - std::size_t res; - int part, kit, vc; - bool isFm; - - // test a full string with OscilSmp - res = zyn::idsFromMsg("/part1/kit2/adpars/VoicePar3/OscilSmp", &part, &kit, &vc, &isFm); - TS_ASSERT(res); - TS_ASSERT_EQUALS(part, 1); - TS_ASSERT_EQUALS(kit, 2); - TS_ASSERT_EQUALS(vc, 3); - TS_ASSERT(!isFm); - // translate back into string - std::string str = zyn::buildVoiceParMsg(&part, &kit, &vc, &isFm); - TS_ASSERT_EQUALS(str, "/part1/kit2/adpars/VoicePar3/OscilSmp"); - - // same with FMSmp - res = zyn::idsFromMsg("/part11/kit12/adpars/VoicePar13/FMSmp", &part, &kit, &vc, &isFm); - TS_ASSERT(res); - TS_ASSERT_EQUALS(part, 11); - TS_ASSERT_EQUALS(kit, 12); - TS_ASSERT_EQUALS(vc, 13); - TS_ASSERT(isFm); - // translate back into string - str = zyn::buildVoiceParMsg(&part, &kit, &vc, &isFm); - TS_ASSERT_EQUALS(str, "/part11/kit12/adpars/VoicePar13/FMSmp"); - - // check return values - TS_ASSERT(!zyn::idsFromMsg("/part", &part, &kit, nullptr)); - TS_ASSERT(!zyn::idsFromMsg("/part1", &part, &kit, nullptr)); - TS_ASSERT(!zyn::idsFromMsg("/part1/kit", &part, &kit, nullptr)); - TS_ASSERT(zyn::idsFromMsg("/part1/kit2", &part, &kit, nullptr)); - TS_ASSERT(!zyn::idsFromMsg("/part1/kit2", &part, &kit, &vc)); - TS_ASSERT(!zyn::idsFromMsg("/part1/kit2/adpars/", &part, &kit, &vc)); - TS_ASSERT(!zyn::idsFromMsg("/part1/kit2/adpars/", &part, &kit, &vc)); - TS_ASSERT(!zyn::idsFromMsg("/part1/kit2/adpars/VoicePar", &part, &kit, &vc)); - TS_ASSERT(!zyn::idsFromMsg("/part1/kit2/adpars/VoicePar/", &part, &kit, &vc)); - TS_ASSERT(zyn::idsFromMsg("/part1/kit2/adpars/VoicePar0/", &part, &kit, &vc)); - TS_ASSERT(zyn::idsFromMsg("/part1/kit2/adpars/VoicePar0/XXX", &part, &kit, &vc)); - TS_ASSERT(!zyn::idsFromMsg("/part1/kit2/adpars/VoicePar0/XXX", &part, &kit, &vc, &isFm)); - TS_ASSERT(zyn::idsFromMsg("/part1/kit2/adpars/VoicePar0/OscilSmp", &part, &kit, &vc, &isFm)); - TS_ASSERT(zyn::idsFromMsg("/part1/kit2/adpars/VoicePar0/FMSmp", &part, &kit, &vc, &isFm)); - } -}; - -#endif // MSGPARSETEST_H diff --git a/src/Tests/OscilGenTest.cpp b/src/Tests/OscilGenTest.cpp @@ -0,0 +1,138 @@ +/* + ZynAddSubFX - a software synthesizer + + AdNoteTest.h - CxxTest for Synth/OscilGen + Copyright (C) 20011-2012 Mark McCurry + Author: Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ +#include "test-suite.h" +#include <string> +#include "../Synth/OscilGen.h" +#include "../Misc/XMLwrapper.h" +#include "../DSP/FFTwrapper.h" +#include "../Misc/Util.h" +#include "../globals.h" +using namespace std; +using namespace zyn; + +SYNTH_T *synth; + +class OscilGenTest +{ + public: + float freq; + float *outR, *outL; + FFTwrapper *fft; + OscilGen *oscil; + + void setUp() { + synth = new SYNTH_T; + //First the sensible settings and variables that have to be set: + synth->buffersize = 256; + synth->oscilsize = 1024; + + outL = new float[synth->oscilsize]; + outR = new float[synth->oscilsize]; + memset(outL, 0, sizeof(float) * synth->oscilsize); + memset(outR, 0, sizeof(float) * synth->oscilsize); + + //prepare the default settings + fft = new FFTwrapper(synth->oscilsize); + oscil = new OscilGen(*synth, fft, NULL); + + //Assert defaults [TODO] + + + XMLwrapper wrap; + wrap.loadXMLfile(string(SOURCE_DIR) + + string("/guitar-adnote.xmz")); + TS_ASSERT(wrap.enterbranch("MASTER")); + TS_ASSERT(wrap.enterbranch("PART", 0)); + TS_ASSERT(wrap.enterbranch("INSTRUMENT")); + TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT")); + TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT_ITEM", 0)); + TS_ASSERT(wrap.enterbranch("ADD_SYNTH_PARAMETERS")); + TS_ASSERT(wrap.enterbranch("VOICE", 0)); + TS_ASSERT(wrap.enterbranch("OSCIL")); + oscil->getfromXML(wrap); + + //verify xml was loaded [TODO] + + //lets go with.... 50! as a nice note + const char testnote = 50; + freq = 440.0f * powf(2.0f, (testnote - 69.0f) / 12.0f); + } + + void tearDown() { + delete oscil; + delete fft; + delete[] outL; + delete[] outR; + FFT_cleanup(); + delete synth; + } + + //verifies that initialization occurs + void testInit(void) + { + oscil->get(outL, freq); + } + + void testOutput(void) + { + oscil->get(outL, freq); + TS_ASSERT_DELTA(outL[23], -0.5371f, 0.0001f); + TS_ASSERT_DELTA(outL[129], 0.3613f, 0.0001f); + TS_ASSERT_DELTA(outL[586], 0.1118f, 0.0001f); + TS_ASSERT_DELTA(outL[1023], -0.6889f, 0.0001f); + } + + void testSpectrum(void) + { + oscil->getspectrum(synth->oscilsize / 2, outR, 1); + TS_ASSERT_DELTA(outR[1], 350.698059f, 0.0001f); + TS_ASSERT_DELTA(outR[2], 228.889267f, 0.0001f); + TS_ASSERT_DELTA(outR[3], 62.187931f, 0.0001f); + TS_ASSERT_DELTA(outR[4], 22.295225f, 0.0001f); + TS_ASSERT_DELTA(outR[5], 6.942001f, 0.0001f); + TS_ASSERT_DELTA(outR[27], 0.015110f, 0.0001f); + TS_ASSERT_DELTA(outR[48], 0.003425f, 0.0001f); + TS_ASSERT_DELTA(outR[66], 0.001293f, 0.0001f); + } + + //performance testing + void testSpeed() { + const int samps = 15000; + + int t_on = clock(); // timer before calling func + for(int i = 0; i < samps; ++i) + oscil->prepare(); + int t_off = clock(); // timer when func returns + + printf("OscilGenTest: %f seconds for %d prepares.\n", + (static_cast<float>(t_off - t_on)) / CLOCKS_PER_SEC, samps); + + t_on = clock(); // timer before calling func + for(int i = 0; i < samps; ++i) + oscil->get(outL, freq); + t_off = clock(); // timer when func returns + + printf("OscilGenTest: %f seconds for %d gets.\n", + (static_cast<float>(t_off - t_on)) / CLOCKS_PER_SEC, samps); + } +}; + +int main() +{ + OscilGenTest test; + RUN_TEST(testInit); + RUN_TEST(testOutput); + RUN_TEST(testSpectrum); + RUN_TEST(testSpeed); + return test_summary(); +} diff --git a/src/Tests/OscilGenTest.h b/src/Tests/OscilGenTest.h @@ -1,128 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - AdNoteTest.h - CxxTest for Synth/OscilGen - Copyright (C) 20011-2012 Mark McCurry - Author: Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ -#include <cxxtest/TestSuite.h> -#include <string> -#include "../Synth/OscilGen.h" -#include "../Misc/XMLwrapper.h" -#include "../DSP/FFTwrapper.h" -#include "../Misc/Util.h" -#include "../globals.h" -using namespace std; -using namespace zyn; - -SYNTH_T *synth; - -class OscilGenTest:public CxxTest::TestSuite -{ - public: - float freq; - float *outR, *outL; - FFTwrapper *fft; - OscilGen *oscil; - - void setUp() { - synth = new SYNTH_T; - //First the sensible settings and variables that have to be set: - synth->buffersize = 256; - synth->oscilsize = 1024; - - outL = new float[synth->oscilsize]; - outR = new float[synth->oscilsize]; - memset(outL, 0, sizeof(float) * synth->oscilsize); - memset(outR, 0, sizeof(float) * synth->oscilsize); - - //prepare the default settings - fft = new FFTwrapper(synth->oscilsize); - oscil = new OscilGen(*synth, fft, NULL); - - //Assert defaults [TODO] - - - XMLwrapper wrap; - wrap.loadXMLfile(string(SOURCE_DIR) - + string("/guitar-adnote.xmz")); - TS_ASSERT(wrap.enterbranch("MASTER")); - TS_ASSERT(wrap.enterbranch("PART", 0)); - TS_ASSERT(wrap.enterbranch("INSTRUMENT")); - TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT")); - TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT_ITEM", 0)); - TS_ASSERT(wrap.enterbranch("ADD_SYNTH_PARAMETERS")); - TS_ASSERT(wrap.enterbranch("VOICE", 0)); - TS_ASSERT(wrap.enterbranch("OSCIL")); - oscil->getfromXML(wrap); - - //verify xml was loaded [TODO] - - //lets go with.... 50! as a nice note - const char testnote = 50; - freq = 440.0f * powf(2.0f, (testnote - 69.0f) / 12.0f); - } - - void tearDown() { - delete oscil; - delete fft; - delete[] outL; - delete[] outR; - FFT_cleanup(); - delete synth; - } - - //verifies that initialization occurs - void testInit(void) - { - oscil->get(outL, freq); - } - - void testOutput(void) - { - oscil->get(outL, freq); - TS_ASSERT_DELTA(outL[23], -0.5371f, 0.0001f); - TS_ASSERT_DELTA(outL[129], 0.3613f, 0.0001f); - TS_ASSERT_DELTA(outL[586], 0.1118f, 0.0001f); - TS_ASSERT_DELTA(outL[1023], -0.6889f, 0.0001f); - } - - void testSpectrum(void) - { - oscil->getspectrum(synth->oscilsize / 2, outR, 1); - TS_ASSERT_DELTA(outR[1], 350.698059f, 0.0001f); - TS_ASSERT_DELTA(outR[2], 228.889267f, 0.0001f); - TS_ASSERT_DELTA(outR[3], 62.187931f, 0.0001f); - TS_ASSERT_DELTA(outR[4], 22.295225f, 0.0001f); - TS_ASSERT_DELTA(outR[5], 6.942001f, 0.0001f); - TS_ASSERT_DELTA(outR[27], 0.015110f, 0.0001f); - TS_ASSERT_DELTA(outR[48], 0.003425f, 0.0001f); - TS_ASSERT_DELTA(outR[66], 0.001293f, 0.0001f); - } - - //performance testing - void testSpeed() { - const int samps = 15000; - - int t_on = clock(); // timer before calling func - for(int i = 0; i < samps; ++i) - oscil->prepare(); - int t_off = clock(); // timer when func returns - - printf("OscilGenTest: %f seconds for %d prepares.\n", - (static_cast<float>(t_off - t_on)) / CLOCKS_PER_SEC, samps); - - t_on = clock(); // timer before calling func - for(int i = 0; i < samps; ++i) - oscil->get(outL, freq); - t_off = clock(); // timer when func returns - - printf("OscilGenTest: %f seconds for %d gets.\n", - (static_cast<float>(t_off - t_on)) / CLOCKS_PER_SEC, samps); - } -}; diff --git a/src/Tests/PadNoteTest.cpp b/src/Tests/PadNoteTest.cpp @@ -0,0 +1,299 @@ +/* + ZynAddSubFX - a software synthesizer + + PadNoteTest.h - CxxTest for Synth/PADnote + Copyright (C) 20012 zco + Author: zco + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ + + +//Based Upon AdNoteTest.h and SubNoteTest.h +#include "test-suite.h" +#include <complex> +#include <ctime> +#include <string> +#define private public +#include "../Synth/PADnote.h" +#undef private +#include "../Misc/Master.h" +#include "../Misc/Util.h" +#include "../Misc/Allocator.h" +#include "../Misc/XMLwrapper.h" +#include "../Synth/PADnote.h" +#include "../Synth/OscilGen.h" +#include "../Params/PADnoteParameters.h" +#include "../Params/Presets.h" +#include "../DSP/FFTwrapper.h" +#include "../globals.h" +#include <rtosc/thread-link.h> +using namespace std; +using namespace zyn; + +SYNTH_T *synth; + +#ifndef SOURCE_DIR +#define SOURCE_DIR "BE QUIET COMPILER" +#endif + +class PadNoteTest +{ + public: + PADnote *note; + PADnoteParameters *pars; + Master *master; + FFTwrapper *fft; + Controller *controller; + AbsTime *time; + float test_freq_log2; + Alloc memory; + int interpolation; + rtosc::ThreadLink *tr; + WatchManager *w; + + + float *outR, *outL; + + void setUp() { + interpolation = 0; + synth = new SYNTH_T; + //First the sensible settings and variables that have to be set: + synth->buffersize = 256; + time = new AbsTime(*synth); + + outL = new float[synth->buffersize]; + for(int i = 0; i < synth->buffersize; ++i) + *(outL + i) = 0; + outR = new float[synth->buffersize]; + for(int i = 0; i < synth->buffersize; ++i) + *(outR + i) = 0; + + tr = new rtosc::ThreadLink(1024,3); + w = new WatchManager(tr); + + fft = new FFTwrapper(synth->oscilsize); + //prepare the default settings + pars = new PADnoteParameters(*synth, fft, time); + + + //Assert defaults + ///TS_ASSERT(!defaultPreset->VoicePar[1].Enabled); + + XMLwrapper wrap; + //cout << string(SOURCE_DIR) + string("/guitar-adnote.xmz") + // << endl; + wrap.loadXMLfile(string(SOURCE_DIR) + + string("/guitar-adnote.xmz")); + TS_ASSERT(wrap.enterbranch("MASTER")); + TS_ASSERT(wrap.enterbranch("PART", 2)); + TS_ASSERT(wrap.enterbranch("INSTRUMENT")); + TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT")); + TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT_ITEM", 0)); + TS_ASSERT(wrap.enterbranch("PAD_SYNTH_PARAMETERS")); + pars->getfromXML(wrap); + + + //defaultPreset->defaults(); + pars->applyparameters([]{return false;}, 1); + + //verify xml was loaded + ///TS_ASSERT(defaultPreset->VoicePar[1].Enabled); + + + + controller = new Controller(*synth, time); + + //lets go with.... 50! as a nice note + test_freq_log2 = log2f(440.0f) + (50.0 - 69.0f) / 12.0f; + SynthParams pars_{memory, *controller, *synth, *time, 120, 0, test_freq_log2, false, prng()}; + + note = new PADnote(pars, pars_, interpolation); + } + + void tearDown() { + delete note; + delete controller; + delete fft; + delete [] outL; + delete [] outR; + delete pars; + FFT_cleanup(); + delete synth; + + note = NULL; + controller = NULL; + fft = NULL; + outL = NULL; + outR = NULL; + pars = NULL; + synth = NULL; + } + + + void testDefaults() { + int sampleCount = 0; + + +//#define WRITE_OUTPUT + +#ifdef WRITE_OUTPUT + ofstream file("padnoteout", ios::out); +#endif + note->noteout(outL, outR); + +#ifdef WRITE_OUTPUT + for(int i = 0; i < synth->buffersize; ++i) + file << outL[i] << std::endl; + +#endif + sampleCount += synth->buffersize; + + TS_ASSERT_DELTA(outL[255], 0.3950, 0.0005f); + + + note->releasekey(); + + TS_ASSERT(!tr->hasNext()); + w->add_watch("noteout"); + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], -0.2305f, 0.0005f); + w->tick(); + TS_ASSERT(!tr->hasNext()); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], -0.1164f, 0.0005f); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], 0.1079, 0.0005f); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], 0.0841f, 0.0001f); + + while(!note->finished()) { + note->noteout(outL, outR); + +#ifdef WRITE_OUTPUT + for(int i = 0; i < synth->buffersize; ++i) + file << outL[i] << std::endl; + +#endif + sampleCount += synth->buffersize; + } +#ifdef WRITE_OUTPUT + file.close(); +#endif + + TS_ASSERT_EQUAL_INT(sampleCount, 5888); + } + + void testInitialization() { + TS_ASSERT(pars->Pmode == PADnoteParameters::pad_mode::bandwidth); + + TS_ASSERT_EQUAL_INT(pars->PVolume, 90); + TS_NON_NULL(pars->oscilgen); + TS_NON_NULL(pars->resonance); + + TS_ASSERT_DELTA(note->NoteGlobalPar.Volume, 2.597527f, 0.001f); + TS_ASSERT_DELTA(note->NoteGlobalPar.Panning, 0.500000f, 0.01f); + + + for(int i=0; i<8; ++i) + TS_NON_NULL(pars->sample[i].smp); + for(int i=8; i<PAD_MAX_SAMPLES; ++i) + TS_ASSERT(!pars->sample[i].smp); + + TS_ASSERT_DELTA(pars->sample[0].smp[0], 0.0516f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[1], 0.0845f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[2], 0.1021f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[3], 0.0919f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[4], 0.0708f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[5], 0.0414f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[6], 0.0318f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[7], 0.0217f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[8], 0.0309f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[9], 0.0584f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[10], 0.0266f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[11], 0.0436f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[12], 0.0199f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[13], 0.0505f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[14], 0.0438f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[15], 0.0024f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[16], 0.0052f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[17], -0.0180f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[18], 0.0342f, 0.0005f); + TS_ASSERT_DELTA(pars->sample[0].smp[19], 0.0051f, 0.0005f); + + + //Verify Harmonic Input + float harmonics[synth->oscilsize]; + memset(harmonics, 0, sizeof(float) * synth->oscilsize); + + pars->oscilgen->get(harmonics, 440.0f, false); + + TS_ASSERT_DELTA(harmonics[0] ,0.683947, 0.0005f); + TS_ASSERT_DELTA(harmonics[1] ,0.128246, 0.0005f); + TS_ASSERT_DELTA(harmonics[2] ,0.003238, 0.0005f); + TS_ASSERT_DELTA(harmonics[3] ,0.280945, 0.0005f); + TS_ASSERT_DELTA(harmonics[4] ,0.263548, 0.0005f); + TS_ASSERT_DELTA(harmonics[5] ,0.357070, 0.0005f); + TS_ASSERT_DELTA(harmonics[6] ,0.096287, 0.0005f); + TS_ASSERT_DELTA(harmonics[7] ,0.128685, 0.0005f); + TS_ASSERT_DELTA(harmonics[8] ,0.003238, 0.0005f); + TS_ASSERT_DELTA(harmonics[9] ,0.149376, 0.0005f); + TS_ASSERT_DELTA(harmonics[10],0.063892, 0.0005f); + TS_ASSERT_DELTA(harmonics[11],0.296716, 0.0005f); + TS_ASSERT_DELTA(harmonics[12],0.051057, 0.0005f); + TS_ASSERT_DELTA(harmonics[13],0.066310, 0.0005f); + TS_ASSERT_DELTA(harmonics[14],0.004006, 0.0005f); + TS_ASSERT_DELTA(harmonics[15],0.038662, 0.0005f); + + float sum = 0; + for(int i=0; i<synth->oscilsize/2; ++i) + sum += harmonics[i]; + TS_ASSERT_DELTA(sum, 5.863001, 0.0005f); + + TS_ASSERT_DELTA(pars->getNhr(0), 0.000000, 0.0005f); + TS_ASSERT_DELTA(pars->getNhr(1), 1.000000, 0.0005f); + TS_ASSERT_DELTA(pars->getNhr(2), 2.000000, 0.0005f); + TS_ASSERT_DELTA(pars->getNhr(3), 3.000000, 0.0005f); + TS_ASSERT_DELTA(pars->getNhr(4), 4.000000, 0.0005f); + TS_ASSERT_DELTA(pars->getNhr(5), 5.000000, 0.0005f); + TS_ASSERT_DELTA(pars->getNhr(6), 6.000000, 0.0005f); + TS_ASSERT_DELTA(pars->getNhr(7), 7.000000, 0.0005f); + TS_ASSERT_DELTA(pars->getNhr(8), 8.000000, 0.0005f); + TS_ASSERT_DELTA(pars->getNhr(9), 9.000000, 0.0005f); + + } + +#define OUTPUT_PROFILE +#ifdef OUTPUT_PROFILE + void testSpeed() { + const int samps = 15000; + + int t_on = clock(); // timer before calling func + for(int i = 0; i < samps; ++i) + note->noteout(outL, outR); + int t_off = clock(); // timer when func returns + + printf("PadNoteTest: %f seconds for %d Samples to be generated.\n", + (static_cast<float>(t_off - t_on)) / CLOCKS_PER_SEC, samps); + } +#endif +}; + +int main() +{ + PadNoteTest test; + RUN_TEST(testDefaults); + RUN_TEST(testInitialization); + RUN_TEST(testSpeed); + return test_summary(); +} diff --git a/src/Tests/PadNoteTest.h b/src/Tests/PadNoteTest.h @@ -1,289 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - PadNoteTest.h - CxxTest for Synth/PADnote - Copyright (C) 20012 zco - Author: zco - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ - - -//Based Upon AdNoteTest.h and SubNoteTest.h -#include <cxxtest/TestSuite.h> -#include <iostream> -#include <fstream> -#include <ctime> -#include <string> -#define private public -#include "../Misc/Master.h" -#include "../Misc/Util.h" -#include "../Misc/Allocator.h" -#include "../Misc/XMLwrapper.h" -#include "../Synth/PADnote.h" -#include "../Synth/OscilGen.h" -#include "../Params/PADnoteParameters.h" -#include "../Params/Presets.h" -#include "../DSP/FFTwrapper.h" -#include "../globals.h" -#include <rtosc/thread-link.h> -using namespace std; -using namespace zyn; - -SYNTH_T *synth; - -#ifndef SOURCE_DIR -#define SOURCE_DIR "BE QUIET COMPILER" -#endif - -class PadNoteTest:public CxxTest::TestSuite -{ - public: - PADnote *note; - PADnoteParameters *pars; - Master *master; - FFTwrapper *fft; - Controller *controller; - AbsTime *time; - float test_freq_log2; - Alloc memory; - int interpolation; - rtosc::ThreadLink *tr; - WatchManager *w; - - - float *outR, *outL; - - void setUp() { - interpolation = 0; - synth = new SYNTH_T; - //First the sensible settings and variables that have to be set: - synth->buffersize = 256; - time = new AbsTime(*synth); - - outL = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - *(outL + i) = 0; - outR = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - *(outR + i) = 0; - - tr = new rtosc::ThreadLink(1024,3); - w = new WatchManager(tr); - - fft = new FFTwrapper(synth->oscilsize); - //prepare the default settings - pars = new PADnoteParameters(*synth, fft, time); - - - //Assert defaults - ///TS_ASSERT(!defaultPreset->VoicePar[1].Enabled); - - XMLwrapper wrap; - cout << string(SOURCE_DIR) + string("/guitar-adnote.xmz") - << endl; - wrap.loadXMLfile(string(SOURCE_DIR) - + string("/guitar-adnote.xmz")); - TS_ASSERT(wrap.enterbranch("MASTER")); - TS_ASSERT(wrap.enterbranch("PART", 2)); - TS_ASSERT(wrap.enterbranch("INSTRUMENT")); - TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT")); - TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT_ITEM", 0)); - TS_ASSERT(wrap.enterbranch("PAD_SYNTH_PARAMETERS")); - pars->getfromXML(wrap); - - - //defaultPreset->defaults(); - pars->applyparameters([]{return false;}, 1); - - //verify xml was loaded - ///TS_ASSERT(defaultPreset->VoicePar[1].Enabled); - - - - controller = new Controller(*synth, time); - - //lets go with.... 50! as a nice note - test_freq_log2 = log2f(440.0f) + (50.0 - 69.0f) / 12.0f; - SynthParams pars_{memory, *controller, *synth, *time, 120, 0, test_freq_log2, false, prng()}; - - note = new PADnote(pars, pars_, interpolation); - } - - void tearDown() { - delete note; - delete controller; - delete fft; - delete [] outL; - delete [] outR; - delete pars; - FFT_cleanup(); - delete synth; - - note = NULL; - controller = NULL; - fft = NULL; - outL = NULL; - outR = NULL; - pars = NULL; - synth = NULL; - } - - - void testDefaults() { - int sampleCount = 0; - - -//#define WRITE_OUTPUT - -#ifdef WRITE_OUTPUT - ofstream file("padnoteout", ios::out); -#endif - note->noteout(outL, outR); - -#ifdef WRITE_OUTPUT - for(int i = 0; i < synth->buffersize; ++i) - file << outL[i] << std::endl; - -#endif - sampleCount += synth->buffersize; - - TS_ASSERT_DELTA(outL[255], 0.3950, 0.0005f); - - - note->releasekey(); - - TS_ASSERT(!tr->hasNext()); - w->add_watch("noteout"); - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.2305f, 0.0005f); - w->tick(); - TS_ASSERT(!tr->hasNext()); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.1164f, 0.0005f); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.1079, 0.0005f); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.0841f, 0.0001f); - - while(!note->finished()) { - note->noteout(outL, outR); - -#ifdef WRITE_OUTPUT - for(int i = 0; i < synth->buffersize; ++i) - file << outL[i] << std::endl; - -#endif - sampleCount += synth->buffersize; - } -#ifdef WRITE_OUTPUT - file.close(); -#endif - - TS_ASSERT_EQUALS(sampleCount, 5888); - } - - void testInitialization() { - TS_ASSERT_EQUALS(pars->Pmode, PADnoteParameters::pad_mode::bandwidth); - - TS_ASSERT_EQUALS(pars->PVolume, 90); - TS_ASSERT(pars->oscilgen); - TS_ASSERT(pars->resonance); - - TS_ASSERT_DELTA(note->NoteGlobalPar.Volume, 2.597527f, 0.001f); - TS_ASSERT_DELTA(note->NoteGlobalPar.Panning, 0.500000f, 0.01f); - - - for(int i=0; i<8; ++i) - TS_ASSERT(pars->sample[i].smp); - for(int i=8; i<PAD_MAX_SAMPLES; ++i) - TS_ASSERT(!pars->sample[i].smp); - - TS_ASSERT_DELTA(pars->sample[0].smp[0], 0.0516f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[1], 0.0845f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[2], 0.1021f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[3], 0.0919f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[4], 0.0708f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[5], 0.0414f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[6], 0.0318f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[7], 0.0217f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[8], 0.0309f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[9], 0.0584f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[10], 0.0266f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[11], 0.0436f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[12], 0.0199f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[13], 0.0505f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[14], 0.0438f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[15], 0.0024f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[16], 0.0052f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[17], -0.0180f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[18], 0.0342f, 0.0005f); - TS_ASSERT_DELTA(pars->sample[0].smp[19], 0.0051f, 0.0005f); - - - //Verify Harmonic Input - float harmonics[synth->oscilsize]; - memset(harmonics, 0, sizeof(float) * synth->oscilsize); - - pars->oscilgen->get(harmonics, 440.0f, false); - - TS_ASSERT_DELTA(harmonics[0] ,0.683947, 0.0005f); - TS_ASSERT_DELTA(harmonics[1] ,0.128246, 0.0005f); - TS_ASSERT_DELTA(harmonics[2] ,0.003238, 0.0005f); - TS_ASSERT_DELTA(harmonics[3] ,0.280945, 0.0005f); - TS_ASSERT_DELTA(harmonics[4] ,0.263548, 0.0005f); - TS_ASSERT_DELTA(harmonics[5] ,0.357070, 0.0005f); - TS_ASSERT_DELTA(harmonics[6] ,0.096287, 0.0005f); - TS_ASSERT_DELTA(harmonics[7] ,0.128685, 0.0005f); - TS_ASSERT_DELTA(harmonics[8] ,0.003238, 0.0005f); - TS_ASSERT_DELTA(harmonics[9] ,0.149376, 0.0005f); - TS_ASSERT_DELTA(harmonics[10],0.063892, 0.0005f); - TS_ASSERT_DELTA(harmonics[11],0.296716, 0.0005f); - TS_ASSERT_DELTA(harmonics[12],0.051057, 0.0005f); - TS_ASSERT_DELTA(harmonics[13],0.066310, 0.0005f); - TS_ASSERT_DELTA(harmonics[14],0.004006, 0.0005f); - TS_ASSERT_DELTA(harmonics[15],0.038662, 0.0005f); - - float sum = 0; - for(int i=0; i<synth->oscilsize/2; ++i) - sum += harmonics[i]; - TS_ASSERT_DELTA(sum, 5.863001, 0.0005f); - - TS_ASSERT_DELTA(pars->getNhr(0), 0.000000, 0.0005f); - TS_ASSERT_DELTA(pars->getNhr(1), 1.000000, 0.0005f); - TS_ASSERT_DELTA(pars->getNhr(2), 2.000000, 0.0005f); - TS_ASSERT_DELTA(pars->getNhr(3), 3.000000, 0.0005f); - TS_ASSERT_DELTA(pars->getNhr(4), 4.000000, 0.0005f); - TS_ASSERT_DELTA(pars->getNhr(5), 5.000000, 0.0005f); - TS_ASSERT_DELTA(pars->getNhr(6), 6.000000, 0.0005f); - TS_ASSERT_DELTA(pars->getNhr(7), 7.000000, 0.0005f); - TS_ASSERT_DELTA(pars->getNhr(8), 8.000000, 0.0005f); - TS_ASSERT_DELTA(pars->getNhr(9), 9.000000, 0.0005f); - - } - -#define OUTPUT_PROFILE -#ifdef OUTPUT_PROFILE - void testSpeed() { - const int samps = 15000; - - int t_on = clock(); // timer before calling func - for(int i = 0; i < samps; ++i) - note->noteout(outL, outR); - int t_off = clock(); // timer when func returns - - printf("PadNoteTest: %f seconds for %d Samples to be generated.\n", - (static_cast<float>(t_off - t_on)) / CLOCKS_PER_SEC, samps); - } -#endif -}; diff --git a/src/Tests/PluginTest.cpp b/src/Tests/PluginTest.cpp @@ -0,0 +1,252 @@ +/* + ZynAddSubFX - a software synthesizer + + PluginTest.h - CxxTest for embedding zyn + Copyright (C) 2013-2013 Mark McCurry + Authors: Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ +#include "test-suite.h" +#include <cmath> +#include <cstdlib> +#include <iostream> +#include <fstream> +#include <string> +#include "../Misc/MiddleWare.h" +#include "../Misc/Master.h" +#include "../Misc/PresetExtractor.h" +#include "../Misc/PresetExtractor.cpp" +#include "../Misc/Util.h" +#include "../globals.h" +#include "../UI/NSM.H" + +using namespace std; +using namespace zyn; + +SYNTH_T *synth; +NSM_Client *nsm = 0; + +char *instance_name=(char*)""; +MiddleWare *middleware; + +void fill_vec_with_lines(std::vector<string> &v, string s) +{ + std::istringstream stream(s); + std::string line; + while(std::getline(stream, line)) + v.push_back(line); +} +void print_string_differences(string orig, string next) +{ + std::vector<string> a, b; + fill_vec_with_lines(a, orig); + fill_vec_with_lines(b, next); + int N = a.size(); + int M = b.size(); + printf("%d vs %d\n", N, M); + + //Original String by New String + //Each step is either an insertion, deletion, or match + //Match is 0 cost and moves +1 State (if symbols are the same) + //Replace is 3 cost and moves +1 State (if symbols are different) + //Insertion is 2 cost and moves +2 State (+2 if symbols are different) + //Deletion is 1 cost and moves +0 State (+2 if symbols are different) + char *transition = new char[N*M]; + float *cost = new float[N*M]; + + const int match = 1; + const int insert = 2; + const int del = 3; + for(int i=0; i<N; ++i) { + for(int j=0; j<M; ++j) { + transition[i*M + j] = 0; + cost[i*M + j] = 0xffff; + } + } + + //Just assume the -1 line is the same + cost[0*M + 0] = (a[0] != b[0])*3; + cost[0*M + 1] = (a[1] != b[0])*2 + 2; + for(int i=1; i<N; ++i) { + for(int j=0; j<M; ++j) { + int cost_match = 0xffffff; + int cost_ins = 0xffffff; + int cost_del = 0xffffff; + cost_del = cost[(i-1)*M + j] + 2 + (a[i] != b[j])*2; + if(j > 1) + cost_ins = cost[(i-1)*M + (j-2)] + 1 + 2*(a[i] != b[j]); + if(j > 0) + cost_match = cost[(i-1)*M + (j-1)] + 3*(a[i] != b[j]); + + if(cost_match >= 0xffff && cost_ins >= 0xffff && cost_del >= 0xffff) { + ; + } else if(cost_match < cost_ins && cost_match < cost_del) { + cost[i*M+j] = cost_match; + transition[i*M+j] = match; + } else if(cost_ins < cost_del) { + cost[i*M+j] = cost_ins; + transition[i*M+j] = insert; + } else { + cost[i*M+j] = cost_del; + transition[i*M+j] = del; + } + } + } + + //int off = 0; + //int len = N; + //for(int i=off; i<off+len; ++i) { + // for(int j=off; j<off+len; ++j) { + // printf("%4d ", (int)(cost[i*M+j] > 4000 ? -1 : cost[i*M+j])); + // } + // printf("\n"); + //} + //for(int i=off; i<off+len; ++i) { + // for(int j=off; j<off+len; ++j) { + // printf("%d ", transition[i*M+j]); + // } + // printf("\n"); + //} + + //for(int i=off; i<off+len; ++i) + // printf("%d: %s\n", i, a[i].c_str()); + //for(int i=off; i<off+len; ++i) + // printf("%d: %s\n", i, b[i].c_str()); + //exit(1); + + int total_cost = cost[(N-1)*M + (M-1)]; + if(total_cost < 500) { + printf("total cost = %f\n", cost[(N-1)*M + (M-1)]); + + int b_pos = b.size()-1; + int a_pos = a.size()-1; + while(a_pos > 0 && b_pos > 0) { + //printf("state = (%d, %d) => %f\n", a_pos, b_pos, cost[a_pos*M+b_pos]); + if(transition[a_pos*M+b_pos] == match) { + if(a[a_pos] != b[b_pos]) { + printf("REF - %s\n", a[a_pos].c_str()); + printf("NEW + %s\n", b[b_pos].c_str()); + } + //printf("R"); + a_pos -= 1; + b_pos -= 1; + } else if(transition[a_pos*M+b_pos] == del) { + //printf("D"); + //if(a[a_pos] != b[b_pos]) { + //printf("- %s\n", a[a_pos].c_str()); + printf("NEW - %s\n", b[b_pos].c_str()); + //} + b_pos -= 1; + } else if(transition[a_pos*M+b_pos] == insert) { + //if(a[a_pos] != b[b_pos]) { + printf("REF - %s\n", a[a_pos].c_str()); + printf("NEW + %s\n", b[b_pos].c_str()); + printf("NEW + %s\n", b[b_pos-1].c_str()); + //} + //printf("I"); + a_pos -= 1; + b_pos -= 2; + } else { + printf("ERROR STATE @(%d, %d)\n", a_pos, b_pos); + exit(1); + } + + } + //printf("%d vs %d\n", N, M); + } else { + printf("[WARNING] XML File appears to be radically different\n"); + } +} + +class PluginTest +{ + public: + Config config; + void setUp() { + synth = new SYNTH_T; + synth->buffersize = 256; + synth->samplerate = 48000; + synth->alias(); + + outL = new float[1024]; + for(int i = 0; i < synth->buffersize; ++i) + outL[i] = 0.0f; + outR = new float[1024]; + for(int i = 0; i < synth->buffersize; ++i) + outR[i] = 0.0f; + + for(int i = 0; i < 16; ++i) + master[i] = new Master(*synth, &config); + } + + void tearDown() { + for(int i = 0; i < 16; ++i) + delete master[i]; + + delete[] outL; + delete[] outR; + delete synth; + } + + + void testInit() { + + for(int x=0; x<100; ++x) + for(int i=0; i<16; ++i) + master[i]->GetAudioOutSamples(rand()%1025, + synth->samplerate, outL, outR); + } + + void testPanic() + { + master[0]->setController(0, 0x64, 0); + master[0]->noteOn(0,64,64); + master[0]->AudioOut(outL, outR); + + float sum = 0.0f; + for(int i = 0; i < synth->buffersize; ++i) + sum += fabsf(outL[i]); + + TS_ASSERT(0.1f < sum); + } + + string loadfile(string fname) const + { + std::ifstream t(fname.c_str()); + std::string str((std::istreambuf_iterator<char>(t)), + std::istreambuf_iterator<char>()); + return str; + } + + + void testLoadSave(void) + { + const string fname = string(SOURCE_DIR) + "/guitar-adnote.xmz"; + const string fdata = loadfile(fname); + char *result = NULL; + master[0]->putalldata((char*)fdata.c_str()); + int res = master[0]->getalldata(&result); + + TS_ASSERT_EQUAL_INT((int)(fdata.length()+1), res); + TS_ASSERT(fdata == result); + if(fdata != result) + print_string_differences(fdata, result); + } + + + private: + float *outR, *outL; + Master *master[16]; +}; + +int main() +{ + PluginTest test; + RUN_TEST(testInit); + RUN_TEST(testPanic); + RUN_TEST(testLoadSave); +} diff --git a/src/Tests/PluginTest.h b/src/Tests/PluginTest.h @@ -1,244 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - PluginTest.h - CxxTest for embedding zyn - Copyright (C) 2013-2013 Mark McCurry - Authors: Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ -#include <cxxtest/TestSuite.h> -#include <cmath> -#include <cstdlib> -#include <iostream> -#include <fstream> -#include <string> -#include "../Misc/MiddleWare.h" -#include "../Misc/Master.h" -#include "../Misc/PresetExtractor.h" -#include "../Misc/PresetExtractor.cpp" -#include "../Misc/Util.h" -#include "../globals.h" -#include "../UI/NSM.H" - -using namespace std; -using namespace zyn; - -SYNTH_T *synth; -NSM_Client *nsm = 0; - -char *instance_name=(char*)""; -MiddleWare *middleware; - -void fill_vec_with_lines(std::vector<string> &v, string s) -{ - std::istringstream stream(s); - std::string line; - while(std::getline(stream, line)) - v.push_back(line); -} -void print_string_differences(string orig, string next) -{ - std::vector<string> a, b; - fill_vec_with_lines(a, orig); - fill_vec_with_lines(b, next); - int N = a.size(); - int M = b.size(); - printf("%d vs %d\n", N, M); - - //Original String by New String - //Each step is either an insertion, deletion, or match - //Match is 0 cost and moves +1 State (if symbols are the same) - //Replace is 3 cost and moves +1 State (if symbols are different) - //Insertion is 2 cost and moves +2 State (+2 if symbols are different) - //Deletion is 1 cost and moves +0 State (+2 if symbols are different) - char *transition = new char[N*M]; - float *cost = new float[N*M]; - - const int match = 1; - const int insert = 2; - const int del = 3; - for(int i=0; i<N; ++i) { - for(int j=0; j<M; ++j) { - transition[i*M + j] = 0; - cost[i*M + j] = 0xffff; - } - } - - //Just assume the -1 line is the same - cost[0*M + 0] = (a[0] != b[0])*3; - cost[0*M + 1] = (a[1] != b[0])*2 + 2; - for(int i=1; i<N; ++i) { - for(int j=0; j<M; ++j) { - int cost_match = 0xffffff; - int cost_ins = 0xffffff; - int cost_del = 0xffffff; - cost_del = cost[(i-1)*M + j] + 2 + (a[i] != b[j])*2; - if(j > 1) - cost_ins = cost[(i-1)*M + (j-2)] + 1 + 2*(a[i] != b[j]); - if(j > 0) - cost_match = cost[(i-1)*M + (j-1)] + 3*(a[i] != b[j]); - - if(cost_match >= 0xffff && cost_ins >= 0xffff && cost_del >= 0xffff) { - ; - } else if(cost_match < cost_ins && cost_match < cost_del) { - cost[i*M+j] = cost_match; - transition[i*M+j] = match; - } else if(cost_ins < cost_del) { - cost[i*M+j] = cost_ins; - transition[i*M+j] = insert; - } else { - cost[i*M+j] = cost_del; - transition[i*M+j] = del; - } - } - } - - //int off = 0; - //int len = N; - //for(int i=off; i<off+len; ++i) { - // for(int j=off; j<off+len; ++j) { - // printf("%4d ", (int)(cost[i*M+j] > 4000 ? -1 : cost[i*M+j])); - // } - // printf("\n"); - //} - //for(int i=off; i<off+len; ++i) { - // for(int j=off; j<off+len; ++j) { - // printf("%d ", transition[i*M+j]); - // } - // printf("\n"); - //} - - //for(int i=off; i<off+len; ++i) - // printf("%d: %s\n", i, a[i].c_str()); - //for(int i=off; i<off+len; ++i) - // printf("%d: %s\n", i, b[i].c_str()); - //exit(1); - - int total_cost = cost[(N-1)*M + (M-1)]; - if(total_cost < 500) { - printf("total cost = %f\n", cost[(N-1)*M + (M-1)]); - - int b_pos = b.size()-1; - int a_pos = a.size()-1; - while(a_pos > 0 && b_pos > 0) { - //printf("state = (%d, %d) => %f\n", a_pos, b_pos, cost[a_pos*M+b_pos]); - if(transition[a_pos*M+b_pos] == match) { - if(a[a_pos] != b[b_pos]) { - printf("REF - %s\n", a[a_pos].c_str()); - printf("NEW + %s\n", b[b_pos].c_str()); - } - //printf("R"); - a_pos -= 1; - b_pos -= 1; - } else if(transition[a_pos*M+b_pos] == del) { - //printf("D"); - //if(a[a_pos] != b[b_pos]) { - //printf("- %s\n", a[a_pos].c_str()); - printf("NEW - %s\n", b[b_pos].c_str()); - //} - b_pos -= 1; - } else if(transition[a_pos*M+b_pos] == insert) { - //if(a[a_pos] != b[b_pos]) { - printf("REF - %s\n", a[a_pos].c_str()); - printf("NEW + %s\n", b[b_pos].c_str()); - printf("NEW + %s\n", b[b_pos-1].c_str()); - //} - //printf("I"); - a_pos -= 1; - b_pos -= 2; - } else { - printf("ERROR STATE @(%d, %d)\n", a_pos, b_pos); - exit(1); - } - - } - //printf("%d vs %d\n", N, M); - } else { - printf("[WARNING] XML File appears to be radically different\n"); - } -} - -class PluginTest:public CxxTest::TestSuite -{ - public: - Config config; - void setUp() { - synth = new SYNTH_T; - synth->buffersize = 256; - synth->samplerate = 48000; - synth->alias(); - - outL = new float[1024]; - for(int i = 0; i < synth->buffersize; ++i) - outL[i] = 0.0f; - outR = new float[1024]; - for(int i = 0; i < synth->buffersize; ++i) - outR[i] = 0.0f; - - for(int i = 0; i < 16; ++i) - master[i] = new Master(*synth, &config); - } - - void tearDown() { - for(int i = 0; i < 16; ++i) - delete master[i]; - - delete[] outL; - delete[] outR; - delete synth; - } - - - void testInit() { - - for(int x=0; x<100; ++x) - for(int i=0; i<16; ++i) - master[i]->GetAudioOutSamples(rand()%1025, - synth->samplerate, outL, outR); - } - - void testPanic() - { - master[0]->setController(0, 0x64, 0); - master[0]->noteOn(0,64,64); - master[0]->AudioOut(outL, outR); - - float sum = 0.0f; - for(int i = 0; i < synth->buffersize; ++i) - sum += fabsf(outL[i]); - - TS_ASSERT_LESS_THAN(0.1f, sum); - } - - string loadfile(string fname) const - { - std::ifstream t(fname.c_str()); - std::string str((std::istreambuf_iterator<char>(t)), - std::istreambuf_iterator<char>()); - return str; - } - - - void testLoadSave(void) - { - const string fname = string(SOURCE_DIR) + "/guitar-adnote.xmz"; - const string fdata = loadfile(fname); - char *result = NULL; - master[0]->putalldata((char*)fdata.c_str()); - int res = master[0]->getalldata(&result); - - TS_ASSERT_EQUALS((int)(fdata.length()+1), res); - TS_ASSERT(fdata == result); - if(fdata != result) - print_string_differences(fdata, result); - } - - - private: - float *outR, *outL; - Master *master[16]; -}; diff --git a/src/Tests/RandTest.cpp b/src/Tests/RandTest.cpp @@ -0,0 +1,26 @@ +/* + ZynAddSubFX - a software synthesizer + + RandTest.h - CxxTest for Pseudo-Random Number Generator + Copyright (C) 2009-2009 Mark McCurry + Author: Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ + +#include "../Misc/Util.h" +#include "test-suite.h" +using namespace zyn; + +int main() +{ + TS_ASSERT_DELTA(RND, 0.607781, 0.00001); + TS_ASSERT_DELTA(RND, 0.591761, 0.00001); + TS_ASSERT_DELTA(RND, 0.186133, 0.00001); + TS_ASSERT_DELTA(RND, 0.286319, 0.00001); + TS_ASSERT_DELTA(RND, 0.511766, 0.00001); + return test_summary(); +}; diff --git a/src/Tests/RandTest.h b/src/Tests/RandTest.h @@ -1,31 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - RandTest.h - CxxTest for Pseudo-Random Number Generator - Copyright (C) 2009-2009 Mark McCurry - Author: Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ - -#include "../Misc/Util.h" -#include <cstdlib> -#include <cstdio> -#include <cxxtest/TestSuite.h> -using namespace zyn; - -class RandTest:public CxxTest::TestSuite -{ - public: - void testPRNG(void) { - //verify RND returns expected pattern when unseeded - TS_ASSERT_DELTA(RND, 0.607781, 0.00001); - TS_ASSERT_DELTA(RND, 0.591761, 0.00001); - TS_ASSERT_DELTA(RND, 0.186133, 0.00001); - TS_ASSERT_DELTA(RND, 0.286319, 0.00001); - TS_ASSERT_DELTA(RND, 0.511766, 0.00001); - } -}; diff --git a/src/Tests/RtAllocTest.h b/src/Tests/RtAllocTest.cpp diff --git a/src/Tests/SubNoteTest.cpp b/src/Tests/SubNoteTest.cpp @@ -0,0 +1,192 @@ +/* + ZynAddSubFX - a software synthesizer + + AdNoteTest.h - CxxTest for Synth/SUBnote + Copyright (C) 2009-2011 Mark McCurry + Author: Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ + +//Based Upon AdNoteTest.h +#include "test-suite.h" +#include <iostream> +#include <fstream> +#include <ctime> +#include <string> +#include "../Misc/Master.h" +#include "../Misc/Allocator.h" +#include "../Misc/Util.h" +#include "../Misc/XMLwrapper.h" +#include "../Synth/SUBnote.h" +#include "../Params/SUBnoteParameters.h" +#include "../Params/Presets.h" +#include "../globals.h" +#include <rtosc/thread-link.h> + +using namespace std; +using namespace zyn; + +SYNTH_T *synth; + +class SubNoteTest +{ + public: + + SUBnoteParameters *pars; + SUBnote *note; + Master *master; + AbsTime *time; + Controller *controller; + float test_freq_log2; + Alloc memory; + rtosc::ThreadLink *tr; + WatchManager *w; + + + float *outR, *outL; + + void setUp() { + synth = new SYNTH_T; + //First the sensible settings and variables that have to be set: + synth->buffersize = 256; + time = new AbsTime(*synth); + + outL = new float[synth->buffersize]; + for(int i = 0; i < synth->buffersize; ++i) + *(outL + i) = 0; + outR = new float[synth->buffersize]; + for(int i = 0; i < synth->buffersize; ++i) + *(outR + i) = 0; + + tr = new rtosc::ThreadLink(1024,3); + w = new WatchManager(tr); + + //prepare the default settings + SUBnoteParameters *defaultPreset = new SUBnoteParameters(time); + XMLwrapper wrap; + wrap.loadXMLfile(string(SOURCE_DIR) + + string("/guitar-adnote.xmz")); + TS_ASSERT(wrap.enterbranch("MASTER")); + TS_ASSERT(wrap.enterbranch("PART", 1)); + TS_ASSERT(wrap.enterbranch("INSTRUMENT")); + TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT")); + TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT_ITEM", 0)); + TS_ASSERT(wrap.enterbranch("SUB_SYNTH_PARAMETERS")); + defaultPreset->getfromXML(wrap); + + controller = new Controller(*synth, time); + + //lets go with.... 50! as a nice note + test_freq_log2 = log2f(440.0f) + (50.0 - 69.0f) / 12.0f; + + SynthParams pars{memory, *controller, *synth, *time, 120, 0, test_freq_log2, false, prng()}; + note = new SUBnote(defaultPreset, pars, w); + this->pars = defaultPreset; + } + + void tearDown() { + delete controller; + delete note; + delete [] outL; + delete [] outR; + delete time; + delete synth; + delete pars; + } + + void testDefaults() { + //Note: if these tests fail it is due to the relationship between + //global.h::RND and SUBnote.cpp + + int sampleCount = 0; + +//#define WRITE_OUTPUT + +#ifdef WRITE_OUTPUT + ofstream file("subnoteout", ios::out); +#endif + note->noteout(outL, outR); +#ifdef WRITE_OUTPUT + for(int i = 0; i < synth->buffersize; ++i) + file << outL[i] << std::endl; + +#endif + sampleCount += synth->buffersize; + + TS_ASSERT_DELTA(outL[255], 0.0010f, 0.0001f); + + note->releasekey(); + + TS_ASSERT(!tr->hasNext()); + w->add_watch("noteout/filter"); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], 0.0114f, 0.0001f); + w->tick(); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], -0.0014f, 0.0001f); + w->tick(); + + TS_ASSERT(tr->hasNext()); + TS_ASSERT_EQUAL_STR("noteout/filter", tr->read()); + TS_ASSERT(!tr->hasNext()); + + w->add_watch("noteout/amp_int"); + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], -0.0031f, 0.0001f); + w->tick(); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], -0.0013f, 0.0001f); + w->tick(); + TS_ASSERT(tr->hasNext()); + TS_ASSERT_EQUAL_STR("noteout/amp_int", tr->read()); + TS_ASSERT(!tr->hasNext()); + + while(!note->finished()) { + note->noteout(outL, outR); +#ifdef WRITE_OUTPUT + for(int i = 0; i < synth->buffersize; ++i) + file << outL[i] << std::endl; + +#endif + sampleCount += synth->buffersize; + } +#ifdef WRITE_OUTPUT + file.close(); +#endif + + TS_ASSERT_EQUAL_INT(sampleCount, 5888); + } + +#define OUTPUT_PROFILE +#ifdef OUTPUT_PROFILE + void testSpeed() { + const int samps = 15000; + + int t_on = clock(); // timer before calling func + for(int i = 0; i < samps; ++i) + note->noteout(outL, outR); + int t_off = clock(); // timer when func returns + + printf("SubNoteTest: %f seconds for %d Samples to be generated.\n", + (static_cast<float>(t_off - t_on)) / CLOCKS_PER_SEC, samps); + } +#endif +}; + +int main(void) +{ + SubNoteTest test; + RUN_TEST(testDefaults); + return test_summary(); +} diff --git a/src/Tests/SubNoteTest.h b/src/Tests/SubNoteTest.h @@ -1,185 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - AdNoteTest.h - CxxTest for Synth/SUBnote - Copyright (C) 2009-2011 Mark McCurry - Author: Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ - -//Based Upon AdNoteTest.h -#include <cxxtest/TestSuite.h> -#include <iostream> -#include <fstream> -#include <ctime> -#include <string> -#include "../Misc/Master.h" -#include "../Misc/Allocator.h" -#include "../Misc/Util.h" -#include "../Misc/XMLwrapper.h" -#include "../Synth/SUBnote.h" -#include "../Params/SUBnoteParameters.h" -#include "../Params/Presets.h" -#include "../globals.h" -#include <rtosc/thread-link.h> - -using namespace std; -using namespace zyn; - -SYNTH_T *synth; - -class SubNoteTest:public CxxTest::TestSuite -{ - public: - - SUBnoteParameters *pars; - SUBnote *note; - Master *master; - AbsTime *time; - Controller *controller; - float test_freq_log2; - Alloc memory; - rtosc::ThreadLink *tr; - WatchManager *w; - - - float *outR, *outL; - - void setUp() { - synth = new SYNTH_T; - //First the sensible settings and variables that have to be set: - synth->buffersize = 256; - time = new AbsTime(*synth); - - outL = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - *(outL + i) = 0; - outR = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - *(outR + i) = 0; - - tr = new rtosc::ThreadLink(1024,3); - w = new WatchManager(tr); - - //prepare the default settings - SUBnoteParameters *defaultPreset = new SUBnoteParameters(time); - XMLwrapper wrap; - wrap.loadXMLfile(string(SOURCE_DIR) - + string("/guitar-adnote.xmz")); - TS_ASSERT(wrap.enterbranch("MASTER")); - TS_ASSERT(wrap.enterbranch("PART", 1)); - TS_ASSERT(wrap.enterbranch("INSTRUMENT")); - TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT")); - TS_ASSERT(wrap.enterbranch("INSTRUMENT_KIT_ITEM", 0)); - TS_ASSERT(wrap.enterbranch("SUB_SYNTH_PARAMETERS")); - defaultPreset->getfromXML(wrap); - - controller = new Controller(*synth, time); - - //lets go with.... 50! as a nice note - test_freq_log2 = log2f(440.0f) + (50.0 - 69.0f) / 12.0f; - - SynthParams pars{memory, *controller, *synth, *time, 120, 0, test_freq_log2, false, prng()}; - note = new SUBnote(defaultPreset, pars, w); - this->pars = defaultPreset; - } - - void tearDown() { - delete controller; - delete note; - delete [] outL; - delete [] outR; - delete time; - delete synth; - delete pars; - } - - void testDefaults() { - //Note: if these tests fail it is due to the relationship between - //global.h::RND and SUBnote.cpp - - int sampleCount = 0; - -//#define WRITE_OUTPUT - -#ifdef WRITE_OUTPUT - ofstream file("subnoteout", ios::out); -#endif - note->noteout(outL, outR); -#ifdef WRITE_OUTPUT - for(int i = 0; i < synth->buffersize; ++i) - file << outL[i] << std::endl; - -#endif - sampleCount += synth->buffersize; - - TS_ASSERT_DELTA(outL[255], 0.0010f, 0.0001f); - - note->releasekey(); - - TS_ASSERT(!tr->hasNext()); - w->add_watch("noteout/filter"); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.0114f, 0.0001f); - w->tick(); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.0014f, 0.0001f); - w->tick(); - - TS_ASSERT(tr->hasNext()); - TS_ASSERT_EQUALS(string("noteout/filter"), tr->read()); - TS_ASSERT(!tr->hasNext()); - - w->add_watch("noteout/amp_int"); - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.0031f, 0.0001f); - w->tick(); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.0013f, 0.0001f); - w->tick(); - TS_ASSERT(tr->hasNext()); - TS_ASSERT_EQUALS(string("noteout/amp_int"), tr->read()); - TS_ASSERT(!tr->hasNext()); - - while(!note->finished()) { - note->noteout(outL, outR); -#ifdef WRITE_OUTPUT - for(int i = 0; i < synth->buffersize; ++i) - file << outL[i] << std::endl; - -#endif - sampleCount += synth->buffersize; - } -#ifdef WRITE_OUTPUT - file.close(); -#endif - - TS_ASSERT_EQUALS(sampleCount, 5888); - } - -#define OUTPUT_PROFILE -#ifdef OUTPUT_PROFILE - void testSpeed() { - const int samps = 15000; - - int t_on = clock(); // timer before calling func - for(int i = 0; i < samps; ++i) - note->noteout(outL, outR); - int t_off = clock(); // timer when func returns - - printf("SubNoteTest: %f seconds for %d Samples to be generated.\n", - (static_cast<float>(t_off - t_on)) / CLOCKS_PER_SEC, samps); - } -#endif -}; diff --git a/src/Tests/TriggerTest.cpp b/src/Tests/TriggerTest.cpp @@ -0,0 +1,265 @@ +/* + ZynAddSubFX - a software synthesizer + + AdNoteTest.h - CxxTest for Synth/SUBnote + Copyright (C) 2009-2011 Mark McCurry + Author: Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ + +//Based Upon AdNoteTest.h +#include "test-suite.h" +#include <iostream> +#include <fstream> +#include <ctime> +#include <string> +#include "../Misc/Master.h" +#include "../Misc/Allocator.h" +#include "../Misc/Util.h" +#include "../Misc/XMLwrapper.h" +#include "../Synth/SUBnote.h" +#include "../Params/SUBnoteParameters.h" +#include "../Params/Presets.h" +#include "../globals.h" +#include <rtosc/thread-link.h> +#include <rtosc/rtosc.h> + +using namespace std; +using namespace zyn; + +SYNTH_T *synth; + +class TriggerTest +{ + public: + + SUBnoteParameters *pars; + SUBnote *note; + Master *master; + AbsTime *time; + Controller *controller; + float test_freq_log2; + Alloc memory; + rtosc::ThreadLink *tr; + WatchManager *w; + + + float *outR, *outL; + + void setUp() { + synth = new SYNTH_T; + // //First the sensible settings and variables that have to be set: + synth->buffersize = 32; + synth->alias(false); + outL = new float[synth->buffersize]; + outR = new float[synth->buffersize]; + for(int i = 0; i < synth->buffersize; ++i) { + outL[i] = 0; + outR[i] = 0; + } + + time = new AbsTime(*synth); + + tr = new rtosc::ThreadLink(1024,3); + w = new WatchManager(tr); + + //prepare the default settings + SUBnoteParameters *defaultPreset = new SUBnoteParameters(time); + sprng(3543); + + controller = new Controller(*synth, time); + + //lets go with.... 50! as a nice note + test_freq_log2 = log2f(440.0f) + (50.0 - 69.0f) / 12.0f; + + SynthParams pars{memory, *controller, *synth, *time, 120, 0, test_freq_log2, false, prng()}; + note = new SUBnote(defaultPreset, pars, w); + this->pars = defaultPreset; + } + + void tearDown() { + delete controller; + delete note; + delete [] outL; + delete [] outR; + delete time; + delete synth; + delete pars; + } + + void dump_samples(const char *s) { + puts(s); + for(int i=0; i<synth->buffersize; ++i) + printf(w->prebuffer[0][i]>0?"+":"-"); + printf("\n"); + for(int i=0; i<synth->buffersize; ++i) + printf(w->prebuffer[1][i]>0?"+":"-"); + printf("\n"); + //for(int i=0; i<synth->buffersize; ++i) + // printf("%d->%f\n", i, w->prebuffer[0][i]); + //for(int i=0; i<synth->buffersize; ++i) + // printf("%d->%f\n", i, w->prebuffer[1][i]); + } + + void testSine(void) { + //Generate a sine table + float data[1024] = {}; + for(int i=0; i<1024; ++i) + data[i] = -sin(2*M_PI*(i/1024.0)); + + //Preconditions + // + //- No pending messages + //- No active watch points + // + TS_ASSERT(!tr->hasNext()); + TS_ASSERT_EQUAL_STR("", w->active_list[0]); + TS_ASSERT_EQUAL_INT(0, w->sample_list[0]); + TS_ASSERT(!w->trigger_active("data")); + + + w->add_watch("noteout/filter"); + for(int i=0; i<1024; ++i) { + w->satisfy("noteout/filter", &data[i], 1); + w->tick(); + } + const char *msg1 = tr->read(); + float buf1[128] = {}; + assert_non_null(msg1, "valid message", __LINE__); + TS_ASSERT_EQUAL_INT(127, rtosc_narguments(msg1)); + + printf("msg1 = %s\n", msg1); + printf("msg1 = <%s>\n", rtosc_argument_string(msg1)); + printf("nargs = %d\n", rtosc_narguments(msg1)); + for(int i=0; i<127; ++i) + buf1[i] = rtosc_argument(msg1, i).f; + + w->add_watch("noteout/amp_int"); + for(int i=0; i<1024/97; ++i) { + w->satisfy("noteout/amp_int", &data[i*97], 97); + w->tick(); + } + const char *msg2 = tr->read(); + assert_non_null(msg2, "valid message", __LINE__); + TS_ASSERT_EQUAL_INT(127, rtosc_narguments(msg2)); + float buf2[128] = {}; + printf("nargs = %d\n", rtosc_narguments(msg2)); + for(int i=0; i<127; ++i) + buf2[i] = rtosc_argument(msg2, i).f; + for(int i=0; i<127; ++i){ + TS_ASSERT_EQUAL_FLT(buf1[i], buf2[i]); + TS_ASSERT_EQUAL_FLT(buf1[i],data[450+i]); + TS_ASSERT_EQUAL_FLT(buf2[i],data[450+i]); + } + } + + void testCombinedTrigger() { + //Generate a note + note->noteout(outL, outR); + note->releasekey(); + + //Preconditions + // + //- No pending messages + //- No active watch points + // + TS_ASSERT(!tr->hasNext()); + TS_ASSERT_EQUAL_STR("", w->active_list[0]); + TS_ASSERT_EQUAL_STR("", w->active_list[1]); + TS_ASSERT_EQUAL_INT(0, w->sample_list[0]); + TS_ASSERT_EQUAL_INT(0, w->sample_list[1]); + TS_ASSERT(!w->trigger_active("noteout/filter")); + TS_ASSERT(!w->trigger_active("noteout/amp_int")); + + //Setup a watchpoint + // + // - Watchpoints will be added to the active list in the watch + // manager + // - Watchpoints will not be triggered + w->add_watch("noteout/filter"); + w->add_watch("noteout/amp_int"); + TS_ASSERT(!w->trigger_active("noteout/filter")); + TS_ASSERT(!w->trigger_active("noteout/amp_int")); + TS_ASSERT_EQUAL_STR("noteout/filter", w->active_list[0]); + TS_ASSERT_EQUAL_STR("noteout/amp_int", w->active_list[1]); + TS_ASSERT_EQUAL_INT(0, w->sample_list[0]); + TS_ASSERT_EQUAL_INT(0, w->sample_list[1]); + dump_samples("Initial pre-buffer"); + + //Run the system + //noteout1 should trigger on this buffer + note->noteout(outL, outR); + + w->tick(); + dump_samples("Step 1 pre-buffer"); + TS_ASSERT(!w->trigger_active("noteout/filter")); //not active as prebuffer is not filled + TS_ASSERT(!w->trigger_active("noteout/amp_int")); + TS_ASSERT(!tr->hasNext()); + TS_ASSERT(w->sample_list[0] <= 0); // Is 0 as prebuffer not filled + TS_ASSERT(w->sample_list[1] <= 0); + + + //Both should continue to accumulate samples + note->noteout(outL, outR); + w->tick(); + dump_samples("Step 2 pre-buffer\n"); + TS_ASSERT(!w->trigger_active("noteout/filter")); //not active as prebuffer is not filled + TS_ASSERT(!w->trigger_active("noteout/amp_int")); + TS_ASSERT(!tr->hasNext()); + TS_ASSERT(w->sample_list[0] <= 0); // Is 0 as prebuffer not filled + TS_ASSERT(w->sample_list[1] <= 0); + + //Continue accum samples + note->noteout(outL, outR); + w->tick(); + dump_samples("Step 3 pre-buffer\n"); + TS_ASSERT(!w->trigger_active("noteout/filter")); + TS_ASSERT(!w->trigger_active("noteout/amp_int")); + TS_ASSERT(!tr->hasNext()); + TS_ASSERT(w->sample_list[0] <= 0); // Is 0 as prebuffer not filled + TS_ASSERT(w->sample_list[1] <= 0); + + //Finish accumulating samples + note->noteout(outL, outR); + w->tick(); + dump_samples("Step 4 pre-buffer\n"); + TS_ASSERT(w->trigger_active("noteout/filter")); // trigger activate and filling post buffer + TS_ASSERT(w->trigger_active("noteout/amp_int")); + TS_ASSERT(!tr->hasNext()); // post buffer not reach 128 + TS_ASSERT(w->sample_list[1] <= 128); // prebuffer + postbuffer filled in + TS_ASSERT(w->sample_list[0] <= 128); + note->noteout(outL, outR); + w->tick(); + note->noteout(outL, outR); + w->tick(); + +#define f32 "ffffffffffffffffffffffffffffffff" +#define f128 f32 f32 f32 f32 + //Verify the output to the user interface + //if 128 samples are requested, then 128 should be delivered + const char *msg1 = tr->read(); + TS_ASSERT_EQUAL_STR("noteout/filter", msg1); + TS_ASSERT_EQUAL_STR(f128, rtosc_argument_string(msg1)); + TS_ASSERT_EQUAL_INT(128, strlen(rtosc_argument_string(msg1))); + note->noteout(outL, outR); + w->tick(); + TS_ASSERT(tr->hasNext()); + const char *msg2 = tr->read(); + TS_ASSERT_EQUAL_STR("noteout/amp_int", msg2); + TS_ASSERT_EQUAL_INT(128, strlen(rtosc_argument_string(msg2))); + TS_ASSERT_EQUAL_STR(f128, rtosc_argument_string(msg2)); + TS_ASSERT(!tr->hasNext()); + } + +}; + +int main() +{ + TriggerTest test; + RUN_TEST(testSine); + RUN_TEST(testCombinedTrigger); +} diff --git a/src/Tests/TriggerTest.h b/src/Tests/TriggerTest.h @@ -1,258 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - AdNoteTest.h - CxxTest for Synth/SUBnote - Copyright (C) 2009-2011 Mark McCurry - Author: Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ - -//Based Upon AdNoteTest.h -#include <cxxtest/TestSuite.h> -#include <iostream> -#include <fstream> -#include <ctime> -#include <string> -#include "../Misc/Master.h" -#include "../Misc/Allocator.h" -#include "../Misc/Util.h" -#include "../Misc/XMLwrapper.h" -#include "../Synth/SUBnote.h" -#include "../Params/SUBnoteParameters.h" -#include "../Params/Presets.h" -#include "../globals.h" -#include <rtosc/thread-link.h> -#include <rtosc/rtosc.h> - -using namespace std; -using namespace zyn; - -SYNTH_T *synth; - -class TriggerTest:public CxxTest::TestSuite -{ - public: - - SUBnoteParameters *pars; - SUBnote *note; - Master *master; - AbsTime *time; - Controller *controller; - float test_freq_log2; - Alloc memory; - rtosc::ThreadLink *tr; - WatchManager *w; - - - float *outR, *outL; - - void setUp() { - synth = new SYNTH_T; - // //First the sensible settings and variables that have to be set: - synth->buffersize = 32; - synth->alias(false); - outL = new float[synth->buffersize]; - outR = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) { - outL[i] = 0; - outR[i] = 0; - } - - time = new AbsTime(*synth); - - tr = new rtosc::ThreadLink(1024,3); - w = new WatchManager(tr); - - //prepare the default settings - SUBnoteParameters *defaultPreset = new SUBnoteParameters(time); - sprng(3543); - - controller = new Controller(*synth, time); - - //lets go with.... 50! as a nice note - test_freq_log2 = log2f(440.0f) + (50.0 - 69.0f) / 12.0f; - - SynthParams pars{memory, *controller, *synth, *time, 120, 0, test_freq_log2, false, prng()}; - note = new SUBnote(defaultPreset, pars, w); - this->pars = defaultPreset; - } - - void tearDown() { - delete controller; - delete note; - delete [] outL; - delete [] outR; - delete time; - delete synth; - delete pars; - } - - void dump_samples(const char *s) { - puts(s); - for(int i=0; i<synth->buffersize; ++i) - printf(w->prebuffer[0][i]>0?"+":"-"); - printf("\n"); - for(int i=0; i<synth->buffersize; ++i) - printf(w->prebuffer[1][i]>0?"+":"-"); - printf("\n"); - //for(int i=0; i<synth->buffersize; ++i) - // printf("%d->%f\n", i, w->prebuffer[0][i]); - //for(int i=0; i<synth->buffersize; ++i) - // printf("%d->%f\n", i, w->prebuffer[1][i]); - } - - void testSine(void) { - //Generate a sine table - float data[1024] = {}; - for(int i=0; i<1024; ++i) - data[i] = -sin(2*M_PI*(i/1024.0)); - - //Preconditions - // - //- No pending messages - //- No active watch points - // - TS_ASSERT(!tr->hasNext()); - TS_ASSERT_EQUALS(string(""), w->active_list[0]); - TS_ASSERT_EQUALS(0, w->sample_list[0]); - TS_ASSERT(!w->trigger_active("data")); - - - w->add_watch("noteout/filter"); - for(int i=0; i<1024; ++i) { - w->satisfy("noteout/filter", &data[i], 1); - w->tick(); - } - const char *msg1 = tr->read(); - float buf1[128] = {}; - TS_ASSERT(msg1); - TS_ASSERT_EQUALS(127, rtosc_narguments(msg1)); - - printf("msg1 = %s\n", msg1); - printf("msg1 = <%s>\n", rtosc_argument_string(msg1)); - printf("nargs = %d\n", rtosc_narguments(msg1)); - for(int i=0; i<127; ++i) - buf1[i] = rtosc_argument(msg1, i).f; - - w->add_watch("noteout/amp_int"); - for(int i=0; i<1024/97; ++i) { - w->satisfy("noteout/amp_int", &data[i*97], 97); - w->tick(); - } - const char *msg2 = tr->read(); - TS_ASSERT(msg2); - TS_ASSERT_EQUALS(127, rtosc_narguments(msg2)); - float buf2[128] = {}; - printf("nargs = %d\n", rtosc_narguments(msg2)); - for(int i=0; i<127; ++i) - buf2[i] = rtosc_argument(msg2, i).f; - for(int i=0; i<127; ++i){ - TS_ASSERT_EQUALS(buf1[i], buf2[i]); - TS_ASSERT_EQUALS(buf1[i],data[450+i]); - TS_ASSERT_EQUALS(buf2[i],data[450+i]); - } - } - - void testCombinedTrigger() { - //Generate a note - note->noteout(outL, outR); - note->releasekey(); - - //Preconditions - // - //- No pending messages - //- No active watch points - // - TS_ASSERT(!tr->hasNext()); - TS_ASSERT_EQUALS(string(""), w->active_list[0]); - TS_ASSERT_EQUALS(string(""), w->active_list[1]); - TS_ASSERT_EQUALS(0, w->sample_list[0]); - TS_ASSERT_EQUALS(0, w->sample_list[1]); - TS_ASSERT(!w->trigger_active("noteout/filter")); - TS_ASSERT(!w->trigger_active("noteout/amp_int")); - - //Setup a watchpoint - // - // - Watchpoints will be added to the active list in the watch - // manager - // - Watchpoints will not be triggered - w->add_watch("noteout/filter"); - w->add_watch("noteout/amp_int"); - TS_ASSERT(!w->trigger_active("noteout/filter")); - TS_ASSERT(!w->trigger_active("noteout/amp_int")); - TS_ASSERT_EQUALS(string("noteout/filter"), w->active_list[0]); - TS_ASSERT_EQUALS(string("noteout/amp_int"), w->active_list[1]); - TS_ASSERT_EQUALS(0, w->sample_list[0]); - TS_ASSERT_EQUALS(0, w->sample_list[1]); - dump_samples("Initial pre-buffer"); - - //Run the system - //noteout1 should trigger on this buffer - note->noteout(outL, outR); - - w->tick(); - dump_samples("Step 1 pre-buffer"); - TS_ASSERT(!w->trigger_active("noteout/filter")); //not active as prebuffer is not filled - TS_ASSERT(!w->trigger_active("noteout/amp_int")); - TS_ASSERT(!tr->hasNext()); - TS_ASSERT_LESS_THAN_EQUALS(w->sample_list[0], 0); // Is 0 as prebuffer not filled - TS_ASSERT_LESS_THAN_EQUALS(w->sample_list[1], 0); - - - //Both should continue to accumulate samples - note->noteout(outL, outR); - w->tick(); - dump_samples("Step 2 pre-buffer\n"); - TS_ASSERT(!w->trigger_active("noteout/filter")); //not active as prebuffer is not filled - TS_ASSERT(!w->trigger_active("noteout/amp_int")); - TS_ASSERT(!tr->hasNext()); - TS_ASSERT_LESS_THAN_EQUALS(w->sample_list[0], 0); // Is 0 as prebuffer not filled - TS_ASSERT_LESS_THAN_EQUALS(w->sample_list[1], 0); - - //Continue accum samples - note->noteout(outL, outR); - w->tick(); - dump_samples("Step 3 pre-buffer\n"); - TS_ASSERT(!w->trigger_active("noteout/filter")); - TS_ASSERT(!w->trigger_active("noteout/amp_int")); - TS_ASSERT(!tr->hasNext()); - TS_ASSERT_LESS_THAN_EQUALS(w->sample_list[0], 0); // Is 0 as prebuffer not filled - TS_ASSERT_LESS_THAN_EQUALS(w->sample_list[1], 0); - - //Finish accumulating samples - note->noteout(outL, outR); - w->tick(); - dump_samples("Step 4 pre-buffer\n"); - TS_ASSERT(w->trigger_active("noteout/filter")); // trigger activate and filling post buffer - TS_ASSERT(w->trigger_active("noteout/amp_int")); - TS_ASSERT(!tr->hasNext()); // post buffer not reach 128 - TS_ASSERT_LESS_THAN_EQUALS(w->sample_list[1], 128); // prebuffer + postbuffer filled in - TS_ASSERT_LESS_THAN_EQUALS(w->sample_list[0], 128); - note->noteout(outL, outR); - w->tick(); - note->noteout(outL, outR); - w->tick(); - -#define f32 "ffffffffffffffffffffffffffffffff" -#define f128 f32 f32 f32 f32 - //Verify the output to the user interface - //if 128 samples are requested, then 128 should be delivered - const char *msg1 = tr->read(); - TS_ASSERT_EQUALS(string("noteout/filter"), msg1); - TS_ASSERT_EQUALS(string(f128), rtosc_argument_string(msg1)); - TS_ASSERT_EQUALS(128, strlen(rtosc_argument_string(msg1))); - note->noteout(outL, outR); - w->tick(); - TS_ASSERT(tr->hasNext()); - const char *msg2 = tr->read(); - TS_ASSERT_EQUALS(string("noteout/amp_int"), msg2); - TS_ASSERT_EQUALS(128, strlen(rtosc_argument_string(msg2))); - TS_ASSERT_EQUALS(string(f128), rtosc_argument_string(msg2)); - TS_ASSERT(!tr->hasNext()); - } - -}; diff --git a/src/Tests/UnisonTest.cpp b/src/Tests/UnisonTest.cpp @@ -0,0 +1,187 @@ +/* + ZynAddSubFX - a software synthesizer + + AdNoteTest.h - CxxTest for Synth/ADnote + Copyright (C) 2009-2011 Mark McCurry + Copyright (C) 2009 Harald Hvaal + Authors: Mark McCurry, Harald Hvaal + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ + + +#include "test-suite.h" +#include <iostream> +#include <fstream> +#include <ctime> +#include <string> +#include "../Misc/Util.h" +#include "../Misc/Allocator.h" +#include "../Synth/ADnote.h" +#include "../Synth/OscilGen.h" +#include "../Params/Presets.h" +#include "../Params/FilterParams.h" +#include "../DSP/FFTwrapper.h" +#include "../globals.h" +using namespace std; +using namespace zyn; + +SYNTH_T *synth; + +#define BUF 256 +class UnisonTest +{ + public: + + ADnote *note; + FFTwrapper *fft; + Controller *controller; + float test_freq_log2; + ADnoteParameters *params; + AbsTime *time; + Alloc memory; + + + float outR[BUF], outL[BUF]; + + void setUp() { + //First the sensible settings and variables that have to be set: + synth = new SYNTH_T; + synth->buffersize = BUF; + synth->alias(); + time = new AbsTime(*synth); + + memset(outL,0,sizeof(outL)); + memset(outR,0,sizeof(outR)); + + fft = new FFTwrapper(BUF); + //prepare the default settings + params = new ADnoteParameters(*synth, fft, time); + + //sawtooth to make things a bit more interesting + params->VoicePar[0].OscilGn->Pcurrentbasefunc = 3; + + params->GlobalPar.PFilterVelocityScale = 64; + params->GlobalPar.GlobalFilter->basefreq = 5076.203125; + + controller = new Controller(*synth, time); + + //lets go with.... 50! as a nice note + test_freq_log2 = log2f(440.0f) + (50.0 - 69.0f) / 12.0f; + } + + void tearDown() { + delete note; + delete controller; + delete fft; + FFT_cleanup(); + delete time; + delete synth; + delete params; + } + + void run_test(int a, int b, int c, int d, int e, int f, float values[4]) + { + sprng(0); + + const int ADnote_unison_sizes[] = + {1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 0}; + params->VoicePar[0].Unison_size = ADnote_unison_sizes[a]; + params->VoicePar[0].Unison_frequency_spread = b; + params->VoicePar[0].Unison_stereo_spread = c; + params->VoicePar[0].Unison_vibratto = d; + params->VoicePar[0].Unison_vibratto_speed = e; + params->VoicePar[0].Unison_invert_phase = f; + + SynthParams pars{memory, *controller, *synth, *time, 120, 0, test_freq_log2, false, prng()}; + note = new ADnote(params, pars); + note->noteout(outL, outR); + TS_ASSERT_DELTA(outL[80], values[0], 1.9e-5); + printf("{%f,", outL[80]); + note->noteout(outL, outR); + TS_ASSERT_DELTA(outR[90], values[1], 1.9e-5); + printf("%f,", outR[90]); + note->noteout(outL, outR); + TS_ASSERT_DELTA(outL[20], values[2], 1.9e-5); + printf("%f,", outL[20]); + note->noteout(outL, outR); + TS_ASSERT_DELTA(outR[200], values[3], 1.9e-5); + printf("%f},\n", outR[200]); + } + + void testUnison() { + sprng(0xbeef); + + float data[][4] = { + {0.125972,0.029887,0.000000,0.138013}, + {-0.095414,-0.083965,-0.000000,0.009048}, + {-0.077587,-0.001760,-0.021463,-0.013995}, + {0.041240,-0.008561,-0.000000,-0.099298}, + {-0.098969,-0.048030,-0.000052,-0.087053}, + {0.104913,-0.081452,-0.017700,0.000978}, + {0.041270,0.003788,0.006064,0.002436}, + {-0.030791,-0.036072,-0.007964,-0.015141}, + {0.009218,0.015333,-0.007500,0.083076}, + {0.058909,0.064450,-0.002517,0.041595}, + {-0.007731,-0.009040,-0.068033,-0.016573}, + {-0.047286,-0.002355,-0.049196,0.016222}, + {0.014014,-0.002635,0.006542,0.050710}, + {-0.054877,-0.027135,0.040211,0.031927}, + {-0.048367,0.022010,0.018224,0.032846}, + }; + + int freq_spread[15]; + int stereo_spread[15]; + int vibrato[15]; + int vibrato_speed[15]; + int inv_phase[15]; + for(int i=0; i<15; ++i) + { + freq_spread[i] = prng()%0x7f; + stereo_spread[i] = prng()%0x7f; + vibrato[i] = prng()%0x7f; + vibrato_speed[i] = prng()%0x7f; + inv_phase[i] = prng()%5; + } + + printf("\n"); + for(int i=0; i<15; ++i) + { + run_test(i, freq_spread[i], stereo_spread[i], + vibrato[i], vibrato_speed[i], inv_phase[i], data[i]); + } +#if 0 + int sampleCount = 0; + + sampleCount += synth->buffersize; + + TS_ASSERT_DELTA(outL[255], 0.254609f, 0.0001f); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], -0.102197f, 0.0001f); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], -0.111422f, 0.0001f); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], -0.021375f, 0.0001f); + + note->noteout(outL, outR); + sampleCount += synth->buffersize; + TS_ASSERT_DELTA(outL[255], 0.149882f, 0.0001f); +#endif + } +}; + +int main() +{ + UnisonTest test; + RUN_TEST(testUnison); + return test_summary(); +} diff --git a/src/Tests/UnisonTest.h b/src/Tests/UnisonTest.h @@ -1,180 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - AdNoteTest.h - CxxTest for Synth/ADnote - Copyright (C) 2009-2011 Mark McCurry - Copyright (C) 2009 Harald Hvaal - Authors: Mark McCurry, Harald Hvaal - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ - - -#include <cxxtest/TestSuite.h> -#include <iostream> -#include <fstream> -#include <ctime> -#include <string> -#include "../Misc/Util.h" -#include "../Misc/Allocator.h" -#include "../Synth/ADnote.h" -#include "../Synth/OscilGen.h" -#include "../Params/Presets.h" -#include "../Params/FilterParams.h" -#include "../DSP/FFTwrapper.h" -#include "../globals.h" -using namespace std; -using namespace zyn; - -SYNTH_T *synth; - -#define BUF 256 -class AdNoteTest:public CxxTest::TestSuite -{ - public: - - ADnote *note; - FFTwrapper *fft; - Controller *controller; - float test_freq_log2; - ADnoteParameters *params; - AbsTime *time; - Alloc memory; - - - float outR[BUF], outL[BUF]; - - void setUp() { - //First the sensible settings and variables that have to be set: - synth = new SYNTH_T; - synth->buffersize = BUF; - synth->alias(); - time = new AbsTime(*synth); - - memset(outL,0,sizeof(outL)); - memset(outR,0,sizeof(outR)); - - fft = new FFTwrapper(BUF); - //prepare the default settings - params = new ADnoteParameters(*synth, fft, time); - - //sawtooth to make things a bit more interesting - params->VoicePar[0].OscilGn->Pcurrentbasefunc = 3; - - params->GlobalPar.PFilterVelocityScale = 64; - params->GlobalPar.GlobalFilter->basefreq = 5076.203125; - - controller = new Controller(*synth, time); - - //lets go with.... 50! as a nice note - test_freq_log2 = log2f(440.0f) + (50.0 - 69.0f) / 12.0f; - } - - void tearDown() { - delete note; - delete controller; - delete fft; - FFT_cleanup(); - delete time; - delete synth; - delete params; - } - - void run_test(int a, int b, int c, int d, int e, int f, float values[4]) - { - sprng(0); - - const int ADnote_unison_sizes[] = - {1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 0}; - params->VoicePar[0].Unison_size = ADnote_unison_sizes[a]; - params->VoicePar[0].Unison_frequency_spread = b; - params->VoicePar[0].Unison_stereo_spread = c; - params->VoicePar[0].Unison_vibratto = d; - params->VoicePar[0].Unison_vibratto_speed = e; - params->VoicePar[0].Unison_invert_phase = f; - - SynthParams pars{memory, *controller, *synth, *time, 120, 0, test_freq_log2, false, prng()}; - note = new ADnote(params, pars); - note->noteout(outL, outR); - TS_ASSERT_DELTA(outL[80], values[0], 1.9e-5); - printf("{%f,", outL[80]); - note->noteout(outL, outR); - TS_ASSERT_DELTA(outR[90], values[1], 1.9e-5); - printf("%f,", outR[90]); - note->noteout(outL, outR); - TS_ASSERT_DELTA(outL[20], values[2], 1.9e-5); - printf("%f,", outL[20]); - note->noteout(outL, outR); - TS_ASSERT_DELTA(outR[200], values[3], 1.9e-5); - printf("%f},\n", outR[200]); - } - - void testUnison() { - sprng(0xbeef); - - float data[][4] = { - {0.125972,0.029887,0.000000,0.138013}, - {-0.095414,-0.083965,-0.000000,0.009048}, - {-0.077587,-0.001760,-0.021463,-0.013995}, - {0.041240,-0.008561,-0.000000,-0.099298}, - {-0.098969,-0.048030,-0.000052,-0.087053}, - {0.104913,-0.081452,-0.017700,0.000978}, - {0.041270,0.003788,0.006064,0.002436}, - {-0.030791,-0.036072,-0.007964,-0.015141}, - {0.009218,0.015333,-0.007500,0.083076}, - {0.058909,0.064450,-0.002517,0.041595}, - {-0.007731,-0.009040,-0.068033,-0.016573}, - {-0.047286,-0.002355,-0.049196,0.016222}, - {0.014014,-0.002635,0.006542,0.050710}, - {-0.054877,-0.027135,0.040211,0.031927}, - {-0.048367,0.022010,0.018224,0.032846}, - }; - - int freq_spread[15]; - int stereo_spread[15]; - int vibrato[15]; - int vibrato_speed[15]; - int inv_phase[15]; - for(int i=0; i<15; ++i) - { - freq_spread[i] = prng()%0x7f; - stereo_spread[i] = prng()%0x7f; - vibrato[i] = prng()%0x7f; - vibrato_speed[i] = prng()%0x7f; - inv_phase[i] = prng()%5; - } - - printf("\n"); - for(int i=0; i<15; ++i) - { - run_test(i, freq_spread[i], stereo_spread[i], - vibrato[i], vibrato_speed[i], inv_phase[i], data[i]); - } -#if 0 - int sampleCount = 0; - - sampleCount += synth->buffersize; - - TS_ASSERT_DELTA(outL[255], 0.254609f, 0.0001f); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.102197f, 0.0001f); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.111422f, 0.0001f); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.021375f, 0.0001f); - - note->noteout(outL, outR); - sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.149882f, 0.0001f); -#endif - } -}; diff --git a/src/Tests/WatchTest.cpp b/src/Tests/WatchTest.cpp @@ -0,0 +1,91 @@ +/* + ZynAddSubFX - a software synthesizer + + PluginTest.h - CxxTest for realtime watch points + Copyright (C) 2015-2015 Mark McCurry + Authors: 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 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2 or later) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#include "test-suite.h" +#include <cmath> +#include <cstdlib> +#include <iostream> +#include <fstream> +#include <string> +#include <thread> +#include <rtosc/thread-link.h> +#include "../Misc/Time.h" +#include "../Params/LFOParams.h" +#include "../Synth/LFO.h" +#include "../Synth/SynthNote.h" +#include <unistd.h> +using namespace std; +using namespace zyn; + +char *instance_name=(char*)""; + +class WatchTest +{ + public: + rtosc::ThreadLink *tr; + SYNTH_T *s; + AbsTime *at; + WatchManager *w; + LFOParams *par; + LFO *l; + void setUp() { + tr = new rtosc::ThreadLink(1024,3); + s = new SYNTH_T; + at = new AbsTime(*s); + w = new WatchManager(tr); + par = new LFOParams; + l = new LFO(*par, 440.0, *at, w); + + } + + void tearDown() { + delete at; + delete s; + delete tr; + } + + void testNoWatch(void) + { + TS_ASSERT(!tr->hasNext()); + l->lfoout(); + TS_ASSERT(!tr->hasNext()); + } + + void testPhaseWatch(void) + { + TS_ASSERT(!tr->hasNext()); + w->add_watch("out"); + l->lfoout(); + w->tick(); + TS_ASSERT(tr->hasNext()); + TS_ASSERT_EQUAL_STR("out", tr->read()); + TS_ASSERT(!tr->hasNext()); + } + +}; + +int main() +{ + WatchTest test; + RUN_TEST(testNoWatch); + RUN_TEST(testPhaseWatch); + return test_summary(); +} diff --git a/src/Tests/WatchTest.h b/src/Tests/WatchTest.h @@ -1,83 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - PluginTest.h - CxxTest for realtime watch points - Copyright (C) 2015-2015 Mark McCurry - Authors: 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 - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License (version 2 or later) for more details. - - You should have received a copy of the GNU General Public License (version 2) - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ -#include <cxxtest/TestSuite.h> -#include <cmath> -#include <cstdlib> -#include <iostream> -#include <fstream> -#include <string> -#include <thread> -#include <rtosc/thread-link.h> -#include "../Misc/Time.h" -#include "../Params/LFOParams.h" -#include "../Synth/LFO.h" -#include "../Synth/SynthNote.h" -#include <unistd.h> -using namespace std; -using namespace zyn; - -char *instance_name=(char*)""; - -class WatchTest:public CxxTest::TestSuite -{ - public: - rtosc::ThreadLink *tr; - SYNTH_T *s; - AbsTime *at; - WatchManager *w; - LFOParams *par; - LFO *l; - void setUp() { - tr = new rtosc::ThreadLink(1024,3); - s = new SYNTH_T; - at = new AbsTime(*s); - w = new WatchManager(tr); - par = new LFOParams; - l = new LFO(*par, 440.0, *at, w); - - } - - void tearDown() { - delete at; - delete s; - delete tr; - } - - void testNoWatch(void) - { - TS_ASSERT(!tr->hasNext()); - l->lfoout(); - TS_ASSERT(!tr->hasNext()); - } - - void testPhaseWatch(void) - { - TS_ASSERT(!tr->hasNext()); - w->add_watch("out"); - l->lfoout(); - w->tick(); - TS_ASSERT(tr->hasNext()); - TS_ASSERT_EQUALS(string("out"), tr->read()); - TS_ASSERT(!tr->hasNext()); - } - -}; diff --git a/src/Tests/XMLwrapperTest.cpp b/src/Tests/XMLwrapperTest.cpp @@ -0,0 +1,73 @@ +/* + ZynAddSubFX - a software synthesizer + + XMLwrapperTest.h - CxxTest for Misc/XMLwrapper + Copyright (C) 2009-2009 Mark McCurry + Author: Mark McCurry + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. +*/ +#include "test-suite.h" +#include "../Misc/XMLwrapper.h" +#include <string> +#include "../globals.h" +using namespace std; +using namespace zyn; + +SYNTH_T *synth; + +class XMLwrapperTest +{ + public: + void setUp() { + xmla = new XMLwrapper; + xmlb = new XMLwrapper; + } + + + void testAddPar() { + xmla->addpar("my Pa*_ramet@er", 75); + TS_ASSERT_EQUAL_INT(xmla->getpar("my Pa*_ramet@er", 0, -200, 200), 75); + } + + //here to verify that no leaks occur + void testLoad() { + string location = string(SOURCE_DIR) + string( + "/Tests/guitar-adnote.xmz"); + xmla->loadXMLfile(location); + } + + void testAnotherLoad() + { + string dat = + "\n<?xml version=\"1.0f\" encoding=\"UTF-8\"?>\n\ +<!DOCTYPE ZynAddSubFX-data>\n\ +<ZynAddSubFX-data version-major=\"2\" version-minor=\"4\"\n\ +version-revision=\"1\" ZynAddSubFX-author=\"Nasca Octavian Paul\">\n\ +</ZynAddSubFX-data>\n"; + xmlb->putXMLdata(dat.c_str()); + } + + void tearDown() { + delete xmla; + delete xmlb; + } + + + private: + XMLwrapper *xmla; + XMLwrapper *xmlb; +}; + +int main() +{ + XMLwrapperTest test; + RUN_TEST(testAddPar); + RUN_TEST(testLoad); + RUN_TEST(testAnotherLoad); + return test_summary(); +} + diff --git a/src/Tests/XMLwrapperTest.h b/src/Tests/XMLwrapperTest.h @@ -1,63 +0,0 @@ -/* - ZynAddSubFX - a software synthesizer - - XMLwrapperTest.h - CxxTest for Misc/XMLwrapper - Copyright (C) 2009-2009 Mark McCurry - Author: Mark McCurry - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. -*/ -#include <cxxtest/TestSuite.h> -#include "../Misc/XMLwrapper.h" -#include <string> -#include "../globals.h" -using namespace std; -using namespace zyn; - -SYNTH_T *synth; - -class XMLwrapperTest:public CxxTest::TestSuite -{ - public: - void setUp() { - xmla = new XMLwrapper; - xmlb = new XMLwrapper; - } - - - void testAddPar() { - xmla->addpar("my Pa*_ramet@er", 75); - TS_ASSERT_EQUALS(xmla->getpar("my Pa*_ramet@er", 0, -200, 200), 75); - } - - //here to verify that no leaks occur - void testLoad() { - string location = string(SOURCE_DIR) + string( - "/Tests/guitar-adnote.xmz"); - xmla->loadXMLfile(location); - } - - void testAnotherLoad() - { - string dat = - "\n<?xml version=\"1.0f\" encoding=\"UTF-8\"?>\n\ -<!DOCTYPE ZynAddSubFX-data>\n\ -<ZynAddSubFX-data version-major=\"2\" version-minor=\"4\"\n\ -version-revision=\"1\" ZynAddSubFX-author=\"Nasca Octavian Paul\">\n\ -</ZynAddSubFX-data>\n"; - xmlb->putXMLdata(dat.c_str()); - } - - void tearDown() { - delete xmla; - delete xmlb; - } - - - private: - XMLwrapper *xmla; - XMLwrapper *xmlb; -}; diff --git a/src/Tests/common.h b/src/Tests/common.h @@ -0,0 +1,250 @@ +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> + +int tap_quiet = 0; +int global_err = 0; +int test_counter = 0; +//expect a +//actual b +int assert_int_eq(int a, int b, const char *testcase, int line) +{ + test_counter++; + int err = a!=b; + if(err) { + printf("not ok %d - %s...\n", test_counter, testcase); + printf("# Expected %d, but observed %d instead (line %d)\n", a, b, line); + global_err++; + } else if(!tap_quiet) + printf("ok %d - %s...\n", test_counter, testcase); + return err; +} + +int assert_char_eq(char a, char b, const char *testcase, int line) +{ + test_counter++; + int err = a!=b; + if(err) { + printf("not ok %d - %s...\n", test_counter, testcase); + printf("# Expected %c, but observed %c instead (line %d)\n", a, b, line); + global_err++; + } else if(!tap_quiet) + printf("ok %d - %s...\n", test_counter, testcase); + return err; +} + +int assert_ptr_eq(const void* a, const void* b, const char *testcase, int line) +{ + test_counter++; + int err = a!=b; + if(err) { + printf("not ok %d - %s...\n", test_counter, testcase); + printf("# Expected %p, but observed %p instead (line %d)\n", a, b, line); + global_err++; + } else if(!tap_quiet) + printf("ok %d - %s...\n", test_counter, testcase); + return err; +} + +int assert_true(int a, const char *testcase, int line) +{ + test_counter++; + int err = !a; + if(err) { + printf("not ok %d - %s...\n", test_counter, testcase); + printf("# Failure on line %d\n", line); + global_err++; + } else if(!tap_quiet) + printf("ok %d - %s...\n", test_counter, testcase); + return err; +} + +int assert_false(int a, const char *testcase, int line) +{ + return assert_true(!a, testcase, line); +} + + +int assert_str_eq(const char *a, const char *b, const char *testcase, int line) +{ + test_counter++; + int err = strcmp(a,b); + if(err) { + printf("not ok %d - %s...\n", test_counter, testcase); + printf("# Expected '%s', but observed '%s' instead (line %d)\n", a, b, line); + global_err++; + } else if(!tap_quiet) + printf("ok %d - %s...\n", test_counter, testcase); + return err; +} + +int assert_null(const void *v, const char *testcase, int line) +{ + test_counter++; + int err = !!v; + if(err) { + printf("not ok %d - %s...\n", test_counter, testcase); + printf("# Expected NULL value, but observed Non-NULL instead (line %d)\n", line); + global_err++; + } else if(!tap_quiet) + printf("ok %d - %s...\n", test_counter, testcase); + return err; +} + +int assert_non_null(const void *v, const char *testcase, int line) +{ + test_counter++; + int err = !v; + if(err) { + printf("not ok %d - %s...\n", test_counter, testcase); + printf("# Expected Non-NULL value, but observed NULL instead (line %d)\n", line); + global_err++; + } else if(!tap_quiet) + printf("ok %d - %s...\n", test_counter, testcase); + return err; +} + +int assert_f32_eq(float a, float b,const char *testcase, int line) +{ + test_counter++; + int err = a!=b; + if(err) { + printf("not ok %d - %s...\n", test_counter, testcase); + printf("# Expected %f, but observed %f instead (line %d)\n", a, b, line); + global_err++; + } else if(!tap_quiet) + printf("ok %d - %s...\n", test_counter, testcase); + return err; +} + +int assert_f32_sim(float a, float b, float t, const char *testcase, int line) +{ + test_counter++; + float tmp = (a-b); + tmp = tmp<0?-tmp:tmp; + int err = tmp > t; + if(err) { + printf("not ok %d - %s...\n", test_counter, testcase); + printf("# Expected %f+-%f, but observed %f instead (line %d)\n", a, t, b, line); + global_err++; + } else if(!tap_quiet) + printf("ok %d - %s...\n", test_counter, testcase); + return err; +} + +//produce a xxd style hexdump with sections highlighted using escape sequences +// +//e.g. +//0000000: 2369 6e63 6c75 6465 203c 7374 6469 6f2e #include <stdio. +//0000010: 683e 0a23 696e 636c 7564 6520 3c73 7472 h>.#include <str +//0000020: 696e 672e 683e 0a0a 696e 7420 676c 6f62 ing.h>..int glob +//0000030: 616c 5f65 7272 203d 2030 3b0a 696e 7420 al_err = 0;.int +//0000040: 7465 7374 5f63 6f75 6e74 6572 203d 2030 test_counter = 0 +//0000050: 3b0a 2f2f 6578 7065 6374 2061 0a2f 2f61 ;.//expect a.//a +// +void hexdump(const char *data, const char *mask, size_t len) +{ + const char *bold_gray = "\x1b[30;1m"; + const char *reset = "\x1b[0m"; + int offset = 0; + while(1) + { + //print line + printf("#%07x: ", offset); + + int char_covered = 0; + + //print hex groups (8) + for(int i=0; i<8; ++i) { + + //print doublet + for(int j=0; j<2; ++j) { + int loffset = offset + 2*i + j; + if(loffset >= (int)len) + goto escape; + + //print hex + { + //start highlight + if(mask && mask[loffset]){printf("%s", bold_gray);} + + //print chars + printf("%02x", 0xff&data[loffset]); + + //end highlight + if(mask && mask[loffset]){printf("%s", reset);} + char_covered += 2; + } + } + printf(" "); + char_covered += 1; + } +escape: + + //print filler if needed + for(int i=char_covered; i<41; ++i) + printf(" "); + + //print ascii (16) + for(int i=0; i<16; ++i) { + if(isprint(data[offset+i])) + printf("%c", data[offset+i]); + else + printf("."); + } + printf("\n"); + offset += 16; + if(offset >= (int)len) + return; + } +} + + +int assert_hex_eq(const char *a, const char *b, size_t size_a, size_t size_b, + const char *testcase, int line) +{ + test_counter++; + int err = (size_a != size_b) || memcmp(a, b, size_a); + if(err) { + printf("not ok %d - %s...\n", test_counter, testcase); + printf("# Error on line %d\n", line); + //printf("# Expected '%s', but observed '%s' instead (line %d)\n", a, b, line); + + //create difference mask + const int longer = size_a > size_b ? size_a : size_b; + const int shorter = size_a < size_b ? size_a : size_b; + char mask[longer]; + memset(mask, 0, longer); + for(int i=0; i<shorter; ++i) + if(a[i] != b[i]) + mask[i] = 1; + + printf("#\n"); + printf("# Expected:\n"); + hexdump(a, mask, size_a); + printf("#\n"); + printf("# Observed:\n"); + hexdump(b, mask, size_b); + + global_err++; + } else if(!tap_quiet) + printf("ok %d - %s...\n", test_counter, testcase); + return err; +} + +int assert_flt_eq(float a, float b, const char *testcase, int line) +{ + int ret = assert_hex_eq((char*)&a, (char*)&b, sizeof(float), sizeof(float), + testcase, line); + if(ret) + printf("#expected=%f actual %f\n", a, b); + return ret; +} + +int test_summary(void) +{ + printf("# %d test(s) failed out of %d (currently passing %f%% tests)\n", + global_err, test_counter, 100.0-global_err*100./test_counter); + return global_err ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/Tests/test-suite.h b/src/Tests/test-suite.h @@ -0,0 +1,26 @@ +#include "common.h" + +#define TS_ASSERT(b) \ + assert_true(b, #b, __LINE__) + +#define TS_ASSERT_DELTA(a,b,t) \ + assert_f32_sim(a,b,t,"similar floats", __LINE__) + +#define TS_ASSERT_EQUAL_STR(a,b) \ + assert_str_eq(a,b,a " == " #b, __LINE__) + +#define TS_ASSERT_EQUAL_CPP(a,b) \ + assert_true(a == b,"equality check", __LINE__) + +#define TS_ASSERT_EQUAL_INT(a,b) \ + assert_int_eq(a,b,"similar ints", __LINE__) + +#define TS_ASSERT_EQUAL_FLT(a,b) \ + assert_f32_eq(a,b,"similar ints", __LINE__) +#define TS_NON_NULL(a) \ + assert_non_null(a, "valid pointer", __LINE__) + +#define RUN_TEST(x) \ + test.setUp();\ + test.x();\ + test.tearDown()