/[svn]/linuxsampler/trunk/src/drivers/midi/VirtualMidiDevice.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/drivers/midi/VirtualMidiDevice.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3986 - (show annotations) (download)
Wed Aug 4 18:04:12 2021 UTC (2 years, 8 months ago) by schoenebeck
File size: 7852 byte(s)
* VirtualMidiDevice: add method Reset() which is e.g. intended to be used
  in "panic" / MIDI "all sound off" / MIDI "all note off" situations.

1 /*
2 Copyright (C) 2008 - 2021 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 #define DEFAULT_CC_VALUE 0
19 #define DEFAULT_VELOCITY 127
20
21 namespace LinuxSampler {
22
23 struct VirtualMidiDevice::private_data_t {
24 atomic_t notesChanged; // whether some key changed at all
25 atomic_t pNoteChanged[MIDI_KEYS]; // which key(s) changed
26 atomic_t pNoteIsActive[MIDI_KEYS]; // status of each key (either active or inactive)
27 atomic_t pNoteOnVelocity[MIDI_KEYS];
28 atomic_t pNoteOffVelocity[MIDI_KEYS];
29 atomic_t ccsChanged; // whether some controller changed at all
30 atomic_t pCCChanged[MIDI_CONTROLLERS]; // which controller(s) changed
31 atomic_t pCCValue[MIDI_CONTROLLERS]; // current value of each controller
32 RingBuffer<VirtualMidiDevice::event_t,false> events;
33
34 private_data_t() : events(MAX_EVENTS, 0) {}
35
36 void resetNotes() {
37 for (int i = 0; i < MIDI_KEYS; i++) {
38 atomic_set( &pNoteOnVelocity[i], DEFAULT_VELOCITY );
39 atomic_set( &pNoteOffVelocity[i], DEFAULT_VELOCITY );
40 atomic_set( &pNoteIsActive[i], 0 );
41 // should be non zero, because we changed the state above, that
42 // way forcing the virtual MIDI device user (e.g. UI) to refresh
43 atomic_inc( &pNoteChanged[i] );
44 }
45 // this should also be non zero, for the same reason as above
46 atomic_inc( &notesChanged );
47 }
48
49 void resetCCs() {
50 for (int i = 0; i < MIDI_CONTROLLERS; i++) {
51 atomic_set( &pCCValue[i], DEFAULT_CC_VALUE );
52 // should be non zero, because we changed the state above, that
53 // way forcing the virtual MIDI device user (e.g. UI) to refresh
54 atomic_inc( &pCCChanged[i] );
55 }
56 // this should also be non zero, for the same reason as above
57 atomic_inc( &ccsChanged );
58 }
59 };
60
61 VirtualMidiDevice::VirtualMidiDevice() : p(new private_data_t) {
62 atomic_t zero = ATOMIC_INIT(0);
63 atomic_t defaultVelocity = ATOMIC_INIT(127);
64 atomic_t defaultCCValue = ATOMIC_INIT(0);
65 p->notesChanged = zero;
66 p->ccsChanged = zero;
67 for (int i = 0; i < MIDI_KEYS; i++) {
68 p->pNoteChanged[i] = zero;
69 p->pNoteIsActive[i] = zero;
70 p->pNoteOnVelocity[i] = defaultVelocity;
71 p->pNoteOffVelocity[i] = defaultVelocity;
72 p->pCCChanged[i] = zero;
73 p->pCCValue[i] = defaultCCValue;
74 }
75 }
76
77 VirtualMidiDevice::~VirtualMidiDevice() {
78 delete p;
79 }
80
81 void VirtualMidiDevice::SetMaxEvents(int n) {
82 p->events.resize(n);
83 }
84
85 bool VirtualMidiDevice::SendNoteOnToSampler(uint8_t Key, uint8_t Velocity) {
86 if (Key >= MIDI_KEYS || Velocity > 127) return false;
87 if (Velocity == 0) {
88 return SendNoteOffToSampler(Key, Velocity);
89 }
90 event_t ev = { EVENT_TYPE_NOTEON, Key, Velocity };
91 if (p->events.write_space() <= 0) return false;
92 p->events.push(&ev);
93 return true;
94 }
95
96 bool VirtualMidiDevice::SendNoteOffToSampler(uint8_t Key, uint8_t Velocity) {
97 if (Key >= MIDI_KEYS || Velocity > 127) return false;
98 event_t ev = { EVENT_TYPE_NOTEOFF, Key, Velocity };
99 if (p->events.write_space() <= 0) return false;
100 p->events.push(&ev);
101 return true;
102 }
103
104 bool VirtualMidiDevice::SendCCToSampler(uint8_t Controller, uint8_t Value) {
105 if (Controller >= MIDI_CONTROLLERS || Value > 127) return false;
106 event_t ev = { EVENT_TYPE_CC, Controller, Value };
107 if (p->events.write_space() <= 0) return false;
108 p->events.push(&ev);
109 return true;
110 }
111
112 bool VirtualMidiDevice::SendChannelPressureToSampler(uint8_t Pressure) {
113 if (Pressure > 127) return false;
114 event_t ev = { EVENT_TYPE_CHPRESSURE, 128 /*actually ignored by engine*/, Pressure };
115 if (p->events.write_space() <= 0) return false;
116 p->events.push(&ev);
117 return true;
118 }
119
120 bool VirtualMidiDevice::SendPitchBendToSampler(int Pitch) {
121 if (Pitch < -8192 || Pitch > 8191) return false;
122 Pitch += 8192;
123 // order: LSB, MSB like it would be in a regular pitch bend MIDI message
124 event_t ev = {
125 EVENT_TYPE_PITCHBEND,
126 static_cast<uint8_t>(Pitch & 0x7f),
127 static_cast<uint8_t>((Pitch >> 7) & 0x7f)
128 };
129 if (p->events.write_space() <= 0) return false;
130 p->events.push(&ev);
131 return true;
132 }
133
134 bool VirtualMidiDevice::SendProgramChangeToSampler(uint8_t Program) {
135 if (Program > 127) return false;
136 event_t ev = { EVENT_TYPE_PROGRAM, Program, 0 };
137 if (p->events.write_space() <= 0) return false;
138 p->events.push(&ev);
139 return true;
140 }
141
142 bool VirtualMidiDevice::GetMidiEventFromDevice(event_t& Event) {
143 return (p->events.pop(&Event) > 0);
144 }
145
146 bool VirtualMidiDevice::NotesChanged() {
147 int c = atomic_read( &p->notesChanged );
148 atomic_sub(c, &p->notesChanged );
149 return c;
150 }
151
152 bool VirtualMidiDevice::ControllersChanged() {
153 int c = atomic_read( &p->ccsChanged );
154 atomic_sub(c, &p->ccsChanged );
155 return c;
156 }
157
158 bool VirtualMidiDevice::NoteChanged(uint8_t Key) {
159 int c = atomic_read( &(p->pNoteChanged)[Key] );
160 atomic_sub(c, &(p->pNoteChanged)[Key] );
161 return c;
162 }
163
164 bool VirtualMidiDevice::ControllerChanged(uint8_t Controller) {
165 int c = atomic_read( &(p->pCCChanged)[Controller] );
166 atomic_sub(c, &(p->pCCChanged)[Controller] );
167 return c;
168 }
169
170 bool VirtualMidiDevice::NoteIsActive(uint8_t Key) {
171 return atomic_read( &(p->pNoteIsActive)[Key] );
172 }
173
174 uint8_t VirtualMidiDevice::NoteOnVelocity(uint8_t Key) {
175 return atomic_read( &(p->pNoteOnVelocity)[Key] );
176 }
177
178 uint8_t VirtualMidiDevice::NoteOffVelocity(uint8_t Key) {
179 return atomic_read( &(p->pNoteOffVelocity)[Key] );
180 }
181
182 uint8_t VirtualMidiDevice::ControllerValue(uint8_t Controller) {
183 return atomic_read( &(p->pCCValue)[Controller] );
184 }
185
186 void VirtualMidiDevice::SendNoteOnToDevice(uint8_t Key, uint8_t Velocity) {
187 if (Key >= MIDI_KEYS) return;
188 if (Velocity == 0) {
189 SendNoteOffToDevice(Key, Velocity);
190 return;
191 }
192 atomic_set( &(p->pNoteOnVelocity)[Key], Velocity );
193 atomic_inc( &(p->pNoteIsActive)[Key] );
194 atomic_inc( &(p->pNoteChanged)[Key] );
195 atomic_inc( &p->notesChanged );
196 }
197
198 void VirtualMidiDevice::SendNoteOffToDevice(uint8_t Key, uint8_t Velocity) {
199 if (Key >= MIDI_KEYS) return;
200 atomic_set( &(p->pNoteOffVelocity)[Key], Velocity );
201 if (atomic_read( &(p->pNoteIsActive)[Key] )) // only decrement if not zero
202 atomic_dec( &(p->pNoteIsActive)[Key] );
203 atomic_inc( &(p->pNoteChanged)[Key] );
204 atomic_inc( &p->notesChanged );
205 }
206
207 void VirtualMidiDevice::SendCCToDevice(uint8_t Controller, uint8_t Value) {
208 if (Controller >= MIDI_CONTROLLERS) return;
209 atomic_set( &(p->pCCValue)[Controller], Value );
210 atomic_inc( &(p->pCCChanged)[Controller] );
211 atomic_inc( &p->ccsChanged );
212 }
213
214 void VirtualMidiDevice::Reset() {
215 p->resetNotes();
216 p->resetCCs();
217 }
218
219 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC