zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

InMgr.cpp (5446B)


      1 /*
      2   ZynAddSubFX - a software synthesizer
      3 
      4   InMgr.cpp - MIDI Input Manager
      5   Copyright (C) 2016 Mark McCurry
      6 
      7   This program is free software; you can redistribute it and/or
      8   modify it under the terms of the GNU General Public License
      9   as published by the Free Software Foundation; either version 2
     10   of the License, or (at your option) any later version.
     11 */
     12 #include "InMgr.h"
     13 #include "MidiIn.h"
     14 #include "EngineMgr.h"
     15 #include "../Misc/Master.h"
     16 #include "../Misc/Part.h"
     17 #include "../Misc/MiddleWare.h"
     18 #include <rtosc/thread-link.h>
     19 #include <iostream>
     20 using namespace std;
     21 
     22 extern zyn::MiddleWare *middleware;
     23 
     24 namespace zyn {
     25 
     26 ostream &operator<<(ostream &out, const MidiEvent &ev)
     27 {
     28     switch(ev.type) {
     29         case M_NOTE:
     30             out << "MidiNote: note(" << ev.num << ")\n"
     31             << "          channel(" << ev.channel << ")\n"
     32             << "          velocity(" << ev.value << ")";
     33             break;
     34 
     35         case M_FLOAT_NOTE:
     36             out << "MidiNote: note(" << ev.num << ")\n"
     37             << "          channel(" << ev.channel << ")\n"
     38             << "          velocity(" << ev.value << ")\n"
     39             << "          log2_freq(" << ev.log2_freq << ")";
     40             break;
     41 
     42         case M_CONTROLLER:
     43             out << "MidiCtl: controller(" << ev.num << ")\n"
     44             << "         channel(" << ev.channel << ")\n"
     45             << "         value(" << ev.value << ")";
     46             break;
     47 
     48         case M_FLOAT_CTRL:
     49             out << "MidiNote: controller(" << ev.num << ")\n"
     50             << "          channel(" << ev.channel << ")\n"
     51             << "          note(" << ev.value << ")\n"
     52             << "          log2_value(" << ev.log2_freq << ")";
     53             break;
     54 
     55         case M_PGMCHANGE:
     56             out << "PgmChange: program(" << ev.num << ")\n"
     57             << "           channel(" << ev.channel << ")";
     58             break;
     59     }
     60 
     61     return out;
     62 }
     63 
     64 MidiEvent::MidiEvent()
     65     :channel(0), type(0), num(0), value(0), time(0)
     66 {}
     67 
     68 InMgr &InMgr::getInstance()
     69 {
     70     static InMgr instance;
     71     return instance;
     72 }
     73 
     74 InMgr::InMgr()
     75     :queue(256), master(NULL)
     76 {
     77     current = NULL;
     78     work.init(PTHREAD_PROCESS_PRIVATE, 0);
     79 }
     80 
     81 InMgr::~InMgr()
     82 {
     83     //lets stop the consumer thread
     84 }
     85 
     86 void InMgr::putEvent(MidiEvent ev)
     87 {
     88     if(queue.push(ev)) //check for error
     89         cerr << "ERROR: MIDI ringbuffer is FULL" << endl;
     90     else
     91         work.post();
     92 }
     93 
     94 bool InMgr::flush(unsigned frameStart, unsigned frameStop)
     95 {
     96     MidiEvent ev;
     97     bool endReached = true;
     98 
     99     while(!work.trywait()) {
    100         queue.peak(ev);
    101         if(ev.time < (int)frameStart || ev.time > (int)frameStop) {
    102             //Check if end was reached
    103             endReached = ev.time < (int)frameStart;
    104             //Back out of transaction
    105             work.post();
    106             //printf("%d vs [%d..%d]\n",ev.time, frameStart, frameStop);
    107             break;
    108         }
    109         queue.pop(ev);
    110         //cout << ev << endl;
    111 
    112         switch(ev.type) {
    113             case M_NOTE:
    114                 master->noteOn(ev.channel, ev.num, ev.value);
    115                 break;
    116 
    117             case M_FLOAT_NOTE:
    118                 master->noteOn(ev.channel, ev.num, ev.value, ev.log2_freq);
    119                 break;
    120 
    121             case M_CONTROLLER:
    122                 if(ev.num == C_bankselectmsb) {        // Change current bank
    123                     middleware->spawnMaster()->bToU->write("/forward", "");
    124                     middleware->spawnMaster()->bToU->write("/bank/msb", "i", ev.value);
    125                     middleware->spawnMaster()->bToU->write("/bank/bank_select", "i", ev.value);
    126 
    127                 } else if(ev.num == C_bankselectlsb)  {// Change current bank (LSB)
    128                     middleware->spawnMaster()->bToU->write("/forward", "");
    129                     middleware->spawnMaster()->bToU->write("/bank/lsb", "i", ev.value);
    130                 } else
    131                     master->setController(ev.channel, ev.num, ev.value);
    132                 break;
    133 
    134             case M_FLOAT_CTRL:
    135                 master->setController(ev.channel, ev.num, ev.value, ev.log2_freq);
    136                 break;
    137 
    138             case M_PGMCHANGE:
    139                 for(int i=0; i < NUM_MIDI_PARTS; ++i) {
    140                     //set the program of the parts assigned to the midi channel
    141                     if(master->part[i]->Prcvchn == ev.channel) {
    142                         middleware->pendingSetProgram(i, ev.num);
    143                     }
    144                 }
    145                 break;
    146 
    147             case M_PRESSURE:
    148                 master->polyphonicAftertouch(ev.channel, ev.num, ev.value);
    149                 break;
    150         }
    151     }
    152     return endReached;
    153 }
    154 
    155 bool InMgr::empty(void) const
    156 {
    157     int semvalue = work.getvalue();
    158     return semvalue <= 0;
    159 }
    160 
    161 bool InMgr::setSource(string name)
    162 {
    163     MidiIn *src = getIn(name);
    164 
    165     if(!src)
    166         return false;
    167 
    168     if(current)
    169         current->setMidiEn(false);
    170     current = src;
    171     current->setMidiEn(true);
    172 
    173     bool success = current->getMidiEn();
    174 
    175     //Keep system in a valid state (aka with a running driver)
    176     if(!success)
    177         (current = getIn("NULL"))->setMidiEn(true);
    178 
    179     return success;
    180 }
    181 
    182 string InMgr::getSource() const
    183 {
    184     if(current)
    185         return current->name;
    186     else
    187         return "ERROR";
    188 }
    189 
    190 MidiIn *InMgr::getIn(string name)
    191 {
    192     EngineMgr &eng = EngineMgr::getInstance(NULL);
    193     return dynamic_cast<MidiIn *>(eng.getEng(name));
    194 }
    195 
    196 void InMgr::setMaster(Master *master_)
    197 {
    198     master = master_;
    199 }
    200 
    201 }