--- linuxsampler/trunk/src/drivers/midi/VirtualMidiDevice.cpp 2008/02/03 00:13:27 1659 +++ linuxsampler/trunk/src/drivers/midi/VirtualMidiDevice.cpp 2014/02/19 19:02:43 2521 @@ -1,5 +1,5 @@ /* - Copyright (C) 2008 Christian Schoenebeck + Copyright (C) 2008 - 2014 Christian Schoenebeck */ #include "VirtualMidiDevice.h" @@ -8,7 +8,8 @@ #include "../../common/atomic.h" #include "../../common/RingBuffer.h" -#define MIDI_KEYS 128 +#define MIDI_KEYS 128 +#define MIDI_CONTROLLERS 128 // assuming VirtualMidiDevice implementation is only controlled // by mouse (and the user not being Billy the Kid) @@ -16,33 +17,49 @@ namespace LinuxSampler { - struct _private_data_t { + struct VirtualMidiDevice::private_data_t { atomic_t notesChanged; // whether some key changed at all atomic_t pNoteChanged[MIDI_KEYS]; // which key(s) changed atomic_t pNoteIsActive[MIDI_KEYS]; // status of each key (either active or inactive) + atomic_t pNoteOnVelocity[MIDI_KEYS]; + atomic_t pNoteOffVelocity[MIDI_KEYS]; + atomic_t ccsChanged; // whether some controller changed at all + atomic_t pCCChanged[MIDI_CONTROLLERS]; // which controller(s) changed + atomic_t pCCValue[MIDI_CONTROLLERS]; // current value of each controller RingBuffer events; - _private_data_t() : events(MAX_EVENTS, 0) {} + private_data_t() : events(MAX_EVENTS, 0) {} }; - VirtualMidiDevice::VirtualMidiDevice() { - _private_data_t* p = new _private_data_t; - pPrivateData = p; + VirtualMidiDevice::VirtualMidiDevice() : p(new private_data_t) { atomic_t zero = ATOMIC_INIT(0); + atomic_t defaultVelocity = ATOMIC_INIT(127); + atomic_t defaultCCValue = ATOMIC_INIT(0); p->notesChanged = zero; + p->ccsChanged = zero; for (int i = 0; i < MIDI_KEYS; i++) { p->pNoteChanged[i] = zero; p->pNoteIsActive[i] = zero; + p->pNoteOnVelocity[i] = defaultVelocity; + p->pNoteOffVelocity[i] = defaultVelocity; + p->pCCChanged[i] = zero; + p->pCCValue[i] = defaultCCValue; } } VirtualMidiDevice::~VirtualMidiDevice() { - if (pPrivateData) delete (_private_data_t*)pPrivateData; + delete p; + } + + void VirtualMidiDevice::SetMaxEvents(int n) { + p->events.resize(n); } bool VirtualMidiDevice::SendNoteOnToSampler(uint8_t Key, uint8_t Velocity) { if (Key >= MIDI_KEYS || Velocity > 127) return false; - _private_data_t* p = (_private_data_t*)pPrivateData; + if (Velocity == 0) { + return SendNoteOffToSampler(Key, Velocity); + } event_t ev = { EVENT_TYPE_NOTEON, Key, Velocity }; if (p->events.write_space() <= 0) return false; p->events.push(&ev); @@ -51,51 +68,108 @@ bool VirtualMidiDevice::SendNoteOffToSampler(uint8_t Key, uint8_t Velocity) { if (Key >= MIDI_KEYS || Velocity > 127) return false; - _private_data_t* p = (_private_data_t*)pPrivateData; event_t ev = { EVENT_TYPE_NOTEOFF, Key, Velocity }; if (p->events.write_space() <= 0) return false; p->events.push(&ev); return true; } + + bool VirtualMidiDevice::SendCCToSampler(uint8_t Controller, uint8_t Value) { + if (Controller >= MIDI_CONTROLLERS || Value > 127) return false; + event_t ev = { EVENT_TYPE_CC, Controller, Value }; + if (p->events.write_space() <= 0) return false; + p->events.push(&ev); + return true; + } + + bool VirtualMidiDevice::SendPitchBendToSampler(int Pitch) { + if (Pitch < -8192 || Pitch > 8191) return false; + Pitch += 8192; + // order: LSB, MSB like it would be in a regular pitch bend MIDI message + event_t ev = { EVENT_TYPE_PITCHBEND, Pitch & 0x7f, (Pitch >> 7) & 0x7f }; + if (p->events.write_space() <= 0) return false; + p->events.push(&ev); + return true; + } + + bool VirtualMidiDevice::SendProgramChangeToSampler(int Program) { + if (Program < 0 || Program > 127) return false; + event_t ev = { EVENT_TYPE_PROGRAM, Program, 0 }; + if (p->events.write_space() <= 0) return false; + p->events.push(&ev); + return true; + } bool VirtualMidiDevice::GetMidiEventFromDevice(event_t& Event) { - _private_data_t* p = (_private_data_t*)pPrivateData; return (p->events.pop(&Event) > 0); } bool VirtualMidiDevice::NotesChanged() { - _private_data_t* p = (_private_data_t*)pPrivateData; int c = atomic_read( &p->notesChanged ); atomic_sub(c, &p->notesChanged ); return c; } + + bool VirtualMidiDevice::ControllersChanged() { + int c = atomic_read( &p->ccsChanged ); + atomic_sub(c, &p->ccsChanged ); + return c; + } bool VirtualMidiDevice::NoteChanged(uint8_t Key) { - _private_data_t* p = (_private_data_t*)pPrivateData; int c = atomic_read( &(p->pNoteChanged)[Key] ); atomic_sub(c, &(p->pNoteChanged)[Key] ); return c; } + + bool VirtualMidiDevice::ControllerChanged(uint8_t Controller) { + int c = atomic_read( &(p->pCCChanged)[Controller] ); + atomic_sub(c, &(p->pCCChanged)[Controller] ); + return c; + } bool VirtualMidiDevice::NoteIsActive(uint8_t Key) { - _private_data_t* p = (_private_data_t*)pPrivateData; return atomic_read( &(p->pNoteIsActive)[Key] ); } - void VirtualMidiDevice::SendNoteOnToDevice(uint8_t Key, uint8_t /*Velocity*/) { + uint8_t VirtualMidiDevice::NoteOnVelocity(uint8_t Key) { + return atomic_read( &(p->pNoteOnVelocity)[Key] ); + } + + uint8_t VirtualMidiDevice::NoteOffVelocity(uint8_t Key) { + return atomic_read( &(p->pNoteOffVelocity)[Key] ); + } + + uint8_t VirtualMidiDevice::ControllerValue(uint8_t Controller) { + return atomic_read( &(p->pCCValue)[Controller] ); + } + + void VirtualMidiDevice::SendNoteOnToDevice(uint8_t Key, uint8_t Velocity) { if (Key >= MIDI_KEYS) return; - _private_data_t* p = (_private_data_t*)pPrivateData; + if (Velocity == 0) { + SendNoteOffToDevice(Key, Velocity); + return; + } + atomic_set( &(p->pNoteOnVelocity)[Key], Velocity ); atomic_inc( &(p->pNoteIsActive)[Key] ); atomic_inc( &(p->pNoteChanged)[Key] ); atomic_inc( &p->notesChanged ); } - void VirtualMidiDevice::SendNoteOffToDevice(uint8_t Key, uint8_t /*Velocity*/) { + void VirtualMidiDevice::SendNoteOffToDevice(uint8_t Key, uint8_t Velocity) { if (Key >= MIDI_KEYS) return; - _private_data_t* p = (_private_data_t*)pPrivateData; - atomic_dec( &(p->pNoteIsActive)[Key] ); + atomic_set( &(p->pNoteOffVelocity)[Key], Velocity ); + if (atomic_read( &(p->pNoteIsActive)[Key] )) // only decrement if not zero + atomic_dec( &(p->pNoteIsActive)[Key] ); atomic_inc( &(p->pNoteChanged)[Key] ); atomic_inc( &p->notesChanged ); } + + void VirtualMidiDevice::SendCCToDevice(uint8_t Controller, uint8_t Value) { + if (Controller >= MIDI_CONTROLLERS) return; + atomic_set( &(p->pCCValue)[Controller], Value ); + atomic_inc( &(p->pCCChanged)[Controller] ); + atomic_inc( &p->ccsChanged ); + } } // namespace LinuxSampler