zynaddsubfx

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

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 }