MessageTest.cpp (12426B)
1 /* 2 ZynAddSubFX - a software synthesizer 3 4 PluginTest.h - CxxTest for embedding zyn 5 Copyright (C) 2013-2013 Mark McCurry 6 Authors: Mark McCurry 7 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. 12 */ 13 #include "test-suite.h" 14 #include <cmath> 15 #include <cstdlib> 16 #include <iostream> 17 #include <fstream> 18 #include <string> 19 #include <thread> 20 #include <rtosc/thread-link.h> 21 #include <unistd.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" 30 using namespace std; 31 using namespace zyn; 32 33 class NSM_Client *nsm = 0; 34 MiddleWare *middleware = 0; 35 36 char *instance_name=(char*)""; 37 38 #define NUM_MIDDLEWARE 3 39 40 class MessageTest 41 { 42 public: 43 struct FFTCleaner { ~FFTCleaner() { FFT_cleanup(); } } cleaner; 44 Config config; 45 void setUp() { 46 synth = new SYNTH_T; 47 mw = new MiddleWare(std::move(*synth), &config); 48 ms = mw->spawnMaster(); 49 realtime = NULL; 50 } 51 52 void tearDown() { 53 delete mw; 54 delete synth; 55 } 56 57 void testKitEnable(void) 58 { 59 const char *msg = NULL; 60 mw->transmitMsg("/part0/kit0/Psubenabled", "T"); 61 TS_ASSERT(ms->uToB->hasNext()); 62 msg = ms->uToB->read(); 63 TS_ASSERT_EQUAL_STR("/part0/kit0/subpars-data", msg); 64 TS_ASSERT_EQUAL_INT(rtosc_narguments(msg), 1U); 65 TS_ASSERT_EQUAL_INT(sizeof(SUBnoteParameters*), rtosc_argument(msg, 0).b.len); 66 SUBnoteParameters* ptr = *(SUBnoteParameters**)rtosc_argument(msg, 0).b.data; 67 TS_ASSERT(ms->uToB->hasNext()); 68 msg = ms->uToB->read(); 69 TS_ASSERT_EQUAL_STR("/part0/kit0/Psubenabled", msg); 70 delete ptr; 71 } 72 73 void testBankCapture(void) 74 { 75 mw->transmitMsg("/bank/slot23", ""); 76 TS_ASSERT(!ms->uToB->hasNext()); 77 mw->transmitMsg("/bank/fake", ""); 78 TS_ASSERT(ms->uToB->hasNext()); 79 const char *msg = ms->uToB->read(); 80 TS_ASSERT_EQUAL_STR("/bank/fake", msg); 81 } 82 83 void testOscCopyPaste(void) 84 { 85 //Enable pad synth 86 mw->transmitMsg("/part0/kit0/Ppadenabled", "T"); 87 88 TS_ASSERT(ms->uToB->hasNext()); 89 ms->applyOscEvent(ms->uToB->read()); 90 TS_ASSERT(ms->uToB->hasNext()); 91 ms->applyOscEvent(ms->uToB->read()); 92 TS_ASSERT(!ms->uToB->hasNext()); 93 94 auto &osc_src = *ms->part[0]->kit[0].adpars->VoicePar[0].FmGn; 95 auto &osc_dst = *ms->part[0]->kit[0].padpars->oscilgen; 96 auto &osc_oth = *ms->part[0]->kit[0].adpars->VoicePar[1].OscilGn; 97 98 TS_ASSERT_EQUAL_INT(osc_src.Pbasefuncpar, 64); 99 osc_src.Pbasefuncpar = 32; 100 TS_ASSERT_EQUAL_INT(osc_src.Pbasefuncpar, 32); 101 102 //Copy From ADsynth modulator 103 printf("====Copy From ADsynth modulator\n"); 104 start_realtime(); 105 mw->transmitMsg("/presets/copy", "s", "/part0/kit0/adpars/VoicePar0/FMSmp/"); 106 107 TS_ASSERT_EQUAL_STR("Poscilgen", mw->getPresetsStore().clipboard.type.c_str()); 108 //Use XMLwrapper to validate copied XML 109 { 110 XMLwrapper xml; 111 bool couldPutXml = xml.putXMLdata(mw->getPresetsStore().clipboard.data.c_str()); 112 TS_ASSERT(couldPutXml); 113 xml.enterbranch("Poscilgen"); 114 unsigned char copiedBasefuncPar = xml.getpar127("base_function_par", 0); 115 xml.exitbranch(); 116 TS_ASSERT_EQUAL_INT(+copiedBasefuncPar, 32); 117 } 118 119 TS_ASSERT_EQUAL_INT(osc_dst.Pbasefuncpar, 64); 120 TS_ASSERT_EQUAL_INT(osc_oth.Pbasefuncpar, 64); 121 122 //Paste to PADsynth 123 printf("====Paste to PADsynth\n"); 124 mw->transmitMsg("/presets/paste", "s", "/part0/kit0/padpars/oscilgen/"); 125 126 printf("====Paste to ADsynth\n"); 127 mw->transmitMsg("/presets/paste", "s", "/part0/kit0/adpars/VoicePar1/OscilSmp/"); 128 129 stop_realtime(); 130 TS_ASSERT_EQUAL_INT(osc_dst.Pbasefuncpar, 32); 131 TS_ASSERT_EQUAL_INT(osc_oth.Pbasefuncpar, 32); 132 133 mw->tick(); // Let MW handle all "/free" messages 134 } 135 136 137 void start_realtime(void) 138 { 139 do_exit = false; 140 realtime = new std::thread([this](){ 141 int tries = 0; 142 while(tries < 10000) { 143 if(!ms->uToB->hasNext()) { 144 if(do_exit) 145 break; 146 147 usleep(500); 148 continue; 149 } 150 const char *msg = ms->uToB->read(); 151 printf("RT: handling <%s>\n", msg); 152 ms->applyOscEvent(msg); 153 }}); 154 } 155 156 void stop_realtime(void) 157 { 158 do_exit = true; 159 realtime->join(); 160 delete realtime; 161 realtime = NULL; 162 } 163 164 void run_realtime(void) 165 { 166 start_realtime(); 167 stop_realtime(); 168 } 169 170 void testMidiLearn(void) 171 { 172 mw->transmitMsg("/learn", "s", "/Pkeyshift"); 173 mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 108); 174 TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 64); 175 176 //Perform a learning operation 177 178 run_realtime(); //1. runs learning and identifies a CC to bind 179 mw->tick(); //2. produces new binding table 180 run_realtime(); //3. applies new binding table 181 182 183 //Verify that the learning actually worked 184 mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 13); 185 run_realtime(); 186 TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 13); 187 188 mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 2); 189 run_realtime(); 190 TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 2); 191 192 mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 0); 193 run_realtime(); 194 TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 0); 195 196 mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 127); 197 run_realtime(); 198 TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 127); 199 } 200 201 void testMidiLearnSave(void) 202 { 203 mw->transmitMsg("/learn", "s", "/Pkeyshift"); 204 mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 108); 205 206 //param is at default until rt-thread is run 207 TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 64); 208 209 210 //Perform a learning operation 211 run_realtime(); 212 213 //Verify binding affects control 214 TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 108); 215 216 217 printf("# Trying to save automations\n"); 218 start_realtime(); 219 mw->transmitMsg("/save_xlz", "s", "test-midi-learn.xlz"); 220 stop_realtime(); 221 222 //Verify that some file exists 223 printf("# Verifying file exists\n"); 224 FILE *f = fopen("test-midi-learn.xlz", "r"); 225 assert_non_null(f, "test file exists", __LINE__); 226 227 if(f) 228 fclose(f); 229 230 printf("# Clearing automation\n"); 231 //Clear out state 232 mw->transmitMsg("/clear_xlz", ""); 233 //Send dummy message 234 mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 27); 235 run_realtime(); 236 237 //Verify automation table is clear 238 TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 108); 239 240 printf("# Loading automation\n"); 241 mw->transmitMsg("/load_xlz", "s", "test-midi-learn.xlz"); 242 //Send message 243 mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 28); 244 run_realtime(); 245 246 //Verify automation table is restored 247 TS_ASSERT_EQUAL_INT(ms->Pkeyshift, 28); 248 249 mw->tick(); // Let MW handle all "/free" messages 250 } 251 252 void testLfoPaste(void) 253 { 254 start_realtime(); 255 ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand = 32; 256 TS_ASSERT_EQUAL_INT(ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand, 32); 257 258 //Copy 259 mw->transmitMsg("/presets/copy", "s", "/part0/kit0/adpars/GlobalPar/FreqLfo/"); 260 261 ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand = 99; 262 TS_ASSERT_EQUAL_INT(ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand, 99); 263 264 //Paste 265 mw->transmitMsg("/presets/paste", "s", "/part0/kit0/adpars/GlobalPar/FreqLfo/"); 266 stop_realtime(); 267 268 TS_ASSERT_EQUAL_INT(ms->part[0]->kit[0].adpars->GlobalPar.FreqLfo->Pfreqrand, 32); 269 270 mw->tick(); // Let MW handle all "/free" messages 271 } 272 273 void testPadPaste(void) 274 { 275 mw->transmitMsg("/part0/kit0/Ppadenabled", "T"); 276 run_realtime(); 277 278 start_realtime(); 279 280 auto &field1 = ms->part[0]->kit[0].padpars->PVolume; 281 auto &field2 = ms->part[0]->kit[0].padpars->oscilgen->Pfilterpar1; 282 field1 = 32; 283 TS_ASSERT_EQUAL_INT(field1, 32); 284 field2 = 35; 285 TS_ASSERT_EQUAL_INT(field2, 35); 286 287 //Copy 288 mw->transmitMsg("/presets/copy", "s", "/part0/kit0/padpars/"); 289 290 field1 = 99; 291 TS_ASSERT_EQUAL_INT(field1, 99); 292 field2 = 95; 293 TS_ASSERT_EQUAL_INT(field2, 95); 294 295 //Paste 296 mw->transmitMsg("/presets/paste", "s", "/part0/kit0/padpars/"); 297 stop_realtime(); 298 299 TS_ASSERT_EQUAL_INT(field1, 32); 300 TS_ASSERT_EQUAL_INT(field2, 35); 301 302 mw->tick(); // Let MW handle all "/free" messages 303 } 304 305 void testFilterDepricated(void) 306 { 307 vector<string> v = {"Pfreq", "Pfreqtrack", "Pgain", "Pq"}; 308 for(size_t i=0; i<v.size(); ++i) { 309 string path = "/part0/kit0/adpars/GlobalPar/GlobalFilter/"+v[i]; 310 for(int j=0; j<128; ++j) { 311 mw->transmitMsg(path.c_str(), "i", j); //Set 312 mw->transmitMsg(path.c_str(), ""); //Get 313 } 314 315 } 316 while(ms->uToB->hasNext()) { 317 const char *msg = ms->uToB->read(); 318 //printf("RT: handling <%s>\n", msg); 319 ms->applyOscEvent(msg); 320 } 321 322 int id = 0; 323 int state = 0; 324 int value = 0; 325 // 0 - broadcast 326 // 1 - true value (set) 327 // 2 - expected value (get) 328 while(ms->bToU->hasNext()) { 329 const char *msg = ms->bToU->read(); 330 if(state == 0) { 331 TS_ASSERT_EQUAL_INT(rtosc_narguments(msg), 0U); 332 state = 1; 333 } else if(state == 1) { 334 TS_ASSERT_EQUAL_INT(rtosc_narguments(msg), 1U); 335 value = rtosc_argument(msg, 0).i; 336 state = 2; 337 } else if(state == 2) { 338 int val = rtosc_argument(msg, 0).i; 339 if(value != val) { 340 printf("%s - %d should equal %d\n", msg, value, val); 341 TS_ASSERT(0); 342 } 343 state = 0; 344 } 345 346 (void) id; 347 //printf("Message #%d %s:%s\n", id++, msg, rtosc_argument_string(msg)); 348 //if(rtosc_narguments(msg)) 349 // printf(" %d\n", rtosc_argument(msg, 0).i); 350 } 351 } 352 353 354 private: 355 SYNTH_T *synth; 356 MiddleWare *mw; 357 Master *ms; 358 std::thread *realtime; 359 bool do_exit; 360 }; 361 362 int main() 363 { 364 MessageTest test; 365 RUN_TEST(testKitEnable); 366 RUN_TEST(testBankCapture); 367 RUN_TEST(testOscCopyPaste); 368 RUN_TEST(testMidiLearn); 369 RUN_TEST(testMidiLearnSave); 370 RUN_TEST(testLfoPaste); 371 RUN_TEST(testPadPaste); 372 RUN_TEST(testFilterDepricated); 373 return test_summary(); 374 }