3 |
* LinuxSampler - modular, streaming capable sampler * |
* LinuxSampler - modular, streaming capable sampler * |
4 |
* * |
* * |
5 |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
6 |
* Copyright (C) 2005 - 2012 Christian Schoenebeck * |
* Copyright (C) 2005 - 2013 Christian Schoenebeck * |
7 |
* * |
* * |
8 |
* This program is free software; you can redistribute it and/or modify * |
* This program is free software; you can redistribute it and/or modify * |
9 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
77 |
MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber) |
MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber) |
78 |
: MidiChannelMapReader(MidiChannelMap), |
: MidiChannelMapReader(MidiChannelMap), |
79 |
SysexListenersReader(SysexListeners), |
SysexListenersReader(SysexListeners), |
80 |
virtualMidiDevicesReader(virtualMidiDevices) { |
virtualMidiDevicesReader(virtualMidiDevices), |
81 |
|
noteOnVelocityFilterReader(noteOnVelocityFilter) |
82 |
|
{ |
83 |
this->pDevice = pDevice; |
this->pDevice = pDevice; |
84 |
this->portNumber = portNumber; |
this->portNumber = portNumber; |
85 |
|
runningStatusBuf[0] = 0; |
86 |
Parameters["NAME"] = new ParameterName(this); |
Parameters["NAME"] = new ParameterName(this); |
87 |
} |
} |
88 |
|
|
100 |
|
|
101 |
void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel) { |
void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel) { |
102 |
if (Key > 127 || Velocity > 127 || MidiChannel > 16) return; |
if (Key > 127 || Velocity > 127 || MidiChannel > 16) return; |
103 |
|
|
104 |
|
// apply velocity filter (if any) |
105 |
|
const std::vector<uint8_t>& velocityFilter = noteOnVelocityFilterReader.Lock(); |
106 |
|
if (!velocityFilter.empty()) Velocity = velocityFilter[Velocity]; |
107 |
|
noteOnVelocityFilterReader.Unlock(); |
108 |
|
|
109 |
const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock(); |
const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock(); |
110 |
// dispatch event for engines listening to the same MIDI channel |
// dispatch event for engines listening to the same MIDI channel |
111 |
{ |
{ |
131 |
|
|
132 |
void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) { |
void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) { |
133 |
if (Key > 127 || Velocity > 127 || MidiChannel > 16) return; |
if (Key > 127 || Velocity > 127 || MidiChannel > 16) return; |
134 |
|
|
135 |
|
// apply velocity filter (if any) |
136 |
|
const std::vector<uint8_t>& velocityFilter = noteOnVelocityFilterReader.Lock(); |
137 |
|
if (!velocityFilter.empty()) Velocity = velocityFilter[Velocity]; |
138 |
|
noteOnVelocityFilterReader.Unlock(); |
139 |
|
|
140 |
const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock(); |
const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock(); |
141 |
// dispatch event for engines listening to the same MIDI channel |
// dispatch event for engines listening to the same MIDI channel |
142 |
{ |
{ |
378 |
} |
} |
379 |
MidiChannelMapReader.Unlock(); |
MidiChannelMapReader.Unlock(); |
380 |
} |
} |
381 |
|
|
382 |
|
/** |
383 |
|
* Handles the so called MIDI "running status" mode, which allows devices |
384 |
|
* to reduce bandwidth (data reduction). |
385 |
|
* |
386 |
|
* If the passed in MIDI data is regular MIDI data, this method will simply |
387 |
|
* return the original data pointer and just stores the status byte for |
388 |
|
* potential "running status" event eventually coming next. |
389 |
|
* |
390 |
|
* If the passed in MIDI data however seems to be in "running status" mode, |
391 |
|
* this method will return another buffer, which allows the MIDI parser |
392 |
|
* to handle the MIDI data as usually with "normal" MIDI data. |
393 |
|
*/ |
394 |
|
uint8_t* MidiInputPort::handleRunningStatus(uint8_t* pData) { |
395 |
|
if ((pData[0] & 0x80) || !runningStatusBuf[0]) { |
396 |
|
// store status byte for eventual "running status" in next event |
397 |
|
if (pData[0] & 0x80) { |
398 |
|
if (pData[0] < 0xf0) { |
399 |
|
// "running status" is only allowed for channel messages |
400 |
|
runningStatusBuf[0] = pData[0]; |
401 |
|
} else if (pData[0] < 0xf8) { |
402 |
|
// "system common" messages (0xf0..0xf7) shall reset any running |
403 |
|
// status, however "realtime" messages (0xf8..0xff) shall be |
404 |
|
// ignored here |
405 |
|
runningStatusBuf[0] = 0; |
406 |
|
} |
407 |
|
} |
408 |
|
// it's either a regular status byte, or some invalid "running status" |
409 |
|
return pData; |
410 |
|
} else { // "running status" mode ... |
411 |
|
const uint8_t type = runningStatusBuf[0] & 0xf0; |
412 |
|
const int size = (type == 0xc0 || type == 0xd0) ? 1 : 2; // only program change & channel pressure have 1 data bytes |
413 |
|
memcpy(&runningStatusBuf[1], pData, size); |
414 |
|
return runningStatusBuf; |
415 |
|
} |
416 |
|
} |
417 |
|
|
418 |
void MidiInputPort::DispatchRaw(uint8_t* pData) { |
void MidiInputPort::DispatchRaw(uint8_t* pData) { |
419 |
|
pData = handleRunningStatus(pData); |
420 |
|
|
421 |
uint8_t channel = pData[0] & 0x0f; |
uint8_t channel = pData[0] & 0x0f; |
422 |
switch (pData[0] & 0xf0) { |
switch (pData[0] & 0xf0) { |
423 |
case 0x80: |
case 0x80: |
451 |
} |
} |
452 |
|
|
453 |
void MidiInputPort::DispatchRaw(uint8_t* pData, int32_t FragmentPos) { |
void MidiInputPort::DispatchRaw(uint8_t* pData, int32_t FragmentPos) { |
454 |
|
pData = handleRunningStatus(pData); |
455 |
|
|
456 |
uint8_t channel = pData[0] & 0x0f; |
uint8_t channel = pData[0] & 0x0f; |
457 |
switch (pData[0] & 0xf0) { |
switch (pData[0] & 0xf0) { |
458 |
case 0x80: |
case 0x80: |
484 |
break; |
break; |
485 |
} |
} |
486 |
} |
} |
487 |
|
|
488 |
|
void MidiInputPort::SetNoteOnVelocityFilter(const std::vector<uint8_t>& filter) { |
489 |
|
if (filter.size() != 128 && filter.size() != 0) |
490 |
|
throw MidiInputException("Note on velocity filter must be either of size 128 or 0"); |
491 |
|
|
492 |
|
// check the value range of the filter |
493 |
|
if (!filter.empty()) |
494 |
|
for (int i = 0; i < 128; i++) |
495 |
|
if (filter[i] > 127) |
496 |
|
throw MidiInputException("Invalid note on velocity filter, values must be in range 0 .. 127"); |
497 |
|
|
498 |
|
// apply new filter ... |
499 |
|
noteOnVelocityFilterMutex.Lock(); |
500 |
|
// double buffer ... double work ... |
501 |
|
{ |
502 |
|
std::vector<uint8_t>& config = |
503 |
|
noteOnVelocityFilter.GetConfigForUpdate(); |
504 |
|
config = filter; |
505 |
|
} |
506 |
|
{ |
507 |
|
std::vector<uint8_t>& config = |
508 |
|
noteOnVelocityFilter.SwitchConfig(); |
509 |
|
config = filter; |
510 |
|
} |
511 |
|
noteOnVelocityFilterMutex.Unlock(); |
512 |
|
} |
513 |
|
|
514 |
void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) { |
void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) { |
515 |
if (MidiChannel < 0 || MidiChannel > 16) |
if (MidiChannel < 0 || MidiChannel > 16) |