/[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 2015 by iliev, Sun Oct 25 22:22:52 2009 UTC revision 2244 by iliev, Thu Aug 18 11:32:33 2011 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-2011 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 190  namespace LinuxSampler { Line 190  namespace LinuxSampler {
190                  // been deleted by the disk thread                  // been deleted by the disk thread
191                  if (iPendingStreamDeletions) ProcessPendingStreamDeletions();                  if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
192    
193                    // Release the instrument change command. (This has to
194                    // be done after all voices have been rendered and not
195                    // in HandleInstrumentChanges, as the RegionsInUse
196                    // list has been built up by the voice renderers.)
197                    for (int i = 0; i < engineChannels.size(); i++) {
198                        EngineChannelBase<V, R, I>* channel =
199                            static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
200                        channel->InstrumentChangeCommandReader.Unlock();
201                    }
202                  FrameTime += Samples;                  FrameTime += Samples;
203    
204                  EngineDisabled.RttDone();                  EngineDisabled.RttDone();
# Line 234  namespace LinuxSampler { Line 243  namespace LinuxSampler {
243                  }                  }
244                  pVoicePool->clear();                  pVoicePool->clear();
245    
246                    PostSetMaxVoices(iVoices);
247                  ResumeAll();                  ResumeAll();
248              }              }
249                
250                /** Called after the new max number of voices is set and before resuming the engine. */
251                virtual void PostSetMaxVoices(int iVoices) { }
252    
253              virtual uint DiskStreamCount() { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }              virtual uint DiskStreamCount() { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }
254              virtual uint DiskStreamCountMax() { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }              virtual uint DiskStreamCountMax() { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }
# Line 299  namespace LinuxSampler { Line 312  namespace LinuxSampler {
312                      // lower minimum release time                      // lower minimum release time
313                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
314                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
315                          iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->pEG1->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
316                      }                      }
317                      pVoicePool->clear();                      pVoicePool->clear();
318                  }                  }
# Line 339  namespace LinuxSampler { Line 352  namespace LinuxSampler {
352                      }                      }
353                  }                  }
354                  pVoicePool->clear();                  pVoicePool->clear();
355                    
356                    // (re)create dedicated voice audio buffers
357                    //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
358                    if (pDedicatedVoiceChannelLeft)  delete pDedicatedVoiceChannelLeft;
359                    if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
360                    pDedicatedVoiceChannelLeft  = new AudioChannel(0, MaxSamplesPerCycle);
361                    pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
362              }              }
363    
364              /**              /**
# Line 530  namespace LinuxSampler { Line 550  namespace LinuxSampler {
550    
551              //friend class EngineChannelBase<V, R, I>;              //friend class EngineChannelBase<V, R, I>;
552    
553                static IM instruments;
554    
555          protected:          protected:
556              class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {              class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
557              public:              public:
# Line 558  namespace LinuxSampler { Line 580  namespace LinuxSampler {
580                  }                  }
581              };              };
582    
             static IM instruments;  
   
583              Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.              Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.
584              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.
585              D*        pDiskThread;              D*        pDiskThread;
586    
             int                          VoiceSpawnsLeft;       ///< We only allow CONFIG_MAX_VOICES voices to be spawned per audio fragment, we use this variable to ensure this limit.  
587              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)
588              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.
589              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 766  namespace LinuxSampler { Line 785  namespace LinuxSampler {
785                      //TODO: this is a lazy solution ATM and not safe in case somebody is currently editing the instrument we're currently switching to (we should store all suspended regions on instrument manager side and when switching to another instrument copy that list to the engine's local list of suspensions                      //TODO: this is a lazy solution ATM and not safe in case somebody is currently editing the instrument we're currently switching to (we should store all suspended regions on instrument manager side and when switching to another instrument copy that list to the engine's local list of suspensions
786                      ResetSuspendedRegions();                      ResetSuspendedRegions();
787                  }                  }
   
                 for (int i = 0; i < engineChannels.size(); i++) {  
                     EngineChannelBase<V, R, I>* channel =  
                         static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);  
                     channel->InstrumentChangeCommandReader.Unlock();  
                 }  
788              }              }
789    
790              /**              /**
# Line 858  namespace LinuxSampler { Line 871  namespace LinuxSampler {
871                  pChannel->ClearEventLists();                  pChannel->ClearEventLists();
872              }              }
873    
874                /**
875                 * Process MIDI control change events with hard coded behavior,
876                 * that is controllers whose behavior is defined independently
877                 * of the actual sampler engine type and instrument.
878                 *
879                 * @param pEngineChannel - engine channel on which the MIDI CC event was received
880                 * @param itControlChangeEvent - the actual MIDI CC event
881                 */
882              void ProcessHardcodedControllers (              void ProcessHardcodedControllers (
883                  EngineChannel*          pEngineChannel,                  EngineChannel*          pEngineChannel,
884                  Pool<Event>::Iterator&  itControlChangeEvent                  Pool<Event>::Iterator&  itControlChangeEvent
# Line 870  namespace LinuxSampler { Line 891  namespace LinuxSampler {
891                          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;
892                          break;                          break;
893                      }                      }
894                      case 6: { // data entry (currently only used for RPN controllers)                      case 6: { // data entry (currently only used for RPN and NRPN controllers)
895                          if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones                          //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
896                              int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;                          if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
897                              // limit to +- two octaves for now                              dmsg(4,("Guess it's an RPN ...\n"));
898                              transpose = RTMath::Min(transpose,  24);                              if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
899                              transpose = RTMath::Max(transpose, -24);                                  int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
900                              pChannel->GlobalTranspose = transpose;                                  // limit to +- two octaves for now
901                              // workaround, so we won't have hanging notes                                  transpose = RTMath::Min(transpose,  24);
902                              pChannel->ReleaseAllVoices(itControlChangeEvent);                                  transpose = RTMath::Max(transpose, -24);
903                                    pChannel->GlobalTranspose = transpose;
904                                    // workaround, so we won't have hanging notes
905                                    pChannel->ReleaseAllVoices(itControlChangeEvent);
906                                }
907                                // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
908                                pChannel->ResetMidiRpnController();
909                            } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
910                                dmsg(4,("Guess it's an NRPN ...\n"));
911                                const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
912                                const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
913                                dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
914                                switch (NrpnCtrlMSB) {
915                                    case 0x1a: { // volume level of note (Roland GS NRPN)
916                                        const uint note = NrpnCtrlLSB;
917                                        const uint vol  = itControlChangeEvent->Param.CC.Value;
918                                        dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
919                                        if (note < 128 && vol < 128)
920                                            pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
921                                        break;
922                                    }
923                                    case 0x1c: { // panpot of note (Roland GS NRPN)
924                                        const uint note = NrpnCtrlLSB;
925                                        const uint pan  = itControlChangeEvent->Param.CC.Value;
926                                        dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
927                                        if (note < 128 && pan < 128) {
928                                            pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];
929                                            pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
930                                        }
931                                        break;
932                                    }
933                                    case 0x1d: { // reverb send of note (Roland GS NRPN)
934                                        const uint note = NrpnCtrlLSB;
935                                        const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
936                                        dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));
937                                        if (note < 128)
938                                            pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
939                                        break;
940                                    }
941                                    case 0x1e: { // chorus send of note (Roland GS NRPN)
942                                        const uint note = NrpnCtrlLSB;
943                                        const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
944                                        dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));
945                                        if (note < 128)
946                                            pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
947                                        break;
948                                    }
949                                }
950                                // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
951                                pChannel->ResetMidiNrpnController();
952                          }                          }
                         // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data  
                         pChannel->ResetMidiRpnController();  
953                          break;                          break;
954                      }                      }
955                      case 7: { // volume                      case 7: { // volume
# Line 970  namespace LinuxSampler { Line 1038  namespace LinuxSampler {
1038                          }                          }
1039                          break;                          break;
1040                      }                      }
1041                        case 98: { // NRPN controller LSB
1042                            dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1043                            pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1044                            break;
1045                        }
1046                        case 99: { // NRPN controller MSB
1047                            dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1048                            pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1049                            break;
1050                        }
1051                      case 100: { // RPN controller LSB                      case 100: { // RPN controller LSB
1052                            dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1053                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1054                          break;                          break;
1055                      }                      }
1056                      case 101: { // RPN controller MSB                      case 101: { // RPN controller MSB
1057                            dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1058                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1059                          break;                          break;
1060                      }                      }
# Line 1065  namespace LinuxSampler { Line 1145  namespace LinuxSampler {
1145                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1146                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                              VoiceIterator end               = pOtherKey->pActiveVoices->end();
1147                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1148                                  if (itVoiceToBeKilled->Type != Voice::type_release_trigger)                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1149                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1150                              }                              }
1151                          }                          }
# Line 1097  namespace LinuxSampler { Line 1177  namespace LinuxSampler {
1177                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1178    
1179                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;
1180                  pKey->RoundRobinIndex++;                  if (pKey->pRoundRobinIndex) {
1181                        (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1182                        pChannel->RoundRobinIndex++; // common counter for the channel
1183                    }
1184                  pChannel->listeners.PostProcessNoteOn(key, vel);                  pChannel->listeners.PostProcessNoteOn(key, vel);
1185              }              }
1186    
# Line 1199  namespace LinuxSampler { Line 1282  namespace LinuxSampler {
1282                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1283                              VoiceIterator end               = pKey->pActiveVoices->end();                              VoiceIterator end               = pKey->pActiveVoices->end();
1284                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1285                                  if (itVoiceToBeKilled->Type != Voice::type_release_trigger)                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1286                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1287                              }                              }
1288                          }                          }
# Line 1306  namespace LinuxSampler { Line 1389  namespace LinuxSampler {
1389    
1390              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
1391    
1392                int InitNewVoice (
1393                    EngineChannelBase<V, R, I>*  pChannel,
1394                    R*                           pRegion,
1395                    Pool<Event>::Iterator&       itNoteOnEvent,
1396                    Voice::type_t                VoiceType,
1397                    int                          iLayer,
1398                    int                          iKeyGroup,
1399                    bool                         ReleaseTriggerVoice,
1400                    bool                         VoiceStealing,
1401                    typename Pool<V>::Iterator&  itNewVoice
1402                ) {
1403                    int key = itNoteOnEvent->Param.Note.Key;
1404                    typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1405                    if (itNewVoice) {
1406                        // launch the new voice
1407                        if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1408                            dmsg(4,("Voice not triggered\n"));
1409                            pKey->pActiveVoices->free(itNewVoice);
1410                        }
1411                        else { // on success
1412                            --VoiceSpawnsLeft;
1413                            if (!pKey->Active) { // mark as active key
1414                                pKey->Active = true;
1415                                pKey->itSelf = pChannel->pActiveKeys->allocAppend();
1416                                *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1417                            }
1418                            if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1419                            return 0; // success
1420                        }
1421                    }
1422                    else if (VoiceStealing) {
1423                        // try to steal one voice
1424                        int result = StealVoice(pChannel, itNoteOnEvent);
1425                        if (!result) { // voice stolen successfully
1426                            // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1427                            RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1428                            if (itStealEvent) {
1429                                *itStealEvent = *itNoteOnEvent; // copy event
1430                                itStealEvent->Param.Note.Layer = iLayer;
1431                                itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1432                                pKey->VoiceTheftsQueued++;
1433                            }
1434                            else dmsg(1,("Voice stealing queue full!\n"));
1435                        }
1436                    }
1437    
1438                    return -1;
1439                }
1440    
1441          private:          private:
1442              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
1443              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;

Legend:
Removed from v.2015  
changed lines
  Added in v.2244

  ViewVC Help
Powered by ViewVC