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 }