/[svn]/linuxsampler/trunk/src/engines/common/MidiKeyboardManager.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/common/MidiKeyboardManager.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2927 - (show annotations) (download) (as text)
Thu Jun 30 16:44:46 2016 UTC (7 years, 9 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 39947 byte(s)
* Fix: Release trigger voices were not spawned on sustain pedal up
  (CC #64) events.
* Fix: Release trigger voices can now also distinguish correctly between
  note-off and sustain pedal up events.
* Bumped version (2.0.0.svn10).

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 #include "Note.h"
34
35 namespace LinuxSampler {
36
37 /**
38 * This class is used as a listener, which is notified
39 * when MIDI keyboard events occur like note on, note off, etc.
40 * Note that all events are triggered even when the channel is muted
41 */
42 class MidiKeyboardListener {
43 public:
44 /** Called before the engine start processing the note on event */
45 virtual void PreProcessNoteOn(uint8_t key, uint8_t velocity) = 0;
46
47 /** Called after the engine has processed the note on event */
48 virtual void PostProcessNoteOn(uint8_t key, uint8_t velocity) = 0;
49
50 /** Called before the engine start processing the note off event */
51 virtual void PreProcessNoteOff(uint8_t key, uint8_t velocity) = 0;
52
53 /** Called after the engine has processed the note off event */
54 virtual void PostProcessNoteOff(uint8_t key, uint8_t velocity) = 0;
55
56 /** Called before the engine start processing the sustain pedal up event */
57 virtual void PreProcessSustainPedalUp() = 0;
58
59 /** Called after the engine has processed the sustain pedal up event */
60 virtual void PostProcessSustainPedalUp() = 0;
61
62 /** Called before the engine start processing the sustain pedal down event */
63 virtual void PreProcessSustainPedalDown() = 0;
64
65 /** Called after the engine has processed the sustain pedal down event */
66 virtual void PostProcessSustainPedalDown() = 0;
67
68 /** Called before the engine start processing the sostenuto pedal up event */
69 virtual void PreProcessSostenutoPedalUp() = 0;
70
71 /** Called after the engine has processed the sostenuto pedal up event */
72 virtual void PostProcessSostenutoPedalUp() = 0;
73
74 /** Called before the engine start processing the sostenuto pedal down event */
75 virtual void PreProcessSostenutoPedalDown() = 0;
76
77 /** Called after the engine has processed the sostenuto pedal down event */
78 virtual void PostProcessSostenutoPedalDown() = 0;
79 };
80
81 /**
82 * This class exists as convenience for creating listener objects.
83 * The methods in this class are empty.
84 */
85 class MidiKeyboardAdapter : public MidiKeyboardListener {
86 public:
87 virtual void PreProcessNoteOn(uint8_t key, uint8_t velocity) { }
88 virtual void PostProcessNoteOn(uint8_t key, uint8_t velocity) { }
89 virtual void PreProcessNoteOff(uint8_t key, uint8_t velocity) { }
90 virtual void PostProcessNoteOff(uint8_t key, uint8_t velocity) { }
91 virtual void PreProcessSustainPedalUp() { }
92 virtual void PostProcessSustainPedalUp() { }
93 virtual void PreProcessSustainPedalDown() { }
94 virtual void PostProcessSustainPedalDown() { }
95 virtual void PreProcessSostenutoPedalUp() { }
96 virtual void PostProcessSostenutoPedalUp() { }
97 virtual void PreProcessSostenutoPedalDown() { }
98 virtual void PostProcessSostenutoPedalDown() { }
99 };
100
101 /**
102 * This is the base class for class MidiKeyboardManager::MidiKey. It is
103 * not intended to be instantiated directly. Instead it just defines
104 * the part of class MidiKey which is not dependant on a C++ template
105 * parameter.
106 *
107 * There are also ScriptEvent lists maintained for each key, which are not
108 * stored here though, but on the InstrumentScript structure. Simply because
109 * RTLists are tied to one Pool instance, and it would be error prone to
110 * maintain @c Pool<ScriptEvent> and @c RTList<ScriptEvent> separately,
111 * since one would need to be very careful to reallocate the lists when the
112 * script was changed or when the Engine instance changed, etc.
113 *
114 * @see InstrumentScript::pKeyEvents
115 */
116 class MidiKeyBase {
117 public:
118 bool KeyPressed; ///< Is true if the respective MIDI key is currently pressed.
119 bool Active; ///< If the key contains active voices.
120 bool ReleaseTrigger; ///< If we have to launch release triggered voice(s) when the key is released
121 Pool<uint>::Iterator itSelf; ///< hack to allow fast deallocation of the key from the list of active keys
122 RTList<Event>* pEvents; ///< Key specific events (only Note-on, Note-off and sustain pedal currently)
123 int VoiceTheftsQueued; ///< Amount of voices postponed due to shortage of voices.
124 uint32_t* pRoundRobinIndex; ///< For the round robin dimension: current articulation for this key, will be incremented for each note on
125 uint8_t Velocity; ///< Latest Note-on velocity for this key
126 unsigned long NoteOnTime; ///< Time for latest Note-on event for this key
127 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())
128 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())
129 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())
130 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())
131 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())
132 };
133
134 class MidiKeyboardManagerBase {
135 public:
136 Pool<uint>* pActiveKeys; ///< Holds all keys in it's allocation list with active voices.
137 bool SoloMode; ///< in Solo Mode we only play one voice (group) at a time
138 int SoloKey; ///< Currently 'active' solo key, that is the key to which the currently sounding voice belongs to (only if SoloMode is enabled)
139 bool SustainPedal; ///< true if sustain pedal is down
140 bool SostenutoPedal; ///< true if sostenuto pedal is down
141 int SostenutoKeys[128];
142 int SostenutoKeyCount;
143 uint32_t RoundRobinIndexes[128];
144 int8_t KeyDown[128]; ///< True if the respective key is currently pressed down. Currently only used as built-in instrument script array variable %KEY_DOWN. It is currently not used by the sampler for any other purpose.
145
146 virtual void ProcessReleaseTrigger(RTList<Event>::Iterator& itEvent) = 0;
147 };
148
149 template <class V>
150 class MidiKeyboardManager : public MidiKeyboardManagerBase {
151 public:
152 /** @brief Voice Stealing Algorithms
153 *
154 * Enumeration of all possible voice stealing algorithms.
155 */
156 enum voice_steal_algo_t {
157 voice_steal_algo_none, ///< Voice stealing disabled.
158 voice_steal_algo_oldestvoiceonkey, ///< Try to kill the oldest voice from same key where the new voice should be spawned.
159 voice_steal_algo_oldestkey ///< Try to kill the oldest voice from the oldest active key.
160 };
161
162
163 /** @brief MIDI key runtime informations
164 *
165 * Reflects runtime informations for one MIDI key.
166 */
167 class MidiKey : public MidiKeyBase {
168 public:
169 RTList< Note<V> >* pActiveNotes; ///< Contains the active notes associated with the MIDI key.
170
171 MidiKey() {
172 pActiveNotes = NULL;
173 KeyPressed = false;
174 Active = false;
175 ReleaseTrigger = false;
176 pEvents = NULL;
177 VoiceTheftsQueued = 0;
178 Volume = 1.0f;
179 PanLeft = 1.0f;
180 PanRight = 1.0f;
181 }
182
183 void Reset() {
184 if (pActiveNotes) {
185 RTListNoteIterator itNote = pActiveNotes->first();
186 RTListNoteIterator itNotesEnd = pActiveNotes->end();
187 for (; itNote != itNotesEnd; ++itNote) { // iterate through all active notes on this key
188 itNote->reset();
189 }
190 pActiveNotes->clear();
191 }
192 if (pEvents) pEvents->clear();
193 KeyPressed = false;
194 Active = false;
195 ReleaseTrigger = false;
196 itSelf = Pool<uint>::Iterator();
197 VoiceTheftsQueued = 0;
198 Volume = 1.0f;
199 PanLeft = 1.0f;
200 PanRight = 1.0f;
201 ReverbSend = optional<float>::nothing;
202 ChorusSend = optional<float>::nothing;
203 }
204 };
205
206 typedef typename RTList< Note<V> >::Iterator RTListNoteIterator;
207 typedef typename RTList<V>::Iterator RTListVoiceIterator;
208 typedef typename Pool<V>::Iterator PoolVoiceIterator;
209
210 /**
211 * Override this class to iterate through all active keys/voices
212 * using ProcessActiveVoices() method.
213 */
214 class VoiceHandler {
215 public:
216 /**
217 * @returns true if the voices on the specified key should be processed
218 * adn false to cancel the processing of the active voices for the
219 * specified key
220 */
221 virtual bool Process(MidiKey* pMidiKey) = 0;
222
223 virtual void Process(RTListVoiceIterator& itVoice) = 0;
224 };
225
226 class VoiceHandlerBase : public VoiceHandler {
227 public:
228 virtual bool Process(MidiKey* pMidiKey) { return true; }
229 virtual void Process(RTListVoiceIterator& itVoice) { }
230 };
231
232 MidiKey* pMIDIKeyInfo; ///< Contains all active voices sorted by MIDI key number and other informations to the respective MIDI key
233
234 MidiKeyboardManager(AbstractEngineChannel* pEngineChannel) {
235 pMIDIKeyInfo = new MidiKey[128];
236 pActiveKeys = new Pool<uint>(128);
237 SoloMode = false;
238 SustainPedal = false;
239 SostenutoPedal = false;
240 for (int i = 0 ; i < 128 ; i++) {
241 RoundRobinIndexes[i] = 0;
242 KeyDown[i] = false;
243
244 // by default use one counter for each key (the
245 // gig engine will change this to one counter per
246 // region)
247 pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i];
248 }
249 m_engineChannel = pEngineChannel;
250 m_voicePool = NULL;
251 }
252
253 virtual ~MidiKeyboardManager() {
254 listeners.RemoveAllListeners();
255 if (pActiveKeys) delete pActiveKeys;
256 if (pMIDIKeyInfo) delete[] pMIDIKeyInfo;
257 }
258
259 void Reset() {
260 SoloKey = -1; // no solo key active yet
261
262 // reset key info
263 for (uint i = 0; i < 128; i++) {
264 pMIDIKeyInfo[i].Reset();
265 KeyDown[i] = false;
266 if (m_engineChannel->pScript)
267 m_engineChannel->pScript->pKeyEvents[i]->clear();
268 }
269
270 // free all active keys
271 pActiveKeys->clear();
272 }
273
274 void AllocateActiveNotesLists(Pool< Note<V> >* pNotePool, Pool<V>* pVoicePool) {
275 DeleteActiveNotesLists();
276
277 m_voicePool = pVoicePool;
278
279 for (uint i = 0; i < 128; i++) {
280 pMIDIKeyInfo[i].pActiveNotes = new RTList< Note<V> >(pNotePool);
281 }
282 }
283
284 void DeleteActiveNotesLists() {
285 for (uint i = 0; i < 128; i++) {
286 if (pMIDIKeyInfo[i].pActiveNotes) {
287 delete pMIDIKeyInfo[i].pActiveNotes;
288 pMIDIKeyInfo[i].pActiveNotes = NULL;
289 }
290 }
291 m_voicePool = NULL;
292 }
293
294 void AllocateEventsLists(Pool<Event>* pEventPool) {
295 DeleteEventsLists();
296
297 for (uint i = 0; i < 128; i++) {
298 pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEventPool);
299 }
300 }
301
302 void DeleteEventsLists() {
303 for (uint i = 0; i < 128; i++) {
304 if (pMIDIKeyInfo[i].pEvents) {
305 delete pMIDIKeyInfo[i].pEvents;
306 pMIDIKeyInfo[i].pEvents = NULL;
307 }
308 }
309 }
310
311 /*void ClearAllActiveKeyEvents() {
312 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
313 RTList<uint>::Iterator end = pActiveKeys->end();
314 for(; iuiKey != end; ++iuiKey) {
315 pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key
316 }
317 }*/
318
319 /**
320 * Removes the given voice from the MIDI key's list of active voices.
321 * This method will be called when a voice went inactive, e.g. because
322 * it finished to playback its sample, finished its release stage or
323 * just was killed.
324 *
325 * @param itVoice - points to the voice to be freed
326 */
327 void FreeVoice(PoolVoiceIterator& itVoice) {
328 if (itVoice) {
329 //MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];
330
331 // if the sample and dimension region belong to an
332 // instrument that is unloaded, tell the disk thread to
333 // release them
334 if (itVoice->Orphan) {
335 if(itVoice->pDiskThread != NULL) {
336 itVoice->pDiskThread->OrderDeletionOfRegion(itVoice->GetRegion());
337 }
338 }
339
340 // free the voice object
341 m_voicePool->free(itVoice);
342 }
343 else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;
344 }
345
346 /**
347 * Called when there's no more voice left on a key, this call will
348 * update the key info respectively.
349 *
350 * @param pEngineChannel - engine channel on which this event occured on
351 * @param pKey - key which is now inactive
352 */
353 void FreeKey(MidiKey* pKey) {
354 if (pKey->pActiveNotes->isEmpty()) {
355 if (m_engineChannel->pScript)
356 m_engineChannel->pScript->pKeyEvents[pKey->itSelf]->clear();
357 pKey->Active = false;
358 pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
359 pKey->itSelf = RTList<uint>::Iterator();
360 pKey->ReleaseTrigger = false;
361 pKey->pEvents->clear();
362 dmsg(3,("Key has no more voices now\n"));
363 }
364 else dmsg(1,("MidiKeyboardManager: Oops, tried to free a key which contains voices.\n"));
365 }
366
367 /**
368 * Free all keys which have no active voices left
369 */
370 void FreeAllInactiveKyes() {
371 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
372 RTList<uint>::Iterator end = pActiveKeys->end();
373 while (iuiKey != end) { // iterate through all active keys
374 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
375 ++iuiKey;
376 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
377 itNotesEnd = pKey->pActiveNotes->end();
378 itNote != itNotesEnd; ++itNote)
379 { // iterate over all active notes on that key ...
380 if (itNote->pActiveVoices->isEmpty()) { // free note ...
381 itNote->reset();
382 pKey->pActiveNotes->free(itNote);
383 }
384 #if CONFIG_DEVMODE
385 else { // just a sanity check for debugging
386 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
387 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
388 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
389 if (itVoice->itKillEvent) {
390 dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));
391 }
392 }
393 }
394 #endif // CONFIG_DEVMODE
395 }
396 if (pKey->pActiveNotes->isEmpty()) FreeKey(pKey);
397 }
398 }
399
400 int StealVoice (
401 Pool<Event>::Iterator& itNoteOnEvent,
402 RTListVoiceIterator* LastStolenVoice,
403 RTListNoteIterator* LastStolenNote,
404 RTList<uint>::Iterator* LastStolenKey
405 ) {
406 RTListVoiceIterator itSelectedVoice;
407
408 // Select one voice for voice stealing
409 switch (CONFIG_VOICE_STEAL_ALGO) {
410
411 // try to pick the oldest voice on the key where the new
412 // voice should be spawned, if there is no voice on that
413 // key, or no voice left to kill, then procceed with
414 // 'oldestkey' algorithm
415 case voice_steal_algo_oldestvoiceonkey: {
416 MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
417 for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(),
418 itNotesEnd = pSelectedKey->pActiveNotes->end();
419 itNote != itNotesEnd; ++itNote)
420 {
421 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice)
422 if (itSelectedVoice->IsStealable()) // proceed iterating if voice was created in this audio fragment cycle
423 goto voiceFound; // selection succeeded
424 }
425 // if we haven't found a voice then proceed with algorithm 'oldestkey' ...
426 } // no break - intentional !
427
428 // try to pick the oldest voice on the oldest active key
429 // from the same engine channel
430 // (caution: must stay after 'oldestvoiceonkey' algorithm !)
431 case voice_steal_algo_oldestkey: {
432 // if we already stole in this fragment, try to proceed to steal on same note
433 if (*LastStolenVoice) {
434 itSelectedVoice = *LastStolenVoice;
435 do {
436 ++itSelectedVoice;
437 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
438 // found a "stealable" voice ?
439 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
440 // remember which voice we stole, so we can simply proceed on next voice stealing
441 *LastStolenVoice = itSelectedVoice;
442 break; // selection succeeded
443 }
444 }
445
446 // get (next) oldest note
447 if (*LastStolenNote) {
448 for (RTListNoteIterator itNote = ++(*LastStolenNote);
449 itNote; ++itNote)
450 {
451 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
452 // proceed iterating if voice was created in this audio fragment cycle
453 if (itSelectedVoice->IsStealable()) {
454 // remember which voice on which note we stole, so we can simply proceed on next voice stealing
455 *LastStolenNote = itNote;
456 *LastStolenVoice = itSelectedVoice;
457 goto voiceFound; // selection succeeded
458 }
459 }
460 }
461 }
462
463 // get (next) oldest key
464 RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first();
465 for (; iuiSelectedKey; ++iuiSelectedKey) {
466 MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey];
467
468 for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(),
469 itNotesEnd = pSelectedKey->pActiveNotes->end();
470 itNote != itNotesEnd; ++itNote)
471 {
472 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
473 // proceed iterating if voice was created in this audio fragment cycle
474 if (itSelectedVoice->IsStealable()) {
475 // remember which voice on which key we stole, so we can simply proceed on next voice stealing
476 *LastStolenKey = iuiSelectedKey;
477 *LastStolenNote = itNote;
478 *LastStolenVoice = itSelectedVoice;
479 goto voiceFound; // selection succeeded
480 }
481 }
482 }
483 }
484 break;
485 }
486
487 // don't steal anything
488 case voice_steal_algo_none:
489 default: {
490 dmsg(1,("No free voice (voice stealing disabled)!\n"));
491 return -1;
492 }
493 }
494
495 voiceFound:
496
497 if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1;
498
499 #if CONFIG_DEVMODE
500 if (!itSelectedVoice->IsActive()) {
501 dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));
502 return -1;
503 }
504 #endif // CONFIG_DEVMODE
505
506 // now kill the selected voice
507 itSelectedVoice->Kill(itNoteOnEvent);
508
509 return 0;
510 }
511
512 /**
513 * Releases all voices. All voices will go into
514 * the release stage and thus it might take some time (e.g. dependant to
515 * their envelope release time) until they actually die.
516 *
517 * @param itReleaseEvent - event which caused this releasing of all voices
518 */
519 void ReleaseAllVoices(Pool<Event>::Iterator& itReleaseEvent) {
520 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
521 while (iuiKey) {
522 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
523 ++iuiKey;
524 // append a 'release' event to the key's own event list
525 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
526 if (itNewEvent) {
527 *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)
528 itNewEvent->Type = Event::type_release; // transform event type
529 }
530 else dmsg(1,("Event pool emtpy!\n"));
531 }
532 }
533
534 /**
535 * Kill all active voices.
536 * @returns The number of voices.
537 */
538 int KillAllVoices(Pool<Event>::Iterator& itKillEvent) {
539 int count = 0;
540
541 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
542 RTList<uint>::Iterator end = pActiveKeys->end();
543 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
544 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
545
546 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
547 itNotesEnd = pKey->pActiveNotes->end();
548 itNote != itNotesEnd; ++itNote)
549 {
550 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
551 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
552 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
553 itVoice->Kill(itKillEvent);
554 count++;
555 }
556 }
557 }
558
559 return count;
560 }
561
562 /**
563 * Kill all voices the *die hard* way.
564 * @returns The number of pending stream deletions
565 */
566 int KillAllVoicesImmediately() {
567 int iPendingStreamDeletions = 0;
568
569 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
570 RTList<uint>::Iterator end = pActiveKeys->end();
571 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
572 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
573
574 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
575 itNotesEnd = pKey->pActiveNotes->end();
576 itNote != itNotesEnd; ++itNote)
577 {
578 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
579 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
580 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
581 // request a notification from disk thread side for stream deletion
582 const Stream::Handle hStream = itVoice->KillImmediately(true);
583 if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
584 iPendingStreamDeletions++;
585 }
586 // free the voice to the voice pool and update key info
587 itVoice->VoiceFreed();
588 FreeVoice(itVoice);
589 }
590 }
591 }
592
593 return iPendingStreamDeletions;
594 }
595
596 /**
597 * Mark all currently active voices as "orphans", which means that the regions and
598 * samples they use should be released to the instrument manager when the voices die.
599 */
600 void MarkAllActiveVoicesAsOrphans() {
601 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
602 RTList<uint>::Iterator end = pActiveKeys->end();
603 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
604 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
605
606 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
607 itNotesEnd = pKey->pActiveNotes->end();
608 itNote != itNotesEnd; ++itNote)
609 {
610 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
611 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
612 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
613 itVoice->Orphan = true;
614 }
615 }
616 }
617 }
618
619 void ProcessActiveVoices(VoiceHandler* pVoiceHandler) {
620 if (pVoiceHandler == NULL) return;
621
622 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
623 RTList<uint>::Iterator end = pActiveKeys->end();
624 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
625 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
626 if (!pVoiceHandler->Process(pKey)) continue;
627
628 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
629 itNotesEnd = pKey->pActiveNotes->end();
630 itNote != itNotesEnd; ++itNote)
631 {
632 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
633 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
634 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
635 pVoiceHandler->Process(itVoice);
636 }
637 }
638 }
639 }
640
641 /**
642 * Recalculate the pitch of all active voices.
643 */
644 void OnScaleTuningChanged() {
645 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
646 for (; iuiKey; ++iuiKey) {
647 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
648
649 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
650 itNotesEnd = pKey->pActiveNotes->end();
651 itNote != itNotesEnd; ++itNote)
652 {
653 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
654 for (; itVoice; ++itVoice) {
655 itVoice->onScaleTuningChanged();
656 }
657 }
658 }
659 }
660
661 void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) {
662 // Cancel release process of all voices
663 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
664 for (; iuiKey; ++iuiKey) {
665 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
666 if (!pKey->KeyPressed) {
667 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
668 if (itNewEvent) {
669 *itNewEvent = *itEvent; // copy event to the key's own event list
670 itNewEvent->Type = Event::type_cancel_release; // transform event type
671 }
672 else dmsg(1,("Event pool emtpy!\n"));
673 }
674 }
675 }
676
677 void ProcessSustainPedalUp(Pool<Event>::Iterator& itEvent) {
678 // release voices if their respective key is not pressed
679 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
680 for (; iuiKey; ++iuiKey) {
681 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
682 if (!pKey->KeyPressed && ShouldReleaseVoice(*iuiKey)) {
683 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
684 if (itNewEvent) {
685 *itNewEvent = *itEvent; // copy event to the key's own event list
686 itNewEvent->Type = Event::type_release; // transform event type
687 itNewEvent->Param.Note.Key = *iuiKey;
688 itNewEvent->Param.Note.Velocity = 127;
689 if (!SostenutoActiveOnKey(*iuiKey)) {
690 //HACK: set sustain CC (64) as "pressed down" for a short moment, so that release trigger voices can distinguish between note off and sustain pedal up cases
691 AbstractEngineChannel* pChannel = (AbstractEngineChannel*) itEvent->pEngineChannel;
692 const int8_t CC64Value = pChannel->ControllerTable[64];
693 pChannel->ControllerTable[64] = 127;
694
695 // now spawn release trigger voices (if required)
696 ProcessReleaseTrigger(itNewEvent);
697
698 //HACK: reset sustain pedal CC value to old one (see comment above)
699 pChannel->ControllerTable[64] = CC64Value;
700 }
701 }
702 else dmsg(1,("Event pool emtpy!\n"));
703 }
704 }
705 }
706
707 /**
708 * Whether @a key is still kept active due to sostenuto pedal usage.
709 *
710 * @param key - note number of key
711 */
712 inline bool SostenutoActiveOnKey(int key) const {
713 if (SostenutoPedal) {
714 for (int i = 0; i < SostenutoKeyCount; i++)
715 if (key == SostenutoKeys[i]) return true;
716 }
717 return false;
718 }
719
720 /**
721 * Determines whether the specified voice should be released.
722 *
723 * @param pEngineChannel - The engine channel on which the voice should be checked
724 * @param Key - The key number
725 * @returns true if the specified voice should be released, false otherwise.
726 */
727 bool ShouldReleaseVoice(int Key) {
728 if (SustainPedal) return false;
729 if (SostenutoActiveOnKey(Key)) return false;
730 return true;
731 }
732
733 void ProcessSostenutoPedalDown() {
734 SostenutoKeyCount = 0;
735 // Remeber the pressed keys
736 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
737 for (; iuiKey; ++iuiKey) {
738 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
739 if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
740 }
741 }
742
743 void ProcessSostenutoPedalUp(Pool<Event>::Iterator& itEvent) {
744 // release voices if the damper pedal is up and their respective key is not pressed
745 for (int i = 0; i < SostenutoKeyCount; i++) {
746 MidiKey* pKey = &pMIDIKeyInfo[SostenutoKeys[i]];
747 if (!pKey->KeyPressed && !SustainPedal) {
748 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
749 if (itNewEvent) {
750 *itNewEvent = *itEvent; // copy event to the key's own event list
751 itNewEvent->Type = Event::type_release; // transform event type
752 }
753 else dmsg(1,("Event pool emtpy!\n"));
754 }
755 }
756 }
757
758 void AddMidiKeyboardListener(MidiKeyboardListener* l) { listeners.AddListener(l); }
759
760 void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); }
761
762 protected:
763 AbstractEngineChannel* m_engineChannel;
764 Pool<V>* m_voicePool;
765
766 class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> {
767 public:
768 REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t)
769 REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOn, uint8_t, uint8_t)
770 REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOff, uint8_t, uint8_t)
771 REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOff, uint8_t, uint8_t)
772 REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalUp)
773 REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalUp)
774 REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalDown)
775 REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalDown)
776 REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalUp)
777 REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalUp)
778 REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalDown)
779 REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalDown)
780 } listeners;
781 };
782 } // namespace LinuxSampler
783
784 #endif /* __LS_MIDIKEYBOARDMANAGER_H__ */

  ViewVC Help
Powered by ViewVC