1 //========================================================= 2 // MusE 3 // Linux Music Editor 4 // $Id: mididev.h,v 1.3.2.4 2009/04/04 01:49:50 terminator356 Exp $ 5 // 6 // (C) Copyright 2000 Werner Schweer (ws@seh.de) 7 // (C) Copyright 2011, 2016 Tim E. Real (terminator356 on users dot sourceforge dot net) 8 // 9 // This program is free software; you can redistribute it and/or 10 // modify it under the terms of the GNU General Public License 11 // as published by the Free Software Foundation; version 2 of 12 // the License, or (at your option) any later version. 13 // 14 // This program is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with this program; if not, write to the Free Software 21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 // 23 //========================================================= 24 25 #ifndef __MIDIDEV_H__ 26 #define __MIDIDEV_H__ 27 28 #include <list> 29 30 #include "mpevent.h" 31 #include "route.h" 32 #include "globaldefs.h" 33 #include <vector> 34 #include <atomic> 35 #include "lock_free_buffer.h" 36 #include "sync.h" 37 #include "evdata.h" 38 #include "latency_info.h" 39 40 #include <QString> 41 42 43 namespace MusECore { 44 45 46 // Forward declarations: 47 class Xml; 48 49 struct MidiOutputParams { 50 int BANKH; 51 int BANKL; 52 int PROG; 53 int RPNL; 54 int RPNH; 55 int NRPNL; 56 int NRPNH; 57 int DATAH; 58 int DATAL; 59 MidiOutputParamsMidiOutputParams60 MidiOutputParams() { reset(); } 61 resetMidiOutputParams62 void reset() { BANKH = BANKL = PROG = 0xff; RPNL = RPNH = NRPNL = NRPNH = DATAH = DATAL = -1; } resetParamNumsMidiOutputParams63 void resetParamNums() { RPNL = RPNH = NRPNL = NRPNH = DATAH = DATAL = -1; } resetPatchMidiOutputParams64 void resetPatch() { BANKH = BANKL = PROG = 0xff; } setRPNLMidiOutputParams65 void setRPNL(int a) { RPNL = a; NRPNL = NRPNH = -1; } setRPNHMidiOutputParams66 void setRPNH(int a) { RPNH = a; NRPNL = NRPNH = -1; } setNRPNLMidiOutputParams67 void setNRPNL(int a) { NRPNL = a; RPNL = RPNH = -1; } setNRPNHMidiOutputParams68 void setNRPNH(int a) { NRPNH = a; RPNL = RPNH = -1; } setDATAHMidiOutputParams69 void setDATAH(int a) { DATAH = a; } setDATALMidiOutputParams70 void setDATAL(int a) { DATAL = a; } setBANKHMidiOutputParams71 void setBANKH(int a) { BANKH = a;} setBANKLMidiOutputParams72 void setBANKL(int a) { BANKL = a;} setPROGMidiOutputParams73 void setPROG(int a) { PROG = a;} currentProgMidiOutputParams74 void currentProg(int *prg, int *lbank, int *hbank) 75 { if(prg) *prg=PROG&0xff; if(lbank) *lbank=BANKL&0xff; if(hbank) *hbank=BANKH&0xff; } setCurrentProgMidiOutputParams76 void setCurrentProg(int prg, int lbank, int hbank) 77 { PROG=prg&0xff; BANKL=lbank&0xff; BANKH=hbank&0xff; } 78 }; 79 80 //--------------------------------------------------------- 81 // MidiDevice 82 //--------------------------------------------------------- 83 84 class MidiDevice { 85 public: 86 // Types of MusE midi devices. 87 enum MidiDeviceType { ALSA_MIDI=0, JACK_MIDI=1, SYNTH_MIDI=2 }; 88 89 // IDs for the various IPC FIFOs that are used. 90 enum EventFifoIds 91 { 92 // Playback queued events put by the audio process thread. 93 PlayFifo=0, 94 // Gui events put by our gui thread. 95 GuiFifo=1, 96 // OSC events put by the OSC thread. 97 OSCFifo=2, 98 // Monitor input passthrough events put by Jack devices (audio process thread). 99 JackFifo=3, 100 // Monitor input passthrough events put by ALSA devices (midi seq thread). 101 ALSAFifo=4 102 }; 103 104 // The desired event buffer when putting an event. 105 enum EventBufferType 106 { 107 // Playback queue for events that are scheduled by the playback engine. 108 PlaybackBuffer=0, 109 // User queue for non-playback events such as from GUI controls or external hw. 110 UserBuffer=1 111 }; 112 113 // Describes latency of events passed to putEvent(). 114 enum LatencyType 115 { 116 // The given event's time will be used 'as is' without modification. 117 NotLate = 0, 118 // The given event's time has some latency. Automatically compensate 119 // by adding an appropriate number of frames, depending on device type. 120 // For example, events sent from a GUI control to the GuiFifo are usually 121 // time-stamped in the past. For Synths and Jack midi (buffer-based systems) 122 // we add a forward offset (one segment size). For ALSA (a poll-based system), 123 // no offset is required. Similarly, events sent from OSC handlers to the 124 // OSCFifo are also usually time-stamped in the past. 125 // Another example, events sent by the play scheduler to the PlayFifo are 126 // /already/ scheduled properly for the future and need /no/ further compensation 127 // for either Jack midi or ALSA devices. 128 Late = 1 129 }; 130 131 private: 132 // Used for multiple reads of fifos during process. 133 int _tmpRecordCount[MusECore::MUSE_MIDI_CHANNELS + 1]; 134 bool _sysexFIFOProcessed; 135 136 protected: 137 QString _name; 138 int _port; // connected to midi port; -1 - not connected 139 int _rwFlags; // possible open flags, 1 write, 2 read, 3 rw 140 int _openFlags; // configured open flags 141 bool _readEnable; // set when opened/closed. 142 bool _writeEnable; // 143 QString _state; 144 std::atomic<bool> _stopFlag; 145 146 // For processing system exclusive input chunks. 147 SysExInputProcessor _sysExInProcessor; 148 // For processing system exclusive output chunks. 149 SysExOutputProcessor _sysExOutProcessor; 150 // Holds all non-realtime events while the sysex processor is in the Sending state. 151 // The official midi specs say only realtime messages can be mingled in the middle of a sysex. 152 std::vector<MidiPlayEvent> *_sysExOutDelayedEvents; 153 154 MPEventList _stuckNotes; // Playback: Pending note-offs put directly to the device corresponding to currently playing notes 155 156 // Playback IPC buffers. For playback events ONLY. Any thread can use this. 157 LockFreeMPSCRingBuffer<MidiPlayEvent> *_playbackEventBuffers; 158 // Various IPC buffers. NOT for playback events. Any thread can use this. 159 LockFreeMPSCRingBuffer<MidiPlayEvent> *_userEventBuffers; 160 161 // Recording fifos. To speed up processing, one per channel plus one special system 'channel' for channel-less events like sysex. 162 MidiRecFifo _recordFifo[MusECore::MUSE_MIDI_CHANNELS + 1]; 163 164 // To hold current output program, and RPN/NRPN parameter numbers and values. 165 MidiOutputParams _curOutParamNums[MusECore::MUSE_MIDI_CHANNELS]; 166 167 RouteList _inRoutes, _outRoutes; 168 169 // Fifo holds brief history of incoming external clock messages. 170 // Timestamped with both tick and frame so that pending play events can 171 // be scheduled by frame. 172 // The audio thread processes this fifo and clears it. 173 LockFreeBuffer<ExtMidiClock> *_extClockHistoryFifo; 174 175 // Holds latency computations each cycle. 176 TrackLatencyInfo _captureLatencyInfo; 177 TrackLatencyInfo _playbackLatencyInfo; 178 179 // Returns the number of frames to shift forward output event scheduling times when putting events 180 // into the eventFifos. This is not quite the same as latency (requiring a backwards shift) 181 // although its requirement is a result of the latency. 182 // For any driver running in the audio thread (Jack midi, synth, metro etc) this value typically 183 // will equal one segment size. 184 // For drivers running in their own thread (ALSA, OSC input) this will typically be near zero: 185 // 1 ms for ALSA given a standard sequencer timer f = 1000Hz, or near zero for OSC input. pbForwardShiftFrames()186 inline virtual unsigned int pbForwardShiftFrames() const { return 0; } 187 188 // Various IPC buffers. Any thread can use this. eventBuffers(EventBufferType bufferType)189 inline LockFreeMPSCRingBuffer<MidiPlayEvent> *eventBuffers(EventBufferType bufferType) 190 { 191 switch(bufferType) 192 { 193 case PlaybackBuffer: 194 return _playbackEventBuffers; 195 196 case UserBuffer: 197 return _userEventBuffers; 198 } 199 return _userEventBuffers; 200 } 201 202 // Informs the device to clear (flush) the outEvents and event buffers. 203 // To be called by audio thread only. Typically from the device's handleStop routine. setStopFlag(bool flag)204 void setStopFlag(bool flag) { _stopFlag.store(flag); } 205 // Returns whether the device is flagged to clear the outEvents and event buffers. 206 // To be called from the device's thread in the process routine. stopFlag()207 bool stopFlag() const { return _stopFlag.load(); } 208 209 void init(); 210 211 public: 212 MidiDevice(); 213 MidiDevice(const QString& name); 214 virtual ~MidiDevice(); 215 sysExInProcessor()216 inline SysExInputProcessor* sysExInProcessor() { return &_sysExInProcessor; } sysExOutProcessor()217 inline SysExOutputProcessor* sysExOutProcessor() { return &_sysExOutProcessor; } 218 219 virtual MidiDeviceType deviceType() const = 0; 220 virtual QString deviceTypeString() const; 221 222 // The meaning of the returned pointer depends on the driver. 223 // For Jack it returns the address of a Jack port, for ALSA it return the address of a snd_seq_addr_t. inClientPort()224 inline virtual void* inClientPort() { return 0; } outClientPort()225 inline virtual void* outClientPort() { return 0; } 226 227 // These three are generally for ALSA. setAddressClient(int)228 inline virtual void setAddressClient(int) { } setAddressPort(int)229 inline virtual void setAddressPort(int) { } 230 // We (ab)use the ALSA value SND_SEQ_ADDRESS_UNKNOWN to 231 // mean 'unavailable' if either client and port equal it. isAddressUnknown()232 inline virtual bool isAddressUnknown() const { return true; } 233 234 virtual QString open() = 0; 235 virtual void close() = 0; writeRouting(int,Xml &)236 virtual void writeRouting(int, Xml&) const { }; 237 inRoutes()238 RouteList* inRoutes() { return &_inRoutes; } outRoutes()239 RouteList* outRoutes() { return &_outRoutes; } noInRoute()240 bool noInRoute() const { return _inRoutes.empty(); } noOutRoute()241 bool noOutRoute() const { return _outRoutes.empty(); } 242 name()243 inline const QString& name() const { return _name; } 244 // setName can be overloaded to do other things like setting port names, while setNameText just sets the text. setName(const QString & s)245 inline virtual void setName(const QString& s) { _name = s; } 246 // setNameText just sets the text, while setName can be overloaded to do other things like setting port names. setNameText(const QString & s)247 inline void setNameText(const QString& s) { _name = s; } 248 midiPort()249 inline int midiPort() const { return _port; } 250 void setPort(int p); 251 rwFlags()252 inline int rwFlags() const { return _rwFlags; } openFlags()253 inline int openFlags() const { return _openFlags; } setOpenFlags(int val)254 inline void setOpenFlags(int val) { _openFlags = val; } setrwFlags(int val)255 inline void setrwFlags(int val) { _rwFlags = val; } state()256 inline const QString& state() const { return _state; } setState(const QString & s)257 inline void setState(const QString& s) { _state = s; } 258 isSynti()259 inline virtual bool isSynti() const { return false; } selectRfd()260 inline virtual int selectRfd() { return -1; } selectWfd()261 inline virtual int selectWfd() { return -1; } bytesToWrite()262 inline virtual int bytesToWrite() { return 0; } flush()263 inline virtual void flush() {} processInput()264 inline virtual void processInput() {} discardInput()265 inline virtual void discardInput() {} 266 267 // Event time and tick must be set by caller beforehand. 268 virtual void recordEvent(MidiRecordEvent&); 269 270 // Add a stuck note. Returns false if event cannot be delivered. addStuckNote(const MidiPlayEvent & ev)271 virtual bool addStuckNote(const MidiPlayEvent& ev) { _stuckNotes.add(ev); return true; } 272 // Put either a playback or a user event. Returns true if event cannot be delivered. 273 virtual bool putEvent(const MidiPlayEvent& ev, 274 LatencyType latencyType, 275 EventBufferType bufferType = UserBuffer); curOutParamNums(int chan)276 MidiOutputParams* curOutParamNums(int chan) { return &_curOutParamNums[chan]; } 277 void resetCurOutParamNums(int chan = -1); // Reset channel's current parameter numbers to -1. All channels if chan = -1. 278 279 virtual void handleStop(); 280 virtual void handleSeek(); 281 282 virtual void processStuckNotes(); 283 collectMidiEvents()284 virtual void collectMidiEvents() {} 285 // Process midi events. The frame is used by devices such as ALSA 286 // that require grabbing a timestamp as early as possible and 287 // passing it along to all the devices. The other devices don't 288 // require the frame since they 'compose' a buffer based on the 289 // frame at cycle start. 290 virtual void processMidi(unsigned int /*curFrame*/ = 0) {} 291 292 void beforeProcess(); 293 void afterProcess(); tmpRecordCount(const unsigned int ch)294 int tmpRecordCount(const unsigned int ch) { return _tmpRecordCount[ch]; } recordEvents(const unsigned int ch)295 MidiRecFifo& recordEvents(const unsigned int ch) { return _recordFifo[ch]; } sysexFIFOProcessed()296 bool sysexFIFOProcessed() { return _sysexFIFOProcessed; } setSysexFIFOProcessed(bool v)297 void setSysexFIFOProcessed(bool v) { _sysexFIFOProcessed = v; } 298 299 static const int extClockHistoryCapacity; extClockHistory()300 LockFreeBuffer<ExtMidiClock> *extClockHistory() { return _extClockHistoryFifo; } 301 void midiClockInput(unsigned int frame); 302 303 304 // Initializes this track's latency information in preparation for a latency scan. 305 virtual void prepareLatencyScan(); 306 // Returns the latency of a given capture or playback port of the device. portLatency(void *,bool)307 inline virtual unsigned int portLatency(void* /*port*/, bool /*capture*/) const { return 0; } 308 // The contribution to latency by the device's own members (midi effect rack, Jack ports etc). 309 // A midi device can contain both an input and an output. The 'capture' parameter determines which one. selfLatencyMidi(int,bool)310 inline virtual float selfLatencyMidi(int /*channel*/, bool /*capture*/) const { return 0.0f; } 311 // The cached worst latency of all the contributions from the track's own members (audio effect rack, etc) 312 // plus any port latency if applicable. 313 virtual float getWorstSelfLatencyMidi(bool capture); 314 // Whether this track (and the branch it is in) can force other parallel branches to 315 // increase their latency compensation to match this one. 316 // If false, this branch will NOT disturb other parallel branches' compensation, 317 // intead only allowing compensation UP TO the worst case in other branches. 318 virtual bool canDominateOutputLatencyMidi(bool capture) const; 319 virtual bool canDominateInputLatencyMidi(bool capture) const; 320 // Whether this track (and the branch it is in) can force other parallel branches to 321 // increase their latency compensation to match this one - IF this track is an end-point 322 // and the branch allows domination. 323 // If false, this branch will NOT disturb other parallel branches' compensation, 324 // intead only allowing compensation UP TO the worst case in other branches. 325 virtual bool canDominateEndPointLatencyMidi(bool capture) const; 326 // Whether this track and its branch can correct for latency, not just compensate. canCorrectOutputLatencyMidi()327 inline virtual bool canCorrectOutputLatencyMidi() const { return false; } 328 // Whether the track can pass latency values through, the SAME as if record monitor is 329 // supported and on BUT does not require record monitor support. 330 // This is for example in the metronome MetronomeSynthI, since it is unique in that it 331 // can correct its own latency unlike other synths, but it does not 'pass through' 332 // the latency values to what drives it like other synths. 333 virtual bool canPassThruLatencyMidi(bool capture) const; 334 // Whether any of the connected output routes are effectively connected. 335 // That means track is not off, track is monitored where applicable, etc, 336 // ie. signal can actually flow. 337 // For Wave Tracks for example, asks whether the track is an end-point from the view of the input side. 338 virtual bool isLatencyInputTerminalMidi(bool capture); 339 // Whether any of the connected output routes are effectively connected. 340 // That means track is not off, track is monitored where applicable, etc, 341 // ie. signal can actually flow. 342 // For Wave Tracks for example, asks whether the track is an end-point from the view of the playback side. 343 virtual bool isLatencyOutputTerminalMidi(bool capture); 344 345 virtual TrackLatencyInfo& getDominanceInfoMidi(bool capture, bool input); 346 virtual TrackLatencyInfo& getDominanceLatencyInfoMidi(bool capture, bool input); 347 // The finalWorstLatency is the grand final worst-case latency, of any output track or open branch, 348 // determined in the complete getDominanceLatencyInfo() scan. 349 // The callerBranchLatency is the inherent branch latency of the calling track, or zero if calling from 350 // the very top outside of the branch heads (outside of output tracks or open branches). 351 // The callerBranchLatency is accumulated as setCorrectionLatencyInfo() is called on each track 352 // in a branch of the graph. 353 virtual TrackLatencyInfo& setCorrectionLatencyInfoMidi(bool capture, bool input, float finalWorstLatency, float callerBranchLatency = 0.0f); 354 virtual TrackLatencyInfo& getLatencyInfoMidi(bool capture, bool input); 355 // Used during latency compensation processing. When analyzing in 'reverse' this mechansim is 356 // needed only to equalize the timing of all the AudioOutput tracks. 357 // It is applied as a direct offset in the latency delay compensator in getData(). 358 virtual unsigned long latencyCompWriteOffsetMidi(bool capture) const; 359 virtual void setLatencyCompWriteOffsetMidi(float worstCase, bool capture); 360 }; 361 362 //--------------------------------------------------------- 363 // MidiDeviceList 364 //--------------------------------------------------------- 365 366 typedef std::list<MidiDevice*>::iterator iMidiDevice; 367 typedef std::list<MidiDevice*>::const_iterator ciMidiDevice; 368 369 class MidiDeviceList : public std::list<MidiDevice*> 370 { 371 public: 372 void add(MidiDevice* dev); 373 void remove(MidiDevice* dev); 374 MidiDevice* find(const QString& name, int typeHint = -1); 375 find(const MidiDevice * dev)376 iterator find(const MidiDevice* dev) 377 { 378 for(iterator i = begin(); i != end(); ++i) 379 if(*i == dev) 380 return i; 381 return end(); 382 } 383 find(const MidiDevice * dev)384 const_iterator find(const MidiDevice* dev) const 385 { 386 for(const_iterator i = begin(); i != end(); ++i) 387 if(*i == dev) 388 return i; 389 return end(); 390 } 391 contains(const MidiDevice * dev)392 bool contains(const MidiDevice* dev) const 393 { 394 for(const_iterator i = begin(); i != end(); ++i) 395 if(*i == dev) 396 return true; 397 return false; 398 } 399 }; 400 401 extern void initMidiDevices(); 402 extern bool filterEvent(const MEvent& event, int type, bool thru); 403 404 } // namespace MusECore 405 406 namespace MusEGlobal { 407 extern MusECore::MidiDeviceList midiDevices; 408 } 409 410 #endif 411 412