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