/[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 2043 by persson, Sat Jan 9 09:37:01 2010 UTC revision 2296 by iliev, Thu Dec 8 20:03:47 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                    if (pEq != NULL) delete pEq;
364                    pEq = new EqSupport;
365                    pEq->InitEffect(pAudioOutputDevice);
366              }              }
367    
368              /**              /**
# Line 530  namespace LinuxSampler { Line 554  namespace LinuxSampler {
554    
555              //friend class EngineChannelBase<V, R, I>;              //friend class EngineChannelBase<V, R, I>;
556    
557                static IM instruments;
558    
559          protected:          protected:
560              class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {              class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
561              public:              public:
# Line 558  namespace LinuxSampler { Line 584  namespace LinuxSampler {
584                  }                  }
585              };              };
586    
             static IM instruments;  
   
587              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.
588              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.
589              D*        pDiskThread;              D*        pDiskThread;
# Line 765  namespace LinuxSampler { Line 789  namespace LinuxSampler {
789                      //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
790                      ResetSuspendedRegions();                      ResetSuspendedRegions();
791                  }                  }
   
                 for (int i = 0; i < engineChannels.size(); i++) {  
                     EngineChannelBase<V, R, I>* channel =  
                         static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);  
                     channel->InstrumentChangeCommandReader.Unlock();  
                 }  
792              }              }
793    
794              /**              /**
# Line 857  namespace LinuxSampler { Line 875  namespace LinuxSampler {
875                  pChannel->ClearEventLists();                  pChannel->ClearEventLists();
876              }              }
877    
878                /**
879                 * Process MIDI control change events with hard coded behavior,
880                 * that is controllers whose behavior is defined independently
881                 * of the actual sampler engine type and instrument.
882                 *
883                 * @param pEngineChannel - engine channel on which the MIDI CC event was received
884                 * @param itControlChangeEvent - the actual MIDI CC event
885                 */
886              void ProcessHardcodedControllers (              void ProcessHardcodedControllers (
887                  EngineChannel*          pEngineChannel,                  EngineChannel*          pEngineChannel,
888                  Pool<Event>::Iterator&  itControlChangeEvent                  Pool<Event>::Iterator&  itControlChangeEvent
# Line 869  namespace LinuxSampler { Line 895  namespace LinuxSampler {
895                          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;
896                          break;                          break;
897                      }                      }
898                      case 6: { // data entry (currently only used for RPN controllers)                      case 6: { // data entry (currently only used for RPN and NRPN controllers)
899                          if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones                          //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
900                              int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;                          if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
901                              // limit to +- two octaves for now                              dmsg(4,("Guess it's an RPN ...\n"));
902                              transpose = RTMath::Min(transpose,  24);                              if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
903                              transpose = RTMath::Max(transpose, -24);                                  int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
904                              pChannel->GlobalTranspose = transpose;                                  // limit to +- two octaves for now
905                              // workaround, so we won't have hanging notes                                  transpose = RTMath::Min(transpose,  24);
906                              pChannel->ReleaseAllVoices(itControlChangeEvent);                                  transpose = RTMath::Max(transpose, -24);
907                                    pChannel->GlobalTranspose = transpose;
908                                    // workaround, so we won't have hanging notes
909                                    pChannel->ReleaseAllVoices(itControlChangeEvent);
910                                }
911                                // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
912                                pChannel->ResetMidiRpnController();
913                            } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
914                                dmsg(4,("Guess it's an NRPN ...\n"));
915                                const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
916                                const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
917                                dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
918                                switch (NrpnCtrlMSB) {
919                                    case 0x1a: { // volume level of note (Roland GS NRPN)
920                                        const uint note = NrpnCtrlLSB;
921                                        const uint vol  = itControlChangeEvent->Param.CC.Value;
922                                        dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
923                                        if (note < 128 && vol < 128)
924                                            pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
925                                        break;
926                                    }
927                                    case 0x1c: { // panpot of note (Roland GS NRPN)
928                                        const uint note = NrpnCtrlLSB;
929                                        const uint pan  = itControlChangeEvent->Param.CC.Value;
930                                        dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
931                                        if (note < 128 && pan < 128) {
932                                            pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];
933                                            pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
934                                        }
935                                        break;
936                                    }
937                                    case 0x1d: { // reverb send of note (Roland GS NRPN)
938                                        const uint note = NrpnCtrlLSB;
939                                        const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
940                                        dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));
941                                        if (note < 128)
942                                            pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
943                                        break;
944                                    }
945                                    case 0x1e: { // chorus send of note (Roland GS NRPN)
946                                        const uint note = NrpnCtrlLSB;
947                                        const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
948                                        dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));
949                                        if (note < 128)
950                                            pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
951                                        break;
952                                    }
953                                }
954                                // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
955                                pChannel->ResetMidiNrpnController();
956                          }                          }
                         // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data  
                         pChannel->ResetMidiRpnController();  
957                          break;                          break;
958                      }                      }
959                      case 7: { // volume                      case 7: { // volume
# Line 969  namespace LinuxSampler { Line 1042  namespace LinuxSampler {
1042                          }                          }
1043                          break;                          break;
1044                      }                      }
1045                        case 98: { // NRPN controller LSB
1046                            dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1047                            pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1048                            break;
1049                        }
1050                        case 99: { // NRPN controller MSB
1051                            dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1052                            pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1053                            break;
1054                        }
1055                      case 100: { // RPN controller LSB                      case 100: { // RPN controller LSB
1056                            dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1057                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1058                          break;                          break;
1059                      }                      }
1060                      case 101: { // RPN controller MSB                      case 101: { // RPN controller MSB
1061                            dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1062                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1063                          break;                          break;
1064                      }                      }
# Line 1064  namespace LinuxSampler { Line 1149  namespace LinuxSampler {
1149                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1150                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                              VoiceIterator end               = pOtherKey->pActiveVoices->end();
1151                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1152                                  if (itVoiceToBeKilled->Type != Voice::type_release_trigger)                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1153                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1154                              }                              }
1155                          }                          }
# Line 1201  namespace LinuxSampler { Line 1286  namespace LinuxSampler {
1286                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1287                              VoiceIterator end               = pKey->pActiveVoices->end();                              VoiceIterator end               = pKey->pActiveVoices->end();
1288                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1289                                  if (itVoiceToBeKilled->Type != Voice::type_release_trigger)                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1290                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1291                              }                              }
1292                          }                          }
# Line 1334  namespace LinuxSampler { Line 1419  namespace LinuxSampler {
1419                              pKey->itSelf = pChannel->pActiveKeys->allocAppend();                              pKey->itSelf = pChannel->pActiveKeys->allocAppend();
1420                              *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                              *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1421                          }                          }
1422                          if (itNewVoice->KeyGroup) {                          if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
                             uint** ppKeyGroup = &pChannel->ActiveKeyGroups[itNewVoice->KeyGroup];  
                             *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group  
                         }  
                         if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)  
1423                          return 0; // success                          return 0; // success
1424                      }                      }
1425                  }                  }

Legend:
Removed from v.2043  
changed lines
  Added in v.2296

  ViewVC Help
Powered by ViewVC