1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2 
3 #include "smmorphoutput.hh"
4 #include "smmorphplan.hh"
5 #include "smleakdebugger.hh"
6 
7 #include <assert.h>
8 
9 #define CHANNEL_OP_COUNT 4
10 
11 using namespace SpectMorph;
12 
13 using std::string;
14 using std::vector;
15 
16 static LeakDebugger leak_debugger ("SpectMorph::MorphOutput");
17 
MorphOutput(MorphPlan * morph_plan)18 MorphOutput::MorphOutput (MorphPlan *morph_plan) :
19   MorphOperator (morph_plan),
20   channel_ops (CHANNEL_OP_COUNT)
21 {
22   connect (morph_plan->signal_operator_removed, this, &MorphOutput::on_operator_removed);
23 
24   m_velocity_sensitivity = 24; /* dB */
25 
26   m_sines = true;
27   m_noise = true;
28 
29   m_unison = false;
30   m_unison_voices = 2;
31   m_unison_detune = 6.0;
32 
33   m_adsr = false;
34   m_adsr_skip     = 500;
35   m_adsr_attack   = 15;
36   m_adsr_decay    = 20;
37   m_adsr_sustain  = 70;
38   m_adsr_release  = 50;
39 
40   m_portamento = false;
41   m_portamento_glide = 200; /* ms */
42 
43   m_vibrato = false;
44   m_vibrato_depth = 10;    /* cent */
45   m_vibrato_frequency = 4; /* Hz */
46   m_vibrato_attack = 0;    /* ms */
47 
48   leak_debugger.add (this);
49 }
50 
MorphOutputProperties(MorphOutput * output)51 MorphOutputProperties::MorphOutputProperties (MorphOutput *output) :
52   adsr_skip (output, "Skip", "%.1f ms", 0, 1000, &MorphOutput::adsr_skip, &MorphOutput::set_adsr_skip),
53   adsr_attack (output, "Attack", "%.1f %%", 0, 100, &MorphOutput::adsr_attack, &MorphOutput::set_adsr_attack),
54   adsr_decay (output, "Decay", "%.1f %%", 0, 100, &MorphOutput::adsr_decay, &MorphOutput::set_adsr_decay),
55   adsr_sustain (output, "Sustain", "%.1f %%", 0, 100, &MorphOutput::adsr_sustain, &MorphOutput::set_adsr_sustain),
56   adsr_release (output, "Release", "%.1f %%", 0, 100, &MorphOutput::adsr_release, &MorphOutput::set_adsr_release),
57   portamento_glide (output, "Glide", "%.2f ms", 0, 1000, 3, &MorphOutput::portamento_glide, &MorphOutput::set_portamento_glide),
58   vibrato_depth (output, "Depth", "%.2f Cent", 0, 50, &MorphOutput::vibrato_depth, &MorphOutput::set_vibrato_depth),
59   vibrato_frequency (output, "Frequency", "%.3f Hz", 1.0, 15, &MorphOutput::vibrato_frequency, &MorphOutput::set_vibrato_frequency),
60   vibrato_attack (output, "Attack", "%.2f ms", 0, 1000, &MorphOutput::vibrato_attack, &MorphOutput::set_vibrato_attack),
61   velocity_sensitivity (output, "Velocity Sns", "%.2f dB", 0, 48, &MorphOutput::velocity_sensitivity, &MorphOutput::set_velocity_sensitivity)
62 {
63 }
64 
~MorphOutput()65 MorphOutput::~MorphOutput()
66 {
67   leak_debugger.del (this);
68 }
69 
70 const char *
type()71 MorphOutput::type()
72 {
73   return "SpectMorph::MorphOutput";
74 }
75 
76 int
insert_order()77 MorphOutput::insert_order()
78 {
79   return 1000;
80 }
81 
82 bool
save(OutFile & out_file)83 MorphOutput::save (OutFile& out_file)
84 {
85   for (size_t i = 0; i < channel_ops.size(); i++)
86     {
87       string name;
88 
89       if (channel_ops[i])   // NULL pointer => name = ""
90         name = channel_ops[i]->name();
91 
92       out_file.write_string ("channel", name);
93     }
94   out_file.write_bool ("sines", m_sines);
95   out_file.write_bool ("noise", m_noise);
96 
97   out_file.write_bool ("unison", m_unison);
98   out_file.write_int ("unison_voices", m_unison_voices);
99   out_file.write_float ("unison_detune", m_unison_detune);
100 
101   out_file.write_bool ("adsr", m_adsr);
102   out_file.write_float ("adsr_skip",    m_adsr_skip);
103   out_file.write_float ("adsr_attack",  m_adsr_attack);
104   out_file.write_float ("adsr_decay",   m_adsr_decay);
105   out_file.write_float ("adsr_sustain", m_adsr_sustain);
106   out_file.write_float ("adsr_release", m_adsr_release);
107 
108   out_file.write_bool ("portamento", m_portamento);
109   out_file.write_float ("portamento_glide", m_portamento_glide);
110 
111   out_file.write_bool ("vibrato", m_vibrato);
112   out_file.write_float ("vibrato_depth", m_vibrato_depth);
113   out_file.write_float ("vibrato_frequency", m_vibrato_frequency);
114   out_file.write_float ("vibrato_attack", m_vibrato_attack);
115 
116   out_file.write_float ("velocity_sensitivity", m_velocity_sensitivity);
117 
118   return true;
119 }
120 
121 bool
load(InFile & ifile)122 MorphOutput::load (InFile& ifile)
123 {
124   load_channel_op_names.clear();
125 
126   while (ifile.event() != InFile::END_OF_FILE)
127     {
128       if (ifile.event() == InFile::STRING)
129         {
130           if (ifile.event_name() == "channel")
131             {
132               load_channel_op_names.push_back (ifile.event_data());
133             }
134           else
135             {
136               g_printerr ("bad string\n");
137               return false;
138             }
139         }
140       else if (ifile.event() == InFile::BOOL)
141         {
142           if (ifile.event_name() == "sines")
143             {
144               m_sines = ifile.event_bool();
145             }
146           else if (ifile.event_name() == "noise")
147             {
148               m_noise = ifile.event_bool();
149             }
150           else if (ifile.event_name() == "unison")
151             {
152               m_unison = ifile.event_bool();
153             }
154           else if (ifile.event_name() == "adsr")
155             {
156               m_adsr = ifile.event_bool();
157             }
158           else if (ifile.event_name() == "portamento")
159             {
160               m_portamento = ifile.event_bool();
161             }
162           else if (ifile.event_name() == "vibrato")
163             {
164               m_vibrato = ifile.event_bool();
165             }
166           else
167             {
168               g_printerr ("bad bool\n");
169               return false;
170             }
171         }
172       else if (ifile.event() == InFile::INT)
173         {
174           if (ifile.event_name() == "unison_voices")
175             {
176               m_unison_voices = ifile.event_int();
177             }
178           else
179             {
180               g_printerr ("bad int\n");
181               return false;
182             }
183         }
184       else if (ifile.event() == InFile::FLOAT)
185         {
186           if (ifile.event_name() == "unison_detune")
187             {
188               m_unison_detune = ifile.event_float();
189             }
190           else if (ifile.event_name() == "adsr_skip")
191             {
192               m_adsr_skip = ifile.event_float();
193             }
194           else if (ifile.event_name() == "adsr_attack")
195             {
196               m_adsr_attack = ifile.event_float();
197             }
198           else if (ifile.event_name() == "adsr_decay")
199             {
200               m_adsr_decay = ifile.event_float();
201             }
202           else if (ifile.event_name() == "adsr_sustain")
203             {
204               m_adsr_sustain = ifile.event_float();
205             }
206           else if (ifile.event_name() == "adsr_release")
207             {
208               m_adsr_release = ifile.event_float();
209             }
210           else if (ifile.event_name() == "portamento_glide")
211             {
212               m_portamento_glide = ifile.event_float();
213             }
214           else if (ifile.event_name() == "vibrato_depth")
215             {
216               m_vibrato_depth = ifile.event_float();
217             }
218           else if (ifile.event_name() == "vibrato_frequency")
219             {
220               m_vibrato_frequency = ifile.event_float();
221             }
222           else if (ifile.event_name() == "vibrato_attack")
223             {
224               m_vibrato_attack = ifile.event_float();
225             }
226           else if (ifile.event_name() == "velocity_sensitivity")
227             {
228               m_velocity_sensitivity = ifile.event_float();
229             }
230           else
231             {
232               g_printerr ("bad float\n");
233               return false;
234             }
235         }
236       else
237         {
238           g_printerr ("bad event\n");
239           return false;
240         }
241       ifile.next_event();
242     }
243   return true;
244 }
245 
246 void
post_load(OpNameMap & op_name_map)247 MorphOutput::post_load (OpNameMap& op_name_map)
248 {
249   for (size_t i = 0; i < channel_ops.size(); i++)
250     {
251       if (i < load_channel_op_names.size())
252         {
253           string name = load_channel_op_names[i];
254           channel_ops[i] = op_name_map[name];
255         }
256     }
257 }
258 
259 MorphOperator::OutputType
output_type()260 MorphOutput::output_type()
261 {
262   return OUTPUT_NONE;
263 }
264 
265 void
set_channel_op(int ch,MorphOperator * op)266 MorphOutput::set_channel_op (int ch, MorphOperator *op)
267 {
268   assert (ch >= 0 && ch < CHANNEL_OP_COUNT);
269 
270   channel_ops[ch] = op;
271   m_morph_plan->emit_plan_changed();
272 }
273 
274 MorphOperator *
channel_op(int ch)275 MorphOutput::channel_op (int ch)
276 {
277   assert (ch >= 0 && ch < CHANNEL_OP_COUNT);
278 
279   return channel_ops[ch];
280 }
281 
282 bool
sines() const283 MorphOutput::sines() const
284 {
285   return m_sines;
286 }
287 
288 void
set_sines(bool es)289 MorphOutput::set_sines (bool es)
290 {
291   m_sines = es;
292 
293   m_morph_plan->emit_plan_changed();
294 }
295 
296 bool
noise() const297 MorphOutput::noise() const
298 {
299   return m_noise;
300 }
301 
302 void
set_noise(bool en)303 MorphOutput::set_noise (bool en)
304 {
305   m_noise = en;
306 
307   m_morph_plan->emit_plan_changed();
308 }
309 
310 //---- unison effect ----
311 
312 bool
unison() const313 MorphOutput::unison() const
314 {
315   return m_unison;
316 }
317 
318 void
set_unison(bool eu)319 MorphOutput::set_unison (bool eu)
320 {
321   m_unison = eu;
322 
323   m_morph_plan->emit_plan_changed();
324 }
325 
326 int
unison_voices() const327 MorphOutput::unison_voices() const
328 {
329   return m_unison_voices;
330 }
331 
332 void
set_unison_voices(int voices)333 MorphOutput::set_unison_voices (int voices)
334 {
335   m_unison_voices = voices;
336 
337   m_morph_plan->emit_plan_changed();
338 }
339 
340 float
unison_detune() const341 MorphOutput::unison_detune() const
342 {
343   return m_unison_detune;
344 }
345 
346 void
set_unison_detune(float detune)347 MorphOutput::set_unison_detune (float detune)
348 {
349   m_unison_detune = detune;
350 
351   m_morph_plan->emit_plan_changed();
352 }
353 
354 //---- adsr ----
355 
356 bool
adsr() const357 MorphOutput::adsr() const
358 {
359   return m_adsr;
360 }
361 
362 void
set_adsr(bool ea)363 MorphOutput::set_adsr (bool ea)
364 {
365   m_adsr = ea;
366 
367   m_morph_plan->emit_plan_changed();
368 }
369 
370 float
adsr_skip() const371 MorphOutput::adsr_skip() const
372 {
373   return m_adsr_skip;
374 }
375 
376 void
set_adsr_skip(float skip)377 MorphOutput::set_adsr_skip (float skip)
378 {
379   m_adsr_skip = skip;
380 
381   m_morph_plan->emit_plan_changed();
382 }
383 
384 float
adsr_attack() const385 MorphOutput::adsr_attack() const
386 {
387   return m_adsr_attack;
388 }
389 
390 void
set_adsr_attack(float attack)391 MorphOutput::set_adsr_attack (float attack)
392 {
393   m_adsr_attack = attack;
394 
395   m_morph_plan->emit_plan_changed();
396 }
397 
398 float
adsr_decay() const399 MorphOutput::adsr_decay() const
400 {
401   return m_adsr_decay;
402 }
403 
404 void
set_adsr_decay(float decay)405 MorphOutput::set_adsr_decay (float decay)
406 {
407   m_adsr_decay = decay;
408 
409   m_morph_plan->emit_plan_changed();
410 }
411 
412 float
adsr_release() const413 MorphOutput::adsr_release() const
414 {
415   return m_adsr_release;
416 }
417 
418 void
set_adsr_release(float release)419 MorphOutput::set_adsr_release (float release)
420 {
421   m_adsr_release = release;
422 
423   m_morph_plan->emit_plan_changed();
424 }
425 
426 float
adsr_sustain() const427 MorphOutput::adsr_sustain() const
428 {
429   return m_adsr_sustain;
430 }
431 
432 void
set_adsr_sustain(float sustain)433 MorphOutput::set_adsr_sustain (float sustain)
434 {
435   m_adsr_sustain = sustain;
436 
437   m_morph_plan->emit_plan_changed();
438 }
439 
440 //---- portamento/mono mode ----
441 
442 bool
portamento() const443 MorphOutput::portamento() const
444 {
445   return m_portamento;
446 }
447 
448 void
set_portamento(bool ep)449 MorphOutput::set_portamento (bool ep)
450 {
451   m_portamento = ep;
452 
453   m_morph_plan->emit_plan_changed();
454 }
455 
456 float
portamento_glide() const457 MorphOutput::portamento_glide() const
458 {
459   return m_portamento_glide;
460 }
461 
462 void
set_portamento_glide(float glide)463 MorphOutput::set_portamento_glide (float glide)
464 {
465   m_portamento_glide = glide;
466 
467   m_morph_plan->emit_plan_changed();
468 }
469 
470 //---- vibrato ----
471 
472 bool
vibrato() const473 MorphOutput::vibrato() const
474 {
475   return m_vibrato;
476 }
477 
478 void
set_vibrato(bool ev)479 MorphOutput::set_vibrato (bool ev)
480 {
481   m_vibrato = ev;
482 
483   m_morph_plan->emit_plan_changed();
484 }
485 
486 float
vibrato_depth() const487 MorphOutput::vibrato_depth() const
488 {
489   return m_vibrato_depth;
490 }
491 
492 void
set_vibrato_depth(float depth)493 MorphOutput::set_vibrato_depth (float depth)
494 {
495   m_vibrato_depth = depth;
496 
497   m_morph_plan->emit_plan_changed();
498 }
499 
500 float
vibrato_frequency() const501 MorphOutput::vibrato_frequency() const
502 {
503   return m_vibrato_frequency;
504 }
505 
506 void
set_vibrato_frequency(float frequency)507 MorphOutput::set_vibrato_frequency (float frequency)
508 {
509   m_vibrato_frequency = frequency;
510 
511   m_morph_plan->emit_plan_changed();
512 }
513 
514 float
vibrato_attack() const515 MorphOutput::vibrato_attack() const
516 {
517   return m_vibrato_attack;
518 }
519 
520 void
set_vibrato_attack(float attack)521 MorphOutput::set_vibrato_attack (float attack)
522 {
523   m_vibrato_attack = attack;
524 
525   m_morph_plan->emit_plan_changed();
526 }
527 
528 float
velocity_sensitivity() const529 MorphOutput::velocity_sensitivity() const
530 {
531   return m_velocity_sensitivity;
532 }
533 
534 void
set_velocity_sensitivity(float velocity_sensitivity)535 MorphOutput::set_velocity_sensitivity (float velocity_sensitivity)
536 {
537   m_velocity_sensitivity = velocity_sensitivity;
538 
539   m_morph_plan->emit_plan_changed();
540 }
541 
542 void
on_operator_removed(MorphOperator * op)543 MorphOutput::on_operator_removed (MorphOperator *op)
544 {
545   for (size_t ch = 0; ch < channel_ops.size(); ch++)
546     {
547       if (channel_ops[ch] == op)
548         channel_ops[ch] = NULL;
549     }
550 }
551 
552 vector<MorphOperator *>
dependencies()553 MorphOutput::dependencies()
554 {
555   return channel_ops;
556 }
557