Euphoria
synth.cc
Go to the documentation of this file.
1 #include "minsynth/synth.h"
2 
3 #include <cmath>
4 #include <set>
5 #include <algorithm>
6 
7 #include <fmt/core.h>
8 #include <fmt/format.h>
9 
10 #include "log/log.h"
11 #include "assert/assert.h"
12 #include "base/numeric.h"
13 #include "base/cint.h"
14 #include "base/angle.h"
15 
16 
17 using namespace fmt::literals;
18 
19 
20 /*
21  Tone names:
22  1 2 3 4 5 6 7
23  C D E F G A B
24  Do Re Mi Fa So La Si
25 */
26 
27 namespace eu::minsynth
28 {
29  std::string
31  {
32  switch(t)
33  {
34  case Tuning::a4: return "A4 (ISO 16) 440 Hz";
35  case Tuning::boston: return "Boston 441 Hz";
36  case Tuning::new_york: return "New York 442 Hz";
37  case Tuning::europe: return "europe 443 Hz";
38  case Tuning::french: return "French 435 Hz";
39  case Tuning::baroque: return "baroque 415 hz";
40  case Tuning::chorton: return "chorton 466 Hz";
41  case Tuning::classical: return "classical 430 Hz";
42  default: return "???";
43  }
44  }
45 
46  std::string
48  {
49  switch(em)
50  {
51  case ChordEmulation::none: return "None";
52  case ChordEmulation::major: return "Major triad";
53  case ChordEmulation::minor: return "Minor Triad";
54  case ChordEmulation::diminished: return "diminished triad";
55  case ChordEmulation::augmented: return "augmented triad";
56  case ChordEmulation::major7: return "Major 7th";
57  case ChordEmulation::dominant7: return "Dominant 7th";
58  case ChordEmulation::augmented7: return "augmented 7th";
59  case ChordEmulation::augmented_major7: return "augmented Major 7th";
60  case ChordEmulation::minor_major7: return "Minor major 7th";
61  default: return "???";
62  }
63  }
64 
65  float
67  {
68  switch(t)
69  {
70  case Tuning::a4: return base_frequencies::a4;
71  case Tuning::boston: return base_frequencies::boston_a4;
72  case Tuning::new_york: return base_frequencies::new_york_a4;
73  case Tuning::europe: return base_frequencies::europe_a4;
74  case Tuning::french: return base_frequencies::french_a4;
75  case Tuning::baroque: return base_frequencies::baroque_a4;
76  case Tuning::chorton: return base_frequencies::chorton_a4;
77  case Tuning::classical: return base_frequencies::classical_a4;
78  default: return base_frequencies::a4;
79  }
80  }
81 
82 
83  std::string
85  {
86  switch(e)
87  {
88  case MidiEvent::note_off: return "Off";
89  case MidiEvent::note_on: return "On";
90  case MidiEvent::aftertouch: return "aftertouch";
91  case MidiEvent::control_change: return "CC";
92  case MidiEvent::program_change: return "PC";
93  case MidiEvent::channel_pressure: return "Channel Pressure";
94  case MidiEvent::pitch_bend: return "pitch_bend";
95  }
96  return "???";
97  }
98 
99 
100  std::string
102  {
103  switch(mode)
104  {
105  case ArpMode::up: return "Up";
106  case ArpMode::down: return "Down";
107  case ArpMode::up_down_inclusive: return "Up/Down (inclusive)";
108  case ArpMode::up_down_exclusive: return "Up/Down (exclusive)";
109  case ArpMode::random: return "Random";
110  case ArpMode::random_no_repeat: return "Random (no repeat)";
111  default: return "???";
112  }
113  }
114 
115 
116  std::string
118  {
119  switch(osc)
120  {
121  case OscilatorType::sine: return "Sine";
122  case OscilatorType::square: return "Square";
123  case OscilatorType::triangle: return "Triangle";
124  case OscilatorType::sawtooth: return "sawtooth";
125  case OscilatorType::noise: return "noise";
126  default: return "?";
127  }
128  }
129 
130  template <int steps_per_octave>
132  {
134  {
135  const float base
136  = std::pow(2.0f, 1.0f / static_cast<float>(steps_per_octave));
137  for(int octave_index = 0; octave_index < steps_per_octave; octave_index += 1)
138  {
139  step_data[octave_index] = std::pow(base, static_cast<float>(octave_index));
140  }
141  }
142 
143  [[nodiscard]] constexpr float
144  get_frequency(int halfstep, float octave_base_frequency) const
145  {
146  float freq = octave_base_frequency;
147 
148  int step = halfstep;
149 
150  while(step >= steps_per_octave)
151  {
152  freq = freq * 2;
153  step -= steps_per_octave;
154  }
155 
156  while(step < 0)
157  {
158  freq = freq / 2;
159  step += steps_per_octave;
160  }
161 
162  ASSERT(step >= 0 && step < steps_per_octave);
163  const auto rf = freq * step_data[step];
164  return rf;
165  }
166 
167  private:
168  float step_data[steps_per_octave] = {
169  0.0f,
170  };
171  };
172 
173 
174  template <int tones_per_octave>
175  float
176  from_tone_to_frequency_impl(int tone, float base_frequency)
177  {
178  const static auto converter = ToneToFrequencyConverter<tones_per_octave>();
179  return converter.get_frequency(tone, base_frequency);
180  }
181 
182  float
183  from_tone_to_frequency(int tone, float base_frequency)
184  {
185  return from_tone_to_frequency_impl<12>(tone, base_frequency);
186  }
187 
188  void
189  Node::update(float /*dt*/, float /*current_time*/)
190  {
191  }
192 
193  void
194  ToneSender::send_tone(int tone, bool down, float time) const
195  {
196  if(next_node != nullptr)
197  {
198  next_node->on_tone(tone, down, time);
199  }
200  }
201 
202 
203  void
204  ToneToFrequencyConverterNode::on_tone(int tone, bool down, float time)
205  {
206  if(next == nullptr)
207  {
208  return;
209  }
210 
211  if(down)
212  {
213  next->on_frequency_down(tone, calc_frequency(tone), time);
214  }
215  else
216  {
217  next->on_frequency_up(tone, calc_frequency(tone), time);
218  }
219  }
220 
221  float
222  ToneToFrequencyConverterNode::calc_frequency(int semitone) const
223  {
224  const float base_freq = from_tuning_to_base_frequency(tuning);
225  const int tone = semitone - 9; // hrm.... why?
226 
227  const float freq = from_tone_to_frequency(tone, base_freq);
228 
229  return freq;
230  }
231 
232  namespace
233  {
234  std::string
235  name_and_octave(const std::string& name, int octave)
236  {
237  return fmt::format("{}{}", name, octave);
238  }
239  }
240 
241  PianoKey::PianoKey(int st, core::Key kc, const std::string& n, int octave)
242  : semitone(st)
243  , keycode(kc)
244  , name(name_and_octave(n, octave))
245  , octave_shift(false)
246  {
247  }
248 
249 
250  bool
252  {
253  const auto is_status = ((b >> 7) & 0x1) == 1;
254  return is_status;
255  }
256 
257  void
259  (
260  double dt,
261  const std::vector<unsigned char>& bytes
262  )
263  {
264  using Byte = unsigned char;
265 
266  const Byte message_mask = 0x7;
267  const Byte channel_mask = 0xF;
268 
269  for(auto b: bytes)
270  {
271  const auto is_status = MidiInNode::is_status_message(b);
272  if(is_status)
273  {
274  const Byte channel = (b >> 0) & channel_mask;
275  const Byte message = (b >> 4) & message_mask;
276 
277  LOG_INFO
278  (
279  "STAT ({0}) {1}",
280  static_cast<unsigned int>(channel),
281  from_midi_event_to_string(static_cast<MidiEvent>(message))
282  );
283  }
284  else
285  {
286  LOG_INFO("{0}", static_cast<unsigned int>(b));
287  }
288  }
289  if(!bytes.empty())
290  {
291  LOG_INFO("stamp = {0}", dt);
292  }
293  }
294 
295  void
296  MidiInNode::on_midi_message(float dt, const std::vector<unsigned char>& bytes)
297  {
298  using Byte = unsigned char;
299 
300  if(bytes.empty())
301  {
302  return;
303  }
304 
305  if(!MidiInNode::is_status_message(bytes[0]))
306  {
307  LOG_ERROR("todo: need to handle data message without status.");
308  return;
309  }
310 
311  const auto bytes_size = bytes.size();
312 
313  const Byte message_mask = 0x7;
314  // const byte channel_mask = 0xF;
315  // const byte channel = (bytes[0] >> 0) & channel_mask;
316  const Byte message = (bytes[0] >> 4) & message_mask;
317 
318  const auto event = static_cast<MidiEvent>(message);
319  switch(event)
320  {
321  case MidiEvent::note_on:
322  case MidiEvent::note_off: {
323  const bool on = event == MidiEvent::note_on;
324  if(bytes_size == 3)
325  {
326  const auto note = bytes[1];
327  const auto velocity = bytes[2];
328 
330  {
331  LOG_ERROR("Unexpected midi command in note on/off data.");
332  return;
333  }
334 
335  // c3 == midi #60
336  if(tones != nullptr)
337  {
338  const int tone = note;
339  float time = dt;
340  tones->on_tone(tone - 60, on, time + last_time);
341  LOG_INFO("Time: {0}", time + last_time);
342  last_time += time;
343  }
344  }
345  else
346  {
347  LOG_ERROR("todo: need to handle note on/off with other sizes.");
348  return;
349  }
350  break;
351  }
352 
353  default: LOG_ERROR("todo: handle {0}", from_midi_event_to_string(event)); return;
354  }
355  }
356 
357 
358  void
360  (
361  int base,
362  bool was_pressed,
363  float time,
364  int first,
365  int second
366  ) const
367  {
368  tones->on_tone(base, was_pressed, time);
369  tones->on_tone(base + first, was_pressed, time);
370  tones->on_tone(base + first + second, was_pressed, time);
371  }
372 
373  void
375  (
376  int base,
377  bool was_pressed,
378  float time,
379  const std::vector<int>& integer_notation
380  ) const
381  {
382  for(auto i: integer_notation)
383  {
384  tones->on_tone(base + i, was_pressed, time);
385  }
386  }
387 
388  void
389  KeyboardInputNode::on_input(core::Key input, bool was_pressed, float time)
390  {
391  if(tones == nullptr)
392  {
393  return;
394  }
395 
396  for(auto& key: keys)
397  {
398  if(key.keycode != core::Key::unbound && input == key.keycode)
399  {
400  if(was_pressed)
401  {
402  key.octave_shift = octave_shift;
403  }
404  const auto octave_shift_semitones = key.octave_shift ? 24 : 0;
405  const int tone = key.semitone + octave_shift_semitones;
406 
407  const auto minor3rd = 3;
408  const auto major3rd = 4;
409  switch(chords_emulation)
410  {
412  tones->on_tone(tone, was_pressed, time);
413  break;
415  on_chord(tone, was_pressed, time, major3rd, minor3rd);
416  break;
418  on_chord(tone, was_pressed, time, minor3rd, major3rd);
419  break;
421  on_chord(tone, was_pressed, time, minor3rd, minor3rd);
422  break;
424  on_chord(tone, was_pressed, time, major3rd, major3rd);
425  break;
427  on_chord(tone, was_pressed, time, {0, 4, 7, 11});
428  break;
430  on_chord(tone, was_pressed, time, {0, 4, 7, 10});
431  break;
433  on_chord(tone, was_pressed, time, {0, 4, 8, 10});
434  break;
436  on_chord(tone, was_pressed, time, {0, 4, 8, 11});
437  break;
439  on_chord(tone, was_pressed, time, {0, 3, 7, 11});
440  break;
441  default: break;
442  }
443  }
444  }
445 
446  if(input == core::Key::shift_left || input == core::Key::shift_right)
447  {
448  octave_shift = was_pressed;
449  }
450  }
451 
452 
453  void
454  SingleToneNode::on_tone(int tone, bool down, float time)
455  {
456  if(down)
457  {
458  if(!down_tones.empty())
459  {
460  const auto current_tone = get_current_tone();
461  send_tone(current_tone, false, time);
462  }
463  // this will override the old tone and this is "wrong",
464  // but we need a better way to handle multiples anyway
465  down_tones[tone] = time;
466 
467  send_tone(tone, down, time);
468  }
469  else
470  {
471  const auto playing_tone = get_current_tone();
472  down_tones.erase(tone);
473 
474  if(playing_tone == tone)
475  {
476  // this means the best match stopped playing
477 
478  send_tone(tone, false, time);
479  if(!down_tones.empty())
480  {
481  const auto new_tone = get_current_tone();
482  send_tone(new_tone, true, time);
483  }
484  }
485  }
486  }
487 
488  int
490  {
491  bool has_tone = false;
492  int tone = 0;
493  float time = 0;
494  for(const auto& k: down_tones)
495  {
496  if(has_tone)
497  {
498  if(k.second > time)
499  {
500  time = k.second;
501  tone = k.first;
502  }
503  }
504  else
505  {
506  has_tone = true;
507  time = k.second;
508  tone = k.first;
509  }
510  }
511 
512  ASSERT(has_tone);
513  return tone;
514  }
515 
516 
517  void
518  ArpegiatorNode::update(float dt, float current_time)
519  {
520  int count = 0;
522  while(current_time_in_interval > update_time && count < 10)
523  {
524  count += 1;
526  if(!tones.empty())
527  {
528  const int size = c_sizet_to_int(tones.size());
529 
531  {
532  const int last_index = index;
533  index = rand() % size;
534  if(mode == ArpMode::random_no_repeat && tones.size() > 1)
535  {
536  while(index == last_index)
537  {
538  index = rand() % size;
539  }
540  }
541  }
542  else
543  {
544  index = (index + 1) % size;
545  }
546  send_tone(tones[index], true, current_time);
547  active_tones[tones[index]] = current_time + tone_time;
548  }
549  }
550 
551  std::vector<int> erase;
552  for(auto& tone: active_tones)
553  {
554  if(tone.second < current_time)
555  {
556  send_tone(tone.first, false, tone.second);
557  erase.emplace_back(tone.first);
558  }
559  }
560  for(auto tone: erase)
561  {
562  active_tones.erase(tone);
563  }
564  }
565 
566  void
567  ArpegiatorNode::on_tone(int tone, bool down, float time)
568  {
569  if(down)
570  {
571  down_tones[tone] = time;
572  }
573  else
574  {
575  down_tones.erase(tone);
576  }
577 
578  tones.resize(0);
579  if(!down_tones.empty())
580  {
581  std::set<int> tt;
582  for(const auto& t: down_tones)
583  {
584  for(int octave_index = 0; octave_index < octaves; octave_index += 1)
585  {
586  tt.insert(t.first + octave_index * 12);
587  }
588  }
589  switch(mode)
590  {
591  case ArpMode::up:
592  tones.insert(tones.begin(), tt.begin(), tt.end());
593  break;
594  case ArpMode::down:
595  tones.insert(tones.begin(), tt.rbegin(), tt.rend());
596  break;
598  tones.insert(tones.begin(), tt.begin(), tt.end());
599  tones.insert(tones.begin(), tt.rbegin(), tt.rend());
600  break;
602  tones.insert(tones.begin(), tt.begin(), tt.end());
603  if(tt.size() > 2)
604  {
605  tt.erase(tt.begin());
606  auto it = tt.end();
607  --it;
608  tt.erase(it);
609  tones.insert(tones.begin(), tt.rbegin(), tt.rend());
610  }
611  break;
612  default:
613  tones.insert(tones.begin(), tt.begin(), tt.end());
614  break;
615  }
616  index = index % c_sizet_to_int(tones.size());
617  }
618  }
619 
620 
621  float
622  run_oscilator(float frequency, float time, OscilatorType osc)
623  {
624  const float sine = sin( Angle::from_percent_of_360(frequency) * time);
625  switch(osc)
626  {
627  case OscilatorType::sine: return sine;
628  case OscilatorType::square: return sine > 0.0f ? 1.0f : -1.0f;
629  case OscilatorType::triangle: return asin(sine).as_radians() * (2.0f / pi);
631  return (2 / pi) * (frequency * pi * fmodf(time, 1 / frequency) - pi / 2);
633  // todo(Gustav): use the improved c++ random library
634  // todo(Gustav): and also add perlin noise?
635  return 2 * (static_cast<float>(rand()) / static_cast<float>(RAND_MAX)) - 1;
636  default: return 0;
637  }
638  }
639 
640 
641  float
642  to01(float lower_bound, float value, float upper_bound)
643  {
644  return (value - lower_bound) / (upper_bound - lower_bound);
645  }
646 
647 
648  float
649  Envelope::get_live(float wave, float start_time, float current_time) const
650  {
651  if(current_time < start_time)
652  {
653  return 0;
654  }
655  else if(current_time > (start_time + time_to_start))
656  {
657  return wave;
658  }
659  else
660  {
661  return wave * to01(start_time, current_time, start_time + time_to_start);
662  }
663  }
664 
665  float
666  Envelope::get_dead(float wave, float end_time, float current_time) const
667  {
668  if(current_time < end_time)
669  {
670  return wave;
671  }
672  else if(current_time > (end_time + time_to_end))
673  {
674  return 0;
675  }
676  else
677  {
678  return wave * (1 - to01(end_time, current_time, end_time + time_to_end));
679  }
680  }
681 
682 
683  int
685  {
686  return c_sizet_to_int(live.size() + dead.size());
687  }
688 
689  int
691  {
692  return c_sizet_to_int(live.size());
693  }
694 
695  int
697  {
698  return c_sizet_to_int(dead.size());
699  }
700 
701  void
702  OscilatorNode::update(float, float current_time)
703  {
704  dead.erase
705  (
706  std::remove_if
707  (
708  dead.begin(),
709  dead.end(),
710  [=, this](const DeadFrequency& df) -> bool
711  {
712  return df.time_end + envelope.time_to_end < current_time;
713  }
714  ),
715  dead.end()
716  );
717  }
718 
719  void
720  OscilatorNode::on_frequency_down(int id, float freq, float time)
721  {
722  live[id] = LiveFrequency {freq, time};
723  }
724 
725  void
726  OscilatorNode::on_frequency_up(int id, float frequency, float time)
727  {
728  const auto scale = envelope.get_live(1.0f, live[id].time_start, time);
729  live.erase(id);
730  dead.emplace_back(DeadFrequency {true, frequency, time, scale});
731  }
732 
733  float
735  {
736  float value = 0;
737 
738  const int maxtones = 10;
739 
740  int tone = 0;
741  for(const auto& li: live)
742  {
743  if(tone++ > maxtones)
744  {
745  break;
746  }
747  const auto& f = li.second;
748  value += envelope.get_live
749  (
750  run_oscilator(f.frequency, time, oscilator),
751  f.time_start,
752  time
753  );
754  }
755 
756  tone = 0;
757  for(const auto& d: dead)
758  {
759  if(tone++ > maxtones)
760  {
761  break;
762  }
763  value += d.scale * envelope.get_dead
764  (
765  run_oscilator(d.frequency, time, oscilator),
766  d.time_end,
767  time
768  );
769  }
770 
771  return value;
772  }
773 
774 
775  namespace
776  {
777  template <typename T>
778  void
779  insert(std::vector<T>* to, const std::vector<T>& from)
780  {
781  for(const auto& t: from)
782  {
783  to->push_back(t);
784  }
785  }
786  }
787 
788 
789  float
790  Effect::get_output(float time)
791  {
792  if(in == nullptr)
793  {
794  return 0;
795  }
796 
797  return on_wave(in->get_output(time));
798  }
799 
800 
801  float
803  {
804  return volume * wave;
805  }
806 
807 
808  float
810  {
811  float w = abs(wave);
812  const auto negative = wave < 0;
813  for(int time_counter = 0; time_counter < times; time_counter += 1)
814  {
815  w = w * w;
816  }
817  return negative ? w * -1 : w;
818  }
819 
820 
821  std::vector<PianoKey>
823  (
824  int octave,
825  int semitone_offset,
826  core::Key c,
827  core::Key d,
828  core::Key e,
829  core::Key f,
830  core::Key g,
831  core::Key a,
832  core::Key b,
833  core::Key c_sharp,
834  core::Key d_sharp,
835  core::Key f_sharp,
836  core::Key g_sharp,
837  core::Key a_sharp
838  )
839  {
840  return
841  {
842  PianoKey(semitone_offset + 0, c, "C", octave),
843  PianoKey(semitone_offset + 1, c_sharp, "C#", octave),
844  PianoKey(semitone_offset + 2, d, "D", octave),
845  PianoKey(semitone_offset + 3, d_sharp, "D#", octave),
846  PianoKey(semitone_offset + 4, e, "E", octave),
847 
848  PianoKey(semitone_offset + 5, f, "F", octave),
849  PianoKey(semitone_offset + 6, f_sharp, "F#", octave),
850  PianoKey(semitone_offset + 7, g, "G", octave),
851  PianoKey(semitone_offset + 8, g_sharp, "G#", octave),
852  PianoKey(semitone_offset + 9, a, "A", octave),
853  PianoKey(semitone_offset + 10, a_sharp, "A#", octave),
854  PianoKey(semitone_offset + 11, b, "B", octave),
855  };
856  }
857 
858 
859  const KeyboardLayout&
861  {
862  using K = eu::core::Key;
863 
864  static const KeyboardLayout k =
865  {
866  {K::num_1, K::num_2, K::num_3, K::num_4, K::num_5, K::num_6, K::num_7, K::num_8, K::num_9, K::num_0},
867  {K::q, K::w, K::e, K::r, K::t, K::y, K::u, K::i, K::o, K::p},
868  {K::a, K::s, K::d, K::f, K::g, K::h, K::j, K::k, K::l},
869  {K::z, K::x, K::c, K::v, K::b, K::n, K::m},
870  };
871 
872  return k;
873  }
874 
875 
876  void
878  (
879  std::vector<PianoKey>* keys,
880  int base_octave,
881  int octave,
882  const KeyboardLayout& k,
883  int start_row,
884  int start_col
885  )
886  {
887  const auto key = [&](int x, int y) -> core::Key
888  {
889  const auto wy = start_row - y + 1;
890  if(wy < 0 || wy > c_sizet_to_int(k.size()))
891  {
892  return core::Key::unbound;
893  }
894  const auto& r = k[wy];
895  const auto wx = start_col + x;
896  if(wx < 0 || wx > c_sizet_to_int(r.size()))
897  {
898  return core::Key::unbound;
899  }
900  return r[wx];
901  };
902  const auto white_key = key;
903  const auto black_key = key;
904 
905  insert
906  (
907  keys,
909  (
910  base_octave + octave,
911  octave * 12,
912  // first 3 white
913  white_key(0, 0), white_key(1, 0), white_key(2, 0),
914  // second 4
915  white_key(3, 0), white_key(4, 0), white_key(5, 0), white_key(6, 0),
916  // first 2 black
917  black_key(1, 1), black_key(2, 1),
918  // second 3
919  black_key(4, 1), black_key(5, 1), black_key(6, 1)
920  )
921  );
922  }
923 
924 
925  void
927  (
928  std::vector<PianoKey>* keys,
929  int base_octave,
930  int octave_offset
931  )
932  {
934  (
935  keys,
936  base_octave,
937  0 + octave_offset,
939  0,
940  3
941  );
943  (
944  keys,
945  base_octave,
946  1 + octave_offset,
948  2,
949  0
950  );
951  }
952 }
ParserBase * base
Definition: argparse.cc:887
#define ASSERT(x)
Definition: assert.h:29
#define LOG_INFO(...)
Definition: log.h:7
#define LOG_ERROR(...)
Definition: log.h:9
constexpr unit3f up
Definition: vec3.h:131
constexpr unit3f down
Definition: vec3.h:132
Key
Definition: key.h:26
constexpr float classical_a4
Definition: synth.h:88
constexpr float baroque_a4
Definition: synth.h:86
constexpr float chorton_a4
Definition: synth.h:87
constexpr float boston_a4
Definition: synth.h:82
constexpr float europe_a4
Definition: synth.h:84
constexpr float french_a4
Definition: synth.h:85
constexpr float a4
Definition: synth.h:81
constexpr float new_york_a4
Definition: synth.h:83
float from_tone_to_frequency_impl(int tone, float base_frequency)
Definition: synth.cc:176
ChordEmulation
Definition: synth.h:27
const KeyboardLayout & create_qwerty_keyboard_layout()
Definition: synth.cc:860
std::string from_midi_event_to_string(MidiEvent e)
Definition: synth.cc:84
float from_tone_to_frequency(int tone, float base_frequency)
Definition: synth.cc:183
float to01(float lower_bound, float value, float upper_bound)
Definition: synth.cc:642
std::vector< std::vector< core::Key > > KeyboardLayout
Definition: synth.h:345
void setup_one_octave_layout(std::vector< PianoKey > *keys, int base_octave, int octave, const KeyboardLayout &k, int start_row, int start_col)
Definition: synth.cc:878
std::string to_string(OscilatorType osc)
Definition: synth.cc:117
float from_tuning_to_base_frequency(Tuning t)
Definition: synth.cc:66
OscilatorType
Definition: synth.h:67
void setup_qwerty_two_octave_layout(std::vector< PianoKey > *keys, int base_octave, int octave_offset)
Definition: synth.cc:927
float run_oscilator(float frequency, float time, OscilatorType osc)
Definition: synth.cc:622
std::vector< PianoKey > build_one_cctave_of_piano_keys(int octave, int semitone_offset, core::Key c, core::Key d, core::Key e, core::Key f, core::Key g, core::Key a, core::Key b, core::Key c_sharp, core::Key d_sharp, core::Key f_sharp, core::Key g_sharp, core::Key a_sharp)
Definition: synth.cc:823
int c_sizet_to_int(size_t t)
Definition: cint.cc:11
constexpr float pi
Definition: numeric.h:127
Angle asin(float v)
Definition: angle.cc:82
constexpr float abs(float r)
Definition: numeric.h:8
float square(float r)
Definition: numeric.cc:94
float sin(const Angle &ang)
Definition: angle.cc:61
constexpr float as_radians() const
Definition: angle.h:50
constexpr float from_percent_of_360() const
Definition: angle.h:56
void update(float dt, float current_time) override
Definition: synth.cc:518
std::map< int, float > down_tones
Definition: synth.h:250
std::vector< int > tones
Definition: synth.h:253
std::map< int, float > active_tones
Definition: synth.h:258
void on_tone(int tone, bool down, float time) override
Definition: synth.cc:567
float get_output(float time) override
Definition: synth.cc:790
WaveOut * in
Definition: synth.h:319
virtual float on_wave(float wave)=0
float get_live(float wave, float start_time, float current_time) const
Definition: synth.cc:649
float get_dead(float wave, float end_time, float current_time) const
Definition: synth.cc:666
std::vector< PianoKey > keys
Definition: synth.h:205
void on_chord(int base, bool was_pressed, float time, int first, int second) const
Definition: synth.cc:360
ChordEmulation chords_emulation
Definition: synth.h:208
void on_input(core::Key input, bool was_pressed, float time)
Definition: synth.cc:389
void on_midi_message(float dt, const std::vector< unsigned char > &bytes)
Definition: synth.cc:296
static void debug_callback(double dt, const std::vector< unsigned char > &bytes)
Definition: synth.cc:259
static bool is_status_message(unsigned char b)
Definition: synth.cc:251
ToneTaker * tones
Definition: synth.h:190
int get_dead_tones() const
Definition: synth.cc:696
int get_total_tones() const
Definition: synth.cc:684
int get_alive_tones() const
Definition: synth.cc:690
std::vector< DeadFrequency > dead
Definition: synth.h:302
void update(float dt, float current_time) override
Definition: synth.cc:702
float get_output(float time) override
Definition: synth.cc:734
std::map< int, LiveFrequency > live
Definition: synth.h:301
void on_frequency_down(int id, float freq, float time) override
Definition: synth.cc:720
OscilatorType oscilator
Definition: synth.h:303
minsynth::Envelope envelope
Definition: synth.h:304
void on_frequency_up(int id, float frequency, float time) override
Definition: synth.cc:726
float on_wave(float wave) override
Definition: synth.cc:809
std::map< int, float > down_tones
Definition: synth.h:237
int get_current_tone() const
Definition: synth.cc:489
void on_tone(int tone, bool down, float time) override
Definition: synth.cc:454
void send_tone(int tone, bool down, float time) const
Definition: synth.cc:194
virtual void on_tone(int tone, bool down, float time)=0
constexpr float get_frequency(int halfstep, float octave_base_frequency) const
Definition: synth.cc:144
float on_wave(float wave) override
Definition: synth.cc:802
virtual float get_output(float time)=0