/[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 1700 by persson, Sun Feb 17 12:40:59 2008 UTC revision 1895 by persson, Sun May 3 12:15:40 2009 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2009 Christian Schoenebeck                         *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 107  namespace LinuxSampler { namespace gig { Line 107  namespace LinuxSampler { namespace gig {
107          pSysexBuffer       = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0);          pSysexBuffer       = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0);
108          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
109          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
110          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);          pVoicePool         = new Pool<Voice>(GLOBAL_MAX_VOICES);
111          pDimRegionPool[0]  = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES);          pDimRegionPool[0]  = new Pool< ::gig::DimensionRegion*>(GLOBAL_MAX_VOICES);
112          pDimRegionPool[1]  = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES);          pDimRegionPool[1]  = new Pool< ::gig::DimensionRegion*>(GLOBAL_MAX_VOICES);
113          pVoiceStealingQueue = new RTList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
114          pGlobalEvents      = new RTList<Event>(pEventPool);          pGlobalEvents      = new RTList<Event>(pEventPool);
115            iMaxDiskStreams    = GLOBAL_MAX_STREAMS;
116            FrameTime          = 0;
117    
118          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
119              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
# Line 211  namespace LinuxSampler { namespace gig { Line 213  namespace LinuxSampler { namespace gig {
213                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
214                          iPendingStreamDeletions++;                          iPendingStreamDeletions++;
215                      }                      }
216                        // free the voice to the voice pool and update key info
217                        FreeVoice(pEngineChannel, itVoice);
218                  }                  }
219              }              }
220          }          }
# Line 291  namespace LinuxSampler { namespace gig { Line 295  namespace LinuxSampler { namespace gig {
295          // make sure that the engine does not get any sysex messages          // make sure that the engine does not get any sysex messages
296          // while it's reseting          // while it's reseting
297          bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);          bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
298          ActiveVoiceCount    = 0;          SetVoiceCount(0);
299          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
300    
301          // reset voice stealing parameters          // reset voice stealing parameters
# Line 342  namespace LinuxSampler { namespace gig { Line 346  namespace LinuxSampler { namespace gig {
346       * @param pAudioOut - audio output device to connect to       * @param pAudioOut - audio output device to connect to
347       */       */
348      void Engine::Connect(AudioOutputDevice* pAudioOut) {      void Engine::Connect(AudioOutputDevice* pAudioOut) {
349            // caution: don't ignore if connecting to the same device here,
350            // because otherwise SetMaxDiskStreams() implementation won't work anymore!
351    
352          pAudioOutputDevice = pAudioOut;          pAudioOutputDevice = pAudioOut;
353    
354          ResetInternal();          ResetInternal();
# Line 358  namespace LinuxSampler { namespace gig { Line 365  namespace LinuxSampler { namespace gig {
365          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
366          this->SampleRate         = pAudioOutputDevice->SampleRate();          this->SampleRate         = pAudioOutputDevice->SampleRate();
367    
368          // FIXME: audio drivers with varying fragment sizes might be a problem here          MinFadeOutSamples = int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
369          MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;          if (MaxSamplesPerCycle < MinFadeOutSamples) {
         if (MaxFadeOutPos < 0) {  
370              std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME "              std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
371                        << "too big for current audio fragment size & sampling rate! "                        << "too big for current audio fragment size & sampling rate! "
372                        << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;                        << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
373              // force volume ramp downs at the beginning of each fragment              // force volume ramp downs at the beginning of each fragment
374              MaxFadeOutPos = 0;              MinFadeOutSamples = MaxSamplesPerCycle;
375              // lower minimum release time              // lower minimum release time
376              const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;              const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
377              for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {              for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
# Line 381  namespace LinuxSampler { namespace gig { Line 387  namespace LinuxSampler { namespace gig {
387              delete this->pDiskThread;              delete this->pDiskThread;
388              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
389          }          }
390          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo          this->pDiskThread =
391                                             &instruments);              new DiskThread(
392                    iMaxDiskStreams,
393                    ((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
394                    &instruments
395                );
396    
397          if (!pDiskThread) {          if (!pDiskThread) {
398              dmsg(0,("gig::Engine  new diskthread = NULL\n"));              dmsg(0,("gig::Engine  new diskthread = NULL\n"));
399              exit(EXIT_FAILURE);              exit(EXIT_FAILURE);
# Line 408  namespace LinuxSampler { namespace gig { Line 419  namespace LinuxSampler { namespace gig {
419                  exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
420              }              }
421          }          }
422            pVoicePool->clear();
423      }      }
424    
425      /**      /**
# Line 434  namespace LinuxSampler { namespace gig { Line 446  namespace LinuxSampler { namespace gig {
446                          if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream                          if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
447                              iPendingStreamDeletions++;                              iPendingStreamDeletions++;
448                          }                          }
449                            //NOTE: maybe we should call FreeVoice() here, shouldn't cause a harm though I think, since the voices should be freed by RenderActiveVoices() in the render loop, they are probably just freed a bit later than they could/should be
450                      }                      }
451                  }                  }
452              }              }
# Line 574  namespace LinuxSampler { namespace gig { Line 587  namespace LinuxSampler { namespace gig {
587          // return if engine disabled          // return if engine disabled
588          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
589              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
590                EngineDisabled.RttDone();
591              return 0;              return 0;
592          }          }
593    
# Line 584  namespace LinuxSampler { namespace gig { Line 598  namespace LinuxSampler { namespace gig {
598          // 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)
599          pEventGenerator->UpdateFragmentTime(Samples);          pEventGenerator->UpdateFragmentTime(Samples);
600    
601          // We only allow a maximum of CONFIG_MAX_VOICES voices to be spawned          // We only allow the given maximum number of voices to be spawned
602          // in each audio fragment. All subsequent request for spawning new          // in each audio fragment. All subsequent request for spawning new
603          // voices in the same audio fragment will be ignored.          // voices in the same audio fragment will be ignored.
604          VoiceSpawnsLeft = CONFIG_MAX_VOICES;          VoiceSpawnsLeft = MaxVoices();
605    
606          // get all events from the engine's global input event queue which belong to the current fragment          // get all events from the engine's global input event queue which belong to the current fragment
607          // (these are usually just SysEx messages)          // (these are usually just SysEx messages)
# Line 686  namespace LinuxSampler { namespace gig { Line 700  namespace LinuxSampler { namespace gig {
700          pVoiceStealingQueue->clear();          pVoiceStealingQueue->clear();
701    
702          // just some statistics about this engine instance          // just some statistics about this engine instance
703          ActiveVoiceCount = ActiveVoiceCountTemp;          SetVoiceCount(ActiveVoiceCountTemp);
704          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;          if (VoiceCount() > ActiveVoiceCountMax) ActiveVoiceCountMax = VoiceCount();
705    
706          // in case regions were previously suspended and we killed voices          // in case regions were previously suspended and we killed voices
707          // with disk streams due to that, check if those streams have finally          // with disk streams due to that, check if those streams have finally
# Line 699  namespace LinuxSampler { namespace gig { Line 713  namespace LinuxSampler { namespace gig {
713          }          }
714          FrameTime += Samples;          FrameTime += Samples;
715    
716            EngineDisabled.RttDone();
717          return 0;          return 0;
718      }      }
719    
# Line 785  namespace LinuxSampler { namespace gig { Line 800  namespace LinuxSampler { namespace gig {
800                      voiceCount++;                      voiceCount++;
801    
802                      if (itVoice->PlaybackState == Voice::playback_state_disk) {                      if (itVoice->PlaybackState == Voice::playback_state_disk) {
803                          if ((itVoice->DiskStreamRef).State == Stream::state_active) streamCount++;                          if ((itVoice->DiskStreamRef).State != Stream::state_unused) streamCount++;
804                      }                      }
805                  }  else { // voice reached end, is now inactive                  }  else { // voice reached end, is now inactive
806                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
# Line 826  namespace LinuxSampler { namespace gig { Line 841  namespace LinuxSampler { namespace gig {
841                      pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);                      pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
842    
843                      if (itNewVoice->PlaybackState == Voice::playback_state_disk) {                      if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
844                          if (itNewVoice->DiskStreamRef.State == Stream::state_active) {                          if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
845                              pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);                              pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
846                          }                          }
847                      }                      }
# Line 857  namespace LinuxSampler { namespace gig { Line 872  namespace LinuxSampler { namespace gig {
872       *                         this audio fragment cycle       *                         this audio fragment cycle
873       */       */
874      void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {      void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
875          // route master signal          // route dry signal
876          {          {
877              AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);              AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
878              AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);              AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
# Line 868  namespace LinuxSampler { namespace gig { Line 883  namespace LinuxSampler { namespace gig {
883          {          {
884              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
885                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
886                  // left channel                  for (int iChan = 0; iChan < 2; ++iChan) {
887                  const int iDstL = pFxSend->DestinationChannel(0);                      AudioChannel* pSource =
888                  if (iDstL < 0) {                          (iChan)
889                      dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));                              ? pEngineChannel->pChannelRight
890                  } else {                              : pEngineChannel->pChannelLeft;
891                      AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);                      const int iDstChan = pFxSend->DestinationChannel(iChan);
892                      if (!pDstL) {                      if (iDstChan < 0) {
893                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
894                      } else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level());                          goto channel_cleanup;
895                  }                      }
896                  // right channel                      AudioChannel* pDstChan = NULL;
897                  const int iDstR = pFxSend->DestinationChannel(1);                      if (pFxSend->DestinationMasterEffectChain() >= 0) { // fx send routed to an internal master effect
898                  if (iDstR < 0) {                          EffectChain* pEffectChain =
899                      dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));                              pAudioOutputDevice->MasterEffectChain(
900                  } else {                                  pFxSend->DestinationMasterEffectChain()
901                      AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);                              );
902                      if (!pDstR) {                          if (!pEffectChain) {
903                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));                              dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffectChain()));
904                      } else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level());                              goto channel_cleanup;
905                            }
906                            Effect* pEffect =
907                                pEffectChain->GetEffect(
908                                    pFxSend->DestinationMasterEffect()
909                                );
910                            if (!pEffect) {
911                                dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffect(), pFxSend->DestinationMasterEffectChain()));
912                                goto channel_cleanup;
913                            }
914                            pDstChan = pEffect->InputChannel(iDstChan);
915                        } else { // FX send routed directly to an audio output channel
916                            pDstChan = pAudioOutputDevice->Channel(iDstChan);
917                        }
918                        if (!pDstChan) {
919                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
920                            goto channel_cleanup;
921                        }
922                        pSource->MixTo(pDstChan, Samples, pFxSend->Level());
923                  }                  }
924              }              }
925          }          }
926            channel_cleanup:
927          // reset buffers with silence (zero out) for the next audio cycle          // reset buffers with silence (zero out) for the next audio cycle
928          pEngineChannel->pChannelLeft->Clear();          pEngineChannel->pChannelLeft->Clear();
929          pEngineChannel->pChannelRight->Clear();          pEngineChannel->pChannelRight->Clear();
# Line 935  namespace LinuxSampler { namespace gig { Line 969  namespace LinuxSampler { namespace gig {
969       *       *
970       *  @param pData - pointer to sysex data       *  @param pData - pointer to sysex data
971       *  @param Size  - lenght of sysex data (in bytes)       *  @param Size  - lenght of sysex data (in bytes)
972         *  @param pSender - the MIDI input port on which the SysEx message was
973         *                   received
974       */       */
975      void Engine::SendSysex(void* pData, uint Size) {      void Engine::SendSysex(void* pData, uint Size, MidiInputPort* pSender) {
976          Event event             = pEventGenerator->CreateEvent();          Event event             = pEventGenerator->CreateEvent();
977          event.Type              = Event::type_sysex;          event.Type              = Event::type_sysex;
978          event.Param.Sysex.Size  = Size;          event.Param.Sysex.Size  = Size;
979          event.pEngineChannel    = NULL; // as Engine global event          event.pEngineChannel    = NULL; // as Engine global event
980            event.pMidiInputPort    = pSender;
981          if (pEventQueue->write_space() > 0) {          if (pEventQueue->write_space() > 0) {
982              if (pSysexBuffer->write_space() >= Size) {              if (pSysexBuffer->write_space() >= Size) {
983                  // copy sysex data to input buffer                  // copy sysex data to input buffer
# Line 1709  namespace LinuxSampler { namespace gig { Line 1746  namespace LinuxSampler { namespace gig {
1746                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1747                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1748                  pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];                  pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
1749                    pEngineChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1750                  break;                  break;
1751              }              }
1752              case 64: { // sustain              case 64: { // sustain
# Line 1849  namespace LinuxSampler { namespace gig { Line 1887  namespace LinuxSampler { namespace gig {
1887          if (!pEngineChannel->fxSends.empty()) {          if (!pEngineChannel->fxSends.empty()) {
1888              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1889                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1890                  if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)                  if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) {
1891                      pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);                      pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1892                      pFxSend->SetInfoChanged(true);                      pFxSend->SetInfoChanged(true);
1893                    }
1894              }              }
1895          }          }
1896      }      }
# Line 1870  namespace LinuxSampler { namespace gig { Line 1909  namespace LinuxSampler { namespace gig {
1909          if (exclusive_status != 0xF0)       goto free_sysex_data;          if (exclusive_status != 0xF0)       goto free_sysex_data;
1910    
1911          switch (id) {          switch (id) {
1912                case 0x7f: { // (Realtime) Universal Sysex (GM Standard)
1913                    uint8_t sysex_channel, sub_id1, sub_id2, val_msb, val_lsb;;
1914                    if (!reader.pop(&sysex_channel)) goto free_sysex_data;
1915                    if (!reader.pop(&sub_id1)) goto free_sysex_data;
1916                    if (!reader.pop(&sub_id2)) goto free_sysex_data;
1917                    if (!reader.pop(&val_lsb)) goto free_sysex_data;
1918                    if (!reader.pop(&val_msb)) goto free_sysex_data;
1919                    //TODO: for now we simply ignore the sysex channel, seldom used anyway
1920                    switch (sub_id1) {
1921                        case 0x04: // Device Control
1922                            switch (sub_id2) {
1923                                case 0x01: { // Master Volume
1924                                    const double volume =
1925                                        double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0;
1926                                    #if CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1927                                    // apply volume to all sampler channels that
1928                                    // are connected to the same MIDI input port
1929                                    // this sysex message arrived on
1930                                    for (int i = 0; i < engineChannels.size(); ++i) {
1931                                        EngineChannel* pEngineChannel = engineChannels[i];
1932                                        if (pEngineChannel->GetMidiInputPort() ==
1933                                            itSysexEvent->pMidiInputPort)
1934                                        {
1935                                            pEngineChannel->Volume(volume);
1936                                        }
1937                                    }
1938                                    #else
1939                                    // apply volume globally to the whole sampler
1940                                    GLOBAL_VOLUME = volume;
1941                                    #endif // CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1942                                    break;
1943                                }
1944                            }
1945                            break;
1946                    }
1947                    break;
1948                }
1949              case 0x41: { // Roland              case 0x41: { // Roland
1950                  dmsg(3,("Roland Sysex\n"));                  dmsg(3,("Roland Sysex\n"));
1951                  uint8_t device_id, model_id, cmd_id;                  uint8_t device_id, model_id, cmd_id;
# Line 1885  namespace LinuxSampler { namespace gig { Line 1961  namespace LinuxSampler { namespace gig {
1961                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1962                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1963                      dmsg(3,("\tSystem Parameter\n"));                      dmsg(3,("\tSystem Parameter\n"));
1964                        if (addr[2] == 0x7f) { // GS reset
1965                            for (int i = 0; i < engineChannels.size(); ++i) {
1966                                EngineChannel* pEngineChannel = engineChannels[i];
1967                                if (pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort) {
1968                                    KillAllVoices(pEngineChannel, itSysexEvent);
1969                                    pEngineChannel->ResetControllers();
1970                                }
1971                            }
1972                        }
1973                  }                  }
1974                  else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters                  else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
1975                      dmsg(3,("\tCommon Parameter\n"));                      dmsg(3,("\tCommon Parameter\n"));
# Line 1906  namespace LinuxSampler { namespace gig { Line 1991  namespace LinuxSampler { namespace gig {
1991                              dmsg(3,("\t\t\tNew scale applied.\n"));                              dmsg(3,("\t\t\tNew scale applied.\n"));
1992                              break;                              break;
1993                          }                          }
1994                            case 0x15: { // chromatic / drumkit mode
1995                                dmsg(3,("\t\tMIDI Instrument Map Switch\n"));
1996                                uint8_t part = addr[1] & 0x0f;
1997                                uint8_t map;
1998                                if (!reader.pop(&map)) goto free_sysex_data;
1999                                for (int i = 0; i < engineChannels.size(); ++i) {
2000                                    EngineChannel* pEngineChannel = engineChannels[i];
2001                                    if (
2002                                        (pEngineChannel->midiChannel == part ||
2003                                         pEngineChannel->midiChannel == midi_chan_all) &&
2004                                         pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort
2005                                    ) {
2006                                        try {
2007                                            pEngineChannel->SetMidiInstrumentMap(map);
2008                                        } catch (Exception e) {
2009                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d: %s\n", map, part, e.Message().c_str()));
2010                                            goto free_sysex_data;
2011                                        } catch (...) {
2012                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d (unknown exception)\n", map, part));
2013                                            goto free_sysex_data;
2014                                        }
2015                                    }
2016                                }
2017                                dmsg(3,("\t\t\tApplied MIDI instrument map %d to part %d.\n", map, part));
2018                                break;
2019                            }
2020                      }                      }
2021                  }                  }
2022                  else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)                  else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)
# Line 2012  namespace LinuxSampler { namespace gig { Line 2123  namespace LinuxSampler { namespace gig {
2123      }      }
2124    
2125      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
2126          return ActiveVoiceCount;          return atomic_read(&ActiveVoiceCount);
2127        }
2128    
2129        void Engine::SetVoiceCount(uint Count) {
2130            atomic_set(&ActiveVoiceCount, Count);
2131      }      }
2132    
2133      uint Engine::VoiceCountMax() {      uint Engine::VoiceCountMax() {
2134          return ActiveVoiceCountMax;          return ActiveVoiceCountMax;
2135      }      }
2136    
2137        int Engine::MaxVoices() {
2138            return pVoicePool->poolSize();
2139        }
2140    
2141        void Engine::SetMaxVoices(int iVoices) throw (Exception) {
2142            if (iVoices < 1)
2143                throw Exception("Maximum voices for an engine cannot be set lower than 1");
2144    
2145            SuspendAll();
2146    
2147            // NOTE: we need to clear pDimRegionsInUse before deleting pDimRegionPool,
2148            // otherwise memory corruption will occur if there are active voices (see bug #118)
2149            for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
2150                engineChannels[iChannel]->ClearDimRegionsInUse();
2151            }
2152    
2153            if (pDimRegionPool[0]) delete pDimRegionPool[0];
2154            if (pDimRegionPool[1]) delete pDimRegionPool[1];
2155    
2156            pDimRegionPool[0] = new Pool< ::gig::DimensionRegion*>(iVoices);
2157            pDimRegionPool[1] = new Pool< ::gig::DimensionRegion*>(iVoices);
2158    
2159            for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
2160                engineChannels[iChannel]->ResetDimRegionsInUse();
2161            }
2162    
2163            try {
2164                pVoicePool->resizePool(iVoices);
2165            } catch (...) {
2166                throw Exception("FATAL: Could not resize voice pool!");
2167            }
2168    
2169            for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2170                iterVoice->SetEngine(this);
2171                iterVoice->pDiskThread = this->pDiskThread;
2172            }
2173            pVoicePool->clear();
2174    
2175            ResumeAll();
2176        }
2177    
2178      bool Engine::DiskStreamSupported() {      bool Engine::DiskStreamSupported() {
2179          return true;          return true;
2180      }      }
2181    
2182      uint Engine::DiskStreamCount() {      uint Engine::DiskStreamCount() {
2183          return (pDiskThread) ? pDiskThread->ActiveStreamCount : 0;          return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0;
2184      }      }
2185    
2186      uint Engine::DiskStreamCountMax() {      uint Engine::DiskStreamCountMax() {
2187          return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;          return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;
2188      }      }
2189    
2190        int Engine::MaxDiskStreams() {
2191            return iMaxDiskStreams;
2192        }
2193    
2194        void Engine::SetMaxDiskStreams(int iStreams) throw (Exception) {
2195            if (iStreams < 0)
2196                throw Exception("Maximum disk streams for an engine cannot be set lower than 0");
2197    
2198            SuspendAll();
2199    
2200            iMaxDiskStreams = iStreams;
2201    
2202            // reconnect to audio output device, because that will automatically
2203            // recreate the disk thread with the required amount of streams
2204            if (pAudioOutputDevice) Connect(pAudioOutputDevice);
2205    
2206            ResumeAll();
2207        }
2208    
2209      String Engine::DiskStreamBufferFillBytes() {      String Engine::DiskStreamBufferFillBytes() {
2210          return pDiskThread->GetBufferFillBytes();          return pDiskThread->GetBufferFillBytes();
2211      }      }
# Line 2048  namespace LinuxSampler { namespace gig { Line 2223  namespace LinuxSampler { namespace gig {
2223      }      }
2224    
2225      String Engine::Version() {      String Engine::Version() {
2226          String s = "$Revision: 1.88 $";          String s = "$Revision: 1.103 $";
2227          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
2228      }      }
2229    

Legend:
Removed from v.1700  
changed lines
  Added in v.1895

  ViewVC Help
Powered by ViewVC