Remove Cxxtest dependency
[zynaddsubfx-code.git] / src / Tests / TriggerTest.cpp
blob0d3fd97f6249f4ac3a82e684d39b59a7c2e3d2b9
1 /*
2 ZynAddSubFX - a software synthesizer
4 AdNoteTest.h - CxxTest for Synth/SUBnote
5 Copyright (C) 2009-2011 Mark McCurry
6 Author: Mark McCurry
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
14 //Based Upon AdNoteTest.h
15 #include "test-suite.h"
16 #include <iostream>
17 #include <fstream>
18 #include <ctime>
19 #include <string>
20 #include "../Misc/Master.h"
21 #include "../Misc/Allocator.h"
22 #include "../Misc/Util.h"
23 #include "../Misc/XMLwrapper.h"
24 #include "../Synth/SUBnote.h"
25 #include "../Params/SUBnoteParameters.h"
26 #include "../Params/Presets.h"
27 #include "../globals.h"
28 #include <rtosc/thread-link.h>
29 #include <rtosc/rtosc.h>
31 using namespace std;
32 using namespace zyn;
34 SYNTH_T *synth;
36 class TriggerTest
38 public:
40 SUBnoteParameters *pars;
41 SUBnote *note;
42 Master *master;
43 AbsTime *time;
44 Controller *controller;
45 float test_freq_log2;
46 Alloc memory;
47 rtosc::ThreadLink *tr;
48 WatchManager *w;
51 float *outR, *outL;
53 void setUp() {
54 synth = new SYNTH_T;
55 // //First the sensible settings and variables that have to be set:
56 synth->buffersize = 32;
57 synth->alias(false);
58 outL = new float[synth->buffersize];
59 outR = new float[synth->buffersize];
60 for(int i = 0; i < synth->buffersize; ++i) {
61 outL[i] = 0;
62 outR[i] = 0;
65 time = new AbsTime(*synth);
67 tr = new rtosc::ThreadLink(1024,3);
68 w = new WatchManager(tr);
70 //prepare the default settings
71 SUBnoteParameters *defaultPreset = new SUBnoteParameters(time);
72 sprng(3543);
74 controller = new Controller(*synth, time);
76 //lets go with.... 50! as a nice note
77 test_freq_log2 = log2f(440.0f) + (50.0 - 69.0f) / 12.0f;
79 SynthParams pars{memory, *controller, *synth, *time, 120, 0, test_freq_log2, false, prng()};
80 note = new SUBnote(defaultPreset, pars, w);
81 this->pars = defaultPreset;
84 void tearDown() {
85 delete controller;
86 delete note;
87 delete [] outL;
88 delete [] outR;
89 delete time;
90 delete synth;
91 delete pars;
94 void dump_samples(const char *s) {
95 puts(s);
96 for(int i=0; i<synth->buffersize; ++i)
97 printf(w->prebuffer[0][i]>0?"+":"-");
98 printf("\n");
99 for(int i=0; i<synth->buffersize; ++i)
100 printf(w->prebuffer[1][i]>0?"+":"-");
101 printf("\n");
102 //for(int i=0; i<synth->buffersize; ++i)
103 // printf("%d->%f\n", i, w->prebuffer[0][i]);
104 //for(int i=0; i<synth->buffersize; ++i)
105 // printf("%d->%f\n", i, w->prebuffer[1][i]);
108 void testSine(void) {
109 //Generate a sine table
110 float data[1024] = {};
111 for(int i=0; i<1024; ++i)
112 data[i] = -sin(2*M_PI*(i/1024.0));
114 //Preconditions
116 //- No pending messages
117 //- No active watch points
119 TS_ASSERT(!tr->hasNext());
120 TS_ASSERT_EQUAL_STR("", w->active_list[0]);
121 TS_ASSERT_EQUAL_INT(0, w->sample_list[0]);
122 TS_ASSERT(!w->trigger_active("data"));
125 w->add_watch("noteout/filter");
126 for(int i=0; i<1024; ++i) {
127 w->satisfy("noteout/filter", &data[i], 1);
128 w->tick();
130 const char *msg1 = tr->read();
131 float buf1[128] = {};
132 assert_non_null(msg1, "valid message", __LINE__);
133 TS_ASSERT_EQUAL_INT(127, rtosc_narguments(msg1));
135 printf("msg1 = %s\n", msg1);
136 printf("msg1 = <%s>\n", rtosc_argument_string(msg1));
137 printf("nargs = %d\n", rtosc_narguments(msg1));
138 for(int i=0; i<127; ++i)
139 buf1[i] = rtosc_argument(msg1, i).f;
141 w->add_watch("noteout/amp_int");
142 for(int i=0; i<1024/97; ++i) {
143 w->satisfy("noteout/amp_int", &data[i*97], 97);
144 w->tick();
146 const char *msg2 = tr->read();
147 assert_non_null(msg2, "valid message", __LINE__);
148 TS_ASSERT_EQUAL_INT(127, rtosc_narguments(msg2));
149 float buf2[128] = {};
150 printf("nargs = %d\n", rtosc_narguments(msg2));
151 for(int i=0; i<127; ++i)
152 buf2[i] = rtosc_argument(msg2, i).f;
153 for(int i=0; i<127; ++i){
154 TS_ASSERT_EQUAL_FLT(buf1[i], buf2[i]);
155 TS_ASSERT_EQUAL_FLT(buf1[i],data[450+i]);
156 TS_ASSERT_EQUAL_FLT(buf2[i],data[450+i]);
160 void testCombinedTrigger() {
161 //Generate a note
162 note->noteout(outL, outR);
163 note->releasekey();
165 //Preconditions
167 //- No pending messages
168 //- No active watch points
170 TS_ASSERT(!tr->hasNext());
171 TS_ASSERT_EQUAL_STR("", w->active_list[0]);
172 TS_ASSERT_EQUAL_STR("", w->active_list[1]);
173 TS_ASSERT_EQUAL_INT(0, w->sample_list[0]);
174 TS_ASSERT_EQUAL_INT(0, w->sample_list[1]);
175 TS_ASSERT(!w->trigger_active("noteout/filter"));
176 TS_ASSERT(!w->trigger_active("noteout/amp_int"));
178 //Setup a watchpoint
180 // - Watchpoints will be added to the active list in the watch
181 // manager
182 // - Watchpoints will not be triggered
183 w->add_watch("noteout/filter");
184 w->add_watch("noteout/amp_int");
185 TS_ASSERT(!w->trigger_active("noteout/filter"));
186 TS_ASSERT(!w->trigger_active("noteout/amp_int"));
187 TS_ASSERT_EQUAL_STR("noteout/filter", w->active_list[0]);
188 TS_ASSERT_EQUAL_STR("noteout/amp_int", w->active_list[1]);
189 TS_ASSERT_EQUAL_INT(0, w->sample_list[0]);
190 TS_ASSERT_EQUAL_INT(0, w->sample_list[1]);
191 dump_samples("Initial pre-buffer");
193 //Run the system
194 //noteout1 should trigger on this buffer
195 note->noteout(outL, outR);
197 w->tick();
198 dump_samples("Step 1 pre-buffer");
199 TS_ASSERT(!w->trigger_active("noteout/filter")); //not active as prebuffer is not filled
200 TS_ASSERT(!w->trigger_active("noteout/amp_int"));
201 TS_ASSERT(!tr->hasNext());
202 TS_ASSERT(w->sample_list[0] <= 0); // Is 0 as prebuffer not filled
203 TS_ASSERT(w->sample_list[1] <= 0);
206 //Both should continue to accumulate samples
207 note->noteout(outL, outR);
208 w->tick();
209 dump_samples("Step 2 pre-buffer\n");
210 TS_ASSERT(!w->trigger_active("noteout/filter")); //not active as prebuffer is not filled
211 TS_ASSERT(!w->trigger_active("noteout/amp_int"));
212 TS_ASSERT(!tr->hasNext());
213 TS_ASSERT(w->sample_list[0] <= 0); // Is 0 as prebuffer not filled
214 TS_ASSERT(w->sample_list[1] <= 0);
216 //Continue accum samples
217 note->noteout(outL, outR);
218 w->tick();
219 dump_samples("Step 3 pre-buffer\n");
220 TS_ASSERT(!w->trigger_active("noteout/filter"));
221 TS_ASSERT(!w->trigger_active("noteout/amp_int"));
222 TS_ASSERT(!tr->hasNext());
223 TS_ASSERT(w->sample_list[0] <= 0); // Is 0 as prebuffer not filled
224 TS_ASSERT(w->sample_list[1] <= 0);
226 //Finish accumulating samples
227 note->noteout(outL, outR);
228 w->tick();
229 dump_samples("Step 4 pre-buffer\n");
230 TS_ASSERT(w->trigger_active("noteout/filter")); // trigger activate and filling post buffer
231 TS_ASSERT(w->trigger_active("noteout/amp_int"));
232 TS_ASSERT(!tr->hasNext()); // post buffer not reach 128
233 TS_ASSERT(w->sample_list[1] <= 128); // prebuffer + postbuffer filled in
234 TS_ASSERT(w->sample_list[0] <= 128);
235 note->noteout(outL, outR);
236 w->tick();
237 note->noteout(outL, outR);
238 w->tick();
240 #define f32 "ffffffffffffffffffffffffffffffff"
241 #define f128 f32 f32 f32 f32
242 //Verify the output to the user interface
243 //if 128 samples are requested, then 128 should be delivered
244 const char *msg1 = tr->read();
245 TS_ASSERT_EQUAL_STR("noteout/filter", msg1);
246 TS_ASSERT_EQUAL_STR(f128, rtosc_argument_string(msg1));
247 TS_ASSERT_EQUAL_INT(128, strlen(rtosc_argument_string(msg1)));
248 note->noteout(outL, outR);
249 w->tick();
250 TS_ASSERT(tr->hasNext());
251 const char *msg2 = tr->read();
252 TS_ASSERT_EQUAL_STR("noteout/amp_int", msg2);
253 TS_ASSERT_EQUAL_INT(128, strlen(rtosc_argument_string(msg2)));
254 TS_ASSERT_EQUAL_STR(f128, rtosc_argument_string(msg2));
255 TS_ASSERT(!tr->hasNext());
260 int main()
262 TriggerTest test;
263 RUN_TEST(testSine);
264 RUN_TEST(testCombinedTrigger);