/[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 56 by schoenebeck, Tue Apr 27 09:21:58 2004 UTC revision 271 by schoenebeck, Fri Oct 8 20:51:39 2004 UTC
# Line 37  namespace LinuxSampler { namespace gig { Line 37  namespace LinuxSampler { namespace gig {
37          pAudioOutputDevice = NULL;          pAudioOutputDevice = NULL;
38          pDiskThread        = NULL;          pDiskThread        = NULL;
39          pEventGenerator    = NULL;          pEventGenerator    = NULL;
40          pEventQueue        = new RingBuffer<Event>(MAX_EVENTS_PER_FRAGMENT);          pSysexBuffer       = new RingBuffer<uint8_t>(SYSEX_BUFFER_SIZE, 0);
41          pEventPool         = new RTELMemoryPool<Event>(MAX_EVENTS_PER_FRAGMENT);          pEventQueue        = new RingBuffer<Event>(MAX_EVENTS_PER_FRAGMENT, 0);
42          pVoicePool         = new RTELMemoryPool<Voice>(MAX_AUDIO_VOICES);          pEventPool         = new Pool<Event>(MAX_EVENTS_PER_FRAGMENT);
43          pActiveKeys        = new RTELMemoryPool<uint>(128);          pVoicePool         = new Pool<Voice>(MAX_AUDIO_VOICES);
44          pEvents            = new RTEList<Event>(pEventPool);          pActiveKeys        = new Pool<uint>(128);
45          pCCEvents          = new RTEList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
46            pEvents            = new RTList<Event>(pEventPool);
47            pCCEvents          = new RTList<Event>(pEventPool);
48          for (uint i = 0; i < Event::destination_count; i++) {          for (uint i = 0; i < Event::destination_count; i++) {
49              pSynthesisEvents[i] = new RTEList<Event>(pEventPool);              pSynthesisEvents[i] = new RTList<Event>(pEventPool);
50          }          }
51          for (uint i = 0; i < 128; i++) {          for (uint i = 0; i < 128; i++) {
52              pMIDIKeyInfo[i].pActiveVoices = new RTEList<Voice>(pVoicePool);              pMIDIKeyInfo[i].pActiveVoices  = new RTList<Voice>(pVoicePool);
53              pMIDIKeyInfo[i].KeyPressed    = false;              pMIDIKeyInfo[i].KeyPressed     = false;
54              pMIDIKeyInfo[i].Active        = false;              pMIDIKeyInfo[i].Active         = false;
55              pMIDIKeyInfo[i].pSelf         = NULL;              pMIDIKeyInfo[i].ReleaseTrigger = false;
56              pMIDIKeyInfo[i].pEvents       = new RTEList<Event>(pEventPool);              pMIDIKeyInfo[i].pEvents        = new RTList<Event>(pEventPool);
57          }          }
58          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
59              pVoice->SetEngine(this);              iterVoice->SetEngine(this);
60          }          }
61          pVoicePool->clear();          pVoicePool->clear();
62    
63          pSynthesisParameters[0] = NULL; // we allocate when an audio device is connected          pSynthesisParameters[0] = NULL; // we allocate when an audio device is connected
64            pBasicFilterParameters  = NULL;
65            pMainFilterParameters   = NULL;
66    
67            InstrumentIdx = -1;
68            InstrumentStat = -1;
69    
70            AudioDeviceChannelLeft  = -1;
71            AudioDeviceChannelRight = -1;
72    
73          ResetInternal();          ResetInternal();
74      }      }
# Line 84  namespace LinuxSampler { namespace gig { Line 94  namespace LinuxSampler { namespace gig {
94          if (pEventPool)  delete pEventPool;          if (pEventPool)  delete pEventPool;
95          if (pVoicePool)  delete pVoicePool;          if (pVoicePool)  delete pVoicePool;
96          if (pActiveKeys) delete pActiveKeys;          if (pActiveKeys) delete pActiveKeys;
97            if (pSysexBuffer) delete pSysexBuffer;
98          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
99            if (pMainFilterParameters) delete[] pMainFilterParameters;
100            if (pBasicFilterParameters) delete[] pBasicFilterParameters;
101          if (pSynthesisParameters[0]) delete[] pSynthesisParameters[0];          if (pSynthesisParameters[0]) delete[] pSynthesisParameters[0];
102            if (pVoiceStealingQueue) delete pVoiceStealingQueue;
103      }      }
104    
105      void Engine::Enable() {      void Engine::Enable() {
106          dmsg(3,("gig::Engine: enabling\n"));          dmsg(3,("gig::Engine: enabling\n"));
107          EngineDisabled.PushAndUnlock(false, 2); // set condition object 'EngineDisabled' to false (wait max. 2s)          EngineDisabled.PushAndUnlock(false, 2); // set condition object 'EngineDisabled' to false (wait max. 2s)
108          dmsg(1,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));          dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
109      }      }
110    
111      void Engine::Disable() {      void Engine::Disable() {
# Line 142  namespace LinuxSampler { namespace gig { Line 156  namespace LinuxSampler { namespace gig {
156          SustainPedal        = false;          SustainPedal        = false;
157          ActiveVoiceCount    = 0;          ActiveVoiceCount    = 0;
158          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
159            GlobalVolume        = 1.0;
160    
161            // reset voice stealing parameters
162            itLastStolenVoice = RTList<Voice>::Iterator();
163            iuiLastStolenKey  = RTList<uint>::Iterator();
164            pVoiceStealingQueue->clear();
165    
166            // reset to normal chromatic scale (means equal temper)
167            memset(&ScaleTuning[0], 0x00, 12);
168    
169          // set all MIDI controller values to zero          // set all MIDI controller values to zero
170          memset(ControllerTable, 0x00, 128);          memset(ControllerTable, 0x00, 128);
# Line 150  namespace LinuxSampler { namespace gig { Line 173  namespace LinuxSampler { namespace gig {
173          for (uint i = 0; i < 128; i++) {          for (uint i = 0; i < 128; i++) {
174              pMIDIKeyInfo[i].pActiveVoices->clear();              pMIDIKeyInfo[i].pActiveVoices->clear();
175              pMIDIKeyInfo[i].pEvents->clear();              pMIDIKeyInfo[i].pEvents->clear();
176              pMIDIKeyInfo[i].KeyPressed = false;              pMIDIKeyInfo[i].KeyPressed     = false;
177              pMIDIKeyInfo[i].Active     = false;              pMIDIKeyInfo[i].Active         = false;
178              pMIDIKeyInfo[i].pSelf      = NULL;              pMIDIKeyInfo[i].ReleaseTrigger = false;
179                pMIDIKeyInfo[i].itSelf         = Pool<uint>::Iterator();
180          }          }
181    
182            // reset all key groups
183            map<uint,uint*>::iterator iter = ActiveKeyGroups.begin();
184            for (; iter != ActiveKeyGroups.end(); iter++) iter->second = NULL;
185    
186          // reset all voices          // reset all voices
187          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
188              pVoice->Reset();              iterVoice->Reset();
189          }          }
190          pVoicePool->clear();          pVoicePool->clear();
191    
# Line 191  namespace LinuxSampler { namespace gig { Line 219  namespace LinuxSampler { namespace gig {
219              Instruments.HandBack(pInstrument, this);              Instruments.HandBack(pInstrument, this);
220          }          }
221    
222            InstrumentFile = FileName;
223            InstrumentIdx = Instrument;
224            InstrumentStat = 0;
225    
226            // delete all key groups
227            ActiveKeyGroups.clear();
228    
229          // request gig instrument from instrument manager          // request gig instrument from instrument manager
230          try {          try {
231              instrument_id_t instrid;              instrument_id_t instrid;
# Line 198  namespace LinuxSampler { namespace gig { Line 233  namespace LinuxSampler { namespace gig {
233              instrid.iInstrument = Instrument;              instrid.iInstrument = Instrument;
234              pInstrument = Instruments.Borrow(instrid, this);              pInstrument = Instruments.Borrow(instrid, this);
235              if (!pInstrument) {              if (!pInstrument) {
236                    InstrumentStat = -1;
237                  dmsg(1,("no instrument loaded!!!\n"));                  dmsg(1,("no instrument loaded!!!\n"));
238                  exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
239              }              }
240          }          }
241          catch (RIFF::Exception e) {          catch (RIFF::Exception e) {
242                InstrumentStat = -2;
243              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;
244              throw LinuxSamplerException(msg);              throw LinuxSamplerException(msg);
245          }          }
246          catch (InstrumentResourceManagerException e) {          catch (InstrumentResourceManagerException e) {
247                InstrumentStat = -3;
248              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();
249              throw LinuxSamplerException(msg);              throw LinuxSamplerException(msg);
250          }          }
251          catch (...) {          catch (...) {
252                InstrumentStat = -4;
253              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.");
254          }          }
255    
256            // rebuild ActiveKeyGroups map with key groups of current instrument
257            for (::gig::Region* pRegion = pInstrument->GetFirstRegion(); pRegion; pRegion = pInstrument->GetNextRegion())
258                if (pRegion->KeyGroup) ActiveKeyGroups[pRegion->KeyGroup] = NULL;
259    
260            InstrumentStat = 100;
261    
262          // inform audio driver for the need of two channels          // inform audio driver for the need of two channels
263          try {          try {
264              if (pAudioOutputDevice) pAudioOutputDevice->AcquireChannels(2); // gig Engine only stereo              if (pAudioOutputDevice) pAudioOutputDevice->AcquireChannels(2); // gig Engine only stereo
# Line 243  namespace LinuxSampler { namespace gig { Line 288  namespace LinuxSampler { namespace gig {
288       * update process was completed, so we can continue with playback.       * update process was completed, so we can continue with playback.
289       */       */
290      void Engine::ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) {      void Engine::ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) {
291          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())
292          Enable();          Enable();
293      }      }
294    
# Line 261  namespace LinuxSampler { namespace gig { Line 306  namespace LinuxSampler { namespace gig {
306              throw LinuxSamplerException(msg);              throw LinuxSamplerException(msg);
307          }          }
308    
309            this->AudioDeviceChannelLeft  = 0;
310            this->AudioDeviceChannelRight = 1;
311            this->pOutputLeft             = pAudioOutputDevice->Channel(0)->Buffer();
312            this->pOutputRight            = pAudioOutputDevice->Channel(1)->Buffer();
313            this->MaxSamplesPerCycle      = pAudioOutputDevice->MaxSamplesPerCycle();
314            this->SampleRate              = pAudioOutputDevice->SampleRate();
315    
316          // (re)create disk thread          // (re)create disk thread
317          if (this->pDiskThread) {          if (this->pDiskThread) {
318              this->pDiskThread->StopThread();              this->pDiskThread->StopThread();
# Line 272  namespace LinuxSampler { namespace gig { Line 324  namespace LinuxSampler { namespace gig {
324              exit(EXIT_FAILURE);              exit(EXIT_FAILURE);
325          }          }
326    
327          for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
328              pVoice->pDiskThread = this->pDiskThread;              iterVoice->pDiskThread = this->pDiskThread;
             pVoice->SetOutput(pAudioOut);  
329              dmsg(3,("d"));              dmsg(3,("d"));
330          }          }
331          pVoicePool->clear();          pVoicePool->clear();
# Line 289  namespace LinuxSampler { namespace gig { Line 340  namespace LinuxSampler { namespace gig {
340          for (int dst = 1; dst < Event::destination_count; dst++)          for (int dst = 1; dst < Event::destination_count; dst++)
341              pSynthesisParameters[dst] = pSynthesisParameters[dst - 1] + pAudioOut->MaxSamplesPerCycle();              pSynthesisParameters[dst] = pSynthesisParameters[dst - 1] + pAudioOut->MaxSamplesPerCycle();
342    
343            // (re)allocate biquad filter parameter sequence
344            if (pBasicFilterParameters) delete[] pBasicFilterParameters;
345            if (pMainFilterParameters)  delete[] pMainFilterParameters;
346            pBasicFilterParameters = new biquad_param_t[pAudioOut->MaxSamplesPerCycle()];
347            pMainFilterParameters  = new biquad_param_t[pAudioOut->MaxSamplesPerCycle()];
348    
349          dmsg(1,("Starting disk thread..."));          dmsg(1,("Starting disk thread..."));
350          pDiskThread->StartThread();          pDiskThread->StartThread();
351          dmsg(1,("OK\n"));          dmsg(1,("OK\n"));
352    
353          for (Voice* pVoice = pVoicePool->first(); pVoice; pVoice = pVoicePool->next()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
354              if (!pVoice->pDiskThread) {              if (!iterVoice->pDiskThread) {
355                  dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));                  dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
356                  exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
357              }              }
# Line 306  namespace LinuxSampler { namespace gig { Line 363  namespace LinuxSampler { namespace gig {
363              AudioOutputDevice* olddevice = pAudioOutputDevice;              AudioOutputDevice* olddevice = pAudioOutputDevice;
364              pAudioOutputDevice = NULL;              pAudioOutputDevice = NULL;
365              olddevice->Disconnect(this);              olddevice->Disconnect(this);
366                AudioDeviceChannelLeft  = -1;
367                AudioDeviceChannelRight = -1;
368          }          }
369      }      }
370    
# Line 339  namespace LinuxSampler { namespace gig { Line 398  namespace LinuxSampler { namespace gig {
398          for (uint i = 0; i < Event::destination_count; i++) {          for (uint i = 0; i < Event::destination_count; i++) {
399              pSynthesisEvents[i]->clear();              pSynthesisEvents[i]->clear();
400          }          }
401            {
402                RTList<uint>::Iterator iuiKey = pActiveKeys->first();
403                RTList<uint>::Iterator end    = pActiveKeys->end();
404                for(; iuiKey != end; ++iuiKey) {
405                    pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key
406                }
407            }
408    
409          // read and copy events from input queue          // read and copy events from input queue
410          Event event = pEventGenerator->CreateEvent();          Event event = pEventGenerator->CreateEvent();
411          while (true) {          while (true) {
412              if (!pEventQueue->pop(&event)) break;              if (!pEventQueue->pop(&event) || pEvents->poolIsEmpty()) break;
413              pEvents->alloc_assign(event);              *pEvents->allocAppend() = event;
414          }          }
415    
416    
# Line 353  namespace LinuxSampler { namespace gig { Line 419  namespace LinuxSampler { namespace gig {
419    
420    
421          // process events          // process events
422          Event* pNextEvent = pEvents->first();          {
423          while (pNextEvent) {              RTList<Event>::Iterator itEvent = pEvents->first();
424              Event* pEvent = pNextEvent;              RTList<Event>::Iterator end     = pEvents->end();
425              pEvents->set_current(pEvent);              for (; itEvent != end; ++itEvent) {
426              pNextEvent = pEvents->next();                  switch (itEvent->Type) {
427              switch (pEvent->Type) {                      case Event::type_note_on:
428                  case Event::type_note_on:                          dmsg(5,("Engine: Note on received\n"));
429                      dmsg(5,("Audio Thread: Note on received\n"));                          ProcessNoteOn(itEvent);
430                      ProcessNoteOn(pEvent);                          break;
431                      break;                      case Event::type_note_off:
432                  case Event::type_note_off:                          dmsg(5,("Engine: Note off received\n"));
433                      dmsg(5,("Audio Thread: Note off received\n"));                          ProcessNoteOff(itEvent);
434                      ProcessNoteOff(pEvent);                          break;
435                      break;                      case Event::type_control_change:
436                  case Event::type_control_change:                          dmsg(5,("Engine: MIDI CC received\n"));
437                      dmsg(5,("Audio Thread: MIDI CC received\n"));                          ProcessControlChange(itEvent);
438                      ProcessControlChange(pEvent);                          break;
439                      break;                      case Event::type_pitchbend:
440                  case Event::type_pitchbend:                          dmsg(5,("Engine: Pitchbend received\n"));
441                      dmsg(5,("Audio Thread: Pitchbend received\n"));                          ProcessPitchbend(itEvent);
442                      ProcessPitchbend(pEvent);                          break;
443                      break;                      case Event::type_sysex:
444                            dmsg(5,("Engine: Sysex received\n"));
445                            ProcessSysex(itEvent);
446                            break;
447                    }
448              }              }
449          }          }
450    
451    
         // render audio from all active voices  
452          int active_voices = 0;          int active_voices = 0;
453          uint* piKey = pActiveKeys->first();  
454          while (piKey) { // iterate through all active keys          // render audio from all active voices
455              midi_key_info_t* pKey = &pMIDIKeyInfo[*piKey];          {
456              pActiveKeys->set_current(piKey);              RTList<uint>::Iterator iuiKey = pActiveKeys->first();
457              piKey = pActiveKeys->next();              RTList<uint>::Iterator end    = pActiveKeys->end();
458                while (iuiKey != end) { // iterate through all active keys
459              Voice* pVoiceNext = pKey->pActiveVoices->first();                  midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];
460              while (pVoiceNext) { // iterate through all voices on this key                  ++iuiKey;
461                  // already get next voice on key  
462                  Voice* pVoice = pVoiceNext;                  RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
463                  pKey->pActiveVoices->set_current(pVoice);                  RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
464                  pVoiceNext = pKey->pActiveVoices->next();                  for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
465                        // now render current voice
466                  // now render current voice                      itVoice->Render(Samples);
467                  pVoice->Render(Samples);                      if (itVoice->IsActive()) active_voices++; // still active
468                  if (pVoice->IsActive()) active_voices++; // still active                      else { // voice reached end, is now inactive
469                  else { // voice reached end, is now inactive                          KillVoiceImmediately(itVoice); // remove voice from the list of active voices
470                      KillVoice(pVoice); // remove voice from the list of active voices                      }
471                    }
472                }
473            }
474    
475    
476            // now render all postponed voices from voice stealing
477            {
478                RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
479                RTList<Event>::Iterator end               = pVoiceStealingQueue->end();
480                for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
481                    Pool<Voice>::Iterator itNewVoice = LaunchVoice(itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false);
482                    if (itNewVoice) {
483                        itNewVoice->Render(Samples);
484                        if (itNewVoice->IsActive()) active_voices++; // still active
485                        else { // voice reached end, is now inactive
486                            KillVoiceImmediately(itNewVoice); // remove voice from the list of active voices
487                        }
488                  }                  }
489                    else dmsg(1,("Ouch, voice stealing didn't work out!\n"));
490              }              }
             pKey->pEvents->clear(); // free all events on the key  
491          }          }
492            // reset voice stealing for the new fragment
493            pVoiceStealingQueue->clear();
494            itLastStolenVoice = RTList<Voice>::Iterator();
495            iuiLastStolenKey  = RTList<uint>::Iterator();
496    
497    
498          // write that to the disk thread class so that it can print it          // write that to the disk thread class so that it can print it
# Line 422  namespace LinuxSampler { namespace gig { Line 512  namespace LinuxSampler { namespace gig {
512       *  @param Velocity - MIDI velocity value of the triggered key       *  @param Velocity - MIDI velocity value of the triggered key
513       */       */
514      void Engine::SendNoteOn(uint8_t Key, uint8_t Velocity) {      void Engine::SendNoteOn(uint8_t Key, uint8_t Velocity) {
515          Event event    = pEventGenerator->CreateEvent();          Event event               = pEventGenerator->CreateEvent();
516          event.Type     = Event::type_note_on;          event.Type                = Event::type_note_on;
517          event.Key      = Key;          event.Param.Note.Key      = Key;
518          event.Velocity = Velocity;          event.Param.Note.Velocity = Velocity;
519          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
520          else dmsg(1,("Engine: Input event queue full!"));          else dmsg(1,("Engine: Input event queue full!"));
521      }      }
# Line 438  namespace LinuxSampler { namespace gig { Line 528  namespace LinuxSampler { namespace gig {
528       *  @param Velocity - MIDI release velocity value of the released key       *  @param Velocity - MIDI release velocity value of the released key
529       */       */
530      void Engine::SendNoteOff(uint8_t Key, uint8_t Velocity) {      void Engine::SendNoteOff(uint8_t Key, uint8_t Velocity) {
531          Event event    = pEventGenerator->CreateEvent();          Event event               = pEventGenerator->CreateEvent();
532          event.Type     = Event::type_note_off;          event.Type                = Event::type_note_off;
533          event.Key      = Key;          event.Param.Note.Key      = Key;
534          event.Velocity = Velocity;          event.Param.Note.Velocity = Velocity;
535          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
536          else dmsg(1,("Engine: Input event queue full!"));          else dmsg(1,("Engine: Input event queue full!"));
537      }      }
# Line 453  namespace LinuxSampler { namespace gig { Line 543  namespace LinuxSampler { namespace gig {
543       *  @param Pitch - MIDI pitch value (-8192 ... +8191)       *  @param Pitch - MIDI pitch value (-8192 ... +8191)
544       */       */
545      void Engine::SendPitchbend(int Pitch) {      void Engine::SendPitchbend(int Pitch) {
546          Event event = pEventGenerator->CreateEvent();          Event event             = pEventGenerator->CreateEvent();
547          event.Type  = Event::type_pitchbend;          event.Type              = Event::type_pitchbend;
548          event.Pitch = Pitch;          event.Param.Pitch.Pitch = Pitch;
549          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
550          else dmsg(1,("Engine: Input event queue full!"));          else dmsg(1,("Engine: Input event queue full!"));
551      }      }
# Line 468  namespace LinuxSampler { namespace gig { Line 558  namespace LinuxSampler { namespace gig {
558       *  @param Value      - value of the control change       *  @param Value      - value of the control change
559       */       */
560      void Engine::SendControlChange(uint8_t Controller, uint8_t Value) {      void Engine::SendControlChange(uint8_t Controller, uint8_t Value) {
561          Event event      = pEventGenerator->CreateEvent();          Event event               = pEventGenerator->CreateEvent();
562          event.Type       = Event::type_control_change;          event.Type                = Event::type_control_change;
563          event.Controller = Controller;          event.Param.CC.Controller = Controller;
564          event.Value      = Value;          event.Param.CC.Value      = Value;
565          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
566          else dmsg(1,("Engine: Input event queue full!"));          else dmsg(1,("Engine: Input event queue full!"));
567      }      }
568    
569      /**      /**
570         *  Will be called by the MIDI input device whenever a MIDI system
571         *  exclusive message has arrived.
572         *
573         *  @param pData - pointer to sysex data
574         *  @param Size  - lenght of sysex data (in bytes)
575         */
576        void Engine::SendSysex(void* pData, uint Size) {
577            Event event             = pEventGenerator->CreateEvent();
578            event.Type              = Event::type_sysex;
579            event.Param.Sysex.Size  = Size;
580            if (pEventQueue->write_space() > 0) {
581                if (pSysexBuffer->write_space() >= Size) {
582                    // copy sysex data to input buffer
583                    uint toWrite = Size;
584                    uint8_t* pPos = (uint8_t*) pData;
585                    while (toWrite) {
586                        const uint writeNow = RTMath::Min(toWrite, pSysexBuffer->write_space_to_end());
587                        pSysexBuffer->write(pPos, writeNow);
588                        toWrite -= writeNow;
589                        pPos    += writeNow;
590    
591                    }
592                    // finally place sysex event into input event queue
593                    pEventQueue->push(&event);
594                }
595                else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,SYSEX_BUFFER_SIZE));
596            }
597            else dmsg(1,("Engine: Input event queue full!"));
598        }
599    
600        /**
601       *  Assigns and triggers a new voice for the respective MIDI key.       *  Assigns and triggers a new voice for the respective MIDI key.
602       *       *
603       *  @param pNoteOnEvent - key, velocity and time stamp of the event       *  @param itNoteOnEvent - key, velocity and time stamp of the event
604       */       */
605      void Engine::ProcessNoteOn(Event* pNoteOnEvent) {      void Engine::ProcessNoteOn(Pool<Event>::Iterator& itNoteOnEvent) {
606          midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Key];          midi_key_info_t* pKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
607    
608          pKey->KeyPressed = true; // the MIDI key was now pressed down          pKey->KeyPressed = true; // the MIDI key was now pressed down
609    
610          // cancel release process of voices on this key if needed          // cancel release process of voices on this key if needed
611          if (pKey->Active && !SustainPedal) {          if (pKey->Active && !SustainPedal) {
612              pNoteOnEvent->Type = Event::type_cancel_release; // transform event type              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
613              pEvents->move(pNoteOnEvent, pKey->pEvents); // move event to the key's own event list              if (itCancelReleaseEvent) {
614          }                  *itCancelReleaseEvent = *itNoteOnEvent;                  // copy event
615                    itCancelReleaseEvent->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;  
616              }              }
617                else dmsg(1,("Event pool emtpy!\n"));
618          }          }
619          else std::cerr << "No free voice!" << std::endl << std::flush;  
620            // move note on event to the key's own event list
621            RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
622    
623            // allocate and trigger a new voice for the key
624            LaunchVoice(itNoteOnEventOnKeyList);
625      }      }
626    
627      /**      /**
# Line 515  namespace LinuxSampler { namespace gig { Line 630  namespace LinuxSampler { namespace gig {
630       *  sustain pedal will be released or voice turned inactive by itself (e.g.       *  sustain pedal will be released or voice turned inactive by itself (e.g.
631       *  due to completion of sample playback).       *  due to completion of sample playback).
632       *       *
633       *  @param pNoteOffEvent - key, velocity and time stamp of the event       *  @param itNoteOffEvent - key, velocity and time stamp of the event
634       */       */
635      void Engine::ProcessNoteOff(Event* pNoteOffEvent) {      void Engine::ProcessNoteOff(Pool<Event>::Iterator& itNoteOffEvent) {
636          midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOffEvent->Key];          midi_key_info_t* pKey = &pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];
637    
638          pKey->KeyPressed = false; // the MIDI key was now released          pKey->KeyPressed = false; // the MIDI key was now released
639    
640          // release voices on this key if needed          // release voices on this key if needed
641          if (pKey->Active && !SustainPedal) {          if (pKey->Active && !SustainPedal) {
642              pNoteOffEvent->Type = Event::type_release; // transform event type              itNoteOffEvent->Type = Event::type_release; // transform event type
643              pEvents->move(pNoteOffEvent, pKey->pEvents); // move event to the key's own event list          }
644    
645            // move event to the key's own event list
646            RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
647    
648            // spawn release triggered voice(s) if needed
649            if (pKey->ReleaseTrigger) {
650                LaunchVoice(itNoteOffEventOnKeyList, 0, true);
651                pKey->ReleaseTrigger = false;
652          }          }
653      }      }
654    
# Line 533  namespace LinuxSampler { namespace gig { Line 656  namespace LinuxSampler { namespace gig {
656       *  Moves pitchbend event from the general (input) event list to the pitch       *  Moves pitchbend event from the general (input) event list to the pitch
657       *  event list.       *  event list.
658       *       *
659       *  @param pPitchbendEvent - absolute pitch value and time stamp of the event       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event
660       */       */
661      void Engine::ProcessPitchbend(Event* pPitchbendEvent) {      void Engine::ProcessPitchbend(Pool<Event>::Iterator& itPitchbendEvent) {
662          this->Pitch = pPitchbendEvent->Pitch; // store current pitch value          this->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value
663          pEvents->move(pPitchbendEvent, pSynthesisEvents[Event::destination_vco]);          itPitchbendEvent.moveToEndOf(pSynthesisEvents[Event::destination_vco]);
664        }
665    
666        /**
667         *  Allocates and triggers a new voice. This method will usually be
668         *  called by the ProcessNoteOn() method and by the voices itself
669         *  (e.g. to spawn further voices on the same key for layered sounds).
670         *
671         *  @param itNoteOnEvent       - key, velocity and time stamp of the event
672         *  @param iLayer              - layer index for the new voice (optional - only
673         *                               in case of layered sounds of course)
674         *  @param ReleaseTriggerVoice - if new voice is a release triggered voice
675         *                               (optional, default = false)
676         *  @param VoiceStealing       - if voice stealing should be performed
677         *                               when there is no free voice
678         *                               (optional, default = true)
679         *  @returns pointer to new voice or NULL if there was no free voice or
680         *           if an error occured while trying to trigger the new voice
681         */
682        Pool<Voice>::Iterator Engine::LaunchVoice(Pool<Event>::Iterator& itNoteOnEvent, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) {
683            midi_key_info_t* pKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
684    
685            // allocate a new voice for the key
686            Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
687            if (itNewVoice) {
688                // launch the new voice
689                if (itNewVoice->Trigger(itNoteOnEvent, this->Pitch, this->pInstrument, iLayer, ReleaseTriggerVoice) < 0) {
690                    dmsg(1,("Triggering new voice failed!\n"));
691                    pKey->pActiveVoices->free(itNewVoice);
692                }
693                else { // on success
694                    uint** ppKeyGroup = NULL;
695                    if (itNewVoice->KeyGroup) { // if this voice / key belongs to a key group
696                        ppKeyGroup = &ActiveKeyGroups[itNewVoice->KeyGroup];
697                        if (*ppKeyGroup) { // if there's already an active key in that key group
698                            midi_key_info_t* pOtherKey = &pMIDIKeyInfo[**ppKeyGroup];
699                            // kill all voices on the (other) key
700                            RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
701                            RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
702                            for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
703                                if (itVoiceToBeKilled->Type != Voice::type_release_trigger) itVoiceToBeKilled->Kill(itNoteOnEvent);
704                            }
705                        }
706                    }
707                    if (!pKey->Active) { // mark as active key
708                        pKey->Active = true;
709                        pKey->itSelf = pActiveKeys->allocAppend();
710                        *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
711                    }
712                    if (itNewVoice->KeyGroup) {
713                        *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group
714                    }
715                    if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
716                    return itNewVoice; // success
717                }
718            }
719            else if (VoiceStealing) StealVoice(itNoteOnEvent, iLayer, ReleaseTriggerVoice); // no free voice left, so steal one
720    
721            return Pool<Voice>::Iterator(); // no free voice or error
722        }
723    
724        /**
725         *  Will be called by LaunchVoice() method in case there are no free
726         *  voices left. This method will select and kill one old voice for
727         *  voice stealing and postpone the note-on event until the selected
728         *  voice actually died.
729         *
730         *  @param itNoteOnEvent       - key, velocity and time stamp of the event
731         *  @param iLayer              - layer index for the new voice
732         *  @param ReleaseTriggerVoice - if new voice is a release triggered voice
733         */
734        void Engine::StealVoice(Pool<Event>::Iterator& itNoteOnEvent, int iLayer, bool ReleaseTriggerVoice) {
735            if (!pEventPool->poolIsEmpty()) {
736    
737                RTList<uint>::Iterator  iuiOldestKey;
738                RTList<Voice>::Iterator itOldestVoice;
739    
740                // Select one voice for voice stealing
741                switch (VOICE_STEAL_ALGORITHM) {
742    
743                    // try to pick the oldest voice on the key where the new
744                    // voice should be spawned, if there is no voice on that
745                    // key, or no voice left to kill there, then procceed with
746                    // 'oldestkey' algorithm
747                    case voice_steal_algo_keymask: {
748                        midi_key_info_t* pOldestKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
749                        if (itLastStolenVoice) {
750                            itOldestVoice = itLastStolenVoice;
751                            ++itOldestVoice;
752                        }
753                        else { // no voice stolen in this audio fragment cycle yet
754                            itOldestVoice = pOldestKey->pActiveVoices->first();
755                        }
756                        if (itOldestVoice) {
757                            iuiOldestKey = pOldestKey->itSelf;
758                            break; // selection succeeded
759                        }
760                    } // no break - intentional !
761    
762                    // try to pick the oldest voice on the oldest active key
763                    // (caution: must stay after 'keymask' algorithm !)
764                    case voice_steal_algo_oldestkey: {
765                        if (itLastStolenVoice) {
766                            midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*iuiLastStolenKey];
767                            itOldestVoice = itLastStolenVoice;
768                            ++itOldestVoice;
769                            if (!itOldestVoice) {
770                                iuiOldestKey = iuiLastStolenKey;
771                                ++iuiOldestKey;
772                                if (iuiOldestKey) {
773                                    midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*iuiOldestKey];
774                                    itOldestVoice = pOldestKey->pActiveVoices->first();
775                                }
776                                else { // too less voices, even for voice stealing
777                                    dmsg(1,("Voice overflow! - You might recompile with higher MAX_AUDIO_VOICES!\n"));
778                                    return;
779                                }
780                            }
781                            else iuiOldestKey = iuiLastStolenKey;
782                        }
783                        else { // no voice stolen in this audio fragment cycle yet
784                            iuiOldestKey = pActiveKeys->first();
785                            midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*iuiOldestKey];
786                            itOldestVoice = pOldestKey->pActiveVoices->first();
787                        }
788                        break;
789                    }
790    
791                    // don't steal anything
792                    case voice_steal_algo_none:
793                    default: {
794                        dmsg(1,("No free voice (voice stealing disabled)!\n"));
795                        return;
796                    }
797                }
798    
799                // now kill the selected voice
800                itOldestVoice->Kill(itNoteOnEvent);
801                // remember which voice on which key we stole, so we can simply proceed for the next voice stealing
802                this->itLastStolenVoice = itOldestVoice;
803                this->iuiLastStolenKey = iuiOldestKey;
804                // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
805                RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
806                if (itStealEvent) {
807                    *itStealEvent = *itNoteOnEvent; // copy event
808                    itStealEvent->Param.Note.Layer = iLayer;
809                    itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
810                }
811                else dmsg(1,("Voice stealing queue full!\n"));
812            }
813            else dmsg(1,("Event pool emtpy!\n"));
814      }      }
815    
816      /**      /**
# Line 545  namespace LinuxSampler { namespace gig { Line 818  namespace LinuxSampler { namespace gig {
818       *  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.
819       *  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.
820       *       *
821       *  @param pVoice - points to the voice to be killed       *  @param itVoice - points to the voice to be killed
822       */       */
823      void Engine::KillVoice(Voice* pVoice) {      void Engine::KillVoiceImmediately(Pool<Voice>::Iterator& itVoice) {
824          if (pVoice) {          if (itVoice) {
825              if (pVoice->IsActive()) pVoice->Kill();              if (itVoice->IsActive()) itVoice->KillImmediately();
826    
827                midi_key_info_t* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];
828    
829              midi_key_info_t* pKey = &pMIDIKeyInfo[pVoice->MIDIKey];              uint keygroup = itVoice->KeyGroup;
830    
831              // free the voice object              // free the voice object
832              pVoicePool->free(pVoice);              pVoicePool->free(itVoice);
833    
834              // 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
835              if (pKey->pActiveVoices->is_empty()) {              if (pKey->pActiveVoices->isEmpty()) {
836                    if (keygroup) { // if voice / key belongs to a key group
837                        uint** ppKeyGroup = &ActiveKeyGroups[keygroup];
838                        if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group
839                    }
840                  pKey->Active = false;                  pKey->Active = false;
841                  pActiveKeys->free(pKey->pSelf); // remove key from list of active keys                  pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
842                  pKey->pSelf = NULL;                  pKey->itSelf = RTList<uint>::Iterator();
843                    pKey->ReleaseTrigger = false;
844                    pKey->pEvents->clear();
845                  dmsg(3,("Key has no more voices now\n"));                  dmsg(3,("Key has no more voices now\n"));
846              }              }
847          }          }
# Line 571  namespace LinuxSampler { namespace gig { Line 852  namespace LinuxSampler { namespace gig {
852       *  Reacts on supported control change commands (e.g. pitch bend wheel,       *  Reacts on supported control change commands (e.g. pitch bend wheel,
853       *  modulation wheel, aftertouch).       *  modulation wheel, aftertouch).
854       *       *
855       *  @param pControlChangeEvent - controller, value and time stamp of the event       *  @param itControlChangeEvent - controller, value and time stamp of the event
856       */       */
857      void Engine::ProcessControlChange(Event* pControlChangeEvent) {      void Engine::ProcessControlChange(Pool<Event>::Iterator& itControlChangeEvent) {
858          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", pControlChangeEvent->Controller, pControlChangeEvent->Value));          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));
859    
860          switch (pControlChangeEvent->Controller) {          switch (itControlChangeEvent->Param.CC.Controller) {
861              case 64: {              case 64: {
862                  if (pControlChangeEvent->Value >= 64 && !SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value >= 64 && !SustainPedal) {
863                      dmsg(4,("PEDAL DOWN\n"));                      dmsg(4,("PEDAL DOWN\n"));
864                      SustainPedal = true;                      SustainPedal = true;
865    
866                      // cancel release process of voices if necessary                      // cancel release process of voices if necessary
867                      uint* piKey = pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pActiveKeys->first();
868                      if (piKey) {                      if (iuiKey) {
869                          pControlChangeEvent->Type = Event::type_cancel_release; // transform event type                          itControlChangeEvent->Type = Event::type_cancel_release; // transform event type
870                          while (piKey) {                          while (iuiKey) {
871                              midi_key_info_t* pKey = &pMIDIKeyInfo[*piKey];                              midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];
872                              pActiveKeys->set_current(piKey);                              ++iuiKey;
                             piKey = pActiveKeys->next();  
873                              if (!pKey->KeyPressed) {                              if (!pKey->KeyPressed) {
874                                  Event* pNewEvent = pKey->pEvents->alloc();                                  RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
875                                  if (pNewEvent) *pNewEvent = *pControlChangeEvent; // copy event to the key's own event list                                  if (itNewEvent) *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
876                                  else dmsg(1,("Event pool emtpy!\n"));                                  else dmsg(1,("Event pool emtpy!\n"));
877                              }                              }
878                          }                          }
879                      }                      }
880                  }                  }
881                  if (pControlChangeEvent->Value < 64 && SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value < 64 && SustainPedal) {
882                      dmsg(4,("PEDAL UP\n"));                      dmsg(4,("PEDAL UP\n"));
883                      SustainPedal = false;                      SustainPedal = false;
884    
885                      // release voices if their respective key is not pressed                      // release voices if their respective key is not pressed
886                      uint* piKey = pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pActiveKeys->first();
887                      if (piKey) {                      if (iuiKey) {
888                          pControlChangeEvent->Type = Event::type_release; // transform event type                          itControlChangeEvent->Type = Event::type_release; // transform event type
889                          while (piKey) {                          while (iuiKey) {
890                              midi_key_info_t* pKey = &pMIDIKeyInfo[*piKey];                              midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];
891                              pActiveKeys->set_current(piKey);                              ++iuiKey;
                             piKey = pActiveKeys->next();  
892                              if (!pKey->KeyPressed) {                              if (!pKey->KeyPressed) {
893                                  Event* pNewEvent = pKey->pEvents->alloc();                                  RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
894                                  if (pNewEvent) *pNewEvent = *pControlChangeEvent; // copy event to the key's own event list                                  if (itNewEvent) *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
895                                  else dmsg(1,("Event pool emtpy!\n"));                                  else dmsg(1,("Event pool emtpy!\n"));
896                              }                              }
897                          }                          }
# Line 623  namespace LinuxSampler { namespace gig { Line 902  namespace LinuxSampler { namespace gig {
902          }          }
903    
904          // update controller value in the engine's controller table          // update controller value in the engine's controller table
905          ControllerTable[pControlChangeEvent->Controller] = pControlChangeEvent->Value;          ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
906    
907          // move event from the unsorted event list to the control change event list          // move event from the unsorted event list to the control change event list
908          pEvents->move(pControlChangeEvent, pCCEvents);          itControlChangeEvent.moveToEndOf(pCCEvents);
909        }
910    
911        /**
912         *  Reacts on MIDI system exclusive messages.
913         *
914         *  @param itSysexEvent - sysex data size and time stamp of the sysex event
915         */
916        void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
917            RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
918    
919            uint8_t exclusive_status, id;
920            if (!reader.pop(&exclusive_status)) goto free_sysex_data;
921            if (!reader.pop(&id))               goto free_sysex_data;
922            if (exclusive_status != 0xF0)       goto free_sysex_data;
923    
924            switch (id) {
925                case 0x41: { // Roland
926                    uint8_t device_id, model_id, cmd_id;
927                    if (!reader.pop(&device_id)) goto free_sysex_data;
928                    if (!reader.pop(&model_id))  goto free_sysex_data;
929                    if (!reader.pop(&cmd_id))    goto free_sysex_data;
930                    if (model_id != 0x42 /*GS*/) goto free_sysex_data;
931                    if (cmd_id != 0x12 /*DT1*/)  goto free_sysex_data;
932    
933                    // command address
934                    uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB)
935                    const RingBuffer<uint8_t>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later
936                    if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
937                    if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
938                    }
939                    else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
940                    }
941                    else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)
942                        switch (addr[3]) {
943                            case 0x40: { // scale tuning
944                                uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave
945                                if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;
946                                uint8_t checksum;
947                                if (!reader.pop(&checksum))                      goto free_sysex_data;
948                                if (GSCheckSum(checksum_reader, 12) != checksum) goto free_sysex_data;
949                                for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;
950                                AdjustScale((int8_t*) scale_tunes);
951                                break;
952                            }
953                        }
954                    }
955                    else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)
956                    }
957                    else if (addr[0] == 0x41) { // Drum Setup Parameters
958                    }
959                    break;
960                }
961            }
962    
963            free_sysex_data: // finally free sysex data
964            pSysexBuffer->increment_read_ptr(itSysexEvent->Param.Sysex.Size);
965        }
966    
967        /**
968         * Calculates the Roland GS sysex check sum.
969         *
970         * @param AddrReader - reader which currently points to the first GS
971         *                     command address byte of the GS sysex message in
972         *                     question
973         * @param DataSize   - size of the GS message data (in bytes)
974         */
975        uint8_t Engine::GSCheckSum(const RingBuffer<uint8_t>::NonVolatileReader AddrReader, uint DataSize) {
976            RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader;
977            uint bytes = 3 /*addr*/ + DataSize;
978            uint8_t addr_and_data[bytes];
979            reader.read(&addr_and_data[0], bytes);
980            uint8_t sum = 0;
981            for (uint i = 0; i < bytes; i++) sum += addr_and_data[i];
982            return 128 - sum % 128;
983        }
984    
985        /**
986         * Allows to tune each of the twelve semitones of an octave.
987         *
988         * @param ScaleTunes - detuning of all twelve semitones (in cents)
989         */
990        void Engine::AdjustScale(int8_t ScaleTunes[12]) {
991            memcpy(&this->ScaleTuning[0], &ScaleTunes[0], 12); //TODO: currently not sample accurate
992      }      }
993    
994      /**      /**
# Line 635  namespace LinuxSampler { namespace gig { Line 997  namespace LinuxSampler { namespace gig {
997       */       */
998      void Engine::ResetSynthesisParameters(Event::destination_t dst, float val) {      void Engine::ResetSynthesisParameters(Event::destination_t dst, float val) {
999          int maxsamples = pAudioOutputDevice->MaxSamplesPerCycle();          int maxsamples = pAudioOutputDevice->MaxSamplesPerCycle();
1000          for (int i = 0; i < maxsamples; i++) pSynthesisParameters[dst][i] = val;          float* m = &pSynthesisParameters[dst][0];
1001            for (int i = 0; i < maxsamples; i += 4) {
1002               m[i]   = val;
1003               m[i+1] = val;
1004               m[i+2] = val;
1005               m[i+3] = val;
1006            }
1007      }      }
1008    
1009      float Engine::Volume() {      float Engine::Volume() {
# Line 646  namespace LinuxSampler { namespace gig { Line 1014  namespace LinuxSampler { namespace gig {
1014          GlobalVolume = f;          GlobalVolume = f;
1015      }      }
1016    
1017        uint Engine::Channels() {
1018            return 2;
1019        }
1020    
1021        void Engine::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
1022            AudioChannel* pChannel = pAudioOutputDevice->Channel(AudioDeviceChannel);
1023            if (!pChannel) throw AudioOutputException("Invalid audio output device channel " + ToString(AudioDeviceChannel));
1024            switch (EngineAudioChannel) {
1025                case 0: // left output channel
1026                    pOutputLeft = pChannel->Buffer();
1027                    AudioDeviceChannelLeft = AudioDeviceChannel;
1028                    break;
1029                case 1: // right output channel
1030                    pOutputRight = pChannel->Buffer();
1031                    AudioDeviceChannelRight = AudioDeviceChannel;
1032                    break;
1033                default:
1034                    throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
1035            }
1036        }
1037    
1038        int Engine::OutputChannel(uint EngineAudioChannel) {
1039            switch (EngineAudioChannel) {
1040                case 0: // left channel
1041                    return AudioDeviceChannelLeft;
1042                case 1: // right channel
1043                    return AudioDeviceChannelRight;
1044                default:
1045                    throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
1046            }
1047        }
1048    
1049      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
1050          return ActiveVoiceCount;          return ActiveVoiceCount;
1051      }      }
# Line 674  namespace LinuxSampler { namespace gig { Line 1074  namespace LinuxSampler { namespace gig {
1074          return pDiskThread->GetBufferFillPercentage();          return pDiskThread->GetBufferFillPercentage();
1075      }      }
1076    
1077        String Engine::EngineName() {
1078            return "GigEngine";
1079        }
1080    
1081        String Engine::InstrumentFileName() {
1082            return InstrumentFile;
1083        }
1084    
1085        int Engine::InstrumentIndex() {
1086            return InstrumentIdx;
1087        }
1088    
1089        int Engine::InstrumentStatus() {
1090            return InstrumentStat;
1091        }
1092    
1093      String Engine::Description() {      String Engine::Description() {
1094          return "Gigasampler Engine";          return "Gigasampler Engine";
1095      }      }
1096    
1097      String Engine::Version() {      String Engine::Version() {
1098          return "0.0.1-0cvs20040423";          String s = "$Revision: 1.15 $";
1099            return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
1100      }      }
1101    
1102  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.56  
changed lines
  Added in v.271

  ViewVC Help
Powered by ViewVC