My Project 1.0.5
lv2synth.hpp
1/****************************************************************************
2
3 lv2synth.hpp - support file for writing LV2 plugins in C++
4
5 Copyright (C) 2007 Lars Luthman <lars.luthman@gmail.com>
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
34namespace 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
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
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
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
T *& p(uint32_t port)
Definition: lv2synth.hpp:462
float *& p(uint32_t port)
Definition: lv2synth.hpp:468
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