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 "../Misc/MiddleWare.h"
20 #include "../Misc/Master.h"
21 #include "../Misc/PresetExtractor.h"
22 #include "../Misc/PresetExtractor.cpp"
23 #include "../Misc/Util.h"
24 #include "../globals.h"
25 #include "../UI/NSM.H"
26 
27 using namespace std;
28 using namespace zyn;
29 
30 SYNTH_T *synth;
31 NSM_Client *nsm = 0;
32 
33 char *instance_name=(char*)"";
34 MiddleWare *middleware;
35 
fill_vec_with_lines(std::vector<string> & v,string s)36 void fill_vec_with_lines(std::vector<string> &v, string s)
37 {
38     std::istringstream stream(s);
39     std::string line;
40     while(std::getline(stream, line))
41         v.push_back(line);
42 }
print_string_differences(string orig,string next)43 void print_string_differences(string orig, string next)
44 {
45     std::vector<string> a, b;
46     fill_vec_with_lines(a, orig);
47     fill_vec_with_lines(b, next);
48     int N = a.size();
49     int M = b.size();
50     printf("%d vs %d\n", N, M);
51 
52     //Original String by New String
53     //Each step is either an insertion, deletion, or match
54     //Match     is 0 cost and moves +1 State (if symbols are the same)
55     //Replace   is 3 cost and moves +1 State (if symbols are different)
56     //Insertion is 2 cost and moves +2 State (+2 if symbols are different)
57     //Deletion  is 1 cost and moves +0 State (+2 if symbols are different)
58     char *transition = new char[N*M];
59     float  *cost       = new float[N*M];
60 
61     const int match  = 1;
62     const int insert = 2;
63     const int del    = 3;
64     for(int i=0; i<N; ++i) {
65         for(int j=0; j<M; ++j) {
66             transition[i*M + j] = 0;
67             cost[i*M + j] = 0xffff;
68         }
69     }
70 
71     //Just assume the -1 line is the same
72     cost[0*M + 0] = (a[0] != b[0])*3;
73     cost[0*M + 1] = (a[1] != b[0])*2 + 2;
74     for(int i=1; i<N; ++i) {
75         for(int j=0; j<M; ++j) {
76             int cost_match = 0xffffff;
77             int cost_ins   = 0xffffff;
78             int cost_del   = 0xffffff;
79             cost_del = cost[(i-1)*M + j] + 2 + (a[i] != b[j])*2;
80             if(j > 1)
81                 cost_ins = cost[(i-1)*M + (j-2)] + 1 + 2*(a[i] != b[j]);
82             if(j > 0)
83                 cost_match = cost[(i-1)*M + (j-1)] + 3*(a[i] != b[j]);
84 
85             if(cost_match >= 0xffff && cost_ins >= 0xffff && cost_del >= 0xffff) {
86                 ;
87             } else if(cost_match < cost_ins && cost_match < cost_del) {
88                 cost[i*M+j] = cost_match;
89                 transition[i*M+j] = match;
90             } else if(cost_ins < cost_del) {
91                 cost[i*M+j] = cost_ins;
92                 transition[i*M+j] = insert;
93             } else {
94                 cost[i*M+j] = cost_del;
95                 transition[i*M+j] = del;
96             }
97         }
98     }
99 
100     //int off = 0;
101     //int len = N;
102     //for(int i=off; i<off+len; ++i) {
103     //    for(int j=off; j<off+len; ++j) {
104     //        printf("%4d ", (int)(cost[i*M+j] > 4000 ? -1 : cost[i*M+j]));
105     //    }
106     //    printf("\n");
107     //}
108     //for(int i=off; i<off+len; ++i) {
109     //    for(int j=off; j<off+len; ++j) {
110     //        printf("%d ", transition[i*M+j]);
111     //    }
112     //    printf("\n");
113     //}
114 
115     //for(int i=off; i<off+len; ++i)
116     //    printf("%d: %s\n", i, a[i].c_str());
117     //for(int i=off; i<off+len; ++i)
118     //    printf("%d: %s\n", i, b[i].c_str());
119     //exit(1);
120 
121     int total_cost = cost[(N-1)*M + (M-1)];
122     if(total_cost < 500) {
123         printf("total cost = %f\n", cost[(N-1)*M + (M-1)]);
124 
125         int b_pos = b.size()-1;
126         int a_pos = a.size()-1;
127         while(a_pos > 0 && b_pos > 0) {
128             //printf("state = (%d, %d) => %f\n", a_pos, b_pos, cost[a_pos*M+b_pos]);
129             if(transition[a_pos*M+b_pos] == match) {
130                 if(a[a_pos] != b[b_pos]) {
131                     printf("REF - %s\n", a[a_pos].c_str());
132                     printf("NEW + %s\n", b[b_pos].c_str());
133                 }
134                 //printf("R");
135                 a_pos -= 1;
136                 b_pos -= 1;
137             } else if(transition[a_pos*M+b_pos] == del) {
138                 //printf("D");
139                 //if(a[a_pos] != b[b_pos]) {
140                     //printf("- %s\n", a[a_pos].c_str());
141                     printf("NEW - %s\n", b[b_pos].c_str());
142                 //}
143                 b_pos -= 1;
144             } else if(transition[a_pos*M+b_pos] == insert) {
145                 //if(a[a_pos] != b[b_pos]) {
146                 printf("REF - %s\n", a[a_pos].c_str());
147                 printf("NEW + %s\n", b[b_pos].c_str());
148                 printf("NEW + %s\n", b[b_pos-1].c_str());
149                 //}
150                 //printf("I");
151                 a_pos -= 1;
152                 b_pos -= 2;
153             } else {
154                 printf("ERROR STATE @(%d, %d)\n", a_pos, b_pos);
155                 exit(1);
156             }
157 
158         }
159         //printf("%d vs %d\n", N, M);
160     } else {
161         printf("[WARNING] XML File appears to be radically different\n");
162     }
163 }
164 
165 class PluginTest
166 {
167     public:
168         Config config;
setUp()169         void setUp() {
170             synth = new SYNTH_T;
171             synth->buffersize = 256;
172             synth->samplerate = 48000;
173             synth->alias();
174 
175             outL  = new float[1024];
176             for(int i = 0; i < synth->buffersize; ++i)
177                 outL[i] = 0.0f;
178             outR = new float[1024];
179             for(int i = 0; i < synth->buffersize; ++i)
180                 outR[i] = 0.0f;
181 
182             for(int i = 0; i < 16; ++i)
183                 master[i] = new Master(*synth, &config);
184         }
185 
tearDown()186         void tearDown() {
187             for(int i = 0; i < 16; ++i)
188                 delete master[i];
189 
190             delete[] outL;
191             delete[] outR;
192             delete synth;
193         }
194 
195 
testInit()196         void testInit() {
197 
198             for(int x=0; x<100; ++x)
199                 for(int i=0; i<16; ++i)
200                     master[i]->GetAudioOutSamples(rand()%1025,
201                             synth->samplerate, outL, outR);
202         }
203 
testPanic()204         void testPanic()
205         {
206             master[0]->setController(0, 0x64, 0);
207             master[0]->noteOn(0,64,64);
208             master[0]->AudioOut(outL, outR);
209 
210             float sum = 0.0f;
211             for(int i = 0; i < synth->buffersize; ++i)
212                 sum += fabsf(outL[i]);
213 
214             TS_ASSERT(0.1f < sum);
215         }
216 
loadfile(string fname) const217         string loadfile(string fname) const
218         {
219             std::ifstream t(fname.c_str());
220             std::string str((std::istreambuf_iterator<char>(t)),
221                                      std::istreambuf_iterator<char>());
222             return str;
223         }
224 
225 
testLoadSave(void)226         void testLoadSave(void)
227         {
228             const string fname = string(SOURCE_DIR) + "/guitar-adnote.xmz";
229             const string fdata = loadfile(fname);
230             char *result = NULL;
231             master[0]->putalldata((char*)fdata.c_str());
232             int res = master[0]->getalldata(&result);
233 
234             TS_ASSERT_EQUAL_INT((int)(fdata.length()+1), res);
235             TS_ASSERT(fdata == result);
236             if(fdata != result)
237                 print_string_differences(fdata, result);
238         }
239 
240 
241     private:
242         float *outR, *outL;
243         Master *master[16];
244 };
245 
main()246 int main()
247 {
248     PluginTest test;
249     RUN_TEST(testInit);
250     RUN_TEST(testPanic);
251     RUN_TEST(testLoadSave);
252     return test_summary();
253 }
254