/[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 80 by schoenebeck, Sun May 23 19:16:33 2004 UTC revision 239 by schoenebeck, Sun Sep 12 14:48:19 2004 UTC
# Line 62  namespace LinuxSampler { namespace gig { Line 62  namespace LinuxSampler { namespace gig {
62          pBasicFilterParameters  = NULL;          pBasicFilterParameters  = NULL;
63          pMainFilterParameters   = NULL;          pMainFilterParameters   = NULL;
64    
65            InstrumentIdx = -1;
66            InstrumentStat = -1;
67    
68            AudioDeviceChannelLeft  = -1;
69            AudioDeviceChannelRight = -1;
70    
71          ResetInternal();          ResetInternal();
72      }      }
73    
# Line 146  namespace LinuxSampler { namespace gig { Line 152  namespace LinuxSampler { namespace gig {
152          SustainPedal        = false;          SustainPedal        = false;
153          ActiveVoiceCount    = 0;          ActiveVoiceCount    = 0;
154          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
155            GlobalVolume        = 1.0;
156    
157          // set all MIDI controller values to zero          // set all MIDI controller values to zero
158          memset(ControllerTable, 0x00, 128);          memset(ControllerTable, 0x00, 128);
# Line 159  namespace LinuxSampler { namespace gig { Line 166  namespace LinuxSampler { namespace gig {
166              pMIDIKeyInfo[i].pSelf      = NULL;              pMIDIKeyInfo[i].pSelf      = NULL;
167          }          }
168    
169            // reset all key groups
170            map<uint,uint*>::iterator iter = ActiveKeyGroups.begin();
171            for (; iter != ActiveKeyGroups.end(); iter++) iter->second = NULL;
172    
173          // reset all voices          // reset all voices
174          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {
175              pVoice->Reset();              pVoice->Reset();
# Line 195  namespace LinuxSampler { namespace gig { Line 206  namespace LinuxSampler { namespace gig {
206              Instruments.HandBack(pInstrument, this);              Instruments.HandBack(pInstrument, this);
207          }          }
208    
209            InstrumentFile = FileName;
210            InstrumentIdx = Instrument;
211            InstrumentStat = 0;
212    
213            // delete all key groups
214            ActiveKeyGroups.clear();
215    
216          // request gig instrument from instrument manager          // request gig instrument from instrument manager
217          try {          try {
218              instrument_id_t instrid;              instrument_id_t instrid;
# Line 202  namespace LinuxSampler { namespace gig { Line 220  namespace LinuxSampler { namespace gig {
220              instrid.iInstrument = Instrument;              instrid.iInstrument = Instrument;
221              pInstrument = Instruments.Borrow(instrid, this);              pInstrument = Instruments.Borrow(instrid, this);
222              if (!pInstrument) {              if (!pInstrument) {
223                    InstrumentStat = -1;
224                  dmsg(1,("no instrument loaded!!!\n"));                  dmsg(1,("no instrument loaded!!!\n"));
225                  exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
226              }              }
227          }          }
228          catch (RIFF::Exception e) {          catch (RIFF::Exception e) {
229                InstrumentStat = -2;
230              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;
231              throw LinuxSamplerException(msg);              throw LinuxSamplerException(msg);
232          }          }
233          catch (InstrumentResourceManagerException e) {          catch (InstrumentResourceManagerException e) {
234                InstrumentStat = -3;
235              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();
236              throw LinuxSamplerException(msg);              throw LinuxSamplerException(msg);
237          }          }
238          catch (...) {          catch (...) {
239                InstrumentStat = -4;
240              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.");
241          }          }
242    
243            // rebuild ActiveKeyGroups map with key groups of current instrument
244            for (::gig::Region* pRegion = pInstrument->GetFirstRegion(); pRegion; pRegion = pInstrument->GetNextRegion())
245                if (pRegion->KeyGroup) ActiveKeyGroups[pRegion->KeyGroup] = NULL;
246    
247            InstrumentStat = 100;
248    
249          // inform audio driver for the need of two channels          // inform audio driver for the need of two channels
250          try {          try {
251              if (pAudioOutputDevice) pAudioOutputDevice->AcquireChannels(2); // gig Engine only stereo              if (pAudioOutputDevice) pAudioOutputDevice->AcquireChannels(2); // gig Engine only stereo
# Line 247  namespace LinuxSampler { namespace gig { Line 275  namespace LinuxSampler { namespace gig {
275       * update process was completed, so we can continue with playback.       * update process was completed, so we can continue with playback.
276       */       */
277      void Engine::ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) {      void Engine::ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) {
278          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())
279          Enable();          Enable();
280      }      }
281    
# Line 265  namespace LinuxSampler { namespace gig { Line 293  namespace LinuxSampler { namespace gig {
293              throw LinuxSamplerException(msg);              throw LinuxSamplerException(msg);
294          }          }
295    
296            this->AudioDeviceChannelLeft  = 0;
297            this->AudioDeviceChannelRight = 1;
298            this->pOutputLeft             = pAudioOutputDevice->Channel(0)->Buffer();
299            this->pOutputRight            = pAudioOutputDevice->Channel(1)->Buffer();
300            this->MaxSamplesPerCycle      = pAudioOutputDevice->MaxSamplesPerCycle();
301            this->SampleRate              = pAudioOutputDevice->SampleRate();
302    
303          // (re)create disk thread          // (re)create disk thread
304          if (this->pDiskThread) {          if (this->pDiskThread) {
305              this->pDiskThread->StopThread();              this->pDiskThread->StopThread();
# Line 278  namespace LinuxSampler { namespace gig { Line 313  namespace LinuxSampler { namespace gig {
313    
314          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {
315              pVoice->pDiskThread = this->pDiskThread;              pVoice->pDiskThread = this->pDiskThread;
             pVoice->SetOutput(pAudioOut);  
316              dmsg(3,("d"));              dmsg(3,("d"));
317          }          }
318          pVoicePool->clear();          pVoicePool->clear();
# Line 316  namespace LinuxSampler { namespace gig { Line 350  namespace LinuxSampler { namespace gig {
350              AudioOutputDevice* olddevice = pAudioOutputDevice;              AudioOutputDevice* olddevice = pAudioOutputDevice;
351              pAudioOutputDevice = NULL;              pAudioOutputDevice = NULL;
352              olddevice->Disconnect(this);              olddevice->Disconnect(this);
353                AudioDeviceChannelLeft  = -1;
354                AudioDeviceChannelRight = -1;
355          }          }
356      }      }
357    
# Line 408  namespace LinuxSampler { namespace gig { Line 444  namespace LinuxSampler { namespace gig {
444                  pVoice->Render(Samples);                  pVoice->Render(Samples);
445                  if (pVoice->IsActive()) active_voices++; // still active                  if (pVoice->IsActive()) active_voices++; // still active
446                  else { // voice reached end, is now inactive                  else { // voice reached end, is now inactive
447                      KillVoice(pVoice); // remove voice from the list of active voices                      KillVoiceImmediately(pVoice); // remove voice from the list of active voices
448                  }                  }
449              }              }
450              pKey->pEvents->clear(); // free all events on the key              pKey->pEvents->clear(); // free all events on the key
# Line 498  namespace LinuxSampler { namespace gig { Line 534  namespace LinuxSampler { namespace gig {
534    
535          // cancel release process of voices on this key if needed          // cancel release process of voices on this key if needed
536          if (pKey->Active && !SustainPedal) {          if (pKey->Active && !SustainPedal) {
537              pNoteOnEvent->Type = Event::type_cancel_release; // transform event type              Event* pCancelReleaseEvent = pKey->pEvents->alloc();
538              pEvents->move(pNoteOnEvent, pKey->pEvents); // move event to the key's own event list              if (pCancelReleaseEvent) {
539          }                  *pCancelReleaseEvent = *pNoteOnEvent;
540                    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;  
541              }              }
542                else dmsg(1,("Event pool emtpy!\n"));
543          }          }
544          else std::cerr << "No free voice!" << std::endl << std::flush;  
545            // allocate and trigger a new voice for the key
546            LaunchVoice(pNoteOnEvent);
547    
548            // finally move note on event to the key's own event list
549            pEvents->move(pNoteOnEvent, pKey->pEvents);
550      }      }
551    
552      /**      /**
# Line 551  namespace LinuxSampler { namespace gig { Line 581  namespace LinuxSampler { namespace gig {
581      }      }
582    
583      /**      /**
584         *  Allocates and triggers a new voice. This method will usually be
585         *  called by the ProcessNoteOn() method and by the voices itself
586         *  (e.g. to spawn further voices on the same key for layered sounds).
587         *
588         *  @param pNoteOnEvent - key, velocity and time stamp of the event
589         *  @param iLayer       - layer index for the new voice (optional - only
590         *                        in case of layered sounds of course)
591         */
592        void Engine::LaunchVoice(Event* pNoteOnEvent, int iLayer) {
593            midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Key];
594    
595            // allocate a new voice for the key
596            Voice* pNewVoice = pKey->pActiveVoices->alloc();
597            if (pNewVoice) {
598                // launch the new voice
599                if (pNewVoice->Trigger(pNoteOnEvent, this->Pitch, this->pInstrument, iLayer) < 0) {
600                    dmsg(1,("Triggering new voice failed!\n"));
601                    pKey->pActiveVoices->free(pNewVoice);
602                }
603                else { // on success
604                    uint** ppKeyGroup = NULL;
605                    if (pNewVoice->KeyGroup) { // if this voice / key belongs to a key group
606                        ppKeyGroup = &ActiveKeyGroups[pNewVoice->KeyGroup];
607                        if (*ppKeyGroup) { // if there's already an active key in that key group
608                            midi_key_info_t* pOtherKey = &pMIDIKeyInfo[**ppKeyGroup];
609                            // kill all voices on the (other) key
610                            Voice* pVoiceToBeKilled = pOtherKey->pActiveVoices->first();
611                            for (; pVoiceToBeKilled; pVoiceToBeKilled = pOtherKey->pActiveVoices->next())
612                                if (pVoiceToBeKilled != pNewVoice) pVoiceToBeKilled->Kill(pNoteOnEvent);
613                        }
614                    }
615                    if (!pKey->Active) { // mark as active key
616                        pKey->Active = true;
617                        pKey->pSelf  = pActiveKeys->alloc();
618                        *pKey->pSelf = pNoteOnEvent->Key;
619                    }
620                    if (pNewVoice->KeyGroup) {
621                        *ppKeyGroup = pKey->pSelf; // put key as the (new) active key to its key group
622                    }
623                }
624            }
625            else std::cerr << "No free voice!" << std::endl << std::flush;
626        }
627    
628        /**
629       *  Immediately kills the voice given with pVoice (no matter if sustain is       *  Immediately kills the voice given with pVoice (no matter if sustain is
630       *  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.
631       *  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.
632       *       *
633       *  @param pVoice - points to the voice to be killed       *  @param pVoice - points to the voice to be killed
634       */       */
635      void Engine::KillVoice(Voice* pVoice) {      void Engine::KillVoiceImmediately(Voice* pVoice) {
636          if (pVoice) {          if (pVoice) {
637              if (pVoice->IsActive()) pVoice->Kill();              if (pVoice->IsActive()) pVoice->KillImmediately();
638    
639              midi_key_info_t* pKey = &pMIDIKeyInfo[pVoice->MIDIKey];              midi_key_info_t* pKey = &pMIDIKeyInfo[pVoice->MIDIKey];
640    
# Line 568  namespace LinuxSampler { namespace gig { Line 643  namespace LinuxSampler { namespace gig {
643    
644              // 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
645              if (pKey->pActiveVoices->is_empty()) {              if (pKey->pActiveVoices->is_empty()) {
646                    if (pVoice->KeyGroup) { // if voice / key belongs to a key group
647                        uint** ppKeyGroup = &ActiveKeyGroups[pVoice->KeyGroup];
648                        if (*ppKeyGroup == pKey->pSelf) *ppKeyGroup = NULL; // remove key from key group
649                    }
650                  pKey->Active = false;                  pKey->Active = false;
651                  pActiveKeys->free(pKey->pSelf); // remove key from list of active keys                  pActiveKeys->free(pKey->pSelf); // remove key from list of active keys
652                  pKey->pSelf = NULL;                  pKey->pSelf = NULL;
# Line 662  namespace LinuxSampler { namespace gig { Line 741  namespace LinuxSampler { namespace gig {
741          GlobalVolume = f;          GlobalVolume = f;
742      }      }
743    
744        uint Engine::Channels() {
745            return 2;
746        }
747    
748        void Engine::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
749            AudioChannel* pChannel = pAudioOutputDevice->Channel(AudioDeviceChannel);
750            if (!pChannel) throw AudioOutputException("Invalid audio output device channel " + ToString(AudioDeviceChannel));
751            switch (EngineAudioChannel) {
752                case 0: // left output channel
753                    pOutputLeft = pChannel->Buffer();
754                    AudioDeviceChannelLeft = AudioDeviceChannel;
755                    break;
756                case 1: // right output channel
757                    pOutputRight = pChannel->Buffer();
758                    AudioDeviceChannelRight = AudioDeviceChannel;
759                    break;
760                default:
761                    throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
762            }
763        }
764    
765        int Engine::OutputChannel(uint EngineAudioChannel) {
766            switch (EngineAudioChannel) {
767                case 0: // left channel
768                    return AudioDeviceChannelLeft;
769                case 1: // right channel
770                    return AudioDeviceChannelRight;
771                default:
772                    throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
773            }
774        }
775    
776      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
777          return ActiveVoiceCount;          return ActiveVoiceCount;
778      }      }
# Line 690  namespace LinuxSampler { namespace gig { Line 801  namespace LinuxSampler { namespace gig {
801          return pDiskThread->GetBufferFillPercentage();          return pDiskThread->GetBufferFillPercentage();
802      }      }
803    
804        String Engine::EngineName() {
805            return "GigEngine";
806        }
807    
808        String Engine::InstrumentFileName() {
809            return InstrumentFile;
810        }
811    
812        int Engine::InstrumentIndex() {
813            return InstrumentIdx;
814        }
815    
816        int Engine::InstrumentStatus() {
817            return InstrumentStat;
818        }
819    
820      String Engine::Description() {      String Engine::Description() {
821          return "Gigasampler Engine";          return "Gigasampler Engine";
822      }      }
823    
824      String Engine::Version() {      String Engine::Version() {
825          return "0.0.1-0cvs20040423";          String s = "$Revision: 1.10 $";
826            return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
827      }      }
828    
829  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.80  
changed lines
  Added in v.239

  ViewVC Help
Powered by ViewVC