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