2 ZynAddSubFX - a software synthesizer
4 PluginTest.h - CxxTest for embedding zyn
5 Copyright (C) 2013-2013 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.
13 #include "test-suite.h"
20 #include <rtosc/thread-link.h>
22 #include "../Misc/MiddleWare.h"
23 #include "../Misc/Master.h"
24 #include "../Misc/Part.h"
25 #include "../Misc/PresetExtractor.h"
26 #include "../Misc/PresetExtractor.cpp"
27 #include "../Misc/Util.h"
28 #include "../globals.h"
29 #include "../UI/NSM.H"
33 class NSM_Client
*nsm
= 0;
34 MiddleWare
*middleware
= 0;
36 char *instance_name
=(char*)"";
38 #define NUM_MIDDLEWARE 3
46 mw
= new MiddleWare(std::move(*synth
), &config
);
47 ms
= mw
->spawnMaster();
56 void testKitEnable(void)
58 const char *msg
= NULL
;
59 mw
->transmitMsg("/part0/kit0/Psubenabled", "T");
60 TS_ASSERT(ms
->uToB
->hasNext());
61 msg
= ms
->uToB
->read();
62 TS_ASSERT_EQUAL_STR("/part0/kit0/subpars-data", msg
);
63 TS_ASSERT(ms
->uToB
->hasNext());
64 msg
= ms
->uToB
->read();
65 TS_ASSERT_EQUAL_STR("/part0/kit0/Psubenabled", msg
);
68 void testBankCapture(void)
70 mw
->transmitMsg("/bank/slot23", "");
71 TS_ASSERT(!ms
->uToB
->hasNext());
72 mw
->transmitMsg("/bank/fake", "");
73 TS_ASSERT(ms
->uToB
->hasNext());
74 const char *msg
= ms
->uToB
->read();
75 TS_ASSERT_EQUAL_STR("/bank/fake", msg
);
78 void testOscCopyPaste(void)
81 mw
->transmitMsg("/part0/kit0/Ppadenabled", "T");
83 TS_ASSERT(ms
->uToB
->hasNext());
84 ms
->applyOscEvent(ms
->uToB
->read());
85 TS_ASSERT(ms
->uToB
->hasNext());
86 ms
->applyOscEvent(ms
->uToB
->read());
87 TS_ASSERT(!ms
->uToB
->hasNext());
89 auto &osc_src
= *ms
->part
[0]->kit
[0].adpars
->VoicePar
[0].FmGn
;
90 auto &osc_dst
= *ms
->part
[0]->kit
[0].padpars
->oscilgen
;
91 auto &osc_oth
= *ms
->part
[0]->kit
[0].adpars
->VoicePar
[1].OscilGn
;
93 TS_ASSERT_EQUAL_INT(osc_src
.Pbasefuncpar
, 64);
94 osc_src
.Pbasefuncpar
= 32;
95 TS_ASSERT_EQUAL_INT(osc_src
.Pbasefuncpar
, 32);
97 //Copy From ADsynth modulator
98 printf("====Copy From ADsynth modulator\n");
100 mw
->transmitMsg("/presets/copy", "s", "/part0/kit0/adpars/VoicePar0/FMSmp/");
102 TS_ASSERT_EQUAL_STR("Poscilgen", mw
->getPresetsStore().clipboard
.type
.c_str());
103 // a regex would be better here...
104 // hopefully, mxml will not change its whitespace behavior
105 assert_non_null(strstr(mw
->getPresetsStore().clipboard
.data
.c_str(), "<par name=\"base_function_par\" value=\"32\" />"),
106 "base_function_par at right value", __LINE__
);
108 /* // better test this without string comparison:
111 bool couldPutXml = xml.putXMLdata(mw->getPresetsStore().clipboard.data.c_str());
112 TS_ASSERT(couldPutXml);
113 unsigned char copiedBasefuncPar = xml.getpar127("base_function_par", 0);
114 TS_ASSERT_EQUALS(copiedBasefuncPar, 32);
117 //printf("clipboard type: %s\n",mw->getPresetsStore().clipboard.type.c_str());
118 //printf("clipboard data:\n%s\n",mw->getPresetsStore().clipboard.data.c_str());
120 TS_ASSERT_EQUAL_INT(osc_dst
.Pbasefuncpar
, 64);
121 TS_ASSERT_EQUAL_INT(osc_oth
.Pbasefuncpar
, 64);
124 printf("====Paste to PADsynth\n");
125 mw
->transmitMsg("/presets/paste", "s", "/part0/kit0/padpars/oscilgen/");
127 printf("====Paste to ADsynth\n");
128 mw
->transmitMsg("/presets/paste", "s", "/part0/kit0/adpars/VoicePar1/OscilSmp/");
131 TS_ASSERT_EQUAL_INT(osc_dst
.Pbasefuncpar
, 32);
132 TS_ASSERT_EQUAL_INT(osc_oth
.Pbasefuncpar
, 32);
136 void start_realtime(void)
139 realtime
= new std::thread([this](){
141 while(tries
< 10000) {
142 if(!ms
->uToB
->hasNext()) {
149 const char *msg
= ms
->uToB
->read();
150 printf("RT: handling <%s>\n", msg
);
151 ms
->applyOscEvent(msg
);
155 void stop_realtime(void)
163 void run_realtime(void)
169 void testMidiLearn(void)
171 mw
->transmitMsg("/learn", "s", "/Pkeyshift");
172 mw
->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 108);
173 TS_ASSERT_EQUAL_INT(ms
->Pkeyshift
, 64);
175 //Perform a learning operation
177 run_realtime(); //1. runs learning and identifies a CC to bind
178 mw
->tick(); //2. produces new binding table
179 run_realtime(); //3. applies new binding table
182 //Verify that the learning actually worked
183 mw
->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 13);
185 TS_ASSERT_EQUAL_INT(ms
->Pkeyshift
, 13);
187 mw
->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 2);
189 TS_ASSERT_EQUAL_INT(ms
->Pkeyshift
, 2);
191 mw
->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 0);
193 TS_ASSERT_EQUAL_INT(ms
->Pkeyshift
, 0);
195 mw
->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 127);
197 TS_ASSERT_EQUAL_INT(ms
->Pkeyshift
, 127);
200 void testMidiLearnSave(void)
202 mw
->transmitMsg("/learn", "s", "/Pkeyshift");
203 mw
->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 108);
205 //param is at default until rt-thread is run
206 TS_ASSERT_EQUAL_INT(ms
->Pkeyshift
, 64);
209 //Perform a learning operation
212 //Verify binding affects control
213 TS_ASSERT_EQUAL_INT(ms
->Pkeyshift
, 108);
216 printf("# Trying to save automations\n");
218 mw
->transmitMsg("/save_xlz", "s", "test-midi-learn.xlz");
221 //Verify that some file exists
222 printf("# Verifying file exists\n");
223 FILE *f
= fopen("test-midi-learn.xlz", "r");
224 assert_non_null(f
, "test file exists", __LINE__
);
229 printf("# Clearing automation\n");
231 mw
->transmitMsg("/clear_xlz", "");
233 mw
->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 27);
236 //Verify automation table is clear
237 TS_ASSERT_EQUAL_INT(ms
->Pkeyshift
, 108);
239 printf("# Loading automation\n");
240 mw
->transmitMsg("/load_xlz", "s", "test-midi-learn.xlz");
242 mw
->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 28);
245 //Verify automation table is restored
246 TS_ASSERT_EQUAL_INT(ms
->Pkeyshift
, 28);
249 void testLfoPaste(void)
252 ms
->part
[0]->kit
[0].adpars
->GlobalPar
.FreqLfo
->Pfreqrand
= 32;
253 TS_ASSERT_EQUAL_INT(ms
->part
[0]->kit
[0].adpars
->GlobalPar
.FreqLfo
->Pfreqrand
, 32);
256 mw
->transmitMsg("/presets/copy", "s", "/part0/kit0/adpars/GlobalPar/FreqLfo/");
258 ms
->part
[0]->kit
[0].adpars
->GlobalPar
.FreqLfo
->Pfreqrand
= 99;
259 TS_ASSERT_EQUAL_INT(ms
->part
[0]->kit
[0].adpars
->GlobalPar
.FreqLfo
->Pfreqrand
, 99);
262 mw
->transmitMsg("/presets/paste", "s", "/part0/kit0/adpars/GlobalPar/FreqLfo/");
265 TS_ASSERT_EQUAL_INT(ms
->part
[0]->kit
[0].adpars
->GlobalPar
.FreqLfo
->Pfreqrand
, 32);
268 void testPadPaste(void)
270 mw
->transmitMsg("/part0/kit0/Ppadenabled", "T");
275 auto &field1
= ms
->part
[0]->kit
[0].padpars
->PVolume
;
276 auto &field2
= ms
->part
[0]->kit
[0].padpars
->oscilgen
->Pfilterpar1
;
278 TS_ASSERT_EQUAL_INT(field1
, 32);
280 TS_ASSERT_EQUAL_INT(field2
, 35);
283 mw
->transmitMsg("/presets/copy", "s", "/part0/kit0/padpars/");
286 TS_ASSERT_EQUAL_INT(field1
, 99);
288 TS_ASSERT_EQUAL_INT(field2
, 95);
291 mw
->transmitMsg("/presets/paste", "s", "/part0/kit0/padpars/");
294 TS_ASSERT_EQUAL_INT(field1
, 32);
295 TS_ASSERT_EQUAL_INT(field2
, 35);
298 void testFilterDepricated(void)
300 vector
<string
> v
= {"Pfreq", "Pfreqtrack", "Pgain", "Pq"};
301 for(size_t i
=0; i
<v
.size(); ++i
) {
302 string path
= "/part0/kit0/adpars/GlobalPar/GlobalFilter/"+v
[i
];
303 for(int j
=0; j
<128; ++j
) {
304 mw
->transmitMsg(path
.c_str(), "i", j
); //Set
305 mw
->transmitMsg(path
.c_str(), ""); //Get
309 while(ms
->uToB
->hasNext()) {
310 const char *msg
= ms
->uToB
->read();
311 //printf("RT: handling <%s>\n", msg);
312 ms
->applyOscEvent(msg
);
319 // 1 - true value (set)
320 // 2 - expected value (get)
321 while(ms
->bToU
->hasNext()) {
322 const char *msg
= ms
->bToU
->read();
324 TS_ASSERT_EQUAL_INT(rtosc_narguments(msg
), 0U);
326 } else if(state
== 1) {
327 TS_ASSERT_EQUAL_INT(rtosc_narguments(msg
), 1U);
328 value
= rtosc_argument(msg
, 0).i
;
330 } else if(state
== 2) {
331 int val
= rtosc_argument(msg
, 0).i
;
333 printf("%s - %d should equal %d\n", msg
, value
, val
);
340 //printf("Message #%d %s:%s\n", id++, msg, rtosc_argument_string(msg));
341 //if(rtosc_narguments(msg))
342 // printf(" %d\n", rtosc_argument(msg, 0).i);
351 std::thread
*realtime
;
358 RUN_TEST(testKitEnable
);
359 RUN_TEST(testBankCapture
);
360 RUN_TEST(testOscCopyPaste
);
361 RUN_TEST(testMidiLearn
);
362 RUN_TEST(testMidiLearnSave
);
363 RUN_TEST(testLfoPaste
);
364 RUN_TEST(testPadPaste
);
365 RUN_TEST(testFilterDepricated
);
366 return test_summary();