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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3986 - (hide 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 schoenebeck 1659 /*
2 schoenebeck 3986 Copyright (C) 2008 - 2021 Christian Schoenebeck
3 schoenebeck 1659 */
4    
5     #include "VirtualMidiDevice.h"
6    
7     #include "../../common/global_private.h"
8     #include "../../common/atomic.h"
9     #include "../../common/RingBuffer.h"
10    
11 schoenebeck 2025 #define MIDI_KEYS 128
12     #define MIDI_CONTROLLERS 128
13 schoenebeck 1659
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 schoenebeck 3986 #define DEFAULT_CC_VALUE 0
19     #define DEFAULT_VELOCITY 127
20    
21 schoenebeck 1659 namespace LinuxSampler {
22    
23 persson 1896 struct VirtualMidiDevice::private_data_t {
24 schoenebeck 1659 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 schoenebeck 1663 atomic_t pNoteOnVelocity[MIDI_KEYS];
28     atomic_t pNoteOffVelocity[MIDI_KEYS];
29 schoenebeck 2025 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 schoenebeck 1659 RingBuffer<VirtualMidiDevice::event_t,false> events;
33    
34 persson 1896 private_data_t() : events(MAX_EVENTS, 0) {}
35 schoenebeck 3986
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 schoenebeck 1659 };
60    
61 persson 1896 VirtualMidiDevice::VirtualMidiDevice() : p(new private_data_t) {
62 schoenebeck 1659 atomic_t zero = ATOMIC_INIT(0);
63 schoenebeck 1663 atomic_t defaultVelocity = ATOMIC_INIT(127);
64 schoenebeck 2025 atomic_t defaultCCValue = ATOMIC_INIT(0);
65 schoenebeck 1659 p->notesChanged = zero;
66 schoenebeck 2025 p->ccsChanged = zero;
67 schoenebeck 1659 for (int i = 0; i < MIDI_KEYS; i++) {
68     p->pNoteChanged[i] = zero;
69     p->pNoteIsActive[i] = zero;
70 schoenebeck 1663 p->pNoteOnVelocity[i] = defaultVelocity;
71     p->pNoteOffVelocity[i] = defaultVelocity;
72 schoenebeck 2025 p->pCCChanged[i] = zero;
73     p->pCCValue[i] = defaultCCValue;
74 schoenebeck 1659 }
75     }
76    
77     VirtualMidiDevice::~VirtualMidiDevice() {
78 persson 1896 delete p;
79 schoenebeck 1659 }
80 schoenebeck 2384
81     void VirtualMidiDevice::SetMaxEvents(int n) {
82     p->events.resize(n);
83     }
84 schoenebeck 1659
85     bool VirtualMidiDevice::SendNoteOnToSampler(uint8_t Key, uint8_t Velocity) {
86     if (Key >= MIDI_KEYS || Velocity > 127) return false;
87 schoenebeck 2385 if (Velocity == 0) {
88     return SendNoteOffToSampler(Key, Velocity);
89     }
90 schoenebeck 1659 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 schoenebeck 2025
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 schoenebeck 1659
112 schoenebeck 3018 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 schoenebeck 2521 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 schoenebeck 2522 event_t ev = {
125     EVENT_TYPE_PITCHBEND,
126     static_cast<uint8_t>(Pitch & 0x7f),
127     static_cast<uint8_t>((Pitch >> 7) & 0x7f)
128     };
129 schoenebeck 2521 if (p->events.write_space() <= 0) return false;
130     p->events.push(&ev);
131     return true;
132     }
133    
134 schoenebeck 2522 bool VirtualMidiDevice::SendProgramChangeToSampler(uint8_t Program) {
135     if (Program > 127) return false;
136 schoenebeck 2521 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 schoenebeck 1659 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 schoenebeck 2025
152     bool VirtualMidiDevice::ControllersChanged() {
153     int c = atomic_read( &p->ccsChanged );
154     atomic_sub(c, &p->ccsChanged );
155     return c;
156     }
157 schoenebeck 1659
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 schoenebeck 2025
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 schoenebeck 1659
170     bool VirtualMidiDevice::NoteIsActive(uint8_t Key) {
171     return atomic_read( &(p->pNoteIsActive)[Key] );
172     }
173    
174 schoenebeck 1663 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 schoenebeck 2025
182     uint8_t VirtualMidiDevice::ControllerValue(uint8_t Controller) {
183     return atomic_read( &(p->pCCValue)[Controller] );
184     }
185 schoenebeck 1663
186     void VirtualMidiDevice::SendNoteOnToDevice(uint8_t Key, uint8_t Velocity) {
187 schoenebeck 1659 if (Key >= MIDI_KEYS) return;
188 schoenebeck 2385 if (Velocity == 0) {
189     SendNoteOffToDevice(Key, Velocity);
190     return;
191     }
192 schoenebeck 1663 atomic_set( &(p->pNoteOnVelocity)[Key], Velocity );
193 schoenebeck 1659 atomic_inc( &(p->pNoteIsActive)[Key] );
194     atomic_inc( &(p->pNoteChanged)[Key] );
195     atomic_inc( &p->notesChanged );
196     }
197    
198 schoenebeck 1663 void VirtualMidiDevice::SendNoteOffToDevice(uint8_t Key, uint8_t Velocity) {
199 schoenebeck 1659 if (Key >= MIDI_KEYS) return;
200 schoenebeck 1663 atomic_set( &(p->pNoteOffVelocity)[Key], Velocity );
201 schoenebeck 2384 if (atomic_read( &(p->pNoteIsActive)[Key] )) // only decrement if not zero
202     atomic_dec( &(p->pNoteIsActive)[Key] );
203 schoenebeck 1659 atomic_inc( &(p->pNoteChanged)[Key] );
204     atomic_inc( &p->notesChanged );
205     }
206 schoenebeck 2025
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 schoenebeck 1659
214 schoenebeck 3986 void VirtualMidiDevice::Reset() {
215     p->resetNotes();
216     p->resetCCs();
217     }
218    
219 schoenebeck 1659 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC