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

Diff of /linuxsampler/trunk/src/engines/EngineBase.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2012 by iliev, Fri Oct 23 17:53:17 2009 UTC revision 2121 by schoenebeck, Tue Sep 14 17:09:08 2010 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2009 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009 Grigor Iliev                                       *   *   Copyright (C) 2009-2010 Christian Schoenebeck and Grigor Iliev        *
8   *                                                                         *   *                                                                         *
9   *   This program is free software; you can redistribute it and/or modify  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 299  namespace LinuxSampler { Line 299  namespace LinuxSampler {
299                      // lower minimum release time                      // lower minimum release time
300                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
301                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
302                          iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->pEG1->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
303                      }                      }
304                      pVoicePool->clear();                      pVoicePool->clear();
305                  }                  }
# Line 339  namespace LinuxSampler { Line 339  namespace LinuxSampler {
339                      }                      }
340                  }                  }
341                  pVoicePool->clear();                  pVoicePool->clear();
342                    
343                    // (re)create dedicated voice audio buffers
344                    //TODO: we could optimize resource usage a bit by just allocating these dedicated voice buffers when there is at least one engine channel with FX sends, because only in this case those special buffers are used actually, but since it would usually only save couple bytes in total, its probably not worth it
345                    if (pDedicatedVoiceChannelLeft)  delete pDedicatedVoiceChannelLeft;
346                    if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
347                    pDedicatedVoiceChannelLeft  = new AudioChannel(0, MaxSamplesPerCycle);
348                    pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
349              }              }
350    
351              /**              /**
# Line 564  namespace LinuxSampler { Line 571  namespace LinuxSampler {
571              int       MinFadeOutSamples;     ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.              int       MinFadeOutSamples;     ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.
572              D*        pDiskThread;              D*        pDiskThread;
573    
             int                          VoiceSpawnsLeft;       ///< We only allow CONFIG_MAX_VOICES voices to be spawned per audio fragment, we use this variable to ensure this limit.  
574              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)
575              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
576              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.
# Line 858  namespace LinuxSampler { Line 864  namespace LinuxSampler {
864                  pChannel->ClearEventLists();                  pChannel->ClearEventLists();
865              }              }
866    
867                /**
868                 * Process MIDI control change events with hard coded behavior,
869                 * that is controllers whose behavior is defined independently
870                 * of the actual sampler engine type and instrument.
871                 *
872                 * @param pEngineChannel - engine channel on which the MIDI CC event was received
873                 * @param itControlChangeEvent - the actual MIDI CC event
874                 */
875              void ProcessHardcodedControllers (              void ProcessHardcodedControllers (
876                  EngineChannel*          pEngineChannel,                  EngineChannel*          pEngineChannel,
877                  Pool<Event>::Iterator&  itControlChangeEvent                  Pool<Event>::Iterator&  itControlChangeEvent
# Line 870  namespace LinuxSampler { Line 884  namespace LinuxSampler {
884                          pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;                          pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
885                          break;                          break;
886                      }                      }
887                      case 6: { // data entry (currently only used for RPN controllers)                      case 6: { // data entry (currently only used for RPN and NRPN controllers)
888                          if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones                          //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
889                              int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;                          if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
890                              // limit to +- two octaves for now                              dmsg(4,("Guess it's an RPN ...\n"));
891                              transpose = RTMath::Min(transpose,  24);                              if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
892                              transpose = RTMath::Max(transpose, -24);                                  int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
893                              pChannel->GlobalTranspose = transpose;                                  // limit to +- two octaves for now
894                              // workaround, so we won't have hanging notes                                  transpose = RTMath::Min(transpose,  24);
895                              pChannel->ReleaseAllVoices(itControlChangeEvent);                                  transpose = RTMath::Max(transpose, -24);
896                                    pChannel->GlobalTranspose = transpose;
897                                    // workaround, so we won't have hanging notes
898                                    pChannel->ReleaseAllVoices(itControlChangeEvent);
899                                }
900                                // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
901                                pChannel->ResetMidiRpnController();
902                            } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
903                                dmsg(4,("Guess it's an NRPN ...\n"));
904                                const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
905                                const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
906                                dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
907                                switch (NrpnCtrlMSB) {
908                                    case 0x1a: { // volume level of note (Roland GS NRPN)
909                                        const uint note = NrpnCtrlLSB;
910                                        const uint vol  = itControlChangeEvent->Param.CC.Value;
911                                        dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
912                                        if (note < 128 && vol < 128)
913                                            pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
914                                        break;
915                                    }
916                                    case 0x1c: { // panpot of note (Roland GS NRPN)
917                                        const uint note = NrpnCtrlLSB;
918                                        const uint pan  = itControlChangeEvent->Param.CC.Value;
919                                        dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
920                                        if (note < 128 && pan < 128) {
921                                            pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];
922                                            pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
923                                        }
924                                        break;
925                                    }
926                                    case 0x1d: { // reverb send of note (Roland GS NRPN)
927                                        const uint note = NrpnCtrlLSB;
928                                        const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
929                                        dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));
930                                        if (note < 128)
931                                            pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
932                                        break;
933                                    }
934                                    case 0x1e: { // chorus send of note (Roland GS NRPN)
935                                        const uint note = NrpnCtrlLSB;
936                                        const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
937                                        dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));
938                                        if (note < 128)
939                                            pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
940                                        break;
941                                    }
942                                }
943                                // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
944                                pChannel->ResetMidiNrpnController();
945                          }                          }
                         // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data  
                         pChannel->ResetMidiRpnController();  
946                          break;                          break;
947                      }                      }
948                      case 7: { // volume                      case 7: { // volume
# Line 970  namespace LinuxSampler { Line 1031  namespace LinuxSampler {
1031                          }                          }
1032                          break;                          break;
1033                      }                      }
1034                        case 98: { // NRPN controller LSB
1035                            dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1036                            pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1037                            break;
1038                        }
1039                        case 99: { // NRPN controller MSB
1040                            dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1041                            pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1042                            break;
1043                        }
1044                      case 100: { // RPN controller LSB                      case 100: { // RPN controller LSB
1045                            dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1046                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1047                          break;                          break;
1048                      }                      }
1049                      case 101: { // RPN controller MSB                      case 101: { // RPN controller MSB
1050                            dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1051                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1052                          break;                          break;
1053                      }                      }
# Line 1065  namespace LinuxSampler { Line 1138  namespace LinuxSampler {
1138                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1139                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                              VoiceIterator end               = pOtherKey->pActiveVoices->end();
1140                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1141                                  if (itVoiceToBeKilled->Type != Voice::type_release_trigger)                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1142                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1143                              }                              }
1144                          }                          }
# Line 1097  namespace LinuxSampler { Line 1170  namespace LinuxSampler {
1170                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1171    
1172                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;
1173                  pKey->RoundRobinIndex++;                  if (pKey->pRoundRobinIndex) {
1174                        (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1175                        pChannel->RoundRobinIndex++; // common counter for the channel
1176                    }
1177                  pChannel->listeners.PostProcessNoteOn(key, vel);                  pChannel->listeners.PostProcessNoteOn(key, vel);
1178              }              }
1179    
# Line 1199  namespace LinuxSampler { Line 1275  namespace LinuxSampler {
1275                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1276                              VoiceIterator end               = pKey->pActiveVoices->end();                              VoiceIterator end               = pKey->pActiveVoices->end();
1277                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1278                                  if (itVoiceToBeKilled->Type != Voice::type_release_trigger)                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1279                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1280                              }                              }
1281                          }                          }
# Line 1304  namespace LinuxSampler { Line 1380  namespace LinuxSampler {
1380                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
1381              ) = 0;              ) = 0;
1382    
1383                virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
1384    
1385                int InitNewVoice (
1386                    EngineChannelBase<V, R, I>*  pChannel,
1387                    R*                           pRegion,
1388                    Pool<Event>::Iterator&       itNoteOnEvent,
1389                    Voice::type_t                VoiceType,
1390                    int                          iLayer,
1391                    int                          iKeyGroup,
1392                    bool                         ReleaseTriggerVoice,
1393                    bool                         VoiceStealing,
1394                    typename Pool<V>::Iterator&  itNewVoice
1395                ) {
1396                    int key = itNoteOnEvent->Param.Note.Key;
1397                    typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1398                    if (itNewVoice) {
1399                        // launch the new voice
1400                        if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1401                            dmsg(4,("Voice not triggered\n"));
1402                            pKey->pActiveVoices->free(itNewVoice);
1403                        }
1404                        else { // on success
1405                            --VoiceSpawnsLeft;
1406                            if (!pKey->Active) { // mark as active key
1407                                pKey->Active = true;
1408                                pKey->itSelf = pChannel->pActiveKeys->allocAppend();
1409                                *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1410                            }
1411                            if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1412                            return 0; // success
1413                        }
1414                    }
1415                    else if (VoiceStealing) {
1416                        // try to steal one voice
1417                        int result = StealVoice(pChannel, itNoteOnEvent);
1418                        if (!result) { // voice stolen successfully
1419                            // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1420                            RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1421                            if (itStealEvent) {
1422                                *itStealEvent = *itNoteOnEvent; // copy event
1423                                itStealEvent->Param.Note.Layer = iLayer;
1424                                itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1425                                pKey->VoiceTheftsQueued++;
1426                            }
1427                            else dmsg(1,("Voice stealing queue full!\n"));
1428                        }
1429                    }
1430    
1431                    return -1;
1432                }
1433    
1434          private:          private:
1435              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
1436              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;

Legend:
Removed from v.2012  
changed lines
  Added in v.2121

  ViewVC Help
Powered by ViewVC