• Main Page
  • Modules
  • Classes
  • Files
  • File List

libraries/lv2plugin/lv2synth.hpp

00001 /****************************************************************************
00002     
00003     lv2synth.hpp - support file for writing LV2 plugins in C++
00004     
00005     Copyright (C) 2007 Lars Luthman <lars.luthman@gmail.com>
00006     
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 3 of the License, or
00010     (at your option) any later version.
00011     
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016     
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307  USA
00020 
00021 ****************************************************************************/
00022 
00023 #ifndef LV2SYNTH_HPP
00024 #define LV2SYNTH_HPP
00025 
00026 #include <cmath>
00027 #include <cstring>
00028 #include <vector>
00029 
00030 #include <lv2plugin.hpp>
00031 #include <lv2_event_helpers.h>
00032 
00033 
00034 namespace LV2 {
00035   
00037   static const unsigned char INVALID_KEY = 255;
00038   
00039   
00042   static inline float key2hz(unsigned char key) {
00043     return 8.1758 * std::pow(1.0594, key);
00044   }
00045   
00046   
00050   class Voice {
00051   public:
00052     
00062     void on(unsigned char key, unsigned char velocity) { }
00063     
00068     void off(unsigned char velocity) { }
00069     
00073     unsigned char get_key() const { return LV2::INVALID_KEY; }
00074     
00080     void render(uint32_t from, uint32_t to) { }
00081     
00086     void set_port_buffers(std::vector<void*>& ports) { m_ports = &ports; }
00087 
00088   protected:
00089     
00092     template <typename T> inline T*& p(uint32_t port) {
00093       return reinterpret_cast<T*&>((*m_ports)[port]);
00094     }
00095     
00098     float*& p(uint32_t port) {
00099       return reinterpret_cast<float*&>((*m_ports)[port]);
00100     }
00101     
00104     std::vector<void*>* m_ports;
00105   };
00106   
00107   
00181   template <class V, class D,
00182             class Ext1 = End, class Ext2 = End, class Ext3 = End,
00183             class Ext4 = End, class Ext5 = End, class Ext6 = End,
00184             class Ext7 = End>
00185   class Synth : public Plugin<D, URIMap<true>,
00186                               Ext1, Ext2, Ext3, Ext4, Ext5, Ext6, Ext7> {
00187   public:
00188     
00191     typedef Plugin<D, URIMap<true>, 
00192                    Ext1, Ext2, Ext3, Ext4, Ext5, Ext6, Ext7>
00193     Parent;
00194     
00195 
00202     Synth(uint32_t ports, uint32_t midi_input) 
00203       : Parent(ports),
00204         m_midi_input(midi_input) {
00205       m_midi_type = 
00206         Parent::uri_to_id(LV2_EVENT_URI,
00207                           "http://lv2plug.in/ns/ext/midi#MidiEvent"); 
00208     }
00209     
00210     
00213     ~Synth() {
00214       for (unsigned i = 0; i < m_voices.size(); ++i)
00215         delete m_voices[i];
00216     }
00217     
00218     
00228     unsigned find_free_voice(unsigned char key, unsigned char velocity) {
00229       for (unsigned i = 0; i < m_voices.size(); ++i) {
00230         if (m_voices[i]->get_key() == INVALID_KEY)
00231           return i;
00232       }
00233       return 0;
00234     }
00235     
00236     
00247     void handle_midi(uint32_t size, unsigned char* data) {
00248       if (size != 3)
00249         return;
00250       if (data[0] == 0x90) {
00251         unsigned voice = 
00252           static_cast<D*>(this)->find_free_voice(data[1], data[2]);
00253         if (voice < m_voices.size())
00254           m_voices[voice]->on(data[1], data[2]);
00255       }
00256       else if (data[0] == 0x80) {
00257         for (unsigned i = 0; i < m_voices.size(); ++i) {
00258           if (m_voices[i]->get_key() == data[1]) {
00259             m_voices[i]->off(data[2]);
00260             break;
00261           }
00262         }
00263       }
00264     }
00265     
00266     
00278     void pre_process(uint32_t from, uint32_t to) {
00279 
00280     }
00281     
00282     
00293     void post_process(uint32_t from, uint32_t to) {
00294 
00295     }
00296     
00297     
00302     void run(uint32_t sample_count) {
00303       
00304       // Zero output buffers so voices can add to them
00305       for (unsigned i = 0; i < m_audio_ports.size(); ++i)
00306         std::memset(p(m_audio_ports[i]), 0, 
00307                     sizeof(float) * sample_count);
00308       
00309       // Make the port buffers available to the voices
00310       for (unsigned i = 0; i < m_voices.size(); ++i)
00311         m_voices[i]->set_port_buffers(Parent::m_ports);
00312       
00313       LV2_Event_Iterator iter;
00314       lv2_event_begin(&iter, p<LV2_Event_Buffer>(m_midi_input));
00315       
00316       uint8_t* event_data;
00317       uint32_t samples_done = 0;
00318       
00319       while (samples_done < sample_count) {
00320         uint32_t to = sample_count;
00321         LV2_Event* ev = 0;
00322         if (lv2_event_is_valid(&iter)) {
00323           ev = lv2_event_get(&iter, &event_data);
00324           to = ev->frames;
00325           lv2_event_increment(&iter);
00326         }
00327         if (to > samples_done) {
00328           static_cast<D*>(this)->pre_process(samples_done, to);
00329           for (unsigned i = 0; i < m_voices.size(); ++i)
00330             m_voices[i]->render(samples_done, to);
00331           static_cast<D*>(this)->post_process(samples_done, to);
00332           samples_done = to;
00333         }
00334         
00335         /* This is what we do with events:
00336            - if it's a MIDI event, pass it to handle_midi()
00337            - if it's something else, just ignore it (it's safe)
00338         */
00339         if (ev) {
00340           if (ev->type == m_midi_type)
00341             static_cast<D*>(this)->handle_midi(ev->size, event_data);
00342         }
00343       }
00344       
00345     }
00346     
00347     
00359     void add_audio_outputs(uint32_t p1 = -1, uint32_t p2 = -1, 
00360                            uint32_t p3 = -1, uint32_t p4 = -1, 
00361                            uint32_t p5 = -1, uint32_t p6 = -1) {
00362       if (p1 == uint32_t(-1))
00363         return;
00364       m_audio_ports.push_back(p1);
00365       if (p2 == uint32_t(-1))
00366         return;
00367       m_audio_ports.push_back(p2);
00368       if (p3 == uint32_t(-1))
00369         return;
00370       m_audio_ports.push_back(p3);
00371       if (p4 == uint32_t(-1))
00372         return;
00373       m_audio_ports.push_back(p4);
00374       if (p5 == uint32_t(-1))
00375         return;
00376       m_audio_ports.push_back(p5);
00377       if (p6 == uint32_t(-1))
00378         return;
00379       m_audio_ports.push_back(p6);
00380     }
00381     
00382     
00392     void add_voices(V* v01 = 0, V* v02 = 0, V* v03 = 0, V* v04 = 0, V* v05 = 0,
00393                     V* v06 = 0, V* v07 = 0, V* v08 = 0, V* v09 = 0, V* v10 = 0,
00394                     V* v11 = 0, V* v12 = 0, V* v13 = 0, V* v14 = 0, V* v15 = 0,
00395                     V* v16 = 0, V* v17 = 0, V* v18 = 0, V* v19 = 0, V* v20 = 0){
00396       if (v01 == 0)
00397         return;
00398       m_voices.push_back(v01);
00399       if (v02 == 0)
00400         return;
00401       m_voices.push_back(v02);
00402       if (v03 == 0)
00403         return;
00404       m_voices.push_back(v03);
00405       if (v04 == 0)
00406         return;
00407       m_voices.push_back(v04);
00408       if (v05 == 0)
00409         return;
00410       m_voices.push_back(v05);
00411       if (v06 == 0)
00412         return;
00413       m_voices.push_back(v06);
00414       if (v07 == 0)
00415         return;
00416       m_voices.push_back(v07);
00417       if (v08 == 0)
00418         return;
00419       m_voices.push_back(v08);
00420       if (v09 == 0)
00421         return;
00422       m_voices.push_back(v09);
00423       if (v10 == 0)
00424         return;
00425       m_voices.push_back(v10);
00426       if (v11 == 0)
00427         return;
00428       m_voices.push_back(v11);
00429       if (v12 == 0)
00430         return;
00431       m_voices.push_back(v12);
00432       if (v13 == 0)
00433         return;
00434       m_voices.push_back(v13);
00435       if (v14 == 0)
00436         return;
00437       m_voices.push_back(v14);
00438       if (v15 == 0)
00439         return;
00440       m_voices.push_back(v15);
00441       if (v16 == 0)
00442         return;
00443       m_voices.push_back(v16);
00444       if (v17 == 0)
00445         return;
00446       m_voices.push_back(v17);
00447       if (v18 == 0)
00448         return;
00449       m_voices.push_back(v18);
00450       if (v19 == 0)
00451         return;
00452       m_voices.push_back(v19);
00453       if (v20 == 0)
00454         return;
00455       m_voices.push_back(v20);
00456     }    
00457   protected:
00458     
00462     template <typename T> T*& p(uint32_t port) {
00463       return reinterpret_cast<T*&>(Parent::m_ports[port]);
00464     }
00465   
00468     float*& p(uint32_t port) {
00469       return reinterpret_cast<float*&>(Parent::m_ports[port]);
00470     }
00471 
00472 
00475     std::vector<V*> m_voices;
00476     
00479     std::vector<uint32_t> m_audio_ports;
00480     
00483     uint32_t m_midi_input;
00484     
00487     uint32_t m_midi_type;
00488     
00489   };
00490   
00491 }
00492 
00493 
00494 #endif

Generated on Sun Feb 27 2011 13:41:49 by  doxygen 1.7.1