1 /* SpiralSynth
2 * Copyright (C) 2000 David Griffiths <dave@blueammonite.f9.co.uk>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include "Synth.h"
20
21 #include <FL/Fl.H>
22 #include <FL/Enumerations.H>
23 #include <fstream>
24 #include <sstream>
25 #include <string>
26 #include <time.h>
27 #include <stdlib.h>
28
29 #include "Oscillator.h"
30 #include "Output.h"
31 #include "Midi.h"
32
Synth()33 Synth::Synth():
34 m_Oct(5),
35 m_Databuf(NULL),
36 m_Databuf2(NULL),
37 m_Databuf3(NULL),
38 m_OscControlbuf1(NULL),
39 m_OscControlbuf2(NULL),
40 m_OscControlbuf3(NULL),
41 m_EnvControlbuf(NULL),
42 m_LFOControlbuf(NULL),
43 m_BothControlbuf(NULL),
44 m_Osc1GUI(&m_Osc1),
45 m_Osc2GUI(&m_Osc2),
46 m_Osc3GUI(&m_Osc3),
47 m_Env1GUI(&m_Env1),
48 m_Env2GUI(&m_Env2),
49 m_Env3GUI(&m_Env3),
50 m_FilterGUI(&m_Filter),
51 m_MixerGUI(&m_Mixer),
52 m_Mixer2GUI(&m_Mixer2),
53 m_DelayGUI(&m_Delay),
54 m_FilterEnvGUI(&m_FilterEnv),
55 m_LFOGUI(&m_LFO),
56 m_OutGUI(&m_Out)
57 {
58 cerr<<"Allocating Buffer Memory"<<endl;
59
60 AllocMem();
61
62 m_VoiceNote = new int[SynthInfo::POLY];
63 m_VoiceOctave = new int[SynthInfo::POLY];
64 for (int n=0; n<SynthInfo::POLY; n++)
65 {
66 m_VoiceNote[n] = -1;
67 m_VoiceOctave[n] = -1;
68 }
69
70 if (!m_Databuf || !m_Databuf2 || !m_Databuf3 || !m_OscControlbuf1
71 || !m_OscControlbuf2 || !m_OscControlbuf3 || !m_EnvControlbuf
72 || !m_LFOControlbuf || !m_BothControlbuf )
73 {
74 cerr<<"Not enough memory availible"<<endl;
75 exit(0);
76 }
77
78 m_KeyVoice = new char[SynthInfo::POLY];
79
80 for (int n=0; n<SynthInfo::POLY; n++)
81 {
82 m_KeyVoice[n]=' ';
83 }
84
85 LoadPatch(1);
86 }
87
~Synth()88 Synth::~Synth()
89 {
90 CloseMidi();
91
92 delete[] m_Databuf;
93 delete[] m_Databuf2;
94 delete[] m_Databuf3;
95 delete[] m_OscControlbuf1;
96 delete[] m_OscControlbuf2;
97 delete[] m_OscControlbuf3;
98 delete[] m_EnvControlbuf;
99 delete[] m_LFOControlbuf;
100 delete[] m_BothControlbuf;
101 delete[] m_XModbuf1;
102 delete[] m_XModbuf2;
103 delete[] m_VoiceNote;
104 delete[] m_VoiceOctave;
105 delete[] m_KeyVoice;
106 }
107
AllocMem()108 void Synth::AllocMem()
109 {
110 m_Databuf = new short[SynthInfo::BUFSIZE];
111 m_Databuf2 = new short[SynthInfo::BUFSIZE];
112 m_Databuf3 = new short[SynthInfo::BUFSIZE];
113 m_OscControlbuf1 = new short[SynthInfo::BUFSIZE];
114 m_OscControlbuf2 = new short[SynthInfo::BUFSIZE];
115 m_OscControlbuf3 = new short[SynthInfo::BUFSIZE];
116 m_EnvControlbuf = new short[SynthInfo::BUFSIZE];
117 m_LFOControlbuf = new short[SynthInfo::BUFSIZE];
118 m_BothControlbuf = new short[SynthInfo::BUFSIZE];
119
120 m_XModbuf1 = new short*[SynthInfo::POLY];
121 m_XModbuf2 = new short*[SynthInfo::POLY];
122
123 for (int n=0; n<SynthInfo::POLY; n++)
124 {
125 m_XModbuf1[n] = new short[SynthInfo::BUFSIZE];
126 m_XModbuf2[n] = new short[SynthInfo::BUFSIZE];
127 }
128 }
129
CreateWindow()130 Fl_Window *Synth::CreateWindow()
131 {
132 Fl_Window* w;
133 { Fl_Window* o = Window = new Fl_Window(785, 395);
134 w = o;
135 o->color(SynthInfo::GUIBG_COLOUR);
136
137 // put part guis here
138 m_Osc1GUI.CreateGUI(5,5,"Osc1");
139 m_Osc2GUI.CreateGUI(5,120,"Osc2");
140 m_Osc3GUI.CreateGUI(5,235,"Osc3");
141 m_Env1GUI.CreateGUI(255,5,"Envelope1");
142 m_Env2GUI.CreateGUI(255,120,"Envelope2");
143 m_Env3GUI.CreateGUI(255,235,"Envelope3");
144 m_FilterGUI.CreateGUI(485,5,"Filter");
145 m_MixerGUI.CreateGUI(380,5,"Mixer 1&2");
146 m_Mixer2GUI.CreateGUI(380,120,"Mixer [1,2]&3");
147 m_DelayGUI.CreateGUI(610,5,"Delay");
148 m_FilterEnvGUI.CreateGUI(485,120,"Extra Envelope");
149 m_LFOGUI.CreateGUI(610,120,"LFO");
150 m_OutGUI.CreateGUI(695,5,"Output");
151 m_PatchBank.CreateGUI(5,350,"Patch Bank");
152 m_LFORouteGUI.CreateGUI(610,292,"LFO Route");
153 m_EnvRouteGUI.CreateGUI(610,235,"Envelope Route");
154
155 m_Scope.CreateGUI(380,235,"Scope");
156 }
157
158 return w;
159 }
160
161 void Synth::Trigger(int octave, int note, int vol=128)
162 {
163 // Move to the next voice
164 m_CurrentVoice++;
165
166 if (m_CurrentVoice>=SynthInfo::POLY)
167 {
168 m_CurrentVoice=0;
169 }
170
171 // if it's not free
172 if (m_VoiceNote[m_CurrentVoice]!=-1)
173 {
174 // look for a free voice
175 for (int n=0; n<SynthInfo::POLY; n++)
176 {
177 if (m_VoiceNote[n]==-1 && m_VoiceOctave[n]==-1)
178 {
179 m_CurrentVoice=n;
180 }
181 }
182 }
183
184 m_VoiceNote[m_CurrentVoice]=note;
185 m_VoiceOctave[m_CurrentVoice]=octave;
186
187 m_Osc1.NoteTrigger(m_CurrentVoice,octave,note,vol); m_Env1.Trigger(m_CurrentVoice);
188 m_Osc2.NoteTrigger(m_CurrentVoice,octave,note,vol); m_Env2.Trigger(m_CurrentVoice);
189 m_Osc3.NoteTrigger(m_CurrentVoice,octave,note,vol); m_Env3.Trigger(m_CurrentVoice);
190 m_FilterEnv.Trigger(m_CurrentVoice);
191 }
192
193 void Synth::UnTrigger(int octave=-1,int note=-1)
194 {
195 // clear all voices
196 if (octave==-1 && note==-1)
197 {
198 for (int n=0; n<SynthInfo::POLY; n++)
199 {
200 m_Env1.UnTrigger(n);
201 m_Env2.UnTrigger(n);
202 m_Env3.UnTrigger(n);
203 m_FilterEnv.UnTrigger(n);
204 m_VoiceNote[n]=-1;
205 m_VoiceOctave[n]=-1;
206 }
207 }
208 else
209 {
210 // look for the voice and clear it
211 for (int n=0; n<SynthInfo::POLY; n++)
212 {
213 if (m_VoiceOctave[n]==octave && m_VoiceNote[n]==note)
214 {
215 m_Env1.UnTrigger(n);
216 m_Env2.UnTrigger(n);
217 m_Env3.UnTrigger(n);
218 m_FilterEnv.UnTrigger(n);
219 m_VoiceNote[n]=-1;
220 m_VoiceOctave[n]=-1;
221 }
222 }
223 }
224
225 }
226
DoIdle()227 void Synth::DoIdle()
228 {
229 if (Fl::event_key(FL_F+1)) m_Oct=0;
230 if (Fl::event_key(FL_F+2)) m_Oct=1;
231 if (Fl::event_key(FL_F+3)) m_Oct=2;
232 if (Fl::event_key(FL_F+4)) m_Oct=3;
233 if (Fl::event_key(FL_F+5)) m_Oct=4;
234 if (Fl::event_key(FL_F+6)) m_Oct=5;
235 if (Fl::event_key(FL_F+7)) m_Oct=6;
236 if (Fl::event_key(FL_F+8)) m_Oct=7;
237 if (Fl::event_key(FL_F+9)) m_Oct=8;
238 if (Fl::event_key(FL_F+10)) m_Oct=9;
239 if (Fl::event_key(FL_F+11)) m_Oct=10;
240
241 int note=0;
242 int oct=0;
243 char KeyChar=0;
244 bool KeyPressed=false;
245
246 for (int key=0; key<SynthInfo::NKEYS; key++)
247 {
248 KeyChar=SynthInfo::KEYMAP.c_str()[key];
249
250 // check if a key's been pressed
251 if (Fl::event_key(KeyChar))
252 {
253 KeyPressed=true;
254
255 // check it was pressed last time
256 bool Found=false;
257 for (int n=0; n<SynthInfo::POLY; n++)
258 {
259 if (m_KeyVoice[n]==KeyChar)
260 {
261 Found=true;
262 }
263 }
264
265 if (!Found)
266 {
267 Trigger(m_Oct+oct,note);
268 m_KeyVoice[m_CurrentVoice]=KeyChar;
269 }
270 }
271 else // it's not pressed down
272 {
273 //see if the note was pressed down last time
274 for (int n=0; n<SynthInfo::POLY; n++)
275 {
276 if (m_KeyVoice[n]==KeyChar)
277 {
278 UnTrigger(m_Oct+oct,note);
279 m_KeyVoice[n]=' ';
280 }
281 }
282 }
283
284 note++;
285 if (note>11)
286 {
287 note=0;
288 oct++;
289 }
290 }
291 // reset if no keys have been pressed
292 /*if (!KeyPressed)
293 {
294 if (LastKeyPressed!=0)
295 {
296 UnTrigger();
297 }
298 LastKeyPressed=0;
299 }*/
300
301 m_CurrentEvent=m_Midi.GetEvent();
302
303 if (m_CurrentEvent.GetType()==MidiEvent::ON)
304 {
305 Trigger(m_CurrentEvent.GetOctave(),
306 m_CurrentEvent.GetNote(),
307 m_CurrentEvent.GetVolume());
308 }
309
310 if (m_CurrentEvent.GetType()==MidiEvent::OFF)
311 {
312 UnTrigger(m_CurrentEvent.GetOctave(),m_CurrentEvent.GetNote());
313 }
314
315 float f;
316 m_Out.ClearBuffer();
317
318 m_LFO.GetOutput(0,m_LFOControlbuf);
319
320 // run the synth!
321 for (int Voice=0; Voice<SynthInfo::POLY; Voice++)
322 {
323 // Xmod routing
324 if (m_Mixer.GetType()==Mixer::XMOD)
325 {
326 m_Osc2.ModulateFreq(m_XModbuf1[Voice]);
327 }
328
329 if (m_Mixer2.GetType()==Mixer::XMOD)
330 {
331 m_Osc3.ModulateFreq(m_XModbuf2[Voice]);
332 }
333
334 m_FilterEnv.GetOutput(Voice, m_EnvControlbuf);
335
336 for (int n=0; n<SynthInfo::BUFSIZE; n++)
337 m_BothControlbuf[n] = m_LFOControlbuf[n]+m_EnvControlbuf[n];
338
339 m_Osc1.GetOutput(Voice, m_Databuf);
340 m_Osc2.GetOutput(Voice, m_Databuf2);
341 m_Osc3.GetOutput(Voice, m_Databuf3);
342 m_Env1.GetOutput(Voice, m_OscControlbuf1);
343 m_Env2.GetOutput(Voice, m_OscControlbuf2);
344 m_Env3.GetOutput(Voice, m_OscControlbuf3);
345 m_OscAmp1.GetOutput(m_OscControlbuf1,m_Databuf);
346 m_OscAmp2.GetOutput(m_OscControlbuf2,m_Databuf2);
347 m_OscAmp3.GetOutput(m_OscControlbuf3,m_Databuf3);
348
349 // store the buffer here for feeding back into the oscillator
350 if (m_Mixer.GetType()==Mixer::XMOD)
351 {
352 CopyBuffer(m_Databuf,m_XModbuf1[Voice]);
353 }
354
355 m_Mixer.GetOutput(m_Databuf2,m_Databuf);
356
357 // store the buffer here for feeding back into the oscillator
358 if (m_Mixer2.GetType()==Mixer::XMOD)
359 {
360 CopyBuffer(m_Databuf2,m_XModbuf2[Voice]);
361 }
362
363 m_Mixer2.GetOutput(m_Databuf3,m_Databuf);
364 m_Filter.GetOutput(Voice,m_Databuf);
365
366 m_Out.Send(m_Databuf);
367 }
368
369 m_Delay.GetOutput(m_Out.GetBuffer());
370
371 m_Scope.Display(m_Out.GetBuffer());
372
373 m_Out.Play();
374
375 m_CurrentPatch=m_PatchBank.GetOutput();
376
377 if (m_CurrentPatch>=0)
378 {
379 m_Filter.Reset();
380 if (m_PatchBank.IsSaving())
381 {
382 SavePatch(m_CurrentPatch);
383 }
384 else
385 {
386 LoadPatch(m_CurrentPatch);
387 UpdateValues();
388 }
389 }
390
391 if (m_CurrentPatch==-2)
392 {
393 Randomise();
394 }
395
396 Route();
397 }
398
SavePatch(int n)399 void Synth::SavePatch(int n)
400 {
401 char buf[1024];
402 ostrstream os(buf,1024,ios::out);
403 os<<*this<<"| ";
404 WritePatch(n,buf);
405 }
406
LoadPatch(int n)407 void Synth::LoadPatch(int n)
408 {
409 char buf[1024];
410 if (ReadPatch(n,buf))
411 {
412 istrstream is(buf);
413 is>>*this;
414 }
415 }
416
417
ReadPatch(int n,char * out)418 int Synth::ReadPatch(int n, char *out)
419 {
420 string Patchfn(SynthInfo::Get()->GetHomeDir()+"/.SpiralPatches.bank");
421 ifstream is(Patchfn.c_str());
422
423 if (!is.good()) // make a patch file
424 {
425 cerr<<"SpiralPatches.bank not found - writing new patch file."<<endl;
426
427 ofstream os(Patchfn.c_str());
428 for (int n=0; n<NUM_PATCHES; n++)
429 os<<*this<<"| ";
430
431 return 0;
432 }
433
434 char c=0;
435 int count=0;
436
437 while(is.good() && count!=n)
438 {
439 is.get(c);
440 //cerr<<"c="<<c<<" count="<<count<<endl;
441 if (c=='|') count++;
442 }
443
444 if(is.good())
445 {
446 is.get(out,1024);
447 }
448
449 return 1;
450 }
451
WritePatch(int n,char * in)452 void Synth::WritePatch(int n, char *in)
453 {
454 // todo: get rid of this cheesy implementation
455 string Patchfn(SynthInfo::Get()->GetHomeDir()+"/.SpiralPatches.bank");
456 string Tempfn(SynthInfo::Get()->GetHomeDir()+"/temp");
457 ifstream is(Patchfn.c_str());
458 ofstream os(Tempfn.c_str());
459
460 char c=0;
461 int count=0;
462 int count2=0;
463 bool IgnorePatch=false;
464
465 while(is.good())
466 {
467 is.get(c);
468
469 while (count==n) // this is the patch to overwrite
470 {
471 c=in[count2++];
472
473 if (c=='|') // end of patch
474 {
475 IgnorePatch=true;
476 count++;
477 os<<c<<" ";
478 is.get(c);
479 }
480 else os<<c;
481 }
482
483 if (IgnorePatch) // step through until end
484 {
485
486 if (c=='|')
487 {
488 IgnorePatch=false;
489 count++;
490 }
491 }
492 else // normal write mode
493 {
494 if (c=='|')
495 {
496 count++;
497 }
498
499 os<<c;
500 }
501
502 }
503
504 string command("mv -f "+Tempfn+" "+Patchfn);
505 system(command.c_str());
506 }
507
Route()508 void Synth::Route()
509 {
510 m_Osc1.ModulateFreq(NULL);
511 m_Osc1.ModulatePulseWidth(NULL);
512 m_Osc2.ModulateFreq(NULL);
513 m_Osc2.ModulatePulseWidth(NULL);
514 m_Filter.ModulateCutoff(NULL);
515 m_Filter.ModulateResonance(NULL);
516
517 if (m_LFORouteGUI.Query(RouteGUI::OSC1FREQ))
518 m_Osc1.ModulateFreq(m_LFOControlbuf);
519
520 if (m_LFORouteGUI.Query(RouteGUI::OSC1PW))
521 m_Osc1.ModulatePulseWidth(m_LFOControlbuf);
522
523 if (m_LFORouteGUI.Query(RouteGUI::OSC2FREQ))
524 m_Osc2.ModulateFreq(m_LFOControlbuf);
525
526 if (m_LFORouteGUI.Query(RouteGUI::OSC2PW))
527 m_Osc2.ModulatePulseWidth(m_LFOControlbuf);
528
529 if (m_LFORouteGUI.Query(RouteGUI::FILTERC))
530 m_Filter.ModulateCutoff(m_LFOControlbuf);
531
532 if (m_LFORouteGUI.Query(RouteGUI::FILTERR))
533 m_Filter.ModulateResonance(m_LFOControlbuf);
534
535
536 if (m_EnvRouteGUI.Query(RouteGUI::OSC1FREQ))
537 m_Osc1.ModulateFreq(m_EnvControlbuf);
538
539 if (m_EnvRouteGUI.Query(RouteGUI::OSC1PW))
540 m_Osc1.ModulatePulseWidth(m_EnvControlbuf);
541
542 if (m_EnvRouteGUI.Query(RouteGUI::OSC2FREQ))
543 m_Osc2.ModulateFreq(m_EnvControlbuf);
544
545 if (m_EnvRouteGUI.Query(RouteGUI::OSC2PW))
546 m_Osc2.ModulatePulseWidth(m_EnvControlbuf);
547
548 if (m_EnvRouteGUI.Query(RouteGUI::FILTERC))
549 m_Filter.ModulateCutoff(m_EnvControlbuf);
550
551 if (m_EnvRouteGUI.Query(RouteGUI::FILTERR))
552 m_Filter.ModulateResonance(m_EnvControlbuf);
553
554
555 if (m_LFORouteGUI.Query(RouteGUI::OSC1FREQ) &&
556 m_EnvRouteGUI.Query(RouteGUI::OSC1FREQ))
557 m_Osc1.ModulateFreq(m_BothControlbuf);
558
559 if (m_LFORouteGUI.Query(RouteGUI::OSC1PW) &&
560 m_EnvRouteGUI.Query(RouteGUI::OSC1PW))
561 m_Osc1.ModulatePulseWidth(m_BothControlbuf);
562
563 if (m_LFORouteGUI.Query(RouteGUI::OSC2FREQ) &&
564 m_EnvRouteGUI.Query(RouteGUI::OSC2FREQ))
565 m_Osc2.ModulateFreq(m_BothControlbuf);
566
567 if (m_LFORouteGUI.Query(RouteGUI::OSC2PW) &&
568 m_EnvRouteGUI.Query(RouteGUI::OSC2PW))
569 m_Osc2.ModulatePulseWidth(m_BothControlbuf);
570
571 if (m_LFORouteGUI.Query(RouteGUI::FILTERC) &&
572 m_EnvRouteGUI.Query(RouteGUI::FILTERC))
573 m_Filter.ModulateCutoff(m_BothControlbuf);
574
575 if (m_LFORouteGUI.Query(RouteGUI::FILTERR) &&
576 m_EnvRouteGUI.Query(RouteGUI::FILTERR))
577 m_Filter.ModulateResonance(m_BothControlbuf);
578 }
579
UpdateValues()580 void Synth::UpdateValues()
581 {
582 m_Osc1GUI.UpdateValues();
583 m_Osc2GUI.UpdateValues();
584 m_Osc3GUI.UpdateValues();
585 m_Env1GUI.UpdateValues();
586 m_Env2GUI.UpdateValues();
587 m_Env3GUI.UpdateValues();
588 m_FilterGUI.UpdateValues();
589 m_MixerGUI.UpdateValues();
590 m_Mixer2GUI.UpdateValues();
591 m_DelayGUI.UpdateValues();
592 m_FilterEnvGUI.UpdateValues();
593 m_LFOGUI.UpdateValues();
594 m_LFORouteGUI.UpdateValues();
595 m_EnvRouteGUI.UpdateValues();
596 }
597
Randomise()598 void Synth::Randomise()
599 {
600 m_Osc1.Randomise();
601 m_Osc2.Randomise();
602 m_Osc3.Randomise();
603 m_Env1.Randomise();
604 m_Env2.Randomise();
605 m_Env3.Randomise();
606 m_Filter.Randomise();
607 m_Mixer.Randomise();
608 m_Mixer2.Randomise();
609 m_FilterEnv.Randomise();
610 m_LFO.Randomise();
611 m_LFORouteGUI.Randomise();
612 m_EnvRouteGUI.Randomise();
613
614 UpdateValues();
615 }
616
617 istream &operator>>(istream &s, Synth &o)
618 {
619 char t;
620 s>>o.m_Osc1>>o.m_Osc2>>o.m_Osc3>>o.m_Env1>>o.m_Env2>>
621 o.m_Env3>>o.m_Filter>>o.m_Mixer>>o.m_Mixer2>>o.m_Delay>>
622 o.m_FilterEnv>>o.m_LFO>>o.m_LFORouteGUI>>o.m_EnvRouteGUI;
623 return s;
624 }
625
626 ostream &operator<<(ostream &s, Synth &o)
627 {
628 s<<" "<<o.m_Osc1<<o.m_Osc2<<o.m_Osc3<<o.m_Env1
629 <<o.m_Env2<<o.m_Env3<<o.m_Filter<<o.m_Mixer
630 <<o.m_Mixer2<<o.m_Delay<<o.m_FilterEnv<<o.m_LFO
631 <<o.m_LFORouteGUI<<o.m_EnvRouteGUI<<endl;
632 return s;
633 }
634
main(int argc,char ** argv)635 int main(int argc, char **argv)
636 {
637 srand(time(NULL));
638 SynthInfo::Get()->LoadPrefs();
639
640 Synth *synth=new Synth;
641
642 Fl::visual(FL_DOUBLE|FL_RGB);
643 synth->CreateWindow();
644 synth->Window->show(argc, argv);
645
646 for (;;)
647 {
648 if (!Fl::check()) break;
649 synth->DoIdle();
650 }
651
652 delete synth;
653
654 return 1;
655 }
656