1 |
/*************************************************************************** |
2 |
* * |
3 |
* LinuxSampler - modular, streaming capable sampler * |
4 |
* * |
5 |
* Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * |
6 |
* Copyright (C) 2005-2008 Christian Schoenebeck * |
7 |
* Copyright (C) 2009-2010 Christian Schoenebeck and Grigor Iliev * |
8 |
* * |
9 |
* This program is free software; you can redistribute it and/or modify * |
10 |
* it under the terms of the GNU General Public License as published by * |
11 |
* the Free Software Foundation; either version 2 of the License, or * |
12 |
* (at your option) any later version. * |
13 |
* * |
14 |
* This program is distributed in the hope that it will be useful, * |
15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
16 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
17 |
* GNU General Public License for more details. * |
18 |
* * |
19 |
* You should have received a copy of the GNU General Public License * |
20 |
* along with this program; if not, write to the Free Software * |
21 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, * |
22 |
* MA 02111-1307 USA * |
23 |
***************************************************************************/ |
24 |
|
25 |
#ifndef __LS_MIDIKEYBOARDMANAGER_H__ |
26 |
#define __LS_MIDIKEYBOARDMANAGER_H__ |
27 |
|
28 |
#include "Event.h" |
29 |
#include "Stream.h" |
30 |
#include "../../EventListeners.h" |
31 |
#include "../../common/Pool.h" |
32 |
#include "../../common/global_private.h" |
33 |
|
34 |
namespace LinuxSampler { |
35 |
|
36 |
/** |
37 |
* This class is used as a listener, which is notified |
38 |
* when MIDI keyboard events occur like note on, note off, etc. |
39 |
* Note that all events are triggered even when the channel is muted |
40 |
*/ |
41 |
class MidiKeyboardListener { |
42 |
public: |
43 |
/** Called before the engine start processing the note on event */ |
44 |
virtual void PreProcessNoteOn(uint8_t key, uint8_t velocity) = 0; |
45 |
|
46 |
/** Called after the engine has processed the note on event */ |
47 |
virtual void PostProcessNoteOn(uint8_t key, uint8_t velocity) = 0; |
48 |
|
49 |
/** Called before the engine start processing the note off event */ |
50 |
virtual void PreProcessNoteOff(uint8_t key, uint8_t velocity) = 0; |
51 |
|
52 |
/** Called after the engine has processed the note off event */ |
53 |
virtual void PostProcessNoteOff(uint8_t key, uint8_t velocity) = 0; |
54 |
|
55 |
/** Called before the engine start processing the sustain pedal up event */ |
56 |
virtual void PreProcessSustainPedalUp() = 0; |
57 |
|
58 |
/** Called after the engine has processed the sustain pedal up event */ |
59 |
virtual void PostProcessSustainPedalUp() = 0; |
60 |
|
61 |
/** Called before the engine start processing the sustain pedal down event */ |
62 |
virtual void PreProcessSustainPedalDown() = 0; |
63 |
|
64 |
/** Called after the engine has processed the sustain pedal down event */ |
65 |
virtual void PostProcessSustainPedalDown() = 0; |
66 |
|
67 |
/** Called before the engine start processing the sostenuto pedal up event */ |
68 |
virtual void PreProcessSostenutoPedalUp() = 0; |
69 |
|
70 |
/** Called after the engine has processed the sostenuto pedal up event */ |
71 |
virtual void PostProcessSostenutoPedalUp() = 0; |
72 |
|
73 |
/** Called before the engine start processing the sostenuto pedal down event */ |
74 |
virtual void PreProcessSostenutoPedalDown() = 0; |
75 |
|
76 |
/** Called after the engine has processed the sostenuto pedal down event */ |
77 |
virtual void PostProcessSostenutoPedalDown() = 0; |
78 |
}; |
79 |
|
80 |
/** |
81 |
* This class exists as convenience for creating listener objects. |
82 |
* The methods in this class are empty. |
83 |
*/ |
84 |
class MidiKeyboardAdapter : public MidiKeyboardListener { |
85 |
public: |
86 |
virtual void PreProcessNoteOn(uint8_t key, uint8_t velocity) { } |
87 |
virtual void PostProcessNoteOn(uint8_t key, uint8_t velocity) { } |
88 |
virtual void PreProcessNoteOff(uint8_t key, uint8_t velocity) { } |
89 |
virtual void PostProcessNoteOff(uint8_t key, uint8_t velocity) { } |
90 |
virtual void PreProcessSustainPedalUp() { } |
91 |
virtual void PostProcessSustainPedalUp() { } |
92 |
virtual void PreProcessSustainPedalDown() { } |
93 |
virtual void PostProcessSustainPedalDown() { } |
94 |
virtual void PreProcessSostenutoPedalUp() { } |
95 |
virtual void PostProcessSostenutoPedalUp() { } |
96 |
virtual void PreProcessSostenutoPedalDown() { } |
97 |
virtual void PostProcessSostenutoPedalDown() { } |
98 |
}; |
99 |
|
100 |
/** |
101 |
* This is the base class for class MidiKeyboardManager::MidiKey. It is |
102 |
* not intended to be instantiated directly. Instead it just defines |
103 |
* the part of class MidiKey which is not dependant on a C++ template |
104 |
* parameter. |
105 |
*/ |
106 |
class MidiKeyBase { |
107 |
public: |
108 |
bool KeyPressed; ///< Is true if the respective MIDI key is currently pressed. |
109 |
bool Active; ///< If the key contains active voices. |
110 |
bool ReleaseTrigger; ///< If we have to launch release triggered voice(s) when the key is released |
111 |
Pool<uint>::Iterator itSelf; ///< hack to allow fast deallocation of the key from the list of active keys |
112 |
RTList<Event>* pEvents; ///< Key specific events (only Note-on, Note-off and sustain pedal currently) |
113 |
int VoiceTheftsQueued; ///< Amount of voices postponed due to shortage of voices. |
114 |
uint32_t* pRoundRobinIndex; ///< For the round robin dimension: current articulation for this key, will be incremented for each note on |
115 |
uint8_t Velocity; ///< Latest Note-on velocity for this key |
116 |
unsigned long NoteOnTime; ///< Time for latest Note-on event for this key |
117 |
float Volume; ///< Individual volume level for this MIDI key (usually 1.0f unless Roland GS NRPN 0x1Ann was received, nn reflecting the note number, see EngineBase::ProcessHardcodedControllers()) |
118 |
float PanLeft; ///< Individual volume balance (left channel coefficient) for this MIDI key (usually 1.0f unless Roland GS NRPN 0x1Cnn was received, nn reflecting the note number, see EngineBase::ProcessHardcodedControllers()) |
119 |
float PanRight; ///< Individual volume balance (right channel coefficient) for this MIDI key (usually 1.0f unless Roland GS NRPN 0x1Cnn was received, nn reflecting the note number, see EngineBase::ProcessHardcodedControllers()) |
120 |
optional<float> ReverbSend; ///< Optional individual reverb send level for this MIDI key (usually not set, unless Roland GS NRPN 0x1Dnn was received, nn reflecting the note number, see EngineBase::ProcessHardcodedControllers()) |
121 |
optional<float> ChorusSend; ///< Optional individual chorus send level for this MIDI key (usually not set, unless Roland GS NRPN 0x1Enn was received, nn reflecting the note number, see EngineBase::ProcessHardcodedControllers()) |
122 |
}; |
123 |
|
124 |
template <class V> |
125 |
class MidiKeyboardManager { |
126 |
public: |
127 |
/** @brief Voice Stealing Algorithms |
128 |
* |
129 |
* Enumeration of all possible voice stealing algorithms. |
130 |
*/ |
131 |
enum voice_steal_algo_t { |
132 |
voice_steal_algo_none, ///< Voice stealing disabled. |
133 |
voice_steal_algo_oldestvoiceonkey, ///< Try to kill the oldest voice from same key where the new voice should be spawned. |
134 |
voice_steal_algo_oldestkey ///< Try to kill the oldest voice from the oldest active key. |
135 |
}; |
136 |
|
137 |
|
138 |
/** @brief MIDI key runtime informations |
139 |
* |
140 |
* Reflects runtime informations for one MIDI key. |
141 |
*/ |
142 |
class MidiKey : public MidiKeyBase { |
143 |
public: |
144 |
RTList<V>* pActiveVoices; ///< Contains the active voices associated with the MIDI key. |
145 |
|
146 |
MidiKey() { |
147 |
pActiveVoices = NULL; |
148 |
KeyPressed = false; |
149 |
Active = false; |
150 |
ReleaseTrigger = false; |
151 |
pEvents = NULL; |
152 |
VoiceTheftsQueued = 0; |
153 |
Volume = 1.0f; |
154 |
PanLeft = 1.0f; |
155 |
PanRight = 1.0f; |
156 |
} |
157 |
|
158 |
void Reset() { |
159 |
if (pActiveVoices) pActiveVoices->clear(); |
160 |
if (pEvents) pEvents->clear(); |
161 |
KeyPressed = false; |
162 |
Active = false; |
163 |
ReleaseTrigger = false; |
164 |
itSelf = Pool<uint>::Iterator(); |
165 |
VoiceTheftsQueued = 0; |
166 |
Volume = 1.0f; |
167 |
PanLeft = 1.0f; |
168 |
PanRight = 1.0f; |
169 |
ReverbSend = optional<float>::nothing; |
170 |
ChorusSend = optional<float>::nothing; |
171 |
} |
172 |
}; |
173 |
|
174 |
typedef typename RTList<V>::Iterator RTListVoiceIterator; |
175 |
typedef typename Pool<V>::Iterator PoolVoiceIterator; |
176 |
|
177 |
/** |
178 |
* Override this class to iterate through all active keys/voices |
179 |
* using ProcessActiveVoices() method. |
180 |
*/ |
181 |
class VoiceHandler { |
182 |
public: |
183 |
/** |
184 |
* @returns true if the voices on the specified key should be processed |
185 |
* adn false to cancel the processing of the active voices for the |
186 |
* specified key |
187 |
*/ |
188 |
virtual bool Process(MidiKey* pMidiKey) = 0; |
189 |
|
190 |
virtual void Process(RTListVoiceIterator& itVoice) = 0; |
191 |
}; |
192 |
|
193 |
class VoiceHandlerBase : public VoiceHandler { |
194 |
public: |
195 |
virtual bool Process(MidiKey* pMidiKey) { return true; } |
196 |
virtual void Process(RTListVoiceIterator& itVoice) { } |
197 |
}; |
198 |
|
199 |
MidiKey* pMIDIKeyInfo; ///< Contains all active voices sorted by MIDI key number and other informations to the respective MIDI key |
200 |
Pool<uint>* pActiveKeys; ///< Holds all keys in it's allocation list with active voices. |
201 |
bool SoloMode; ///< in Solo Mode we only play one voice (group) at a time |
202 |
int SoloKey; ///< Currently 'active' solo key, that is the key to which the currently sounding voice belongs to (only if SoloMode is enabled) |
203 |
bool SustainPedal; ///< true if sustain pedal is down |
204 |
bool SostenutoPedal; ///< true if sostenuto pedal is down |
205 |
int SostenutoKeys[128]; |
206 |
int SostenutoKeyCount; |
207 |
uint32_t RoundRobinIndexes[128]; |
208 |
|
209 |
MidiKeyboardManager() { |
210 |
pMIDIKeyInfo = new MidiKey[128]; |
211 |
pActiveKeys = new Pool<uint>(128); |
212 |
SoloMode = false; |
213 |
SustainPedal = false; |
214 |
SostenutoPedal = false; |
215 |
for (int i = 0 ; i < 128 ; i++) { |
216 |
RoundRobinIndexes[i] = 0; |
217 |
|
218 |
// by default use one counter for each key (the |
219 |
// gig engine will change this to one counter per |
220 |
// region) |
221 |
pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i]; |
222 |
} |
223 |
} |
224 |
|
225 |
virtual ~MidiKeyboardManager() { |
226 |
listeners.RemoveAllListeners(); |
227 |
if (pActiveKeys) delete pActiveKeys; |
228 |
if (pMIDIKeyInfo) delete[] pMIDIKeyInfo; |
229 |
} |
230 |
|
231 |
void Reset() { |
232 |
SoloKey = -1; // no solo key active yet |
233 |
|
234 |
// reset key info |
235 |
for (uint i = 0; i < 128; i++) pMIDIKeyInfo[i].Reset(); |
236 |
|
237 |
// free all active keys |
238 |
pActiveKeys->clear(); |
239 |
} |
240 |
|
241 |
void AllocateActiveVoices(Pool<V>* pVoicePool) { |
242 |
DeleteActiveVoices(); |
243 |
|
244 |
for (uint i = 0; i < 128; i++) { |
245 |
pMIDIKeyInfo[i].pActiveVoices = new RTList<V>(pVoicePool); |
246 |
} |
247 |
} |
248 |
|
249 |
void DeleteActiveVoices() { |
250 |
for (uint i = 0; i < 128; i++) { |
251 |
if (pMIDIKeyInfo[i].pActiveVoices) { |
252 |
delete pMIDIKeyInfo[i].pActiveVoices; |
253 |
pMIDIKeyInfo[i].pActiveVoices = NULL; |
254 |
} |
255 |
} |
256 |
} |
257 |
|
258 |
void AllocateEvents(Pool<Event>* pEventPool) { |
259 |
DeleteEvents(); |
260 |
|
261 |
for (uint i = 0; i < 128; i++) { |
262 |
pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEventPool); |
263 |
} |
264 |
} |
265 |
|
266 |
void DeleteEvents() { |
267 |
for (uint i = 0; i < 128; i++) { |
268 |
if (pMIDIKeyInfo[i].pEvents) { |
269 |
delete pMIDIKeyInfo[i].pEvents; |
270 |
pMIDIKeyInfo[i].pEvents = NULL; |
271 |
} |
272 |
} |
273 |
} |
274 |
|
275 |
void ClearAllActiveKeyEvents() { |
276 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
277 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
278 |
for(; iuiKey != end; ++iuiKey) { |
279 |
pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key |
280 |
} |
281 |
} |
282 |
|
283 |
/** |
284 |
* Removes the given voice from the MIDI key's list of active voices. |
285 |
* This method will be called when a voice went inactive, e.g. because |
286 |
* it finished to playback its sample, finished its release stage or |
287 |
* just was killed. |
288 |
* |
289 |
* @param itVoice - points to the voice to be freed |
290 |
*/ |
291 |
void FreeVoice(PoolVoiceIterator& itVoice) { |
292 |
if (itVoice) { |
293 |
MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey]; |
294 |
|
295 |
// if the sample and dimension region belong to an |
296 |
// instrument that is unloaded, tell the disk thread to |
297 |
// release them |
298 |
if (itVoice->Orphan) { |
299 |
if(itVoice->pDiskThread != NULL) { |
300 |
itVoice->pDiskThread->OrderDeletionOfRegion(itVoice->GetRegion()); |
301 |
} |
302 |
} |
303 |
|
304 |
// free the voice object |
305 |
pKey->pActiveVoices->free(itVoice); |
306 |
} |
307 |
else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush; |
308 |
} |
309 |
|
310 |
/** |
311 |
* Called when there's no more voice left on a key, this call will |
312 |
* update the key info respectively. |
313 |
* |
314 |
* @param pEngineChannel - engine channel on which this event occured on |
315 |
* @param pKey - key which is now inactive |
316 |
*/ |
317 |
void FreeKey(MidiKey* pKey) { |
318 |
if (pKey->pActiveVoices->isEmpty()) { |
319 |
pKey->Active = false; |
320 |
pActiveKeys->free(pKey->itSelf); // remove key from list of active keys |
321 |
pKey->itSelf = RTList<uint>::Iterator(); |
322 |
pKey->ReleaseTrigger = false; |
323 |
pKey->pEvents->clear(); |
324 |
dmsg(3,("Key has no more voices now\n")); |
325 |
} |
326 |
else dmsg(1,("MidiKeyboardManager: Oops, tried to free a key which contains voices.\n")); |
327 |
} |
328 |
|
329 |
/** |
330 |
* Free all keys which have no active voices left |
331 |
*/ |
332 |
void FreeAllInactiveKyes() { |
333 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
334 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
335 |
while (iuiKey != end) { // iterate through all active keys |
336 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
337 |
++iuiKey; |
338 |
if (pKey->pActiveVoices->isEmpty()) FreeKey(pKey); |
339 |
#if CONFIG_DEVMODE |
340 |
else { // just a sanity check for debugging |
341 |
RTListVoiceIterator itVoice = pKey->pActiveVoices->first(); |
342 |
RTListVoiceIterator = pKey->pActiveVoices->end(); |
343 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
344 |
if (itVoice->itKillEvent) { |
345 |
dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n")); |
346 |
} |
347 |
} |
348 |
} |
349 |
#endif // CONFIG_DEVMODE |
350 |
} |
351 |
} |
352 |
|
353 |
int StealVoice ( |
354 |
Pool<Event>::Iterator& itNoteOnEvent, |
355 |
RTListVoiceIterator* LastStolenVoice, |
356 |
RTList<uint>::Iterator* LastStolenKey |
357 |
) { |
358 |
RTListVoiceIterator itSelectedVoice; |
359 |
|
360 |
// Select one voice for voice stealing |
361 |
switch (CONFIG_VOICE_STEAL_ALGO) { |
362 |
|
363 |
// try to pick the oldest voice on the key where the new |
364 |
// voice should be spawned, if there is no voice on that |
365 |
// key, or no voice left to kill, then procceed with |
366 |
// 'oldestkey' algorithm |
367 |
case voice_steal_algo_oldestvoiceonkey: { |
368 |
MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key]; |
369 |
itSelectedVoice = pSelectedKey->pActiveVoices->first(); |
370 |
// proceed iterating if voice was created in this fragment cycle |
371 |
while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice; |
372 |
// if we haven't found a voice then proceed with algorithm 'oldestkey' |
373 |
if (itSelectedVoice && itSelectedVoice->IsStealable()) break; |
374 |
} // no break - intentional ! |
375 |
|
376 |
// try to pick the oldest voice on the oldest active key |
377 |
// from the same engine channel |
378 |
// (caution: must stay after 'oldestvoiceonkey' algorithm !) |
379 |
case voice_steal_algo_oldestkey: { |
380 |
// if we already stole in this fragment, try to proceed on same key |
381 |
if (*LastStolenVoice) { |
382 |
itSelectedVoice = *LastStolenVoice; |
383 |
do { |
384 |
++itSelectedVoice; |
385 |
} while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle |
386 |
// found a "stealable" voice ? |
387 |
if (itSelectedVoice && itSelectedVoice->IsStealable()) { |
388 |
// remember which voice we stole, so we can simply proceed on next voice stealing |
389 |
*LastStolenVoice = itSelectedVoice; |
390 |
break; // selection succeeded |
391 |
} |
392 |
} |
393 |
// get (next) oldest key |
394 |
RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first(); |
395 |
while (iuiSelectedKey) { |
396 |
MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey]; |
397 |
itSelectedVoice = pSelectedKey->pActiveVoices->first(); |
398 |
// proceed iterating if voice was created in this fragment cycle |
399 |
while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice; |
400 |
// found a "stealable" voice ? |
401 |
if (itSelectedVoice && itSelectedVoice->IsStealable()) { |
402 |
// remember which voice on which key we stole, so we can simply proceed on next voice stealing |
403 |
*LastStolenKey = iuiSelectedKey; |
404 |
*LastStolenVoice = itSelectedVoice; |
405 |
break; // selection succeeded |
406 |
} |
407 |
++iuiSelectedKey; // get next oldest key |
408 |
} |
409 |
break; |
410 |
} |
411 |
|
412 |
// don't steal anything |
413 |
case voice_steal_algo_none: |
414 |
default: { |
415 |
dmsg(1,("No free voice (voice stealing disabled)!\n")); |
416 |
return -1; |
417 |
} |
418 |
} |
419 |
|
420 |
if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1; |
421 |
|
422 |
#if CONFIG_DEVMODE |
423 |
if (!itSelectedVoice->IsActive()) { |
424 |
dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n")); |
425 |
return -1; |
426 |
} |
427 |
#endif // CONFIG_DEVMODE |
428 |
|
429 |
// now kill the selected voice |
430 |
itSelectedVoice->Kill(itNoteOnEvent); |
431 |
|
432 |
return 0; |
433 |
} |
434 |
|
435 |
/** |
436 |
* Releases all voices. All voices will go into |
437 |
* the release stage and thus it might take some time (e.g. dependant to |
438 |
* their envelope release time) until they actually die. |
439 |
* |
440 |
* @param itReleaseEvent - event which caused this releasing of all voices |
441 |
*/ |
442 |
void ReleaseAllVoices(Pool<Event>::Iterator& itReleaseEvent) { |
443 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
444 |
while (iuiKey) { |
445 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
446 |
++iuiKey; |
447 |
// append a 'release' event to the key's own event list |
448 |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
449 |
if (itNewEvent) { |
450 |
*itNewEvent = *itReleaseEvent; // copy original event (to the key's event list) |
451 |
itNewEvent->Type = Event::type_release; // transform event type |
452 |
} |
453 |
else dmsg(1,("Event pool emtpy!\n")); |
454 |
} |
455 |
} |
456 |
/** |
457 |
* Kill all active voices. |
458 |
* @returns The number of voices. |
459 |
*/ |
460 |
int KillAllVoices(Pool<Event>::Iterator& itKillEvent) { |
461 |
int count = 0; |
462 |
|
463 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
464 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
465 |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
466 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
467 |
RTListVoiceIterator itVoice = pKey->pActiveVoices->first(); |
468 |
RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end(); |
469 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
470 |
itVoice->Kill(itKillEvent); |
471 |
count++; |
472 |
} |
473 |
} |
474 |
|
475 |
return count; |
476 |
} |
477 |
|
478 |
/** |
479 |
* Kill all voices the *die hard* way. |
480 |
* @returns The number of pending stream deletions |
481 |
*/ |
482 |
int KillAllVoicesImmediately() { |
483 |
int iPendingStreamDeletions = 0; |
484 |
|
485 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
486 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
487 |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
488 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
489 |
RTListVoiceIterator itVoice = pKey->pActiveVoices->first(); |
490 |
RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end(); |
491 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
492 |
// request a notification from disk thread side for stream deletion |
493 |
const Stream::Handle hStream = itVoice->KillImmediately(true); |
494 |
if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream |
495 |
iPendingStreamDeletions++; |
496 |
} |
497 |
// free the voice to the voice pool and update key info |
498 |
FreeVoice(itVoice); |
499 |
} |
500 |
} |
501 |
|
502 |
return iPendingStreamDeletions; |
503 |
} |
504 |
|
505 |
/** |
506 |
* Mark all currently active voices as "orphans", which means that the regions and |
507 |
* samples they use should be released to the instrument manager when the voices die. |
508 |
*/ |
509 |
void MarkAllActiveVoicesAsOrphans() { |
510 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
511 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
512 |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
513 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
514 |
RTListVoiceIterator itVoice = pKey->pActiveVoices->first(); |
515 |
RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end(); |
516 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
517 |
itVoice->Orphan = true; |
518 |
} |
519 |
} |
520 |
} |
521 |
|
522 |
void ProcessActiveVoices(VoiceHandler* pVoiceHandler) { |
523 |
if (pVoiceHandler == NULL) return; |
524 |
|
525 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
526 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
527 |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
528 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
529 |
if (!pVoiceHandler->Process(pKey)) continue; |
530 |
|
531 |
RTListVoiceIterator itVoice = pKey->pActiveVoices->first(); |
532 |
RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end(); |
533 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
534 |
pVoiceHandler->Process(itVoice); |
535 |
} |
536 |
} |
537 |
} |
538 |
|
539 |
void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) { |
540 |
// Cancel release process of all voices |
541 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
542 |
for (; iuiKey; ++iuiKey) { |
543 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
544 |
if (!pKey->KeyPressed) { |
545 |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
546 |
if (itNewEvent) { |
547 |
*itNewEvent = *itEvent; // copy event to the key's own event list |
548 |
itNewEvent->Type = Event::type_cancel_release; // transform event type |
549 |
} |
550 |
else dmsg(1,("Event pool emtpy!\n")); |
551 |
} |
552 |
} |
553 |
} |
554 |
|
555 |
void ProcessSustainPedalUp(Pool<Event>::Iterator& itEvent) { |
556 |
// release voices if their respective key is not pressed |
557 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
558 |
for (; iuiKey; ++iuiKey) { |
559 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
560 |
if (!pKey->KeyPressed && ShouldReleaseVoice(*iuiKey)) { |
561 |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
562 |
if (itNewEvent) { |
563 |
*itNewEvent = *itEvent; // copy event to the key's own event list |
564 |
itNewEvent->Type = Event::type_release; // transform event type |
565 |
} |
566 |
else dmsg(1,("Event pool emtpy!\n")); |
567 |
} |
568 |
} |
569 |
} |
570 |
|
571 |
/** |
572 |
* Determines whether the specified voice should be released. |
573 |
* |
574 |
* @param pEngineChannel - The engine channel on which the voice should be checked |
575 |
* @param Key - The key number |
576 |
* @returns true if the specified voice should be released, false otherwise. |
577 |
*/ |
578 |
bool ShouldReleaseVoice(int Key) { |
579 |
if (SustainPedal) return false; |
580 |
|
581 |
if (SostenutoPedal) { |
582 |
for (int i = 0; i < SostenutoKeyCount; i++) |
583 |
if (Key == SostenutoKeys[i]) return false; |
584 |
} |
585 |
|
586 |
return true; |
587 |
} |
588 |
|
589 |
void ProcessSostenutoPedalDown() { |
590 |
SostenutoKeyCount = 0; |
591 |
// Remeber the pressed keys |
592 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
593 |
for (; iuiKey; ++iuiKey) { |
594 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
595 |
if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey; |
596 |
} |
597 |
} |
598 |
|
599 |
void ProcessSostenutoPedalUp(Pool<Event>::Iterator& itEvent) { |
600 |
// release voices if the damper pedal is up and their respective key is not pressed |
601 |
for (int i = 0; i < SostenutoKeyCount; i++) { |
602 |
MidiKey* pKey = &pMIDIKeyInfo[SostenutoKeys[i]]; |
603 |
if (!pKey->KeyPressed && !SustainPedal) { |
604 |
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
605 |
if (itNewEvent) { |
606 |
*itNewEvent = *itEvent; // copy event to the key's own event list |
607 |
itNewEvent->Type = Event::type_release; // transform event type |
608 |
} |
609 |
else dmsg(1,("Event pool emtpy!\n")); |
610 |
} |
611 |
} |
612 |
} |
613 |
|
614 |
void AddMidiKeyboardListener(MidiKeyboardListener* l) { listeners.AddListener(l); } |
615 |
|
616 |
void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); } |
617 |
|
618 |
protected: |
619 |
class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> { |
620 |
public: |
621 |
REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t) |
622 |
REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOn, uint8_t, uint8_t) |
623 |
REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOff, uint8_t, uint8_t) |
624 |
REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOff, uint8_t, uint8_t) |
625 |
REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalUp) |
626 |
REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalUp) |
627 |
REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalDown) |
628 |
REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalDown) |
629 |
REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalUp) |
630 |
REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalUp) |
631 |
REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalDown) |
632 |
REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalDown) |
633 |
} listeners; |
634 |
}; |
635 |
} // namespace LinuxSampler |
636 |
|
637 |
#endif /* __LS_MIDIKEYBOARDMANAGER_H__ */ |