/[svn]/linuxsampler/trunk/src/engines/gig/Engine.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/gig/Engine.cpp

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

revision 2012 by iliev, Fri Oct 23 17:53:17 2009 UTC revision 3015 by schoenebeck, Tue Oct 18 20:13:08 2016 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 24  Line 24 
24    
25  #include "Engine.h"  #include "Engine.h"
26  #include "EngineChannel.h"  #include "EngineChannel.h"
27    #include "InstrumentScriptVM.h"
28    
29  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
30      Engine::Format Engine::GetEngineFormat() { return GIG; }      Engine::Format Engine::GetEngineFormat() { return GIG; }
31    
32        void Engine::CreateInstrumentScriptVM() {
33            dmsg(2,("gig::Engine created Giga format scriptvm\n"));
34            if (pScriptVM) return;
35            pScriptVM = new InstrumentScriptVM; // gig format specific extended script runner
36        }
37    
38      /**      /**
39       *  Reacts on supported control change commands (e.g. pitch bend wheel,       *  Reacts on supported control change commands (e.g. pitch bend wheel,
40       *  modulation wheel, aftertouch).       *  modulation wheel, aftertouch).
# Line 109  namespace LinuxSampler { namespace gig { Line 116  namespace LinuxSampler { namespace gig {
116          ProcessFxSendControllers(pChannel, itControlChangeEvent);          ProcessFxSendControllers(pChannel, itControlChangeEvent);
117      }      }
118    
119        void Engine::ProcessChannelPressure(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itChannelPressureEvent) {
120            // forward this to the CC routine, so it updates the current aftertouch value and may handle aftertouch trigger rules
121            ProcessControlChange(pEngineChannel, itChannelPressureEvent);
122    
123            // if required: engine global aftertouch handling (apart from the per voice handling)
124        }
125    
126        void Engine::ProcessPolyphonicKeyPressure(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNotePressureEvent) {
127            // if required: engine global aftertouch handling (apart from the per voice handling)
128        }
129    
130      DiskThread* Engine::CreateDiskThread() {      DiskThread* Engine::CreateDiskThread() {
131          return new DiskThread (          return new DiskThread (
132              iMaxDiskStreams,              iMaxDiskStreams,
# Line 125  namespace LinuxSampler { namespace gig { Line 143  namespace LinuxSampler { namespace gig {
143          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
144          // first, get total amount of required voices (dependant on amount of layers)          // first, get total amount of required voices (dependant on amount of layers)
145          ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(itNoteOnEvent->Param.Note.Key);          ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(itNoteOnEvent->Param.Note.Key);
146          if (pRegion && !RegionSuspended(pRegion)) {          if (!pRegion || RegionSuspended(pRegion))
147              int voicesRequired = pRegion->Layers;              return;
148              // now launch the required amount of voices          const int voicesRequired = pRegion->Layers;
149              for (int i = 0; i < voicesRequired; i++)          if (voicesRequired <= 0)
150                return;
151    
152            NoteIterator itNote = GetNotePool()->fromID(itNoteOnEvent->Param.Note.ID);
153            if (!itNote) {
154                dmsg(1,("gig::Engine: No Note object for triggering new voices!\n"));
155                return;
156            }
157    
158            // now launch the required amount of voices
159            for (int i = 0; i < voicesRequired; i++) {
160                VoiceIterator itNewVoice =
161                  LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);                  LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
162                if (!itNewVoice) continue;
163                itNewVoice.moveToEndOf(itNote->pActiveVoices);
164          }          }
165      }      }
166    
# Line 141  namespace LinuxSampler { namespace gig { Line 172  namespace LinuxSampler { namespace gig {
172          MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];          MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];
173          // first, get total amount of required voices (dependant on amount of layers)          // first, get total amount of required voices (dependant on amount of layers)
174          ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(itNoteOffEvent->Param.Note.Key);          ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(itNoteOffEvent->Param.Note.Key);
175          if (pRegion) {          if (!pRegion)
176              int voicesRequired = pRegion->Layers;              return;
177            const int voicesRequired = pRegion->Layers;
178            if (voicesRequired <= 0)
179                return;
180    
181            NoteIterator itNote = GetNotePool()->fromID(itNoteOffEvent->Param.Note.ID);
182            if (!itNote) {
183                dmsg(1,("gig::Engine: No Note object for triggering new release voices!\n"));
184                return;
185            }
186    
187              // MIDI note-on velocity is used instead of note-off velocity          // MIDI note-on velocity is used instead of note-off velocity
188              itNoteOffEvent->Param.Note.Velocity = pKey->Velocity;          itNoteOffEvent->Param.Note.Velocity = pKey->Velocity;
189    
190              // now launch the required amount of voices          // now launch the required amount of voices
191              for (int i = 0; i < voicesRequired; i++)          for (int i = 0; i < voicesRequired; i++) {
192                VoiceIterator itNewVoice =
193                  LaunchVoice(pChannel, itNoteOffEvent, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples                  LaunchVoice(pChannel, itNoteOffEvent, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples
194                if (!itNewVoice) continue;
195                itNewVoice.moveToEndOf(itNote->pActiveVoices);
196          }          }
197      }      }
198    
# Line 163  namespace LinuxSampler { namespace gig { Line 206  namespace LinuxSampler { namespace gig {
206      ) {      ) {
207          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
208          int MIDIKey = itNoteOnEvent->Param.Note.Key;          int MIDIKey = itNoteOnEvent->Param.Note.Key;
209          EngineChannel::MidiKey* pKey  = &pChannel->pMIDIKeyInfo[MIDIKey];          //EngineChannel::MidiKey* pKey  = &pChannel->pMIDIKeyInfo[MIDIKey];
210          ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(MIDIKey);          ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(MIDIKey);
211    
212          // if nothing defined for this key          // if nothing defined for this key
213          if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do          if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
214    
215          // only mark the first voice of a layered voice (group) to be in a          int iKeyGroup = pRegion->KeyGroup;
216          // key group, so the layered voices won't kill each other          // only need to send a group event from the first voice in a layered region,
217          int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;          // as all layers in a region always belongs to the same key group
218            if (HandleKeyGroupConflicts && iLayer == 0) pChannel->HandleKeyGroupConflicts(iKeyGroup, itNoteOnEvent);
         // handle key group (a.k.a. exclusive group) conflicts  
         if (HandleKeyGroupConflicts) {  
             if (iKeyGroup) { // if this voice / key belongs to a key group  
                 uint** ppKeyGroup = &pChannel->ActiveKeyGroups[iKeyGroup];  
                 if (*ppKeyGroup) { // if there's already an active key in that key group  
                     EngineChannel::MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[**ppKeyGroup];  
                     // kill all voices on the (other) key  
                     RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();  
                     RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();  
                     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {  
                         if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {  
                             itVoiceToBeKilled->Kill(itNoteOnEvent);  
                             --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict  
                         }  
                     }  
                 }  
             }  
         }  
219    
220          Voice::type_t VoiceType = Voice::type_normal;          Voice::type_t VoiceType = Voice::type_normal;
221    
# Line 220  namespace LinuxSampler { namespace gig { Line 245  namespace LinuxSampler { namespace gig {
245                      DimValues[i] = (uint) (pChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);                      DimValues[i] = (uint) (pChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
246                      break;                      break;
247                  case ::gig::dimension_roundrobin:                  case ::gig::dimension_roundrobin:
248                      DimValues[i] = (uint) pChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on                      DimValues[i] = uint(*pChannel->pMIDIKeyInfo[MIDIKey].pRoundRobinIndex % pRegion->pDimensionDefinitions[i].zones); // RoundRobinIndex is incremented for each note on in this Region
249                        break;
250                    case ::gig::dimension_roundrobinkeyboard:
251                        DimValues[i] = uint(pChannel->RoundRobinIndex % pRegion->pDimensionDefinitions[i].zones); // RoundRobinIndex is incremented for each note on
252                      break;                      break;
253                  case ::gig::dimension_random:                  case ::gig::dimension_random:
254                      RandomSeed   = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator                      DimValues[i] = uint(Random() * pRegion->pDimensionDefinitions[i].zones);
255                      DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random                      break;
256                    case ::gig::dimension_smartmidi:
257                        DimValues[i] = 0;
258                      break;                      break;
259                  case ::gig::dimension_modwheel:                  case ::gig::dimension_modwheel:
260                      DimValues[i] = pChannel->ControllerTable[1];                      DimValues[i] = pChannel->ControllerTable[1];
# Line 306  namespace LinuxSampler { namespace gig { Line 336  namespace LinuxSampler { namespace gig {
336          // return if this is a release triggered voice and there is no          // return if this is a release triggered voice and there is no
337          // releasetrigger dimension (could happen if an instrument          // releasetrigger dimension (could happen if an instrument
338          // change has occured between note on and off)          // change has occured between note on and off)
339          if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();          if (ReleaseTriggerVoice && !(VoiceType & Voice::type_release_trigger)) return Pool<Voice>::Iterator();
340    
341          ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);          NoteIterator itNote = GetNotePool()->fromID(itNoteOnEvent->Param.Note.ID);
342    
343            ::gig::DimensionRegion* pDimRgn;
344            if (!itNote->Format.Gig.DimMask) { // normal case ...
345                pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
346            } else { // some dimension zones were overridden (i.e. by instrument script) ...
347                dmsg(3,("trigger with dim mask=%d val=%d\n", itNote->Format.Gig.DimMask, itNote->Format.Gig.DimBits));
348                int index = pRegion->GetDimensionRegionIndexByValue(DimValues);
349                index &= ~itNote->Format.Gig.DimMask;
350                index |=  itNote->Format.Gig.DimBits & itNote->Format.Gig.DimMask;
351                pDimRgn = pRegion->pDimensionRegions[index & 255];
352            }
353            if (!pDimRgn) return Pool<Voice>::Iterator(); // error (could not resolve dimension region)
354    
355          // no need to continue if sample is silent          // no need to continue if sample is silent
356          if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();          if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
357            
358            dmsg(2,("sample -> \"%s\"\n", pDimRgn->pSample->pInfo->Name.c_str()));
359    
360          // allocate a new voice for the key          // allocate a new voice for the key
361          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();          Pool<Voice>::Iterator itNewVoice = GetVoicePool()->allocAppend();
362          if (itNewVoice) {  
363              // launch the new voice          int res = InitNewVoice (
364              if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) {                  pChannel, pDimRgn, itNoteOnEvent, VoiceType, iLayer,
365                  dmsg(4,("Voice not triggered\n"));                  iKeyGroup, ReleaseTriggerVoice, VoiceStealing, itNewVoice
366                  pKey->pActiveVoices->free(itNewVoice);          );
367              }          if (!res) return itNewVoice;
             else { // on success  
                 --VoiceSpawnsLeft;  
                 if (!pKey->Active) { // mark as active key  
                     pKey->Active = true;  
                     pKey->itSelf = pChannel->pActiveKeys->allocAppend();  
                     *pKey->itSelf = itNoteOnEvent->Param.Note.Key;  
                 }  
                 if (itNewVoice->KeyGroup) {  
                     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)  
                 return itNewVoice; // success  
             }  
         }  
         else if (VoiceStealing) {  
             // try to steal one voice  
             int result = StealVoice(pChannel, itNoteOnEvent);  
             if (!result) { // voice stolen successfully  
                 // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died  
                 RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();  
                 if (itStealEvent) {  
                     *itStealEvent = *itNoteOnEvent; // copy event  
                     itStealEvent->Param.Note.Layer = iLayer;  
                     itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;  
                     pKey->VoiceTheftsQueued++;  
                 }  
                 else dmsg(1,("Voice stealing queue full!\n"));  
             }  
         }  
368    
369          return Pool<Voice>::Iterator(); // no free voice or error          return Pool<Voice>::Iterator(); // no free voice or error
370      }      }
# Line 364  namespace LinuxSampler { namespace gig { Line 378  namespace LinuxSampler { namespace gig {
378      }      }
379    
380      String Engine::Version() {      String Engine::Version() {
381          String s = "$Revision: 1.105 $";          String s = "$Revision$";
382          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
383      }      }
384    

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

  ViewVC Help
Powered by ViewVC