/[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 123 by schoenebeck, Mon Jun 14 19:33:16 2004 UTC revision 242 by schoenebeck, Wed Sep 15 13:59:08 2004 UTC
# Line 47  namespace LinuxSampler { namespace gig { Line 47  namespace LinuxSampler { namespace gig {
47              pSynthesisEvents[i] = new RTEList<Event>(pEventPool);              pSynthesisEvents[i] = new RTEList<Event>(pEventPool);
48          }          }
49          for (uint i = 0; i < 128; i++) {          for (uint i = 0; i < 128; i++) {
50              pMIDIKeyInfo[i].pActiveVoices = new RTEList<Voice>(pVoicePool);              pMIDIKeyInfo[i].pActiveVoices  = new RTEList<Voice>(pVoicePool);
51              pMIDIKeyInfo[i].KeyPressed    = false;              pMIDIKeyInfo[i].KeyPressed     = false;
52              pMIDIKeyInfo[i].Active        = false;              pMIDIKeyInfo[i].Active         = false;
53              pMIDIKeyInfo[i].pSelf         = NULL;              pMIDIKeyInfo[i].ReleaseTrigger = false;
54              pMIDIKeyInfo[i].pEvents       = new RTEList<Event>(pEventPool);              pMIDIKeyInfo[i].pSelf          = NULL;
55                pMIDIKeyInfo[i].pEvents        = new RTEList<Event>(pEventPool);
56          }          }
57          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {
58              pVoice->SetEngine(this);              pVoice->SetEngine(this);
# Line 63  namespace LinuxSampler { namespace gig { Line 64  namespace LinuxSampler { namespace gig {
64          pMainFilterParameters   = NULL;          pMainFilterParameters   = NULL;
65    
66          InstrumentIdx = -1;          InstrumentIdx = -1;
67            InstrumentStat = -1;
68    
69            AudioDeviceChannelLeft  = -1;
70            AudioDeviceChannelRight = -1;
71    
72          ResetInternal();          ResetInternal();
73      }      }
# Line 148  namespace LinuxSampler { namespace gig { Line 153  namespace LinuxSampler { namespace gig {
153          SustainPedal        = false;          SustainPedal        = false;
154          ActiveVoiceCount    = 0;          ActiveVoiceCount    = 0;
155          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
156            GlobalVolume        = 1.0;
157    
158          // set all MIDI controller values to zero          // set all MIDI controller values to zero
159          memset(ControllerTable, 0x00, 128);          memset(ControllerTable, 0x00, 128);
# Line 156  namespace LinuxSampler { namespace gig { Line 162  namespace LinuxSampler { namespace gig {
162          for (uint i = 0; i < 128; i++) {          for (uint i = 0; i < 128; i++) {
163              pMIDIKeyInfo[i].pActiveVoices->clear();              pMIDIKeyInfo[i].pActiveVoices->clear();
164              pMIDIKeyInfo[i].pEvents->clear();              pMIDIKeyInfo[i].pEvents->clear();
165              pMIDIKeyInfo[i].KeyPressed = false;              pMIDIKeyInfo[i].KeyPressed     = false;
166              pMIDIKeyInfo[i].Active     = false;              pMIDIKeyInfo[i].Active         = false;
167              pMIDIKeyInfo[i].pSelf      = NULL;              pMIDIKeyInfo[i].ReleaseTrigger = false;
168                pMIDIKeyInfo[i].pSelf          = NULL;
169          }          }
170    
171            // reset all key groups
172            map<uint,uint*>::iterator iter = ActiveKeyGroups.begin();
173            for (; iter != ActiveKeyGroups.end(); iter++) iter->second = NULL;
174    
175          // reset all voices          // reset all voices
176          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {
177              pVoice->Reset();              pVoice->Reset();
# Line 197  namespace LinuxSampler { namespace gig { Line 208  namespace LinuxSampler { namespace gig {
208              Instruments.HandBack(pInstrument, this);              Instruments.HandBack(pInstrument, this);
209          }          }
210    
211          InstrumentIdx = -1;          InstrumentFile = FileName;
212            InstrumentIdx = Instrument;
213            InstrumentStat = 0;
214    
215            // delete all key groups
216            ActiveKeyGroups.clear();
217    
218          // request gig instrument from instrument manager          // request gig instrument from instrument manager
219          try {          try {
# Line 206  namespace LinuxSampler { namespace gig { Line 222  namespace LinuxSampler { namespace gig {
222              instrid.iInstrument = Instrument;              instrid.iInstrument = Instrument;
223              pInstrument = Instruments.Borrow(instrid, this);              pInstrument = Instruments.Borrow(instrid, this);
224              if (!pInstrument) {              if (!pInstrument) {
225                    InstrumentStat = -1;
226                  dmsg(1,("no instrument loaded!!!\n"));                  dmsg(1,("no instrument loaded!!!\n"));
227                  exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
228              }              }
229          }          }
230          catch (RIFF::Exception e) {          catch (RIFF::Exception e) {
231                InstrumentStat = -2;
232              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;
233              throw LinuxSamplerException(msg);              throw LinuxSamplerException(msg);
234          }          }
235          catch (InstrumentResourceManagerException e) {          catch (InstrumentResourceManagerException e) {
236                InstrumentStat = -3;
237              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();
238              throw LinuxSamplerException(msg);              throw LinuxSamplerException(msg);
239          }          }
240          catch (...) {          catch (...) {
241                InstrumentStat = -4;
242              throw LinuxSamplerException("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file.");              throw LinuxSamplerException("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file.");
243          }          }
244    
245          InstrumentFile = FileName;          // rebuild ActiveKeyGroups map with key groups of current instrument
246          InstrumentIdx = Instrument;          for (::gig::Region* pRegion = pInstrument->GetFirstRegion(); pRegion; pRegion = pInstrument->GetNextRegion())
247                if (pRegion->KeyGroup) ActiveKeyGroups[pRegion->KeyGroup] = NULL;
248    
249            InstrumentStat = 100;
250    
251          // inform audio driver for the need of two channels          // inform audio driver for the need of two channels
252          try {          try {
# Line 254  namespace LinuxSampler { namespace gig { Line 277  namespace LinuxSampler { namespace gig {
277       * update process was completed, so we can continue with playback.       * update process was completed, so we can continue with playback.
278       */       */
279      void Engine::ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) {      void Engine::ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) {
280          this->pInstrument = pNewResource;          this->pInstrument = pNewResource; //TODO: there are couple of engine parameters we should update here as well if the instrument was updated (see LoadInstrument())
281          Enable();          Enable();
282      }      }
283    
# Line 272  namespace LinuxSampler { namespace gig { Line 295  namespace LinuxSampler { namespace gig {
295              throw LinuxSamplerException(msg);              throw LinuxSamplerException(msg);
296          }          }
297    
298            this->AudioDeviceChannelLeft  = 0;
299            this->AudioDeviceChannelRight = 1;
300            this->pOutputLeft             = pAudioOutputDevice->Channel(0)->Buffer();
301            this->pOutputRight            = pAudioOutputDevice->Channel(1)->Buffer();
302            this->MaxSamplesPerCycle      = pAudioOutputDevice->MaxSamplesPerCycle();
303            this->SampleRate              = pAudioOutputDevice->SampleRate();
304    
305          // (re)create disk thread          // (re)create disk thread
306          if (this->pDiskThread) {          if (this->pDiskThread) {
307              this->pDiskThread->StopThread();              this->pDiskThread->StopThread();
# Line 285  namespace LinuxSampler { namespace gig { Line 315  namespace LinuxSampler { namespace gig {
315    
316          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {
317              pVoice->pDiskThread = this->pDiskThread;              pVoice->pDiskThread = this->pDiskThread;
             pVoice->SetOutput(pAudioOut);  
318              dmsg(3,("d"));              dmsg(3,("d"));
319          }          }
320          pVoicePool->clear();          pVoicePool->clear();
# Line 323  namespace LinuxSampler { namespace gig { Line 352  namespace LinuxSampler { namespace gig {
352              AudioOutputDevice* olddevice = pAudioOutputDevice;              AudioOutputDevice* olddevice = pAudioOutputDevice;
353              pAudioOutputDevice = NULL;              pAudioOutputDevice = NULL;
354              olddevice->Disconnect(this);              olddevice->Disconnect(this);
355                AudioDeviceChannelLeft  = -1;
356                AudioDeviceChannelRight = -1;
357          }          }
358      }      }
359    
# Line 415  namespace LinuxSampler { namespace gig { Line 446  namespace LinuxSampler { namespace gig {
446                  pVoice->Render(Samples);                  pVoice->Render(Samples);
447                  if (pVoice->IsActive()) active_voices++; // still active                  if (pVoice->IsActive()) active_voices++; // still active
448                  else { // voice reached end, is now inactive                  else { // voice reached end, is now inactive
449                      KillVoice(pVoice); // remove voice from the list of active voices                      KillVoiceImmediately(pVoice); // remove voice from the list of active voices
450                  }                  }
451              }              }
452              pKey->pEvents->clear(); // free all events on the key              pKey->pEvents->clear(); // free all events on the key
# Line 505  namespace LinuxSampler { namespace gig { Line 536  namespace LinuxSampler { namespace gig {
536    
537          // cancel release process of voices on this key if needed          // cancel release process of voices on this key if needed
538          if (pKey->Active && !SustainPedal) {          if (pKey->Active && !SustainPedal) {
539              pNoteOnEvent->Type = Event::type_cancel_release; // transform event type              Event* pCancelReleaseEvent = pKey->pEvents->alloc();
540              pEvents->move(pNoteOnEvent, pKey->pEvents); // move event to the key's own event list              if (pCancelReleaseEvent) {
541          }                  *pCancelReleaseEvent = *pNoteOnEvent;
542                    pCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
         // allocate a new voice for the key  
         Voice* pNewVoice = pKey->pActiveVoices->alloc();  
         if (pNewVoice) {  
             // launch the new voice  
             if (pNewVoice->Trigger(pNoteOnEvent, this->Pitch, this->pInstrument) < 0) {  
                 dmsg(1,("Triggering new voice failed!\n"));  
                 pKey->pActiveVoices->free(pNewVoice);  
             }  
             else if (!pKey->Active) { // mark as active key  
                 pKey->Active = true;  
                 pKey->pSelf  = pActiveKeys->alloc();  
                 *pKey->pSelf = pNoteOnEvent->Key;  
543              }              }
544                else dmsg(1,("Event pool emtpy!\n"));
545          }          }
546          else std::cerr << "No free voice!" << std::endl << std::flush;  
547            // allocate and trigger a new voice for the key
548            LaunchVoice(pNoteOnEvent);
549    
550            // finally move note on event to the key's own event list
551            pEvents->move(pNoteOnEvent, pKey->pEvents);
552      }      }
553    
554      /**      /**
# Line 542  namespace LinuxSampler { namespace gig { Line 567  namespace LinuxSampler { namespace gig {
567          // release voices on this key if needed          // release voices on this key if needed
568          if (pKey->Active && !SustainPedal) {          if (pKey->Active && !SustainPedal) {
569              pNoteOffEvent->Type = Event::type_release; // transform event type              pNoteOffEvent->Type = Event::type_release; // transform event type
             pEvents->move(pNoteOffEvent, pKey->pEvents); // move event to the key's own event list  
570          }          }
571    
572            // spawn release triggered voice(s) if needed
573            if (pKey->ReleaseTrigger) {
574                LaunchVoice(pNoteOffEvent, 0, true);
575                pKey->ReleaseTrigger = false;
576            }
577    
578            // move event to the key's own event list
579            pEvents->move(pNoteOffEvent, pKey->pEvents);
580      }      }
581    
582      /**      /**
# Line 558  namespace LinuxSampler { namespace gig { Line 591  namespace LinuxSampler { namespace gig {
591      }      }
592    
593      /**      /**
594         *  Allocates and triggers a new voice. This method will usually be
595         *  called by the ProcessNoteOn() method and by the voices itself
596         *  (e.g. to spawn further voices on the same key for layered sounds).
597         *
598         *  @param pNoteOnEvent        - key, velocity and time stamp of the event
599         *  @param iLayer              - layer index for the new voice (optional - only
600         *                               in case of layered sounds of course)
601         *  @param ReleaseTriggerVoice - if new voice is a release triggered voice
602         *                               (optional, default = false)
603         */
604        void Engine::LaunchVoice(Event* pNoteOnEvent, int iLayer, bool ReleaseTriggerVoice) {
605            midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Key];
606    
607            // allocate a new voice for the key
608            Voice* pNewVoice = pKey->pActiveVoices->alloc();
609            if (pNewVoice) {
610                // launch the new voice
611                if (pNewVoice->Trigger(pNoteOnEvent, this->Pitch, this->pInstrument, iLayer, ReleaseTriggerVoice) < 0) {
612                    dmsg(1,("Triggering new voice failed!\n"));
613                    pKey->pActiveVoices->free(pNewVoice);
614                }
615                else { // on success
616                    uint** ppKeyGroup = NULL;
617                    if (pNewVoice->KeyGroup) { // if this voice / key belongs to a key group
618                        ppKeyGroup = &ActiveKeyGroups[pNewVoice->KeyGroup];
619                        if (*ppKeyGroup) { // if there's already an active key in that key group
620                            midi_key_info_t* pOtherKey = &pMIDIKeyInfo[**ppKeyGroup];
621                            // kill all voices on the (other) key
622                            Voice* pVoiceToBeKilled = pOtherKey->pActiveVoices->first();
623                            while (pVoiceToBeKilled) {
624                                Voice* pVoiceToBeKilledNext = pOtherKey->pActiveVoices->next();
625                                if (pVoiceToBeKilled->Type != Voice::type_release_trigger) pVoiceToBeKilled->Kill(pNoteOnEvent);
626                                pOtherKey->pActiveVoices->set_current(pVoiceToBeKilled);
627                                pVoiceToBeKilled = pVoiceToBeKilledNext;
628                            }
629                        }
630                    }
631                    if (!pKey->Active) { // mark as active key
632                        pKey->Active = true;
633                        pKey->pSelf  = pActiveKeys->alloc();
634                        *pKey->pSelf = pNoteOnEvent->Key;
635                    }
636                    if (pNewVoice->KeyGroup) {
637                        *ppKeyGroup = pKey->pSelf; // put key as the (new) active key to its key group
638                    }
639                    if (pNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
640                }
641            }
642            else std::cerr << "No free voice!" << std::endl << std::flush;
643        }
644    
645        /**
646       *  Immediately kills the voice given with pVoice (no matter if sustain is       *  Immediately kills the voice given with pVoice (no matter if sustain is
647       *  pressed or not) and removes it from the MIDI key's list of active voice.       *  pressed or not) and removes it from the MIDI key's list of active voice.
648       *  This method will e.g. be called if a voice went inactive by itself.       *  This method will e.g. be called if a voice went inactive by itself.
649       *       *
650       *  @param pVoice - points to the voice to be killed       *  @param pVoice - points to the voice to be killed
651       */       */
652      void Engine::KillVoice(Voice* pVoice) {      void Engine::KillVoiceImmediately(Voice* pVoice) {
653          if (pVoice) {          if (pVoice) {
654              if (pVoice->IsActive()) pVoice->Kill();              if (pVoice->IsActive()) pVoice->KillImmediately();
655    
656              midi_key_info_t* pKey = &pMIDIKeyInfo[pVoice->MIDIKey];              midi_key_info_t* pKey = &pMIDIKeyInfo[pVoice->MIDIKey];
657    
# Line 575  namespace LinuxSampler { namespace gig { Line 660  namespace LinuxSampler { namespace gig {
660    
661              // check if there are no voices left on the MIDI key and update the key info if so              // check if there are no voices left on the MIDI key and update the key info if so
662              if (pKey->pActiveVoices->is_empty()) {              if (pKey->pActiveVoices->is_empty()) {
663                    if (pVoice->KeyGroup) { // if voice / key belongs to a key group
664                        uint** ppKeyGroup = &ActiveKeyGroups[pVoice->KeyGroup];
665                        if (*ppKeyGroup == pKey->pSelf) *ppKeyGroup = NULL; // remove key from key group
666                    }
667                  pKey->Active = false;                  pKey->Active = false;
668                  pActiveKeys->free(pKey->pSelf); // remove key from list of active keys                  pActiveKeys->free(pKey->pSelf); // remove key from list of active keys
669                  pKey->pSelf = NULL;                  pKey->pSelf = NULL;
670                    pKey->ReleaseTrigger = false;
671                  dmsg(3,("Key has no more voices now\n"));                  dmsg(3,("Key has no more voices now\n"));
672              }              }
673          }          }
# Line 669  namespace LinuxSampler { namespace gig { Line 759  namespace LinuxSampler { namespace gig {
759          GlobalVolume = f;          GlobalVolume = f;
760      }      }
761    
762        uint Engine::Channels() {
763            return 2;
764        }
765    
766        void Engine::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
767            AudioChannel* pChannel = pAudioOutputDevice->Channel(AudioDeviceChannel);
768            if (!pChannel) throw AudioOutputException("Invalid audio output device channel " + ToString(AudioDeviceChannel));
769            switch (EngineAudioChannel) {
770                case 0: // left output channel
771                    pOutputLeft = pChannel->Buffer();
772                    AudioDeviceChannelLeft = AudioDeviceChannel;
773                    break;
774                case 1: // right output channel
775                    pOutputRight = pChannel->Buffer();
776                    AudioDeviceChannelRight = AudioDeviceChannel;
777                    break;
778                default:
779                    throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
780            }
781        }
782    
783        int Engine::OutputChannel(uint EngineAudioChannel) {
784            switch (EngineAudioChannel) {
785                case 0: // left channel
786                    return AudioDeviceChannelLeft;
787                case 1: // right channel
788                    return AudioDeviceChannelRight;
789                default:
790                    throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
791            }
792        }
793    
794      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
795          return ActiveVoiceCount;          return ActiveVoiceCount;
796      }      }
# Line 709  namespace LinuxSampler { namespace gig { Line 831  namespace LinuxSampler { namespace gig {
831          return InstrumentIdx;          return InstrumentIdx;
832      }      }
833    
834        int Engine::InstrumentStatus() {
835            return InstrumentStat;
836        }
837    
838      String Engine::Description() {      String Engine::Description() {
839          return "Gigasampler Engine";          return "Gigasampler Engine";
840      }      }
841    
842      String Engine::Version() {      String Engine::Version() {
843          String s = "$Revision: 1.6 $";          String s = "$Revision: 1.11 $";
844          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
845      }      }
846    

Legend:
Removed from v.123  
changed lines
  Added in v.242

  ViewVC Help
Powered by ViewVC