zynaddsubfx

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

commit 604c9ef7ee3f8f2c5a2093a97b75e090bcc494c8
parent d44dc9b66d503405cac29b73cdd15c962f0098b2
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Tue, 13 Sep 2011 17:02:12 -0400

Rand: Replacing rand() for portable tests

In order to keep tests simple with respect to signal processing code, a portable
Pseudo Random Number Generator was built.
This will ensure that the sequence of random numbers from a given seed are
identical from platform to platform.
As this is not a cryptographic application, this behavior should not be an
issue.
Basic statistics of random source verified.

For source of magic numbers, see glibc.

Diffstat:
Msrc/DSP/Unison.h | 2+-
Msrc/Effects/EffectLFO.cpp | 6+++---
Msrc/Misc/Util.cpp | 5+++--
Msrc/Misc/Util.h | 28++++++++++++++++++++++++++++
Msrc/Output/DSSIaudiooutput.cpp | 5+++--
Msrc/Params/FilterParams.cpp | 3++-
Msrc/Synth/ADnote.cpp | 14+++++++-------
Msrc/Synth/LFO.cpp | 6+++---
Msrc/Synth/OscilGen.cpp | 6+++---
Msrc/Tests/AdNoteTest.h | 10+++++-----
Msrc/Tests/CMakeLists.txt | 1+
Msrc/Tests/OscilGenTest.h | 8++++----
Msrc/Tests/RandTest.h | 12++++++------
Msrc/Tests/SubNoteTest.h | 8++++----
Msrc/globals.h | 6+-----
Msrc/main.cpp | 2+-
16 files changed, 75 insertions(+), 47 deletions(-)

diff --git a/src/DSP/Unison.h b/src/DSP/Unison.h @@ -22,7 +22,7 @@ #ifndef UNISON_H #define UNISON_H #include <stdlib.h> -#include "../globals.h" +#include "../Misc/Util.h" #define UNISON_FREQ_SPAN 2.0f //how much the unison frequencies varies (always >= 1.0f) diff --git a/src/Effects/EffectLFO.cpp b/src/Effects/EffectLFO.cpp @@ -20,11 +20,11 @@ */ -#include <cstdlib> -#include <cmath> - #include "EffectLFO.h" +#include "../Misc/Util.h" +#include <cstdlib> +#include <cmath> EffectLFO::EffectLFO() { diff --git a/src/Misc/Util.cpp b/src/Misc/Util.cpp @@ -35,9 +35,10 @@ #include <sched.h> -int SAMPLE_RATE = 44100; +int SAMPLE_RATE = 44100; int SOUND_BUFFER_SIZE = 256; -int OSCIL_SIZE = 1024; +int OSCIL_SIZE = 1024; +prng_t prng_state = 0x1234; Config config; float *denormalkillbuf; diff --git a/src/Misc/Util.h b/src/Misc/Util.h @@ -25,6 +25,7 @@ #include <string> #include <sstream> +#include <stdint.h> #include "Config.h" #include "../globals.h" @@ -86,6 +87,33 @@ T limit(T val, T min, T max) return (val < min ? min : (val > max ? max : val)); } +//Random number generator + +typedef uint32_t prng_t; +extern prng_t prng_state; + +// Portable Pseudo-Random Number Generator +inline prng_t prng_r(prng_t &p) +{ + return (p = p * 1103515245 + 12345); +} + +inline prng_t prng(void) +{ + return prng_r(prng_state)&0x7fffffff; +} + +inline void sprng(prng_t p) +{ + prng_state = p; +} + +/* + * The random generator (0.0f..1.0f) + */ +# define INT32_MAX (2147483647) +#define RND (prng() / (INT32_MAX * 1.0f)) + #endif diff --git a/src/Output/DSSIaudiooutput.cpp b/src/Output/DSSIaudiooutput.cpp @@ -27,10 +27,11 @@ //this file contains code used from trivial_synth.c from //the DSSI (published by Steve Harris under public domain) as a template. -#include <string.h> #include "DSSIaudiooutput.h" #include "../Misc/Config.h" #include "../Misc/Bank.h" +#include "../Misc/Util.h" +#include <string.h> #include <limits.h> using std::string; @@ -603,7 +604,7 @@ DSSIaudiooutput::DSSIaudiooutput(unsigned long sampleRate) config.init(); - srand(time(NULL)); + sprng(time(NULL)); denormalkillbuf=new float [SOUND_BUFFER_SIZE]; for (int i=0;i<SOUND_BUFFER_SIZE;i++) denormalkillbuf[i]=(RND-0.5f)*1e-16; diff --git a/src/Params/FilterParams.cpp b/src/Params/FilterParams.cpp @@ -20,10 +20,11 @@ */ +#include "FilterParams.h" +#include "../Misc/Util.h" #include <math.h> #include <stdio.h> #include <stdlib.h> -#include "FilterParams.h" FilterParams::FilterParams(unsigned char Ptype_, unsigned char Pfreq_, diff --git a/src/Synth/ADnote.cpp b/src/Synth/ADnote.cpp @@ -93,7 +93,7 @@ ADnote::ADnote(ADnoteParameters *pars, NoteGlobalPar.Punch.Enabled = 0; for(int nvoice = 0; nvoice < NUM_VOICES; ++nvoice) { - pars->VoicePar[nvoice].OscilSmp->newrandseed(rand()); + pars->VoicePar[nvoice].OscilSmp->newrandseed(prng()); NoteVoicePar[nvoice].OscilSmp = NULL; NoteVoicePar[nvoice].FMSmp = NULL; NoteVoicePar[nvoice].VoiceOut = NULL; @@ -275,7 +275,7 @@ ADnote::ADnote(ADnoteParameters *pars, if(pars->VoicePar[nvoice].Pextoscil != -1) vc = pars->VoicePar[nvoice].Pextoscil; if(!pars->GlobalPar.Hrandgrouping) - pars->VoicePar[vc].OscilSmp->newrandseed(rand()); + pars->VoicePar[vc].OscilSmp->newrandseed(prng()); int oscposhi_start = pars->VoicePar[vc].OscilSmp->get(NoteVoicePar[nvoice].OscilSmp, getvoicebasefreq(nvoice), @@ -478,7 +478,7 @@ void ADnote::legatonote(float freq, float velocity, int portamento_, if(pars->VoicePar[nvoice].Pextoscil != -1) vc = pars->VoicePar[nvoice].Pextoscil; if(!pars->GlobalPar.Hrandgrouping) - pars->VoicePar[vc].OscilSmp->newrandseed(rand()); + pars->VoicePar[vc].OscilSmp->newrandseed(prng()); pars->VoicePar[vc].OscilSmp->get(NoteVoicePar[nvoice].OscilSmp, getvoicebasefreq(nvoice), @@ -605,7 +605,7 @@ void ADnote::legatonote(float freq, float velocity, int portamento_, /* Voice Modulation Parameters Init */ if((NoteVoicePar[nvoice].FMEnabled != NONE) && (NoteVoicePar[nvoice].FMVoice < 0)) { - partparams->VoicePar[nvoice].FMSmp->newrandseed(rand()); + partparams->VoicePar[nvoice].FMSmp->newrandseed(prng()); //Perform Anti-aliasing only on MORPH or RING MODULATION @@ -614,7 +614,7 @@ void ADnote::legatonote(float freq, float velocity, int portamento_, vc = partparams->VoicePar[nvoice].PextFMoscil; if(!partparams->GlobalPar.Hrandgrouping) - partparams->VoicePar[vc].FMSmp->newrandseed(rand()); + partparams->VoicePar[vc].FMSmp->newrandseed(prng()); for(int i = 0; i < OSCIL_SMP_EXTRA_SAMPLES; ++i) NoteVoicePar[nvoice].FMSmp[OSCIL_SIZE + i] = @@ -777,7 +777,7 @@ void ADnote::initparameters() /* Voice Modulation Parameters Init */ if((vce.FMEnabled != NONE) && (vce.FMVoice < 0)) { - param.FMSmp->newrandseed(rand()); + param.FMSmp->newrandseed(prng()); vce.FMSmp = new float[OSCIL_SIZE + OSCIL_SMP_EXTRA_SAMPLES]; //Perform Anti-aliasing only on MORPH or RING MODULATION @@ -793,7 +793,7 @@ void ADnote::initparameters() tmp = getFMvoicebasefreq(nvoice); if(!partparams->GlobalPar.Hrandgrouping) - partparams->VoicePar[vc].FMSmp->newrandseed(rand()); + partparams->VoicePar[vc].FMSmp->newrandseed(prng()); for(int k = 0; k < unison_size[nvoice]; ++k) oscposhiFM[nvoice][k] = (oscposhi[nvoice][k] diff --git a/src/Synth/LFO.cpp b/src/Synth/LFO.cpp @@ -20,13 +20,13 @@ */ +#include "LFO.h" +#include "../Misc/Util.h" + #include <stdlib.h> #include <stdio.h> #include <math.h> -#include "LFO.h" - - LFO::LFO(LFOParams *lfopars, float basefreq) { if(lfopars->Pstretch == 0) diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp @@ -852,8 +852,8 @@ short int OscilGen::get(float *smps, float freqHz, int resonance) //Harmonic Amplitude Randomness if((freqHz > 0.1f) && (!ADvsPAD)) { - unsigned int realrnd = rand(); - srand(randseed); + unsigned int realrnd = prng(); + sprng(randseed); float power = Pamprandpower / 127.0f; float normalize = 1.0f / (1.2f - power); switch(Pamprandtype) { @@ -872,7 +872,7 @@ short int OscilGen::get(float *smps, float freqHz, int resonance) * normalize; break; } - srand(realrnd + 1); + sprng(realrnd + 1); } if((freqHz > 0.1f) && (resonance != 0)) diff --git a/src/Tests/AdNoteTest.h b/src/Tests/AdNoteTest.h @@ -118,26 +118,26 @@ class AdNoteTest:public CxxTest::TestSuite #endif sampleCount += SOUND_BUFFER_SIZE; - TS_ASSERT_DELTA(outL[255], 0.3019f, 0.0001f); + TS_ASSERT_DELTA(outL[255], 0.254609f, 0.0001f); note->relasekey(); note->noteout(outL, outR); sampleCount += SOUND_BUFFER_SIZE; - TS_ASSERT_DELTA(outL[255], -0.1382f, 0.0001f); + TS_ASSERT_DELTA(outL[255], -0.102197f, 0.0001f); note->noteout(outL, outR); sampleCount += SOUND_BUFFER_SIZE; - TS_ASSERT_DELTA(outL[255], -0.0334f, 0.0001f); + TS_ASSERT_DELTA(outL[255], -0.111422f, 0.0001f); note->noteout(outL, outR); sampleCount += SOUND_BUFFER_SIZE; - TS_ASSERT_DELTA(outL[255], -0.1329f, 0.0001f); + TS_ASSERT_DELTA(outL[255], -0.021375f, 0.0001f); note->noteout(outL, outR); sampleCount += SOUND_BUFFER_SIZE; - TS_ASSERT_DELTA(outL[255], 0.2690f, 0.0001f); + TS_ASSERT_DELTA(outL[255], 0.149882f, 0.0001f); while(!note->finished()) { note->noteout(outL, outR); diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt @@ -21,3 +21,4 @@ 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}) diff --git a/src/Tests/OscilGenTest.h b/src/Tests/OscilGenTest.h @@ -74,10 +74,10 @@ class OscilGenTest:public CxxTest::TestSuite void testOutput(void) { oscil->get(outL, freq); - TS_ASSERT_DELTA(outL[23], -0.014717f, 0.0001f); - TS_ASSERT_DELTA(outL[129], -0.567502f, 0.0001f); - TS_ASSERT_DELTA(outL[586], -0.030894f, 0.0001f); - TS_ASSERT_DELTA(outL[1023], -0.080001f, 0.0001f); + TS_ASSERT_DELTA(outL[23], -0.044547f, 0.0001f); + TS_ASSERT_DELTA(outL[129], -0.018169f, 0.0001f); + TS_ASSERT_DELTA(outL[586], 0.045647f, 0.0001f); + TS_ASSERT_DELTA(outL[1023], -0.038334f, 0.0001f); } void testSpectrum(void) diff --git a/src/Tests/RandTest.h b/src/Tests/RandTest.h @@ -20,7 +20,7 @@ */ -#include "../globals.h" +#include "../Misc/Util.h" #include <cstdlib> #include <cstdio> @@ -31,11 +31,11 @@ class RandTest:public CxxTest::TestSuite public: void testPRNG(void) { //verify RND returns expected pattern when unseeded - TS_ASSERT_DELTA(RND, 0.840188f, 0.00001f); - TS_ASSERT_DELTA(RND, 0.394383f, 0.00001f); - TS_ASSERT_DELTA(RND, 0.783099f, 0.00001f); - TS_ASSERT_DELTA(RND, 0.798440f, 0.00001f); - TS_ASSERT_DELTA(RND, 0.911647f, 0.00001f); + 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/SubNoteTest.h b/src/Tests/SubNoteTest.h @@ -111,19 +111,19 @@ class SubNoteTest:public CxxTest::TestSuite note->noteout(outL, outR); sampleCount += SOUND_BUFFER_SIZE; - TS_ASSERT_DELTA(outL[255], 0.0022f, 0.0001f); + TS_ASSERT_DELTA(outL[255], 0.0016f, 0.0001f); note->noteout(outL, outR); sampleCount += SOUND_BUFFER_SIZE; - TS_ASSERT_DELTA(outL[255], -0.0020f, 0.0001f); + TS_ASSERT_DELTA(outL[255], -0.0000f, 0.0001f); note->noteout(outL, outR); sampleCount += SOUND_BUFFER_SIZE; - TS_ASSERT_DELTA(outL[255], 0.0010f, 0.0001f); + TS_ASSERT_DELTA(outL[255], -0.0013f, 0.0001f); note->noteout(outL, outR); sampleCount += SOUND_BUFFER_SIZE; - TS_ASSERT_DELTA(outL[255], 0.0005f, 0.0001f); + TS_ASSERT_DELTA(outL[255], -0.0002f, 0.0001f); while(!note->finished()) { note->noteout(outL, outR); diff --git a/src/globals.h b/src/globals.h @@ -24,6 +24,7 @@ #ifndef GLOBALS_H #define GLOBALS_H +#include <stdint.h> /**Sampling rate*/ extern int SAMPLE_RATE; @@ -171,11 +172,6 @@ extern int OSCIL_SIZE; #define dB2rap(dB) ((expf((dB) * LOG_10 / 20.0f))) #define rap2dB(rap) ((20 * logf(rap) / LOG_10)) -/* - * The random generator (0.0f..1.0f) - */ -#define RND (rand() / (RAND_MAX * 1.0f)) - #define ZERO(data, size) {char *data_ = (char *) data; for(int i = 0; \ i < size; \ i++) \ diff --git a/src/main.cpp b/src/main.cpp @@ -194,7 +194,7 @@ int main(int argc, char *argv[]) OSCIL_SIZE = config.cfg.OscilSize; swaplr = config.cfg.SwapStereo; - srand(time(NULL)); + sprng(time(NULL)); //produce denormal buf denormalkillbuf = new float [SOUND_BUFFER_SIZE]; for(int i = 0; i < SOUND_BUFFER_SIZE; ++i)