1 /*************************************************************************** 2 * * 3 * LinuxSampler - modular, streaming capable sampler * 4 * * 5 * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * 6 * Copyright (C) 2005-2020 Christian Schoenebeck * 7 * Copyright (C) 2009-2010 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: PreProcessNoteOn(uint8_t key,uint8_t velocity)87 virtual void PreProcessNoteOn(uint8_t key, uint8_t velocity) { } PostProcessNoteOn(uint8_t key,uint8_t velocity)88 virtual void PostProcessNoteOn(uint8_t key, uint8_t velocity) { } PreProcessNoteOff(uint8_t key,uint8_t velocity)89 virtual void PreProcessNoteOff(uint8_t key, uint8_t velocity) { } PostProcessNoteOff(uint8_t key,uint8_t velocity)90 virtual void PostProcessNoteOff(uint8_t key, uint8_t velocity) { } PreProcessSustainPedalUp()91 virtual void PreProcessSustainPedalUp() { } PostProcessSustainPedalUp()92 virtual void PostProcessSustainPedalUp() { } PreProcessSustainPedalDown()93 virtual void PreProcessSustainPedalDown() { } PostProcessSustainPedalDown()94 virtual void PostProcessSustainPedalDown() { } PreProcessSostenutoPedalUp()95 virtual void PreProcessSostenutoPedalUp() { } PostProcessSostenutoPedalUp()96 virtual void PostProcessSostenutoPedalUp() { } PreProcessSostenutoPedalDown()97 virtual void PreProcessSostenutoPedalDown() { } PostProcessSostenutoPedalDown()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 release_trigger_t ReleaseTrigger; ///< If we have to launch release triggered voice(s) when either the key or sustain pedal 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 ProcessReleaseTriggerBySustain(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 MidiKey()171 MidiKey() { 172 pActiveNotes = NULL; 173 KeyPressed = false; 174 Active = false; 175 ReleaseTrigger = release_trigger_none; 176 pEvents = NULL; 177 VoiceTheftsQueued = 0; 178 Volume = 1.0f; 179 PanLeft = 1.0f; 180 PanRight = 1.0f; 181 } 182 Reset()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 = release_trigger_none; 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: Process(MidiKey * pMidiKey)228 virtual bool Process(MidiKey* pMidiKey) { return true; } Process(RTListVoiceIterator & itVoice)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 MidiKeyboardManager(AbstractEngineChannel * pEngineChannel)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 ~MidiKeyboardManager()253 virtual ~MidiKeyboardManager() { 254 listeners.RemoveAllListeners(); 255 if (pActiveKeys) delete pActiveKeys; 256 if (pMIDIKeyInfo) delete[] pMIDIKeyInfo; 257 } 258 Reset()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 AllocateActiveNotesLists(Pool<Note<V>> * pNotePool,Pool<V> * pVoicePool)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 DeleteActiveNotesLists()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 AllocateEventsLists(Pool<Event> * pEventPool)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 DeleteEventsLists()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 * Make sure the passed MIDI key is part of the list of active keys, 321 * if it is not already, then add it to that list. Accordingly it is 322 * safe to call this method even if the requested key is already 323 * marked as active. 324 */ markKeyAsActive(MidiKey * pKey)325 void markKeyAsActive(MidiKey* pKey) { 326 if (!pKey->Active) { // mark as active key 327 pKey->Active = true; 328 pKey->itSelf = pActiveKeys->allocAppend(); 329 const int iKey = int( pKey - &pMIDIKeyInfo[0] ); 330 *pKey->itSelf = iKey; 331 } 332 } 333 334 /** 335 * Removes the given voice from the MIDI key's list of active voices. 336 * This method will be called when a voice went inactive, e.g. because 337 * it finished to playback its sample, finished its release stage or 338 * just was killed. 339 * 340 * @param itVoice - points to the voice to be freed 341 */ FreeVoice(PoolVoiceIterator & itVoice)342 void FreeVoice(PoolVoiceIterator& itVoice) { 343 if (itVoice) { 344 //MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey]; 345 346 // if the sample and dimension region belong to an 347 // instrument that is unloaded, tell the disk thread to 348 // release them 349 if (itVoice->Orphan) { 350 if(itVoice->pDiskThread != NULL) { 351 itVoice->pDiskThread->OrderDeletionOfRegion(itVoice->GetRegion()); 352 } 353 } 354 355 // free the voice object 356 m_voicePool->free(itVoice); 357 } 358 else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush; 359 } 360 361 /** 362 * Called when there's no more voice left on a key, this call will 363 * update the key info respectively. 364 * 365 * @param pEngineChannel - engine channel on which this event occured on 366 * @param pKey - key which is now inactive 367 */ FreeKey(MidiKey * pKey)368 void FreeKey(MidiKey* pKey) { 369 if (pKey->pActiveNotes->isEmpty()) { 370 if (m_engineChannel->pScript) 371 m_engineChannel->pScript->pKeyEvents[pKey->itSelf]->clear(); 372 pKey->Active = false; 373 pActiveKeys->free(pKey->itSelf); // remove key from list of active keys 374 pKey->itSelf = RTList<uint>::Iterator(); 375 pKey->ReleaseTrigger = release_trigger_none; 376 pKey->pEvents->clear(); 377 dmsg(3,("Key has no more voices now\n")); 378 } 379 else dmsg(1,("MidiKeyboardManager: Oops, tried to free a key which contains voices.\n")); 380 } 381 382 /** 383 * Free all keys which have no active voices left 384 */ FreeAllInactiveKeys()385 void FreeAllInactiveKeys() { 386 RTList<uint>::Iterator iuiKey = pActiveKeys->first(); 387 RTList<uint>::Iterator end = pActiveKeys->end(); 388 while (iuiKey != end) { // iterate through all active keys 389 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; 390 ++iuiKey; 391 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), 392 itNotesEnd = pKey->pActiveNotes->end(); 393 itNote != itNotesEnd; ++itNote) 394 { // iterate over all active notes on that key ... 395 if (itNote->pActiveVoices->isEmpty()) { // free note ... 396 itNote->reset(); 397 pKey->pActiveNotes->free(itNote); 398 } 399 #if CONFIG_DEVMODE 400 else { // just a sanity check for debugging 401 RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); 402 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); 403 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key 404 if (itVoice->itKillEvent) { 405 dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n")); 406 } 407 } 408 } 409 #endif // CONFIG_DEVMODE 410 } 411 if (pKey->pActiveNotes->isEmpty()) FreeKey(pKey); 412 } 413 } 414 StealVoice(Pool<Event>::Iterator & itNoteOnEvent,RTListVoiceIterator * LastStolenVoice,RTListNoteIterator * LastStolenNote,RTList<uint>::Iterator * LastStolenKey)415 int StealVoice ( 416 Pool<Event>::Iterator& itNoteOnEvent, 417 RTListVoiceIterator* LastStolenVoice, 418 RTListNoteIterator* LastStolenNote, 419 RTList<uint>::Iterator* LastStolenKey 420 ) { 421 RTListVoiceIterator itSelectedVoice; 422 423 // Select one voice for voice stealing 424 switch (CONFIG_VOICE_STEAL_ALGO) { 425 426 // try to pick the oldest voice on the key where the new 427 // voice should be spawned, if there is no voice on that 428 // key, or no voice left to kill, then procceed with 429 // 'oldestkey' algorithm 430 case voice_steal_algo_oldestvoiceonkey: { 431 MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key]; 432 for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(), 433 itNotesEnd = pSelectedKey->pActiveNotes->end(); 434 itNote != itNotesEnd; ++itNote) 435 { 436 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) 437 if (itSelectedVoice->IsStealable()) // proceed iterating if voice was created in this audio fragment cycle 438 goto voiceFound; // selection succeeded 439 } 440 // if we haven't found a voice then proceed with algorithm 'oldestkey' ... 441 } // no break - intentional ! 442 443 // try to pick the oldest voice on the oldest active key 444 // from the same engine channel 445 // (caution: must stay after 'oldestvoiceonkey' algorithm !) 446 case voice_steal_algo_oldestkey: { 447 // if we already stole in this fragment, try to proceed to steal on same note 448 if (*LastStolenVoice) { 449 itSelectedVoice = *LastStolenVoice; 450 do { 451 ++itSelectedVoice; 452 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle 453 // found a "stealable" voice ? 454 if (itSelectedVoice && itSelectedVoice->IsStealable()) { 455 // remember which voice we stole, so we can simply proceed on next voice stealing 456 *LastStolenVoice = itSelectedVoice; 457 break; // selection succeeded 458 } 459 } 460 461 // get (next) oldest note 462 if (*LastStolenNote) { 463 for (RTListNoteIterator itNote = ++(*LastStolenNote); 464 itNote; ++itNote) 465 { 466 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) { 467 // proceed iterating if voice was created in this audio fragment cycle 468 if (itSelectedVoice->IsStealable()) { 469 // remember which voice on which note we stole, so we can simply proceed on next voice stealing 470 *LastStolenNote = itNote; 471 *LastStolenVoice = itSelectedVoice; 472 goto voiceFound; // selection succeeded 473 } 474 } 475 } 476 } 477 478 // get (next) oldest key 479 RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first(); 480 for (; iuiSelectedKey; ++iuiSelectedKey) { 481 MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey]; 482 483 for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(), 484 itNotesEnd = pSelectedKey->pActiveNotes->end(); 485 itNote != itNotesEnd; ++itNote) 486 { 487 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) { 488 // proceed iterating if voice was created in this audio fragment cycle 489 if (itSelectedVoice->IsStealable()) { 490 // remember which voice on which key we stole, so we can simply proceed on next voice stealing 491 *LastStolenKey = iuiSelectedKey; 492 *LastStolenNote = itNote; 493 *LastStolenVoice = itSelectedVoice; 494 goto voiceFound; // selection succeeded 495 } 496 } 497 } 498 } 499 break; 500 } 501 502 // don't steal anything 503 case voice_steal_algo_none: 504 default: { 505 dmsg(1,("No free voice (voice stealing disabled)!\n")); 506 return -1; 507 } 508 } 509 510 voiceFound: 511 512 if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1; 513 514 #if CONFIG_DEVMODE 515 if (!itSelectedVoice->IsActive()) { 516 dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n")); 517 return -1; 518 } 519 #endif // CONFIG_DEVMODE 520 521 // now kill the selected voice 522 itSelectedVoice->Kill(itNoteOnEvent); 523 524 return 0; 525 } 526 527 /** 528 * Releases all voices. All voices will go into 529 * the release stage and thus it might take some time (e.g. dependant to 530 * their envelope release time) until they actually die. 531 * 532 * @param itReleaseEvent - event which caused this releasing of all voices 533 */ ReleaseAllVoices(Pool<Event>::Iterator & itReleaseEvent)534 void ReleaseAllVoices(Pool<Event>::Iterator& itReleaseEvent) { 535 RTList<uint>::Iterator iuiKey = pActiveKeys->first(); 536 while (iuiKey) { 537 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; 538 ++iuiKey; 539 // append a 'release' event to the key's own event list 540 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); 541 if (itNewEvent) { 542 *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list) 543 itNewEvent->Type = Event::type_release_key; // transform event type 544 } 545 else dmsg(1,("Event pool emtpy!\n")); 546 } 547 } 548 549 /** 550 * Kill all active voices. 551 * @returns The number of voices. 552 */ KillAllVoices(Pool<Event>::Iterator & itKillEvent)553 int KillAllVoices(Pool<Event>::Iterator& itKillEvent) { 554 int count = 0; 555 556 RTList<uint>::Iterator iuiKey = pActiveKeys->first(); 557 RTList<uint>::Iterator end = pActiveKeys->end(); 558 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys 559 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; 560 561 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), 562 itNotesEnd = pKey->pActiveNotes->end(); 563 itNote != itNotesEnd; ++itNote) 564 { 565 RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); 566 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); 567 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key 568 itVoice->Kill(itKillEvent); 569 count++; 570 } 571 } 572 } 573 574 return count; 575 } 576 577 /** 578 * Kill all voices the *die hard* way. 579 * @returns The number of pending stream deletions 580 */ KillAllVoicesImmediately()581 int KillAllVoicesImmediately() { 582 int iPendingStreamDeletions = 0; 583 584 RTList<uint>::Iterator iuiKey = pActiveKeys->first(); 585 RTList<uint>::Iterator end = pActiveKeys->end(); 586 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys 587 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; 588 589 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), 590 itNotesEnd = pKey->pActiveNotes->end(); 591 itNote != itNotesEnd; ++itNote) 592 { 593 RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); 594 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); 595 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key 596 // request a notification from disk thread side for stream deletion 597 const Stream::Handle hStream = itVoice->KillImmediately(true); 598 if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream 599 iPendingStreamDeletions++; 600 } 601 // free the voice to the voice pool and update key info 602 itVoice->VoiceFreed(); 603 FreeVoice(itVoice); 604 } 605 } 606 } 607 608 return iPendingStreamDeletions; 609 } 610 611 /** 612 * Mark all currently active voices as "orphans", which means that the regions and 613 * samples they use should be released to the instrument manager when the voices die. 614 */ MarkAllActiveVoicesAsOrphans()615 void MarkAllActiveVoicesAsOrphans() { 616 RTList<uint>::Iterator iuiKey = pActiveKeys->first(); 617 RTList<uint>::Iterator end = pActiveKeys->end(); 618 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys 619 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; 620 621 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), 622 itNotesEnd = pKey->pActiveNotes->end(); 623 itNote != itNotesEnd; ++itNote) 624 { 625 RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); 626 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); 627 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key 628 itVoice->Orphan = true; 629 } 630 } 631 } 632 } 633 ProcessActiveVoices(VoiceHandler * pVoiceHandler)634 void ProcessActiveVoices(VoiceHandler* pVoiceHandler) { 635 if (pVoiceHandler == NULL) return; 636 637 RTList<uint>::Iterator iuiKey = pActiveKeys->first(); 638 RTList<uint>::Iterator end = pActiveKeys->end(); 639 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys 640 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; 641 if (!pVoiceHandler->Process(pKey)) continue; 642 643 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), 644 itNotesEnd = pKey->pActiveNotes->end(); 645 itNote != itNotesEnd; ++itNote) 646 { 647 RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); 648 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); 649 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key 650 pVoiceHandler->Process(itVoice); 651 } 652 } 653 } 654 } 655 656 /** 657 * Recalculate the pitch of all active voices. 658 */ OnScaleTuningChanged()659 void OnScaleTuningChanged() { 660 RTList<uint>::Iterator iuiKey = pActiveKeys->first(); 661 for (; iuiKey; ++iuiKey) { 662 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; 663 664 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), 665 itNotesEnd = pKey->pActiveNotes->end(); 666 itNote != itNotesEnd; ++itNote) 667 { 668 RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); 669 for (; itVoice; ++itVoice) { 670 itVoice->onScaleTuningChanged(); 671 } 672 } 673 } 674 } 675 ProcessSustainPedalDown(Pool<Event>::Iterator & itEvent)676 void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) { 677 // Cancel release process of all voices 678 RTList<uint>::Iterator iuiKey = pActiveKeys->first(); 679 for (; iuiKey; ++iuiKey) { 680 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; 681 if (!pKey->KeyPressed) { 682 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); 683 if (itNewEvent) { 684 *itNewEvent = *itEvent; // copy event to the key's own event list 685 itNewEvent->Type = Event::type_cancel_release_key; // transform event type 686 } 687 else dmsg(1,("Event pool emtpy!\n")); 688 } 689 } 690 } 691 ProcessSustainPedalUp(Pool<Event>::Iterator & itEvent)692 void ProcessSustainPedalUp(Pool<Event>::Iterator& itEvent) { 693 // release voices if their respective key is not pressed 694 RTList<uint>::Iterator iuiKey = pActiveKeys->first(); 695 for (; iuiKey; ++iuiKey) { 696 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; 697 if (!pKey->KeyPressed && ShouldReleaseVoice(*iuiKey)) { 698 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); 699 if (itNewEvent) { 700 *itNewEvent = *itEvent; // copy event to the key's own event list 701 itNewEvent->Type = Event::type_release_key; // transform event type 702 itNewEvent->Param.Note.Key = *iuiKey; 703 itNewEvent->Param.Note.Velocity = 127; 704 705 // process release trigger (if requested) 706 if (pKey->ReleaseTrigger & release_trigger_sustain) { 707 if (pKey->ReleaseTrigger & release_trigger_sustain_keyvelocity) 708 itNewEvent->Param.Note.Velocity = pKey->Velocity; 709 710 //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 711 AbstractEngineChannel* pChannel = (AbstractEngineChannel*) itEvent->pEngineChannel; 712 const int8_t CC64Value = pChannel->ControllerTable[64]; 713 pChannel->ControllerTable[64] = 127; 714 715 // now spawn release trigger voices (if required) 716 ProcessReleaseTriggerBySustain(itNewEvent); 717 718 //HACK: reset sustain pedal CC value to old one (see comment above) 719 pChannel->ControllerTable[64] = CC64Value; 720 } 721 } 722 else dmsg(1,("Event pool emtpy!\n")); 723 } 724 } 725 } 726 727 /** 728 * Whether @a key is still kept active due to sostenuto pedal usage. 729 * 730 * @param key - note number of key 731 */ SostenutoActiveOnKey(int key)732 inline bool SostenutoActiveOnKey(int key) const { 733 if (SostenutoPedal) { 734 for (int i = 0; i < SostenutoKeyCount; i++) 735 if (key == SostenutoKeys[i]) return true; 736 } 737 return false; 738 } 739 740 /** 741 * Determines whether the specified voice should be released. 742 * 743 * @param pEngineChannel - The engine channel on which the voice should be checked 744 * @param Key - The key number 745 * @returns true if the specified voice should be released, false otherwise. 746 */ ShouldReleaseVoice(int Key)747 bool ShouldReleaseVoice(int Key) { 748 if (SustainPedal) return false; 749 if (SostenutoActiveOnKey(Key)) return false; 750 return true; 751 } 752 ProcessSostenutoPedalDown()753 void ProcessSostenutoPedalDown() { 754 SostenutoKeyCount = 0; 755 // Remeber the pressed keys 756 RTList<uint>::Iterator iuiKey = pActiveKeys->first(); 757 for (; iuiKey; ++iuiKey) { 758 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; 759 if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey; 760 } 761 } 762 ProcessSostenutoPedalUp(Pool<Event>::Iterator & itEvent)763 void ProcessSostenutoPedalUp(Pool<Event>::Iterator& itEvent) { 764 // release voices if the damper pedal is up and their respective key is not pressed 765 for (int i = 0; i < SostenutoKeyCount; i++) { 766 MidiKey* pKey = &pMIDIKeyInfo[SostenutoKeys[i]]; 767 if (!pKey->KeyPressed && !SustainPedal) { 768 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); 769 if (itNewEvent) { 770 *itNewEvent = *itEvent; // copy event to the key's own event list 771 itNewEvent->Type = Event::type_release_key; // transform event type 772 } 773 else dmsg(1,("Event pool emtpy!\n")); 774 } 775 } 776 } 777 AddMidiKeyboardListener(MidiKeyboardListener * l)778 void AddMidiKeyboardListener(MidiKeyboardListener* l) { listeners.AddListener(l); } 779 RemoveMidiKeyboardListener(MidiKeyboardListener * l)780 void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); } 781 782 protected: 783 AbstractEngineChannel* m_engineChannel; 784 Pool<V>* m_voicePool; 785 786 class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> { 787 public: 788 REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t) 789 REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOn, uint8_t, uint8_t) 790 REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOff, uint8_t, uint8_t) 791 REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOff, uint8_t, uint8_t) 792 REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalUp) 793 REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalUp) 794 REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalDown) 795 REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalDown) 796 REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalUp) 797 REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalUp) 798 REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalDown) 799 REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalDown) 800 } listeners; 801 }; 802 } // namespace LinuxSampler 803 804 #endif /* __LS_MIDIKEYBOARDMANAGER_H__ */ 805