/[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 2879 - (show annotations) (download) (as text)
Tue Apr 19 14:07:53 2016 UTC (8 years ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 38507 byte(s)
* All engines: Active voices are now internally grouped to "Note" objects,
  instead of being directly assigned to a keyboard key. This allows more
  fine graded processing of voices, which is i.e. required for certain
  instrument script features.
* Built-in script function "play_note()": Added support for passing
  special value -1 for "duration-us" argument, which will cause the
  triggered note to be released once the original note was released.
* Bumped version (2.0.0.svn3).

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
147 template <class V>
148 class MidiKeyboardManager : public MidiKeyboardManagerBase {
149 public:
150 /** @brief Voice Stealing Algorithms
151 *
152 * Enumeration of all possible voice stealing algorithms.
153 */
154 enum voice_steal_algo_t {
155 voice_steal_algo_none, ///< Voice stealing disabled.
156 voice_steal_algo_oldestvoiceonkey, ///< Try to kill the oldest voice from same key where the new voice should be spawned.
157 voice_steal_algo_oldestkey ///< Try to kill the oldest voice from the oldest active key.
158 };
159
160
161 /** @brief MIDI key runtime informations
162 *
163 * Reflects runtime informations for one MIDI key.
164 */
165 class MidiKey : public MidiKeyBase {
166 public:
167 RTList< Note<V> >* pActiveNotes; ///< Contains the active notes associated with the MIDI key.
168
169 MidiKey() {
170 pActiveNotes = NULL;
171 KeyPressed = false;
172 Active = false;
173 ReleaseTrigger = false;
174 pEvents = NULL;
175 VoiceTheftsQueued = 0;
176 Volume = 1.0f;
177 PanLeft = 1.0f;
178 PanRight = 1.0f;
179 }
180
181 void Reset() {
182 if (pActiveNotes) {
183 RTListNoteIterator itNote = pActiveNotes->first();
184 RTListNoteIterator itNotesEnd = pActiveNotes->end();
185 for (; itNote != itNotesEnd; ++itNote) { // iterate through all active notes on this key
186 itNote->reset();
187 }
188 pActiveNotes->clear();
189 }
190 if (pEvents) pEvents->clear();
191 KeyPressed = false;
192 Active = false;
193 ReleaseTrigger = false;
194 itSelf = Pool<uint>::Iterator();
195 VoiceTheftsQueued = 0;
196 Volume = 1.0f;
197 PanLeft = 1.0f;
198 PanRight = 1.0f;
199 ReverbSend = optional<float>::nothing;
200 ChorusSend = optional<float>::nothing;
201 }
202 };
203
204 typedef typename RTList< Note<V> >::Iterator RTListNoteIterator;
205 typedef typename RTList<V>::Iterator RTListVoiceIterator;
206 typedef typename Pool<V>::Iterator PoolVoiceIterator;
207
208 /**
209 * Override this class to iterate through all active keys/voices
210 * using ProcessActiveVoices() method.
211 */
212 class VoiceHandler {
213 public:
214 /**
215 * @returns true if the voices on the specified key should be processed
216 * adn false to cancel the processing of the active voices for the
217 * specified key
218 */
219 virtual bool Process(MidiKey* pMidiKey) = 0;
220
221 virtual void Process(RTListVoiceIterator& itVoice) = 0;
222 };
223
224 class VoiceHandlerBase : public VoiceHandler {
225 public:
226 virtual bool Process(MidiKey* pMidiKey) { return true; }
227 virtual void Process(RTListVoiceIterator& itVoice) { }
228 };
229
230 MidiKey* pMIDIKeyInfo; ///< Contains all active voices sorted by MIDI key number and other informations to the respective MIDI key
231
232 MidiKeyboardManager(AbstractEngineChannel* pEngineChannel) {
233 pMIDIKeyInfo = new MidiKey[128];
234 pActiveKeys = new Pool<uint>(128);
235 SoloMode = false;
236 SustainPedal = false;
237 SostenutoPedal = false;
238 for (int i = 0 ; i < 128 ; i++) {
239 RoundRobinIndexes[i] = 0;
240 KeyDown[i] = false;
241
242 // by default use one counter for each key (the
243 // gig engine will change this to one counter per
244 // region)
245 pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i];
246 }
247 m_engineChannel = pEngineChannel;
248 m_voicePool = NULL;
249 }
250
251 virtual ~MidiKeyboardManager() {
252 listeners.RemoveAllListeners();
253 if (pActiveKeys) delete pActiveKeys;
254 if (pMIDIKeyInfo) delete[] pMIDIKeyInfo;
255 }
256
257 void Reset() {
258 SoloKey = -1; // no solo key active yet
259
260 // reset key info
261 for (uint i = 0; i < 128; i++) {
262 pMIDIKeyInfo[i].Reset();
263 KeyDown[i] = false;
264 if (m_engineChannel->pScript)
265 m_engineChannel->pScript->pKeyEvents[i]->clear();
266 }
267
268 // free all active keys
269 pActiveKeys->clear();
270 }
271
272 void AllocateActiveNotesLists(Pool< Note<V> >* pNotePool, Pool<V>* pVoicePool) {
273 DeleteActiveNotesLists();
274
275 m_voicePool = pVoicePool;
276
277 for (uint i = 0; i < 128; i++) {
278 pMIDIKeyInfo[i].pActiveNotes = new RTList< Note<V> >(pNotePool);
279 }
280 }
281
282 void DeleteActiveNotesLists() {
283 for (uint i = 0; i < 128; i++) {
284 if (pMIDIKeyInfo[i].pActiveNotes) {
285 delete pMIDIKeyInfo[i].pActiveNotes;
286 pMIDIKeyInfo[i].pActiveNotes = NULL;
287 }
288 }
289 m_voicePool = NULL;
290 }
291
292 void AllocateEventsLists(Pool<Event>* pEventPool) {
293 DeleteEventsLists();
294
295 for (uint i = 0; i < 128; i++) {
296 pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEventPool);
297 }
298 }
299
300 void DeleteEventsLists() {
301 for (uint i = 0; i < 128; i++) {
302 if (pMIDIKeyInfo[i].pEvents) {
303 delete pMIDIKeyInfo[i].pEvents;
304 pMIDIKeyInfo[i].pEvents = NULL;
305 }
306 }
307 }
308
309 /*void ClearAllActiveKeyEvents() {
310 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
311 RTList<uint>::Iterator end = pActiveKeys->end();
312 for(; iuiKey != end; ++iuiKey) {
313 pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key
314 }
315 }*/
316
317 /**
318 * Removes the given voice from the MIDI key's list of active voices.
319 * This method will be called when a voice went inactive, e.g. because
320 * it finished to playback its sample, finished its release stage or
321 * just was killed.
322 *
323 * @param itVoice - points to the voice to be freed
324 */
325 void FreeVoice(PoolVoiceIterator& itVoice) {
326 if (itVoice) {
327 //MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];
328
329 // if the sample and dimension region belong to an
330 // instrument that is unloaded, tell the disk thread to
331 // release them
332 if (itVoice->Orphan) {
333 if(itVoice->pDiskThread != NULL) {
334 itVoice->pDiskThread->OrderDeletionOfRegion(itVoice->GetRegion());
335 }
336 }
337
338 // free the voice object
339 m_voicePool->free(itVoice);
340 }
341 else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;
342 }
343
344 /**
345 * Called when there's no more voice left on a key, this call will
346 * update the key info respectively.
347 *
348 * @param pEngineChannel - engine channel on which this event occured on
349 * @param pKey - key which is now inactive
350 */
351 void FreeKey(MidiKey* pKey) {
352 if (pKey->pActiveNotes->isEmpty()) {
353 if (m_engineChannel->pScript)
354 m_engineChannel->pScript->pKeyEvents[pKey->itSelf]->clear();
355 pKey->Active = false;
356 pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
357 pKey->itSelf = RTList<uint>::Iterator();
358 pKey->ReleaseTrigger = false;
359 pKey->pEvents->clear();
360 dmsg(3,("Key has no more voices now\n"));
361 }
362 else dmsg(1,("MidiKeyboardManager: Oops, tried to free a key which contains voices.\n"));
363 }
364
365 /**
366 * Free all keys which have no active voices left
367 */
368 void FreeAllInactiveKyes() {
369 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
370 RTList<uint>::Iterator end = pActiveKeys->end();
371 while (iuiKey != end) { // iterate through all active keys
372 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
373 ++iuiKey;
374 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
375 itNotesEnd = pKey->pActiveNotes->end();
376 itNote != itNotesEnd; ++itNote)
377 { // iterate over all active notes on that key ...
378 if (itNote->pActiveVoices->isEmpty()) { // free note ...
379 itNote->reset();
380 pKey->pActiveNotes->free(itNote);
381 }
382 #if CONFIG_DEVMODE
383 else { // just a sanity check for debugging
384 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
385 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
386 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
387 if (itVoice->itKillEvent) {
388 dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));
389 }
390 }
391 }
392 #endif // CONFIG_DEVMODE
393 }
394 if (pKey->pActiveNotes->isEmpty()) FreeKey(pKey);
395 }
396 }
397
398 int StealVoice (
399 Pool<Event>::Iterator& itNoteOnEvent,
400 RTListVoiceIterator* LastStolenVoice,
401 RTListNoteIterator* LastStolenNote,
402 RTList<uint>::Iterator* LastStolenKey
403 ) {
404 RTListVoiceIterator itSelectedVoice;
405
406 // Select one voice for voice stealing
407 switch (CONFIG_VOICE_STEAL_ALGO) {
408
409 // try to pick the oldest voice on the key where the new
410 // voice should be spawned, if there is no voice on that
411 // key, or no voice left to kill, then procceed with
412 // 'oldestkey' algorithm
413 case voice_steal_algo_oldestvoiceonkey: {
414 MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
415 for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(),
416 itNotesEnd = pSelectedKey->pActiveNotes->end();
417 itNote != itNotesEnd; ++itNote)
418 {
419 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice)
420 if (itSelectedVoice->IsStealable()) // proceed iterating if voice was created in this audio fragment cycle
421 goto voiceFound; // selection succeeded
422 }
423 // if we haven't found a voice then proceed with algorithm 'oldestkey' ...
424 } // no break - intentional !
425
426 // try to pick the oldest voice on the oldest active key
427 // from the same engine channel
428 // (caution: must stay after 'oldestvoiceonkey' algorithm !)
429 case voice_steal_algo_oldestkey: {
430 // if we already stole in this fragment, try to proceed to steal on same note
431 if (*LastStolenVoice) {
432 itSelectedVoice = *LastStolenVoice;
433 do {
434 ++itSelectedVoice;
435 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
436 // found a "stealable" voice ?
437 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
438 // remember which voice we stole, so we can simply proceed on next voice stealing
439 *LastStolenVoice = itSelectedVoice;
440 break; // selection succeeded
441 }
442 }
443
444 // get (next) oldest note
445 if (*LastStolenNote) {
446 for (RTListNoteIterator itNote = ++(*LastStolenNote);
447 itNote; ++itNote)
448 {
449 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
450 // proceed iterating if voice was created in this audio fragment cycle
451 if (itSelectedVoice->IsStealable()) {
452 // remember which voice on which note we stole, so we can simply proceed on next voice stealing
453 *LastStolenNote = itNote;
454 *LastStolenVoice = itSelectedVoice;
455 goto voiceFound; // selection succeeded
456 }
457 }
458 }
459 }
460
461 // get (next) oldest key
462 RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first();
463 for (; iuiSelectedKey; ++iuiSelectedKey) {
464 MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey];
465
466 for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(),
467 itNotesEnd = pSelectedKey->pActiveNotes->end();
468 itNote != itNotesEnd; ++itNote)
469 {
470 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
471 // proceed iterating if voice was created in this audio fragment cycle
472 if (itSelectedVoice->IsStealable()) {
473 // remember which voice on which key we stole, so we can simply proceed on next voice stealing
474 *LastStolenKey = iuiSelectedKey;
475 *LastStolenNote = itNote;
476 *LastStolenVoice = itSelectedVoice;
477 goto voiceFound; // selection succeeded
478 }
479 }
480 }
481 }
482 break;
483 }
484
485 // don't steal anything
486 case voice_steal_algo_none:
487 default: {
488 dmsg(1,("No free voice (voice stealing disabled)!\n"));
489 return -1;
490 }
491 }
492
493 voiceFound:
494
495 if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1;
496
497 #if CONFIG_DEVMODE
498 if (!itSelectedVoice->IsActive()) {
499 dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));
500 return -1;
501 }
502 #endif // CONFIG_DEVMODE
503
504 // now kill the selected voice
505 itSelectedVoice->Kill(itNoteOnEvent);
506
507 return 0;
508 }
509
510 /**
511 * Releases all voices. All voices will go into
512 * the release stage and thus it might take some time (e.g. dependant to
513 * their envelope release time) until they actually die.
514 *
515 * @param itReleaseEvent - event which caused this releasing of all voices
516 */
517 void ReleaseAllVoices(Pool<Event>::Iterator& itReleaseEvent) {
518 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
519 while (iuiKey) {
520 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
521 ++iuiKey;
522 // append a 'release' event to the key's own event list
523 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
524 if (itNewEvent) {
525 *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)
526 itNewEvent->Type = Event::type_release; // transform event type
527 }
528 else dmsg(1,("Event pool emtpy!\n"));
529 }
530 }
531
532 /**
533 * Kill all active voices.
534 * @returns The number of voices.
535 */
536 int KillAllVoices(Pool<Event>::Iterator& itKillEvent) {
537 int count = 0;
538
539 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
540 RTList<uint>::Iterator end = pActiveKeys->end();
541 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
542 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
543
544 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
545 itNotesEnd = pKey->pActiveNotes->end();
546 itNote != itNotesEnd; ++itNote)
547 {
548 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
549 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
550 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
551 itVoice->Kill(itKillEvent);
552 count++;
553 }
554 }
555 }
556
557 return count;
558 }
559
560 /**
561 * Kill all voices the *die hard* way.
562 * @returns The number of pending stream deletions
563 */
564 int KillAllVoicesImmediately() {
565 int iPendingStreamDeletions = 0;
566
567 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
568 RTList<uint>::Iterator end = pActiveKeys->end();
569 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
570 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
571
572 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
573 itNotesEnd = pKey->pActiveNotes->end();
574 itNote != itNotesEnd; ++itNote)
575 {
576 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
577 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
578 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
579 // request a notification from disk thread side for stream deletion
580 const Stream::Handle hStream = itVoice->KillImmediately(true);
581 if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
582 iPendingStreamDeletions++;
583 }
584 // free the voice to the voice pool and update key info
585 itVoice->VoiceFreed();
586 FreeVoice(itVoice);
587 }
588 }
589 }
590
591 return iPendingStreamDeletions;
592 }
593
594 /**
595 * Mark all currently active voices as "orphans", which means that the regions and
596 * samples they use should be released to the instrument manager when the voices die.
597 */
598 void MarkAllActiveVoicesAsOrphans() {
599 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
600 RTList<uint>::Iterator end = pActiveKeys->end();
601 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
602 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
603
604 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
605 itNotesEnd = pKey->pActiveNotes->end();
606 itNote != itNotesEnd; ++itNote)
607 {
608 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
609 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
610 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
611 itVoice->Orphan = true;
612 }
613 }
614 }
615 }
616
617 void ProcessActiveVoices(VoiceHandler* pVoiceHandler) {
618 if (pVoiceHandler == NULL) return;
619
620 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
621 RTList<uint>::Iterator end = pActiveKeys->end();
622 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
623 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
624 if (!pVoiceHandler->Process(pKey)) continue;
625
626 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
627 itNotesEnd = pKey->pActiveNotes->end();
628 itNote != itNotesEnd; ++itNote)
629 {
630 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
631 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
632 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
633 pVoiceHandler->Process(itVoice);
634 }
635 }
636 }
637 }
638
639 /**
640 * Recalculate the pitch of all active voices.
641 */
642 void OnScaleTuningChanged() {
643 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
644 for (; iuiKey; ++iuiKey) {
645 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
646
647 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
648 itNotesEnd = pKey->pActiveNotes->end();
649 itNote != itNotesEnd; ++itNote)
650 {
651 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
652 for (; itVoice; ++itVoice) {
653 itVoice->onScaleTuningChanged();
654 }
655 }
656 }
657 }
658
659 void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) {
660 // Cancel release process of all voices
661 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
662 for (; iuiKey; ++iuiKey) {
663 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
664 if (!pKey->KeyPressed) {
665 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
666 if (itNewEvent) {
667 *itNewEvent = *itEvent; // copy event to the key's own event list
668 itNewEvent->Type = Event::type_cancel_release; // transform event type
669 }
670 else dmsg(1,("Event pool emtpy!\n"));
671 }
672 }
673 }
674
675 void ProcessSustainPedalUp(Pool<Event>::Iterator& itEvent) {
676 // release voices if their respective key is not pressed
677 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
678 for (; iuiKey; ++iuiKey) {
679 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
680 if (!pKey->KeyPressed && ShouldReleaseVoice(*iuiKey)) {
681 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
682 if (itNewEvent) {
683 *itNewEvent = *itEvent; // copy event to the key's own event list
684 itNewEvent->Type = Event::type_release; // transform event type
685 }
686 else dmsg(1,("Event pool emtpy!\n"));
687 }
688 }
689 }
690
691 /**
692 * Determines whether the specified voice should be released.
693 *
694 * @param pEngineChannel - The engine channel on which the voice should be checked
695 * @param Key - The key number
696 * @returns true if the specified voice should be released, false otherwise.
697 */
698 bool ShouldReleaseVoice(int Key) {
699 if (SustainPedal) return false;
700
701 if (SostenutoPedal) {
702 for (int i = 0; i < SostenutoKeyCount; i++)
703 if (Key == SostenutoKeys[i]) return false;
704 }
705
706 return true;
707 }
708
709 void ProcessSostenutoPedalDown() {
710 SostenutoKeyCount = 0;
711 // Remeber the pressed keys
712 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
713 for (; iuiKey; ++iuiKey) {
714 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
715 if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
716 }
717 }
718
719 void ProcessSostenutoPedalUp(Pool<Event>::Iterator& itEvent) {
720 // release voices if the damper pedal is up and their respective key is not pressed
721 for (int i = 0; i < SostenutoKeyCount; i++) {
722 MidiKey* pKey = &pMIDIKeyInfo[SostenutoKeys[i]];
723 if (!pKey->KeyPressed && !SustainPedal) {
724 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
725 if (itNewEvent) {
726 *itNewEvent = *itEvent; // copy event to the key's own event list
727 itNewEvent->Type = Event::type_release; // transform event type
728 }
729 else dmsg(1,("Event pool emtpy!\n"));
730 }
731 }
732 }
733
734 void AddMidiKeyboardListener(MidiKeyboardListener* l) { listeners.AddListener(l); }
735
736 void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); }
737
738 protected:
739 AbstractEngineChannel* m_engineChannel;
740 Pool<V>* m_voicePool;
741
742 class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> {
743 public:
744 REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t)
745 REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOn, uint8_t, uint8_t)
746 REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOff, uint8_t, uint8_t)
747 REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOff, uint8_t, uint8_t)
748 REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalUp)
749 REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalUp)
750 REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalDown)
751 REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalDown)
752 REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalUp)
753 REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalUp)
754 REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalDown)
755 REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalDown)
756 } listeners;
757 };
758 } // namespace LinuxSampler
759
760 #endif /* __LS_MIDIKEYBOARDMANAGER_H__ */

  ViewVC Help
Powered by ViewVC