/[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 2410 by schoenebeck, Sat Feb 2 18:52:15 2013 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-2012 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->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
316                      }                      }
317                      pVoicePool->clear();                      pVoicePool->clear();
318                  }                  }
# Line 332  namespace LinuxSampler { Line 345  namespace LinuxSampler {
345                  pDiskThread->StartThread();                  pDiskThread->StartThread();
346                  dmsg(1,("OK\n"));                  dmsg(1,("OK\n"));
347    
348                    bool printEqInfo = true;
349                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
350                      if (!iterVoice->pDiskThread) {                      if (!iterVoice->pDiskThread) {
351                          dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));                          dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
352                          exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
353                      }                      }
354                        
355                        iterVoice->CreateEq();
356                        
357                        if(printEqInfo) {
358                            iterVoice->PrintEqInfo();
359                            printEqInfo = false;
360                        }
361                  }                  }
362                  pVoicePool->clear();                  pVoicePool->clear();
363                    
364                    // (re)create dedicated voice audio buffers
365                    //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
366                    if (pDedicatedVoiceChannelLeft)  delete pDedicatedVoiceChannelLeft;
367                    if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
368                    pDedicatedVoiceChannelLeft  = new AudioChannel(0, MaxSamplesPerCycle);
369                    pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
370                }
371            
372                // Implementattion for abstract method derived from Engine.
373                virtual void ReconnectAudioOutputDevice() {
374                    SuspendAll();
375                    if (pAudioOutputDevice) Connect(pAudioOutputDevice);
376                    ResumeAll();
377              }              }
378    
379              /**              /**
# Line 530  namespace LinuxSampler { Line 565  namespace LinuxSampler {
565    
566              //friend class EngineChannelBase<V, R, I>;              //friend class EngineChannelBase<V, R, I>;
567    
568                static IM instruments;
569    
570          protected:          protected:
571              class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {              class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
572              public:              public:
# Line 558  namespace LinuxSampler { Line 595  namespace LinuxSampler {
595                  }                  }
596              };              };
597    
             static IM instruments;  
   
598              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.
599              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.
600              D*        pDiskThread;              D*        pDiskThread;
601    
             int                          VoiceSpawnsLeft;       ///< We only allow CONFIG_MAX_VOICES voices to be spawned per audio fragment, we use this variable to ensure this limit.  
602              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)
603              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.
604              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 800  namespace LinuxSampler {
800                      //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
801                      ResetSuspendedRegions();                      ResetSuspendedRegions();
802                  }                  }
   
                 for (int i = 0; i < engineChannels.size(); i++) {  
                     EngineChannelBase<V, R, I>* channel =  
                         static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);  
                     channel->InstrumentChangeCommandReader.Unlock();  
                 }  
803              }              }
804    
805              /**              /**
# Line 858  namespace LinuxSampler { Line 886  namespace LinuxSampler {
886                  pChannel->ClearEventLists();                  pChannel->ClearEventLists();
887              }              }
888    
889                /**
890                 * Process MIDI control change events with hard coded behavior,
891                 * that is controllers whose behavior is defined independently
892                 * of the actual sampler engine type and instrument.
893                 *
894                 * @param pEngineChannel - engine channel on which the MIDI CC event was received
895                 * @param itControlChangeEvent - the actual MIDI CC event
896                 */
897              void ProcessHardcodedControllers (              void ProcessHardcodedControllers (
898                  EngineChannel*          pEngineChannel,                  EngineChannel*          pEngineChannel,
899                  Pool<Event>::Iterator&  itControlChangeEvent                  Pool<Event>::Iterator&  itControlChangeEvent
# Line 870  namespace LinuxSampler { Line 906  namespace LinuxSampler {
906                          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;
907                          break;                          break;
908                      }                      }
909                      case 6: { // data entry (currently only used for RPN controllers)                      case 6: { // data entry (currently only used for RPN and NRPN controllers)
910                          if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones                          //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
911                              int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;                          if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
912                              // limit to +- two octaves for now                              dmsg(4,("Guess it's an RPN ...\n"));
913                              transpose = RTMath::Min(transpose,  24);                              if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
914                              transpose = RTMath::Max(transpose, -24);                                  int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
915                              pChannel->GlobalTranspose = transpose;                                  // limit to +- two octaves for now
916                              // workaround, so we won't have hanging notes                                  transpose = RTMath::Min(transpose,  24);
917                              pChannel->ReleaseAllVoices(itControlChangeEvent);                                  transpose = RTMath::Max(transpose, -24);
918                                    pChannel->GlobalTranspose = transpose;
919                                    // workaround, so we won't have hanging notes
920                                    pChannel->ReleaseAllVoices(itControlChangeEvent);
921                                }
922                                // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
923                                pChannel->ResetMidiRpnController();
924                            } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
925                                dmsg(4,("Guess it's an NRPN ...\n"));
926                                const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
927                                const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
928                                dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
929                                switch (NrpnCtrlMSB) {
930                                    case 0x1a: { // volume level of note (Roland GS NRPN)
931                                        const uint note = NrpnCtrlLSB;
932                                        const uint vol  = itControlChangeEvent->Param.CC.Value;
933                                        dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
934                                        if (note < 128 && vol < 128)
935                                            pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
936                                        break;
937                                    }
938                                    case 0x1c: { // panpot of note (Roland GS NRPN)
939                                        const uint note = NrpnCtrlLSB;
940                                        const uint pan  = itControlChangeEvent->Param.CC.Value;
941                                        dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
942                                        if (note < 128 && pan < 128) {
943                                            pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];
944                                            pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
945                                        }
946                                        break;
947                                    }
948                                    case 0x1d: { // reverb send of note (Roland GS NRPN)
949                                        const uint note = NrpnCtrlLSB;
950                                        const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
951                                        dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));
952                                        if (note < 128)
953                                            pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
954                                        break;
955                                    }
956                                    case 0x1e: { // chorus send of note (Roland GS NRPN)
957                                        const uint note = NrpnCtrlLSB;
958                                        const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
959                                        dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));
960                                        if (note < 128)
961                                            pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
962                                        break;
963                                    }
964                                }
965                                // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
966                                pChannel->ResetMidiNrpnController();
967                          }                          }
                         // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data  
                         pChannel->ResetMidiRpnController();  
968                          break;                          break;
969                      }                      }
970                      case 7: { // volume                      case 7: { // volume
# Line 892  namespace LinuxSampler { Line 975  namespace LinuxSampler {
975                      }                      }
976                      case 10: { // panpot                      case 10: { // panpot
977                          //TODO: not sample accurate yet                          //TODO: not sample accurate yet
                         pChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];  
                         pChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];  
978                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
979                          break;                          break;
980                      }                      }
# Line 970  namespace LinuxSampler { Line 1051  namespace LinuxSampler {
1051                          }                          }
1052                          break;                          break;
1053                      }                      }
1054                        case 98: { // NRPN controller LSB
1055                            dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1056                            pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1057                            break;
1058                        }
1059                        case 99: { // NRPN controller MSB
1060                            dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1061                            pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1062                            break;
1063                        }
1064                      case 100: { // RPN controller LSB                      case 100: { // RPN controller LSB
1065                            dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1066                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1067                          break;                          break;
1068                      }                      }
1069                      case 101: { // RPN controller MSB                      case 101: { // RPN controller MSB
1070                            dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1071                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1072                          break;                          break;
1073                      }                      }
# Line 1065  namespace LinuxSampler { Line 1158  namespace LinuxSampler {
1158                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1159                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                              VoiceIterator end               = pOtherKey->pActiveVoices->end();
1160                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1161                                  if (itVoiceToBeKilled->Type != Voice::type_release_trigger)                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1162                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1163                              }                              }
1164                          }                          }
# Line 1097  namespace LinuxSampler { Line 1190  namespace LinuxSampler {
1190                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1191    
1192                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;
1193                  pKey->RoundRobinIndex++;                  if (pKey->pRoundRobinIndex) {
1194                        (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1195                        pChannel->RoundRobinIndex++; // common counter for the channel
1196                    }
1197                  pChannel->listeners.PostProcessNoteOn(key, vel);                  pChannel->listeners.PostProcessNoteOn(key, vel);
1198              }              }
1199    
# Line 1199  namespace LinuxSampler { Line 1295  namespace LinuxSampler {
1295                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1296                              VoiceIterator end               = pKey->pActiveVoices->end();                              VoiceIterator end               = pKey->pActiveVoices->end();
1297                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1298                                  if (itVoiceToBeKilled->Type != Voice::type_release_trigger)                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1299                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1300                              }                              }
1301                          }                          }
# Line 1304  namespace LinuxSampler { Line 1400  namespace LinuxSampler {
1400                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
1401              ) = 0;              ) = 0;
1402    
1403                virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
1404    
1405                int InitNewVoice (
1406                    EngineChannelBase<V, R, I>*  pChannel,
1407                    R*                           pRegion,
1408                    Pool<Event>::Iterator&       itNoteOnEvent,
1409                    Voice::type_t                VoiceType,
1410                    int                          iLayer,
1411                    int                          iKeyGroup,
1412                    bool                         ReleaseTriggerVoice,
1413                    bool                         VoiceStealing,
1414                    typename Pool<V>::Iterator&  itNewVoice
1415                ) {
1416                    int key = itNoteOnEvent->Param.Note.Key;
1417                    typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1418                    if (itNewVoice) {
1419                        // launch the new voice
1420                        if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1421                            dmsg(4,("Voice not triggered\n"));
1422                            pKey->pActiveVoices->free(itNewVoice);
1423                        }
1424                        else { // on success
1425                            --VoiceSpawnsLeft;
1426                            if (!pKey->Active) { // mark as active key
1427                                pKey->Active = true;
1428                                pKey->itSelf = pChannel->pActiveKeys->allocAppend();
1429                                *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1430                            }
1431                            if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
1432                            return 0; // success
1433                        }
1434                    }
1435                    else if (VoiceStealing) {
1436                        // try to steal one voice
1437                        int result = StealVoice(pChannel, itNoteOnEvent);
1438                        if (!result) { // voice stolen successfully
1439                            // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1440                            RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1441                            if (itStealEvent) {
1442                                *itStealEvent = *itNoteOnEvent; // copy event
1443                                itStealEvent->Param.Note.Layer = iLayer;
1444                                itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1445                                pKey->VoiceTheftsQueued++;
1446                            }
1447                            else dmsg(1,("Voice stealing queue full!\n"));
1448                        }
1449                    }
1450    
1451                    return -1;
1452                }
1453    
1454          private:          private:
1455              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
1456              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;

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

  ViewVC Help
Powered by ViewVC