1 /* 2 Copyright (C) 2008 - 2016 Christian Schoenebeck 3 */ 4 5 #include "VirtualMidiDevice.h" 6 7 #include "../../common/global_private.h" 8 #include "../../common/atomic.h" 9 #include "../../common/RingBuffer.h" 10 11 #define MIDI_KEYS 128 12 #define MIDI_CONTROLLERS 128 13 14 // assuming VirtualMidiDevice implementation is only controlled 15 // by mouse (and the user not being Billy the Kid) 16 #define MAX_EVENTS 12 17 18 namespace LinuxSampler { 19 20 struct VirtualMidiDevice::private_data_t { 21 atomic_t notesChanged; // whether some key changed at all 22 atomic_t pNoteChanged[MIDI_KEYS]; // which key(s) changed 23 atomic_t pNoteIsActive[MIDI_KEYS]; // status of each key (either active or inactive) 24 atomic_t pNoteOnVelocity[MIDI_KEYS]; 25 atomic_t pNoteOffVelocity[MIDI_KEYS]; 26 atomic_t ccsChanged; // whether some controller changed at all 27 atomic_t pCCChanged[MIDI_CONTROLLERS]; // which controller(s) changed 28 atomic_t pCCValue[MIDI_CONTROLLERS]; // current value of each controller 29 RingBuffer<VirtualMidiDevice::event_t,false> events; 30 private_data_tLinuxSampler::VirtualMidiDevice::private_data_t31 private_data_t() : events(MAX_EVENTS, 0) {} 32 }; 33 VirtualMidiDevice()34 VirtualMidiDevice::VirtualMidiDevice() : p(new private_data_t) { 35 atomic_t zero = ATOMIC_INIT(0); 36 atomic_t defaultVelocity = ATOMIC_INIT(127); 37 atomic_t defaultCCValue = ATOMIC_INIT(0); 38 p->notesChanged = zero; 39 p->ccsChanged = zero; 40 for (int i = 0; i < MIDI_KEYS; i++) { 41 p->pNoteChanged[i] = zero; 42 p->pNoteIsActive[i] = zero; 43 p->pNoteOnVelocity[i] = defaultVelocity; 44 p->pNoteOffVelocity[i] = defaultVelocity; 45 p->pCCChanged[i] = zero; 46 p->pCCValue[i] = defaultCCValue; 47 } 48 } 49 ~VirtualMidiDevice()50 VirtualMidiDevice::~VirtualMidiDevice() { 51 delete p; 52 } 53 SetMaxEvents(int n)54 void VirtualMidiDevice::SetMaxEvents(int n) { 55 p->events.resize(n); 56 } 57 SendNoteOnToSampler(uint8_t Key,uint8_t Velocity)58 bool VirtualMidiDevice::SendNoteOnToSampler(uint8_t Key, uint8_t Velocity) { 59 if (Key >= MIDI_KEYS || Velocity > 127) return false; 60 if (Velocity == 0) { 61 return SendNoteOffToSampler(Key, Velocity); 62 } 63 event_t ev = { EVENT_TYPE_NOTEON, Key, Velocity }; 64 if (p->events.write_space() <= 0) return false; 65 p->events.push(&ev); 66 return true; 67 } 68 SendNoteOffToSampler(uint8_t Key,uint8_t Velocity)69 bool VirtualMidiDevice::SendNoteOffToSampler(uint8_t Key, uint8_t Velocity) { 70 if (Key >= MIDI_KEYS || Velocity > 127) return false; 71 event_t ev = { EVENT_TYPE_NOTEOFF, Key, Velocity }; 72 if (p->events.write_space() <= 0) return false; 73 p->events.push(&ev); 74 return true; 75 } 76 SendCCToSampler(uint8_t Controller,uint8_t Value)77 bool VirtualMidiDevice::SendCCToSampler(uint8_t Controller, uint8_t Value) { 78 if (Controller >= MIDI_CONTROLLERS || Value > 127) return false; 79 event_t ev = { EVENT_TYPE_CC, Controller, Value }; 80 if (p->events.write_space() <= 0) return false; 81 p->events.push(&ev); 82 return true; 83 } 84 SendChannelPressureToSampler(uint8_t Pressure)85 bool VirtualMidiDevice::SendChannelPressureToSampler(uint8_t Pressure) { 86 if (Pressure > 127) return false; 87 event_t ev = { EVENT_TYPE_CHPRESSURE, 128 /*actually ignored by engine*/, Pressure }; 88 if (p->events.write_space() <= 0) return false; 89 p->events.push(&ev); 90 return true; 91 } 92 SendPitchBendToSampler(int Pitch)93 bool VirtualMidiDevice::SendPitchBendToSampler(int Pitch) { 94 if (Pitch < -8192 || Pitch > 8191) return false; 95 Pitch += 8192; 96 // order: LSB, MSB like it would be in a regular pitch bend MIDI message 97 event_t ev = { 98 EVENT_TYPE_PITCHBEND, 99 static_cast<uint8_t>(Pitch & 0x7f), 100 static_cast<uint8_t>((Pitch >> 7) & 0x7f) 101 }; 102 if (p->events.write_space() <= 0) return false; 103 p->events.push(&ev); 104 return true; 105 } 106 SendProgramChangeToSampler(uint8_t Program)107 bool VirtualMidiDevice::SendProgramChangeToSampler(uint8_t Program) { 108 if (Program > 127) return false; 109 event_t ev = { EVENT_TYPE_PROGRAM, Program, 0 }; 110 if (p->events.write_space() <= 0) return false; 111 p->events.push(&ev); 112 return true; 113 } 114 GetMidiEventFromDevice(event_t & Event)115 bool VirtualMidiDevice::GetMidiEventFromDevice(event_t& Event) { 116 return (p->events.pop(&Event) > 0); 117 } 118 NotesChanged()119 bool VirtualMidiDevice::NotesChanged() { 120 int c = atomic_read( &p->notesChanged ); 121 atomic_sub(c, &p->notesChanged ); 122 return c; 123 } 124 ControllersChanged()125 bool VirtualMidiDevice::ControllersChanged() { 126 int c = atomic_read( &p->ccsChanged ); 127 atomic_sub(c, &p->ccsChanged ); 128 return c; 129 } 130 NoteChanged(uint8_t Key)131 bool VirtualMidiDevice::NoteChanged(uint8_t Key) { 132 int c = atomic_read( &(p->pNoteChanged)[Key] ); 133 atomic_sub(c, &(p->pNoteChanged)[Key] ); 134 return c; 135 } 136 ControllerChanged(uint8_t Controller)137 bool VirtualMidiDevice::ControllerChanged(uint8_t Controller) { 138 int c = atomic_read( &(p->pCCChanged)[Controller] ); 139 atomic_sub(c, &(p->pCCChanged)[Controller] ); 140 return c; 141 } 142 NoteIsActive(uint8_t Key)143 bool VirtualMidiDevice::NoteIsActive(uint8_t Key) { 144 return atomic_read( &(p->pNoteIsActive)[Key] ); 145 } 146 NoteOnVelocity(uint8_t Key)147 uint8_t VirtualMidiDevice::NoteOnVelocity(uint8_t Key) { 148 return atomic_read( &(p->pNoteOnVelocity)[Key] ); 149 } 150 NoteOffVelocity(uint8_t Key)151 uint8_t VirtualMidiDevice::NoteOffVelocity(uint8_t Key) { 152 return atomic_read( &(p->pNoteOffVelocity)[Key] ); 153 } 154 ControllerValue(uint8_t Controller)155 uint8_t VirtualMidiDevice::ControllerValue(uint8_t Controller) { 156 return atomic_read( &(p->pCCValue)[Controller] ); 157 } 158 SendNoteOnToDevice(uint8_t Key,uint8_t Velocity)159 void VirtualMidiDevice::SendNoteOnToDevice(uint8_t Key, uint8_t Velocity) { 160 if (Key >= MIDI_KEYS) return; 161 if (Velocity == 0) { 162 SendNoteOffToDevice(Key, Velocity); 163 return; 164 } 165 atomic_set( &(p->pNoteOnVelocity)[Key], Velocity ); 166 atomic_inc( &(p->pNoteIsActive)[Key] ); 167 atomic_inc( &(p->pNoteChanged)[Key] ); 168 atomic_inc( &p->notesChanged ); 169 } 170 SendNoteOffToDevice(uint8_t Key,uint8_t Velocity)171 void VirtualMidiDevice::SendNoteOffToDevice(uint8_t Key, uint8_t Velocity) { 172 if (Key >= MIDI_KEYS) return; 173 atomic_set( &(p->pNoteOffVelocity)[Key], Velocity ); 174 if (atomic_read( &(p->pNoteIsActive)[Key] )) // only decrement if not zero 175 atomic_dec( &(p->pNoteIsActive)[Key] ); 176 atomic_inc( &(p->pNoteChanged)[Key] ); 177 atomic_inc( &p->notesChanged ); 178 } 179 SendCCToDevice(uint8_t Controller,uint8_t Value)180 void VirtualMidiDevice::SendCCToDevice(uint8_t Controller, uint8_t Value) { 181 if (Controller >= MIDI_CONTROLLERS) return; 182 atomic_set( &(p->pCCValue)[Controller], Value ); 183 atomic_inc( &(p->pCCChanged)[Controller] ); 184 atomic_inc( &p->ccsChanged ); 185 } 186 187 } // namespace LinuxSampler 188