lv2-c++-tools  1.0.6
lv2synth.hpp
1 /****************************************************************************
2 
3  lv2synth.hpp - support file for writing LV2 plugins in C++
4 
5  Copyright (C) 2007 Lars Luthman <mail@larsluthman.net>
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA
20 
21 ****************************************************************************/
22 
23 #ifndef LV2SYNTH_HPP
24 #define LV2SYNTH_HPP
25 
26 #include <cmath>
27 #include <cstring>
28 #include <vector>
29 
30 #include <lv2plugin.hpp>
31 #include <lv2_event_helpers.h>
32 
33 
34 namespace LV2 {
35 
37  static const unsigned char INVALID_KEY = 255;
38 
39 
42  static inline float key2hz(unsigned char key) {
43  return 8.1758 * std::pow(1.0594, key);
44  }
45 
46 
50  class Voice {
51  public:
52 
62  void on(unsigned char key, unsigned char velocity) { }
63 
68  void off(unsigned char velocity) { }
69 
73  unsigned char get_key() const { return LV2::INVALID_KEY; }
74 
80  void render(uint32_t from, uint32_t to) { }
81 
86  void set_port_buffers(std::vector<void*>& ports) { m_ports = &ports; }
87 
88  protected:
89 
92  template <typename T> inline T*& p(uint32_t port) {
93  return reinterpret_cast<T*&>((*m_ports)[port]);
94  }
95 
98  float*& p(uint32_t port) {
99  return reinterpret_cast<float*&>((*m_ports)[port]);
100  }
101 
104  std::vector<void*>* m_ports;
105  };
106 
107 
181  template <class V, class D,
182  class Ext1 = End, class Ext2 = End, class Ext3 = End,
183  class Ext4 = End, class Ext5 = End, class Ext6 = End,
184  class Ext7 = End>
185  class Synth : public Plugin<D, URIMap<true>,
186  Ext1, Ext2, Ext3, Ext4, Ext5, Ext6, Ext7> {
187  public:
188 
191  typedef Plugin<D, URIMap<true>,
192  Ext1, Ext2, Ext3, Ext4, Ext5, Ext6, Ext7>
193  Parent;
194 
195 
202  Synth(uint32_t ports, uint32_t midi_input)
203  : Parent(ports),
204  m_midi_input(midi_input) {
205  m_midi_type =
206  Parent::uri_to_id(LV2_EVENT_URI,
207  "http://lv2plug.in/ns/ext/midi#MidiEvent");
208  }
209 
210 
213  ~Synth() {
214  for (unsigned i = 0; i < m_voices.size(); ++i)
215  delete m_voices[i];
216  }
217 
218 
228  unsigned find_free_voice(unsigned char key, unsigned char velocity) {
229  for (unsigned i = 0; i < m_voices.size(); ++i) {
230  if (m_voices[i]->get_key() == INVALID_KEY)
231  return i;
232  }
233  return 0;
234  }
235 
236 
247  void handle_midi(uint32_t size, unsigned char* data) {
248  if (size != 3)
249  return;
250  if (data[0] == 0x90) {
251  unsigned voice =
252  static_cast<D*>(this)->find_free_voice(data[1], data[2]);
253  if (voice < m_voices.size())
254  m_voices[voice]->on(data[1], data[2]);
255  }
256  else if (data[0] == 0x80) {
257  for (unsigned i = 0; i < m_voices.size(); ++i) {
258  if (m_voices[i]->get_key() == data[1]) {
259  m_voices[i]->off(data[2]);
260  break;
261  }
262  }
263  }
264  }
265 
266 
278  void pre_process(uint32_t from, uint32_t to) {
279 
280  }
281 
282 
293  void post_process(uint32_t from, uint32_t to) {
294 
295  }
296 
297 
302  void run(uint32_t sample_count) {
303 
304  // Zero output buffers so voices can add to them
305  for (unsigned i = 0; i < m_audio_ports.size(); ++i)
306  std::memset(p(m_audio_ports[i]), 0,
307  sizeof(float) * sample_count);
308 
309  // Make the port buffers available to the voices
310  for (unsigned i = 0; i < m_voices.size(); ++i)
311  m_voices[i]->set_port_buffers(Parent::m_ports);
312 
313  LV2_Event_Iterator iter;
314  lv2_event_begin(&iter, p<LV2_Event_Buffer>(m_midi_input));
315 
316  uint8_t* event_data;
317  uint32_t samples_done = 0;
318 
319  while (samples_done < sample_count) {
320  uint32_t to = sample_count;
321  LV2_Event* ev = 0;
322  if (lv2_event_is_valid(&iter)) {
323  ev = lv2_event_get(&iter, &event_data);
324  to = ev->frames;
325  lv2_event_increment(&iter);
326  }
327  if (to > samples_done) {
328  static_cast<D*>(this)->pre_process(samples_done, to);
329  for (unsigned i = 0; i < m_voices.size(); ++i)
330  m_voices[i]->render(samples_done, to);
331  static_cast<D*>(this)->post_process(samples_done, to);
332  samples_done = to;
333  }
334 
335  /* This is what we do with events:
336  - if it's a MIDI event, pass it to handle_midi()
337  - if it's something else, just ignore it (it's safe)
338  */
339  if (ev) {
340  if (ev->type == m_midi_type)
341  static_cast<D*>(this)->handle_midi(ev->size, event_data);
342  }
343  }
344 
345  }
346 
347 
359  void add_audio_outputs(uint32_t p1 = -1, uint32_t p2 = -1,
360  uint32_t p3 = -1, uint32_t p4 = -1,
361  uint32_t p5 = -1, uint32_t p6 = -1) {
362  if (p1 == uint32_t(-1))
363  return;
364  m_audio_ports.push_back(p1);
365  if (p2 == uint32_t(-1))
366  return;
367  m_audio_ports.push_back(p2);
368  if (p3 == uint32_t(-1))
369  return;
370  m_audio_ports.push_back(p3);
371  if (p4 == uint32_t(-1))
372  return;
373  m_audio_ports.push_back(p4);
374  if (p5 == uint32_t(-1))
375  return;
376  m_audio_ports.push_back(p5);
377  if (p6 == uint32_t(-1))
378  return;
379  m_audio_ports.push_back(p6);
380  }
381 
382 
392  void add_voices(V* v01 = 0, V* v02 = 0, V* v03 = 0, V* v04 = 0, V* v05 = 0,
393  V* v06 = 0, V* v07 = 0, V* v08 = 0, V* v09 = 0, V* v10 = 0,
394  V* v11 = 0, V* v12 = 0, V* v13 = 0, V* v14 = 0, V* v15 = 0,
395  V* v16 = 0, V* v17 = 0, V* v18 = 0, V* v19 = 0, V* v20 = 0){
396  if (v01 == 0)
397  return;
398  m_voices.push_back(v01);
399  if (v02 == 0)
400  return;
401  m_voices.push_back(v02);
402  if (v03 == 0)
403  return;
404  m_voices.push_back(v03);
405  if (v04 == 0)
406  return;
407  m_voices.push_back(v04);
408  if (v05 == 0)
409  return;
410  m_voices.push_back(v05);
411  if (v06 == 0)
412  return;
413  m_voices.push_back(v06);
414  if (v07 == 0)
415  return;
416  m_voices.push_back(v07);
417  if (v08 == 0)
418  return;
419  m_voices.push_back(v08);
420  if (v09 == 0)
421  return;
422  m_voices.push_back(v09);
423  if (v10 == 0)
424  return;
425  m_voices.push_back(v10);
426  if (v11 == 0)
427  return;
428  m_voices.push_back(v11);
429  if (v12 == 0)
430  return;
431  m_voices.push_back(v12);
432  if (v13 == 0)
433  return;
434  m_voices.push_back(v13);
435  if (v14 == 0)
436  return;
437  m_voices.push_back(v14);
438  if (v15 == 0)
439  return;
440  m_voices.push_back(v15);
441  if (v16 == 0)
442  return;
443  m_voices.push_back(v16);
444  if (v17 == 0)
445  return;
446  m_voices.push_back(v17);
447  if (v18 == 0)
448  return;
449  m_voices.push_back(v18);
450  if (v19 == 0)
451  return;
452  m_voices.push_back(v19);
453  if (v20 == 0)
454  return;
455  m_voices.push_back(v20);
456  }
457  protected:
458 
462  template <typename T> T*& p(uint32_t port) {
463  return reinterpret_cast<T*&>(Parent::m_ports[port]);
464  }
465 
468  float*& p(uint32_t port) {
469  return reinterpret_cast<float*&>(Parent::m_ports[port]);
470  }
471 
472 
475  std::vector<V*> m_voices;
476 
479  std::vector<uint32_t> m_audio_ports;
480 
483  uint32_t m_midi_input;
484 
487  uint32_t m_midi_type;
488 
489  };
490 
491 }
492 
493 
494 #endif
Definition: lv2plugin.hpp:137
Definition: lv2synth.hpp:186
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: lv2synth.hpp:359
float *& p(uint32_t port)
Definition: lv2synth.hpp:468
Synth(uint32_t ports, uint32_t midi_input)
Definition: lv2synth.hpp:202
~Synth()
Definition: lv2synth.hpp:213
void handle_midi(uint32_t size, unsigned char *data)
Definition: lv2synth.hpp:247
void run(uint32_t sample_count)
Definition: lv2synth.hpp:302
T *& p(uint32_t port)
Definition: lv2synth.hpp:462
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: lv2synth.hpp:392
unsigned find_free_voice(unsigned char key, unsigned char velocity)
Definition: lv2synth.hpp:228
void post_process(uint32_t from, uint32_t to)
Definition: lv2synth.hpp:293
void pre_process(uint32_t from, uint32_t to)
Definition: lv2synth.hpp:278
Definition: lv2synth.hpp:50
void render(uint32_t from, uint32_t to)
Definition: lv2synth.hpp:80
float *& p(uint32_t port)
Definition: lv2synth.hpp:98
T *& p(uint32_t port)
Definition: lv2synth.hpp:92
unsigned char get_key() const
Definition: lv2synth.hpp:73
void on(unsigned char key, unsigned char velocity)
Definition: lv2synth.hpp:62
void off(unsigned char velocity)
Definition: lv2synth.hpp:68