LV2 Toolkit  1.2.0
synth.hpp
1 /*
2  synth.hpp - Support file for writing LV2 tone generating plugins in C++
3  Copyright (C) 2007 Lars Luthman <lars.luthman@gmail.com>
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA
18  */
21 #ifndef LVTK_SYNTH_HPP
22 #define LVTK_SYNTH_HPP
23 
24 #include <cmath>
25 #include <cstring>
26 #include <vector>
27 
28 #include <lvtk/plugin.hpp>
29 
30 namespace lvtk {
31 
32  using std::vector;
33 
35  static const unsigned char INVALID_KEY = 255;
36 
37 
40  static inline float key2hz(unsigned char key) {
41  return 440.0f * std::pow(2.0f, (key - 69) / 12.0f);
42  }
43 
44 
49  class Voice {
50  public:
51 
61  void on(unsigned char key, unsigned char velocity) { }
62 
67  void off(unsigned char velocity) { }
68 
73  unsigned char get_key() const { return lvtk::INVALID_KEY; }
74 
80  void render(uint32_t from, uint32_t to) { }
81 
86  void set_port_buffers(vector<void*>& ports) { m_ports = &ports; }
87 
88  protected:
89 
91  template <typename T> inline T*& p(uint32_t port) {
92  return reinterpret_cast<T*&>((*m_ports)[port]);
93  }
94 
96  float*& p(uint32_t port) {
97  return reinterpret_cast<float*&>((*m_ports)[port]);
98  }
99 
101  vector<void*>* m_ports;
102  };
103 
104 
178  template <class V, class D,
179  class Ext1 = end, class Ext2 = end, class Ext3 = end,
180  class Ext4 = end, class Ext5 = end, class Ext6 = end,
181  class Ext7 = end>
182  class Synth : public Plugin<D, URID<true>, Ext1, Ext2, Ext3, Ext4, Ext5, Ext6, Ext7>
183  {
184  public:
185 
187  typedef Plugin<D, URID<true>, Ext1, Ext2, Ext3, Ext4, Ext5, Ext6, Ext7>
188  Parent;
189 
196  Synth(uint32_t ports, uint32_t midi_input)
197  : Parent(ports),
198  m_midi_input (midi_input)
199  {
200  m_midi_type = Parent::map (LV2_MIDI__MidiEvent);
201  }
202 
203 
206  {
207  for (unsigned i = 0; i < m_voices.size(); ++i)
208  delete m_voices[i];
209  }
210 
221  unsigned
222  find_free_voice(unsigned char key, unsigned char velocity)
223  {
224  for (unsigned i = 0; i < m_voices.size(); ++i)
225  {
226  if (m_voices[i]->get_key() == lvtk::INVALID_KEY)
227  return i;
228  }
229 
230  return 0;
231  }
232 
233 
245  void
246  handle_midi (uint32_t size, unsigned char* data)
247  {
248  if (size != 3) return;
249  LV2_Midi_Message_Type type (lv2_midi_message_type (data));
250 
251  if (data[0] == 0x90)
252  {
253  unsigned voice =
254  static_cast<D*>(this)->find_free_voice(data[1], data[2]);
255  if (voice < m_voices.size())
256  m_voices[voice]->on(data[1], data[2]);
257  }
258  else if (data[0] == 0x80)
259  {
260  for (unsigned i = 0; i < m_voices.size(); ++i)
261  {
262  if (m_voices[i]->get_key() == data[1])
263  {
264  m_voices[i]->off(data[2]);
265  break;
266  }
267  }
268  }
269  }
270 
271  void
272  handle_atom_event (LV2_Atom_Event* ev) { }
273 
285  void
286  pre_process(uint32_t from, uint32_t to)
287  { }
288 
289 
300  void
301  post_process(uint32_t from, uint32_t to)
302  { }
303 
304 
309  void
310  run(uint32_t sample_count)
311  {
312  D* synth = static_cast<D*>(this);
313 
314  // Zero output buffers so voices can add to them
315  for (unsigned i = 0; i < m_audio_ports.size(); ++i)
316  std::memset(p(m_audio_ports[i]), 0, sizeof(float) * sample_count);
317 
318  // Make the port buffers available to the voices
319  for (unsigned i = 0; i < m_voices.size(); ++i)
320  m_voices[i]->set_port_buffers(Parent::m_ports);
321 
322  const LV2_Atom_Sequence* seq = p<LV2_Atom_Sequence> (m_midi_input);
323  uint32_t last_frame = 0;
324 
325  for (LV2_Atom_Event* ev = lv2_atom_sequence_begin (&seq->body);
326  !lv2_atom_sequence_is_end(&seq->body, seq->atom.size, ev);
327  ev = lv2_atom_sequence_next (ev))
328  {
329  synth->pre_process (last_frame, ev->time.frames);
330  for (uint32_t i = 0; i < m_voices.size(); ++i)
331  m_voices[i]->render (last_frame, ev->time.frames);
332  synth->post_process (last_frame, ev->time.frames);
333 
334  if (ev->body.type == m_midi_type)
335  synth->handle_midi (ev->body.size, (uint8_t*) LV2_ATOM_BODY (&ev->body));
336  else
337  synth->handle_atom_event (ev);
338 
339  last_frame = ev->time.frames;
340  }
341 
342  if (last_frame < sample_count)
343  {
344  synth->pre_process (last_frame, sample_count);
345  for (uint32_t i = 0; i < m_voices.size(); ++i)
346  m_voices[i]->render (last_frame, sample_count);
347  synth->post_process (last_frame, sample_count);
348  }
349  }
350 
351 
363  void
364  add_audio_outputs(uint32_t p1 = -1, uint32_t p2 = -1,
365  uint32_t p3 = -1, uint32_t p4 = -1,
366  uint32_t p5 = -1, uint32_t p6 = -1)
367  {
368  if (p1 == uint32_t(-1))
369  return;
370  m_audio_ports.push_back(p1);
371  if (p2 == uint32_t(-1))
372  return;
373  m_audio_ports.push_back(p2);
374  if (p3 == uint32_t(-1))
375  return;
376  m_audio_ports.push_back(p3);
377  if (p4 == uint32_t(-1))
378  return;
379  m_audio_ports.push_back(p4);
380  if (p5 == uint32_t(-1))
381  return;
382  m_audio_ports.push_back(p5);
383  if (p6 == uint32_t(-1))
384  return;
385  m_audio_ports.push_back(p6);
386  }
387 
388 
399  void add_voices(V* v01 = 0, V* v02 = 0, V* v03 = 0, V* v04 = 0, V* v05 = 0,
400  V* v06 = 0, V* v07 = 0, V* v08 = 0, V* v09 = 0, V* v10 = 0,
401  V* v11 = 0, V* v12 = 0, V* v13 = 0, V* v14 = 0, V* v15 = 0,
402  V* v16 = 0, V* v17 = 0, V* v18 = 0, V* v19 = 0, V* v20 = 0)
403  {
404  if (v01 == 0)
405  return;
406  m_voices.push_back(v01);
407  if (v02 == 0)
408  return;
409  m_voices.push_back(v02);
410  if (v03 == 0)
411  return;
412  m_voices.push_back(v03);
413  if (v04 == 0)
414  return;
415  m_voices.push_back(v04);
416  if (v05 == 0)
417  return;
418  m_voices.push_back(v05);
419  if (v06 == 0)
420  return;
421  m_voices.push_back(v06);
422  if (v07 == 0)
423  return;
424  m_voices.push_back(v07);
425  if (v08 == 0)
426  return;
427  m_voices.push_back(v08);
428  if (v09 == 0)
429  return;
430  m_voices.push_back(v09);
431  if (v10 == 0)
432  return;
433  m_voices.push_back(v10);
434  if (v11 == 0)
435  return;
436  m_voices.push_back(v11);
437  if (v12 == 0)
438  return;
439  m_voices.push_back(v12);
440  if (v13 == 0)
441  return;
442  m_voices.push_back(v13);
443  if (v14 == 0)
444  return;
445  m_voices.push_back(v14);
446  if (v15 == 0)
447  return;
448  m_voices.push_back(v15);
449  if (v16 == 0)
450  return;
451  m_voices.push_back(v16);
452  if (v17 == 0)
453  return;
454  m_voices.push_back(v17);
455  if (v18 == 0)
456  return;
457  m_voices.push_back(v18);
458  if (v19 == 0)
459  return;
460  m_voices.push_back(v19);
461  if (v20 == 0)
462  return;
463  m_voices.push_back(v20);
464  }
465  protected:
466 
470  template <typename T> T*&
471  p(uint32_t port) {
472  return reinterpret_cast<T*&>(Parent::m_ports[port]);
473  }
474 
476  float*&
477  p(uint32_t port) {
478  return reinterpret_cast<float*&>(Parent::m_ports[port]);
479  }
480 
482  vector<V*> m_voices;
483 
485  vector<uint32_t> m_audio_ports;
486 
488  uint32_t m_midi_input;
489 
491  LV2_URID m_midi_type;
492 
493  };
494 }
495 
496 #endif /* LVTK_SYNTH_HPP */
unsigned char get_key() const
Definition: synth.hpp:73
void pre_process(uint32_t from, uint32_t to)
Definition: synth.hpp:286
void post_process(uint32_t from, uint32_t to)
Definition: synth.hpp:301
float *& p(uint32_t port)
Definition: synth.hpp:96
Definition: synth.hpp:49
void render(uint32_t from, uint32_t to)
Definition: synth.hpp:80
void on(unsigned char key, unsigned char velocity)
Definition: synth.hpp:61
void off(unsigned char velocity)
Definition: synth.hpp:67
void handle_midi(uint32_t size, unsigned char *data)
Definition: synth.hpp:246
void add_voices(V *v01=0, V *v02=0, V *v03=0, V *v04=0, V *v05=0, V *v06=0, V *v07=0, V *v08=0, V *v09=0, V *v10=0, V *v11=0, V *v12=0, V *v13=0, V *v14=0, V *v15=0, V *v16=0, V *v17=0, V *v18=0, V *v19=0, V *v20=0)
Definition: synth.hpp:399
Definition: feature.hpp:34
T *& p(uint32_t port)
Definition: synth.hpp:91
Definition: plugin.hpp:159
float *& p(uint32_t port)
Definition: synth.hpp:477
void add_audio_outputs(uint32_t p1=-1, uint32_t p2=-1, uint32_t p3=-1, uint32_t p4=-1, uint32_t p5=-1, uint32_t p6=-1)
Definition: synth.hpp:364
unsigned find_free_voice(unsigned char key, unsigned char velocity)
Definition: synth.hpp:222
void run(uint32_t sample_count)
Definition: synth.hpp:310
T *& p(uint32_t port)
Definition: synth.hpp:471
~Synth()
Definition: synth.hpp:205
Synth(uint32_t ports, uint32_t midi_input)
Definition: synth.hpp:196
Definition: synth.hpp:182