/[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 411 by schoenebeck, Sat Feb 26 02:01:14 2005 UTC revision 424 by schoenebeck, Fri Mar 4 22:54:11 2005 UTC
# Line 25  Line 25 
25  #include "DiskThread.h"  #include "DiskThread.h"
26  #include "Voice.h"  #include "Voice.h"
27  #include "EGADSR.h"  #include "EGADSR.h"
28    #include "../EngineFactory.h"
29    
30  #include "Engine.h"  #include "Engine.h"
31    
# Line 40  namespace LinuxSampler { namespace gig { Line 41  namespace LinuxSampler { namespace gig {
41    
42      std::map<AudioOutputDevice*,Engine*> Engine::engines;      std::map<AudioOutputDevice*,Engine*> Engine::engines;
43    
44        /**
45         * Get a gig::Engine object for the given gig::EngineChannel and the
46         * given AudioOutputDevice. All engine channels which are connected to
47         * the same audio output device will use the same engine instance. This
48         * method will be called by a gig::EngineChannel whenever it's
49         * connecting to a audio output device.
50         *
51         * @param pChannel - engine channel which acquires an engine object
52         * @param pDevice  - the audio output device \a pChannel is connected to
53         */
54      Engine* Engine::AcquireEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {      Engine* Engine::AcquireEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {
55          Engine* pEngine;          Engine* pEngine = NULL;
56            // check if there's already an engine for the given audio output device
57          if (engines.count(pDevice)) {          if (engines.count(pDevice)) {
58              pEngine = engines[pDevice];              dmsg(4,("Using existing gig::Engine.\n"));
59          } else {              pEngine = engines[pDevice];            
60              pEngine = new Engine;          } else { // create a new engine (and disk thread) instance for the given audio output device
61                dmsg(4,("Creating new gig::Engine.\n"));
62                pEngine = (Engine*) EngineFactory::Create("gig");
63              pEngine->Connect(pDevice);              pEngine->Connect(pDevice);
64                engines[pDevice] = pEngine;            
65          }          }
66          pEngine->samplerChannels.push_back(pChannel);          // register engine channel to the engine instance
67            pEngine->engineChannels.push_back(pChannel);
68            dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
69          return pEngine;          return pEngine;
70      }      }
71    
72        /**
73         * Once an engine channel is disconnected from an audio output device,
74         * it wil immediately call this method to unregister itself from the
75         * engine instance and if that engine instance is not used by any other
76         * engine channel anymore, then that engine instance will be destroyed.
77         *
78         * @param pChannel - engine channel which wants to disconnect from it's
79         *                   engine instance
80         * @param pDevice  - audio output device \a pChannel was connected to
81         */
82      void Engine::FreeEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {      void Engine::FreeEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {
83            dmsg(4,("Disconnecting EngineChannel from gig::Engine.\n"));
84          Engine* pEngine = engines[pDevice];          Engine* pEngine = engines[pDevice];
85          pEngine->samplerChannels.remove(pChannel);          // unregister EngineChannel from the Engine instance
86          if (pEngine->samplerChannels.empty()) delete pEngine;          pEngine->engineChannels.remove(pChannel);
87            // if the used Engine instance is not used anymore, then destroy it
88            if (pEngine->engineChannels.empty()) {
89                pDevice->Disconnect(pEngine);
90                engines.erase(pDevice);
91                delete pEngine;
92                dmsg(4,("Destroying gig::Engine.\n"));
93            }
94            else dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
95      }      }
96    
97      Engine::Engine() {      Engine::Engine() {
# Line 109  namespace LinuxSampler { namespace gig { Line 145  namespace LinuxSampler { namespace gig {
145          if (pSynthesisParameters[0]) free(pSynthesisParameters[0]);          if (pSynthesisParameters[0]) free(pSynthesisParameters[0]);
146          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
147          if (pSysexBuffer) delete pSysexBuffer;          if (pSysexBuffer) delete pSysexBuffer;
148            EngineFactory::Destroy(this);
149      }      }
150    
151      void Engine::Enable() {      void Engine::Enable() {
# Line 148  namespace LinuxSampler { namespace gig { Line 185  namespace LinuxSampler { namespace gig {
185          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
186    
187          // reset voice stealing parameters          // reset voice stealing parameters
         itLastStolenVoice = RTList<Voice>::Iterator();  
         iuiLastStolenKey  = RTList<uint>::Iterator();  
188          pVoiceStealingQueue->clear();          pVoiceStealingQueue->clear();
189    
190          // reset to normal chromatic scale (means equal temper)          // reset to normal chromatic scale (means equal temper)
# Line 166  namespace LinuxSampler { namespace gig { Line 201  namespace LinuxSampler { namespace gig {
201    
202          // delete all input events          // delete all input events
203          pEventQueue->init();          pEventQueue->init();
204      }      }    
205    
206      void Engine::Connect(AudioOutputDevice* pAudioOut) {      void Engine::Connect(AudioOutputDevice* pAudioOut) {
207          pAudioOutputDevice = pAudioOut;          pAudioOutputDevice = pAudioOut;
# Line 242  namespace LinuxSampler { namespace gig { Line 277  namespace LinuxSampler { namespace gig {
277          }          }
278      }      }
279    
280        void Engine::ClearEventLists() {
281            pEvents->clear();
282            pCCEvents->clear();
283            for (uint i = 0; i < Event::destination_count; i++) {
284                pSynthesisEvents[i]->clear();
285            }
286        }
287    
288        /**
289         * Copy all events from the given input queue buffer to the engine's
290         * internal event list. This will be done at the beginning of each audio
291         * cycle (that is each RenderAudio() call) to get all events which have
292         * to be processed in the current audio cycle. Each EngineChannel has
293         * it's own input event queue for the common channel specific events
294         * (like NoteOn, NoteOff and ControlChange events). Beside that, the
295         * engine also has a input event queue for global events (usually SysEx
296         * message).
297         *
298         * @param pEventQueue - input event buffer to read from
299         * @param Samples     - number of sample points to be processed in the
300         *                      current audio cycle
301         */
302        void Engine::ImportEvents(RingBuffer<Event>* pEventQueue, uint Samples) {
303            RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
304            Event* pEvent;
305            while (true) {
306                // get next event from input event queue
307                if (!(pEvent = eventQueueReader.pop())) break;
308                // if younger event reached, ignore that and all subsequent ones for now
309                if (pEvent->FragmentPos() >= Samples) {
310                    eventQueueReader--;
311                    dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
312                    pEvent->ResetFragmentPos();
313                    break;
314                }
315                // copy event to internal event list
316                if (pEvents->poolIsEmpty()) {
317                    dmsg(1,("Event pool emtpy!\n"));
318                    break;
319                }
320                *pEvents->allocAppend() = *pEvent;
321            }
322            eventQueueReader.free(); // free all copied events from input queue
323        }    
324    
325      /**      /**
326       *  Let this engine proceed to render the given amount of sample points. The       *  Let this engine proceed to render the given amount of sample points. The
327       *  calculated audio data of all voices of this engine will be placed into       *  calculated audio data of all voices of this engine will be placed into
# Line 249  namespace LinuxSampler { namespace gig { Line 329  namespace LinuxSampler { namespace gig {
329       *  converted to the appropriate value range by the audio output class (e.g.       *  converted to the appropriate value range by the audio output class (e.g.
330       *  AlsaIO or JackIO) right after.       *  AlsaIO or JackIO) right after.
331       *       *
      *  @param pEngineChannel - the engine's channel to be rendered  
332       *  @param Samples - number of sample points to be rendered       *  @param Samples - number of sample points to be rendered
333       *  @returns       0 on success       *  @returns       0 on success
334       */       */
335      int Engine::RenderAudio(LinuxSampler::gig::EngineChannel* pEngineChannel, uint Samples) {      int Engine::RenderAudio(uint Samples) {
336          dmsg(5,("RenderAudio(Samples=%d)\n", Samples));          dmsg(5,("RenderAudio(Samples=%d)\n", Samples));
337    
338          // return if no instrument loaded or engine disabled          // return if engine disabled
339          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
340              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
341              return 0;              return 0;
342          }          }
         if (!pEngineChannel->pInstrument) {  
             dmsg(5,("gig::Engine: no instrument loaded\n"));  
             return 0;  
         }  
   
343    
344          // update time of start and end of this audio fragment (as events' time stamps relate to this)          // update time of start and end of this audio fragment (as events' time stamps relate to this)
345          pEventGenerator->UpdateFragmentTime(Samples);          pEventGenerator->UpdateFragmentTime(Samples);
346    
347            // empty the engine's event lists for the new fragment
348            ClearEventLists();
349    
350          // empty the event lists for the new fragment          // get all events from the engine's global input event queue which belong to the current fragment
351          pEvents->clear();          // (these are usually just SysEx messages)
352          pCCEvents->clear();          ImportEvents(this->pEventQueue, Samples);
353          for (uint i = 0; i < Event::destination_count; i++) {  
354              pSynthesisEvents[i]->clear();          // process engine global events (these are currently only MIDI System Exclusive messages)
355            {
356                RTList<Event>::Iterator itEvent = pEvents->first();
357                RTList<Event>::Iterator end     = pEvents->end();
358                for (; itEvent != end; ++itEvent) {
359                    switch (itEvent->Type) {
360                        case Event::type_sysex:
361                            dmsg(5,("Engine: Sysex received\n"));
362                            ProcessSysex(itEvent);
363                            break;
364                    }
365                }
366            }
367    
368            // reset internal voice counter (just for statistic of active voices)
369            ActiveVoiceCountTemp = 0;
370    
371            // render audio for all engine channels
372            // TODO: should we make voice stealing engine globally? unfortunately this would mean other disadvantages so I left voice stealing in the engine channel space for now
373            {
374                std::list<EngineChannel*>::iterator itChannel = engineChannels.begin();
375                std::list<EngineChannel*>::iterator end       = engineChannels.end();
376                for (; itChannel != end; itChannel++) {
377                    if (!(*itChannel)->pInstrument) continue; // ignore if no instrument loaded
378                    RenderAudio(*itChannel, Samples);
379                }
380          }          }
381    
382            // just some statistics about this engine instance
383            ActiveVoiceCount = ActiveVoiceCountTemp;
384            if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
385    
386            return 0;
387        }
388    
389        void Engine::RenderAudio(EngineChannel* pEngineChannel, uint Samples) {
390            // empty the engine's event lists for the new fragment
391            ClearEventLists();
392            // empty the engine channel's, MIDI key specific event lists
393          {          {
394              RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();              RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
395              RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();              RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
# Line 286  namespace LinuxSampler { namespace gig { Line 399  namespace LinuxSampler { namespace gig {
399          }          }
400    
401    
402          // get all events from the input event queue which belong to the current fragment          // get all events from the engine channels's input event queue which belong to the current fragment
403          {          // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
404              RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();          ImportEvents(pEngineChannel->pEventQueue, Samples);      
             Event* pEvent;  
             while (true) {  
                 // get next event from input event queue  
                 if (!(pEvent = eventQueueReader.pop())) break;  
                 // if younger event reached, ignore that and all subsequent ones for now  
                 if (pEvent->FragmentPos() >= Samples) {  
                     eventQueueReader--;  
                     dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));  
                     pEvent->ResetFragmentPos();  
                     break;  
                 }  
                 // copy event to internal event list  
                 if (pEvents->poolIsEmpty()) {  
                     dmsg(1,("Event pool emtpy!\n"));  
                     break;  
                 }  
                 *pEvents->allocAppend() = *pEvent;  
             }  
             eventQueueReader.free(); // free all copied events from input queue  
         }  
405    
406    
407          // process events          // process events
# Line 319  namespace LinuxSampler { namespace gig { Line 412  namespace LinuxSampler { namespace gig {
412                  switch (itEvent->Type) {                  switch (itEvent->Type) {
413                      case Event::type_note_on:                      case Event::type_note_on:
414                          dmsg(5,("Engine: Note on received\n"));                          dmsg(5,("Engine: Note on received\n"));
415                          ProcessNoteOn(pEngineChannel, itEvent);                          ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
416                          break;                          break;
417                      case Event::type_note_off:                      case Event::type_note_off:
418                          dmsg(5,("Engine: Note off received\n"));                          dmsg(5,("Engine: Note off received\n"));
419                          ProcessNoteOff(pEngineChannel, itEvent);                          ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
420                          break;                          break;
421                      case Event::type_control_change:                      case Event::type_control_change:
422                          dmsg(5,("Engine: MIDI CC received\n"));                          dmsg(5,("Engine: MIDI CC received\n"));
423                          ProcessControlChange(pEngineChannel, itEvent);                          ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
424                          break;                          break;
425                      case Event::type_pitchbend:                      case Event::type_pitchbend:
426                          dmsg(5,("Engine: Pitchbend received\n"));                          dmsg(5,("Engine: Pitchbend received\n"));
427                          ProcessPitchbend(pEngineChannel, itEvent);                          ProcessPitchbend((EngineChannel*)itEvent->pEngineChannel, itEvent);
                         break;  
                     case Event::type_sysex:  
                         dmsg(5,("Engine: Sysex received\n"));  
                         ProcessSysex(itEvent);  
428                          break;                          break;
429                  }                  }
430              }              }
431          }          }
432    
433    
         int active_voices = 0;  
   
434          // render audio from all active voices          // render audio from all active voices
435          {          {
436              RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();              RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
# Line 357  namespace LinuxSampler { namespace gig { Line 444  namespace LinuxSampler { namespace gig {
444                  for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                  for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
445                      // now render current voice                      // now render current voice
446                      itVoice->Render(Samples);                      itVoice->Render(Samples);
447                      if (itVoice->IsActive()) active_voices++; // still active                      if (itVoice->IsActive()) ActiveVoiceCountTemp++; // still active
448                      else { // voice reached end, is now inactive                      else { // voice reached end, is now inactive
449                          FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices                          FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
450                      }                      }
# Line 365  namespace LinuxSampler { namespace gig { Line 452  namespace LinuxSampler { namespace gig {
452              }              }
453          }          }
454    
455            
456          // now render all postponed voices from voice stealing          // now render all postponed voices from voice stealing
457          {          {
458              RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();              RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
# Line 376  namespace LinuxSampler { namespace gig { Line 463  namespace LinuxSampler { namespace gig {
463                  if (itNewVoice) {                  if (itNewVoice) {
464                      for (; itNewVoice; itNewVoice = itNewVoice->itChildVoice) {                      for (; itNewVoice; itNewVoice = itNewVoice->itChildVoice) {
465                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
466                          if (itNewVoice->IsActive()) active_voices++; // still active                          if (itNewVoice->IsActive()) ActiveVoiceCountTemp++; // still active
467                          else { // voice reached end, is now inactive                          else { // voice reached end, is now inactive
468                              FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices                              FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices
469                          }                          }
# Line 387  namespace LinuxSampler { namespace gig { Line 474  namespace LinuxSampler { namespace gig {
474          }          }
475          // reset voice stealing for the new fragment          // reset voice stealing for the new fragment
476          pVoiceStealingQueue->clear();          pVoiceStealingQueue->clear();
477          itLastStolenVoice = RTList<Voice>::Iterator();          pEngineChannel->itLastStolenVoice = RTList<Voice>::Iterator();
478          iuiLastStolenKey  = RTList<uint>::Iterator();          pEngineChannel->iuiLastStolenKey  = RTList<uint>::Iterator();
479            
480    
481          // free all keys which have no active voices left          // free all keys which have no active voices left
482          {          {
# Line 412  namespace LinuxSampler { namespace gig { Line 499  namespace LinuxSampler { namespace gig {
499                  #endif // DEVMODE                  #endif // DEVMODE
500              }              }
501          }          }
502        }
   
         // write that to the disk thread class so that it can print it  
         // on the console for debugging purposes  
         ActiveVoiceCount = active_voices;  
         if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;  
   
   
         return 0;  
     }      
503    
504      /**      /**
505       *  Will be called by the MIDI input device whenever a MIDI system       *  Will be called by the MIDI input device whenever a MIDI system
# Line 434  namespace LinuxSampler { namespace gig { Line 512  namespace LinuxSampler { namespace gig {
512          Event event             = pEventGenerator->CreateEvent();          Event event             = pEventGenerator->CreateEvent();
513          event.Type              = Event::type_sysex;          event.Type              = Event::type_sysex;
514          event.Param.Sysex.Size  = Size;          event.Param.Sysex.Size  = Size;
515            event.pEngineChannel    = NULL; // as Engine global event
516          if (pEventQueue->write_space() > 0) {          if (pEventQueue->write_space() > 0) {
517              if (pSysexBuffer->write_space() >= Size) {              if (pSysexBuffer->write_space() >= Size) {
518                  // copy sysex data to input buffer                  // copy sysex data to input buffer
# Line 636  namespace LinuxSampler { namespace gig { Line 715  namespace LinuxSampler { namespace gig {
715                  // 'oldestkey' algorithm                  // 'oldestkey' algorithm
716                  case voice_steal_algo_keymask: {                  case voice_steal_algo_keymask: {
717                      midi_key_info_t* pOldestKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];                      midi_key_info_t* pOldestKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
718                      if (itLastStolenVoice) {                      if (pEngineChannel->itLastStolenVoice) {
719                          itOldestVoice = itLastStolenVoice;                          itOldestVoice = pEngineChannel->itLastStolenVoice;
720                          ++itOldestVoice;                          ++itOldestVoice;
721                      }                      }
722                      else { // no voice stolen in this audio fragment cycle yet                      else { // no voice stolen in this audio fragment cycle yet
# Line 652  namespace LinuxSampler { namespace gig { Line 731  namespace LinuxSampler { namespace gig {
731                  // try to pick the oldest voice on the oldest active key                  // try to pick the oldest voice on the oldest active key
732                  // (caution: must stay after 'keymask' algorithm !)                  // (caution: must stay after 'keymask' algorithm !)
733                  case voice_steal_algo_oldestkey: {                  case voice_steal_algo_oldestkey: {
734                      if (itLastStolenVoice) {                      if (pEngineChannel->itLastStolenVoice) {
735                          midi_key_info_t* pOldestKey = &pEngineChannel->pMIDIKeyInfo[*iuiLastStolenKey];                          midi_key_info_t* pOldestKey = &pEngineChannel->pMIDIKeyInfo[*pEngineChannel->iuiLastStolenKey];
736                          itOldestVoice = itLastStolenVoice;                          itOldestVoice = pEngineChannel->itLastStolenVoice;
737                          ++itOldestVoice;                          ++itOldestVoice;
738                          if (!itOldestVoice) {                          if (!itOldestVoice) {
739                              iuiOldestKey = iuiLastStolenKey;                              iuiOldestKey = pEngineChannel->iuiLastStolenKey;
740                              ++iuiOldestKey;                              ++iuiOldestKey;
741                              if (iuiOldestKey) {                              if (iuiOldestKey) {
742                                  midi_key_info_t* pOldestKey = &pEngineChannel->pMIDIKeyInfo[*iuiOldestKey];                                  midi_key_info_t* pOldestKey = &pEngineChannel->pMIDIKeyInfo[*iuiOldestKey];
# Line 668  namespace LinuxSampler { namespace gig { Line 747  namespace LinuxSampler { namespace gig {
747                                  return;                                  return;
748                              }                              }
749                          }                          }
750                          else iuiOldestKey = iuiLastStolenKey;                          else iuiOldestKey = pEngineChannel->iuiLastStolenKey;
751                      }                      }
752                      else { // no voice stolen in this audio fragment cycle yet                      else { // no voice stolen in this audio fragment cycle yet
753                          iuiOldestKey = pEngineChannel->pActiveKeys->first();                          iuiOldestKey = pEngineChannel->pActiveKeys->first();
# Line 692  namespace LinuxSampler { namespace gig { Line 771  namespace LinuxSampler { namespace gig {
771              // now kill the selected voice              // now kill the selected voice
772              itOldestVoice->Kill(itNoteOnEvent);              itOldestVoice->Kill(itNoteOnEvent);
773              // remember which voice on which key we stole, so we can simply proceed for the next voice stealing              // remember which voice on which key we stole, so we can simply proceed for the next voice stealing
774              this->itLastStolenVoice = itOldestVoice;              pEngineChannel->itLastStolenVoice = itOldestVoice;
775              this->iuiLastStolenKey = iuiOldestKey;              pEngineChannel->iuiLastStolenKey = iuiOldestKey;
776          }          }
777          else dmsg(1,("Event pool emtpy!\n"));          else dmsg(1,("Event pool emtpy!\n"));
778      }      }
# Line 755  namespace LinuxSampler { namespace gig { Line 834  namespace LinuxSampler { namespace gig {
834          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));
835    
836          switch (itControlChangeEvent->Param.CC.Controller) {          switch (itControlChangeEvent->Param.CC.Controller) {
837              case 64: {              case 7: { // volume
838                    //TODO: not sample accurate yet
839                    pEngineChannel->GlobalVolume = (float) itControlChangeEvent->Param.CC.Value / 127.0f;
840                    break;
841                }
842                case 10: { // panpot
843                    //TODO: not sample accurate yet
844                    const int pan = (int) itControlChangeEvent->Param.CC.Value - 64;
845                    pEngineChannel->GlobalPanLeft  = 1.0f - float(RTMath::Max(pan, 0)) /  63.0f;
846                    pEngineChannel->GlobalPanRight = 1.0f - float(RTMath::Min(pan, 0)) / -64.0f;
847                    break;
848                }
849                case 64: { // sustain
850                  if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
851                      dmsg(4,("PEDAL DOWN\n"));                      dmsg(4,("PEDAL DOWN\n"));
852                      pEngineChannel->SustainPedal = true;                      pEngineChannel->SustainPedal = true;
# Line 940  namespace LinuxSampler { namespace gig { Line 1031  namespace LinuxSampler { namespace gig {
1031      }      }
1032    
1033      String Engine::Version() {      String Engine::Version() {
1034          String s = "$Revision: 1.26 $";          String s = "$Revision: 1.29 $";
1035          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
1036      }      }
1037    

Legend:
Removed from v.411  
changed lines
  Added in v.424

  ViewVC Help
Powered by ViewVC