/[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 1748 by persson, Sun Jun 22 14:46:46 2008 UTC revision 1893 by schoenebeck, Sat May 2 18:57:49 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    
117          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()) {
118              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
# Line 211  namespace LinuxSampler { namespace gig { Line 212  namespace LinuxSampler { namespace gig {
212                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
213                          iPendingStreamDeletions++;                          iPendingStreamDeletions++;
214                      }                      }
215                        // free the voice to the voice pool and update key info
216                        FreeVoice(pEngineChannel, itVoice);
217                  }                  }
218              }              }
219          }          }
# Line 291  namespace LinuxSampler { namespace gig { Line 294  namespace LinuxSampler { namespace gig {
294          // make sure that the engine does not get any sysex messages          // make sure that the engine does not get any sysex messages
295          // while it's reseting          // while it's reseting
296          bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);          bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
297          ActiveVoiceCount    = 0;          SetVoiceCount(0);
298          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
299    
300          // reset voice stealing parameters          // reset voice stealing parameters
# Line 342  namespace LinuxSampler { namespace gig { Line 345  namespace LinuxSampler { namespace gig {
345       * @param pAudioOut - audio output device to connect to       * @param pAudioOut - audio output device to connect to
346       */       */
347      void Engine::Connect(AudioOutputDevice* pAudioOut) {      void Engine::Connect(AudioOutputDevice* pAudioOut) {
348            // caution: don't ignore if connecting to the same device here,
349            // because otherwise SetMaxDiskStreams() implementation won't work anymore!
350    
351          pAudioOutputDevice = pAudioOut;          pAudioOutputDevice = pAudioOut;
352    
353          ResetInternal();          ResetInternal();
# Line 380  namespace LinuxSampler { namespace gig { Line 386  namespace LinuxSampler { namespace gig {
386              delete this->pDiskThread;              delete this->pDiskThread;
387              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
388          }          }
389          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo          this->pDiskThread =
390                                             &instruments);              new DiskThread(
391                    iMaxDiskStreams,
392                    ((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
393                    &instruments
394                );
395    
396          if (!pDiskThread) {          if (!pDiskThread) {
397              dmsg(0,("gig::Engine  new diskthread = NULL\n"));              dmsg(0,("gig::Engine  new diskthread = NULL\n"));
398              exit(EXIT_FAILURE);              exit(EXIT_FAILURE);
# Line 407  namespace LinuxSampler { namespace gig { Line 418  namespace LinuxSampler { namespace gig {
418                  exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
419              }              }
420          }          }
421            pVoicePool->clear();
422      }      }
423    
424      /**      /**
# Line 433  namespace LinuxSampler { namespace gig { Line 445  namespace LinuxSampler { namespace gig {
445                          if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream                          if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
446                              iPendingStreamDeletions++;                              iPendingStreamDeletions++;
447                          }                          }
448                            //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
449                      }                      }
450                  }                  }
451              }              }
# Line 573  namespace LinuxSampler { namespace gig { Line 586  namespace LinuxSampler { namespace gig {
586          // return if engine disabled          // return if engine disabled
587          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
588              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
589                EngineDisabled.RttDone();
590              return 0;              return 0;
591          }          }
592    
# Line 583  namespace LinuxSampler { namespace gig { Line 597  namespace LinuxSampler { namespace gig {
597          // 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)
598          pEventGenerator->UpdateFragmentTime(Samples);          pEventGenerator->UpdateFragmentTime(Samples);
599    
600          // 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
601          // in each audio fragment. All subsequent request for spawning new          // in each audio fragment. All subsequent request for spawning new
602          // voices in the same audio fragment will be ignored.          // voices in the same audio fragment will be ignored.
603          VoiceSpawnsLeft = CONFIG_MAX_VOICES;          VoiceSpawnsLeft = MaxVoices();
604    
605          // 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
606          // (these are usually just SysEx messages)          // (these are usually just SysEx messages)
# Line 685  namespace LinuxSampler { namespace gig { Line 699  namespace LinuxSampler { namespace gig {
699          pVoiceStealingQueue->clear();          pVoiceStealingQueue->clear();
700    
701          // just some statistics about this engine instance          // just some statistics about this engine instance
702          ActiveVoiceCount = ActiveVoiceCountTemp;          SetVoiceCount(ActiveVoiceCountTemp);
703          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;          if (VoiceCount() > ActiveVoiceCountMax) ActiveVoiceCountMax = VoiceCount();
704    
705          // in case regions were previously suspended and we killed voices          // in case regions were previously suspended and we killed voices
706          // 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 698  namespace LinuxSampler { namespace gig { Line 712  namespace LinuxSampler { namespace gig {
712          }          }
713          FrameTime += Samples;          FrameTime += Samples;
714    
715            EngineDisabled.RttDone();
716          return 0;          return 0;
717      }      }
718    
# Line 784  namespace LinuxSampler { namespace gig { Line 799  namespace LinuxSampler { namespace gig {
799                      voiceCount++;                      voiceCount++;
800    
801                      if (itVoice->PlaybackState == Voice::playback_state_disk) {                      if (itVoice->PlaybackState == Voice::playback_state_disk) {
802                          if ((itVoice->DiskStreamRef).State == Stream::state_active) streamCount++;                          if ((itVoice->DiskStreamRef).State != Stream::state_unused) streamCount++;
803                      }                      }
804                  }  else { // voice reached end, is now inactive                  }  else { // voice reached end, is now inactive
805                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
# Line 825  namespace LinuxSampler { namespace gig { Line 840  namespace LinuxSampler { namespace gig {
840                      pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);                      pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
841    
842                      if (itNewVoice->PlaybackState == Voice::playback_state_disk) {                      if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
843                          if (itNewVoice->DiskStreamRef.State == Stream::state_active) {                          if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
844                              pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);                              pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
845                          }                          }
846                      }                      }
# Line 953  namespace LinuxSampler { namespace gig { Line 968  namespace LinuxSampler { namespace gig {
968       *       *
969       *  @param pData - pointer to sysex data       *  @param pData - pointer to sysex data
970       *  @param Size  - lenght of sysex data (in bytes)       *  @param Size  - lenght of sysex data (in bytes)
971         *  @param pSender - the MIDI input port on which the SysEx message was
972         *                   received
973       */       */
974      void Engine::SendSysex(void* pData, uint Size) {      void Engine::SendSysex(void* pData, uint Size, MidiInputPort* pSender) {
975          Event event             = pEventGenerator->CreateEvent();          Event event             = pEventGenerator->CreateEvent();
976          event.Type              = Event::type_sysex;          event.Type              = Event::type_sysex;
977          event.Param.Sysex.Size  = Size;          event.Param.Sysex.Size  = Size;
978          event.pEngineChannel    = NULL; // as Engine global event          event.pEngineChannel    = NULL; // as Engine global event
979            event.pMidiInputPort    = pSender;
980          if (pEventQueue->write_space() > 0) {          if (pEventQueue->write_space() > 0) {
981              if (pSysexBuffer->write_space() >= Size) {              if (pSysexBuffer->write_space() >= Size) {
982                  // copy sysex data to input buffer                  // copy sysex data to input buffer
# Line 1901  namespace LinuxSampler { namespace gig { Line 1919  namespace LinuxSampler { namespace gig {
1919                  switch (sub_id1) {                  switch (sub_id1) {
1920                      case 0x04: // Device Control                      case 0x04: // Device Control
1921                          switch (sub_id2) {                          switch (sub_id2) {
1922                              case 0x01: // Master Volume                              case 0x01: { // Master Volume
1923                                  GLOBAL_VOLUME =                                  const double volume =
1924                                      double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0;                                      double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0;
1925                                    #if CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1926                                    // apply volume to all sampler channels that
1927                                    // are connected to the same MIDI input port
1928                                    // this sysex message arrived on
1929                                    for (int i = 0; i < engineChannels.size(); ++i) {
1930                                        EngineChannel* pEngineChannel = engineChannels[i];
1931                                        if (pEngineChannel->GetMidiInputPort() ==
1932                                            itSysexEvent->pMidiInputPort)
1933                                        {
1934                                            pEngineChannel->Volume(volume);
1935                                        }
1936                                    }
1937                                    #else
1938                                    // apply volume globally to the whole sampler
1939                                    GLOBAL_VOLUME = volume;
1940                                    #endif // CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1941                                  break;                                  break;
1942                                }
1943                          }                          }
1944                          break;                          break;
1945                  }                  }
# Line 1925  namespace LinuxSampler { namespace gig { Line 1960  namespace LinuxSampler { namespace gig {
1960                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1961                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1962                      dmsg(3,("\tSystem Parameter\n"));                      dmsg(3,("\tSystem Parameter\n"));
1963                        if (addr[2] == 0x7f) { // GS reset
1964                            for (int i = 0; i < engineChannels.size(); ++i) {
1965                                EngineChannel* pEngineChannel = engineChannels[i];
1966                                if (pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort) {
1967                                    KillAllVoices(pEngineChannel, itSysexEvent);
1968                                    pEngineChannel->ResetControllers();
1969                                }
1970                            }
1971                        }
1972                  }                  }
1973                  else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters                  else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
1974                      dmsg(3,("\tCommon Parameter\n"));                      dmsg(3,("\tCommon Parameter\n"));
# Line 1946  namespace LinuxSampler { namespace gig { Line 1990  namespace LinuxSampler { namespace gig {
1990                              dmsg(3,("\t\t\tNew scale applied.\n"));                              dmsg(3,("\t\t\tNew scale applied.\n"));
1991                              break;                              break;
1992                          }                          }
1993                            case 0x15: { // chromatic / drumkit mode
1994                                dmsg(3,("\t\tMIDI Instrument Map Switch\n"));
1995                                uint8_t part = addr[1] & 0x0f;
1996                                uint8_t map;
1997                                if (!reader.pop(&map)) goto free_sysex_data;
1998                                for (int i = 0; i < engineChannels.size(); ++i) {
1999                                    EngineChannel* pEngineChannel = engineChannels[i];
2000                                    if (
2001                                        (pEngineChannel->midiChannel == part ||
2002                                         pEngineChannel->midiChannel == midi_chan_all) &&
2003                                         pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort
2004                                    ) {
2005                                        try {
2006                                            pEngineChannel->SetMidiInstrumentMap(map);
2007                                        } catch (Exception e) {
2008                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d: %s\n", map, part, e.Message().c_str()));
2009                                            goto free_sysex_data;
2010                                        } catch (...) {
2011                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d (unknown exception)\n", map, part));
2012                                            goto free_sysex_data;
2013                                        }
2014                                    }
2015                                }
2016                                dmsg(3,("\t\t\tApplied MIDI instrument map %d to part %d.\n", map, part));
2017                                break;
2018                            }
2019                      }                      }
2020                  }                  }
2021                  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 2052  namespace LinuxSampler { namespace gig { Line 2122  namespace LinuxSampler { namespace gig {
2122      }      }
2123    
2124      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
2125          return ActiveVoiceCount;          return atomic_read(&ActiveVoiceCount);
2126        }
2127    
2128        void Engine::SetVoiceCount(uint Count) {
2129            atomic_set(&ActiveVoiceCount, Count);
2130      }      }
2131    
2132      uint Engine::VoiceCountMax() {      uint Engine::VoiceCountMax() {
2133          return ActiveVoiceCountMax;          return ActiveVoiceCountMax;
2134      }      }
2135    
2136        int Engine::MaxVoices() {
2137            return pVoicePool->poolSize();
2138        }
2139    
2140        void Engine::SetMaxVoices(int iVoices) throw (Exception) {
2141            if (iVoices < 1)
2142                throw Exception("Maximum voices for an engine cannot be set lower than 1");
2143    
2144            SuspendAll();
2145    
2146            // NOTE: we need to clear pDimRegionsInUse before deleting pDimRegionPool,
2147            // otherwise memory corruption will occur if there are active voices (see bug #118)
2148            for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
2149                engineChannels[iChannel]->ClearDimRegionsInUse();
2150            }
2151    
2152            if (pDimRegionPool[0]) delete pDimRegionPool[0];
2153            if (pDimRegionPool[1]) delete pDimRegionPool[1];
2154    
2155            pDimRegionPool[0] = new Pool< ::gig::DimensionRegion*>(iVoices);
2156            pDimRegionPool[1] = new Pool< ::gig::DimensionRegion*>(iVoices);
2157    
2158            for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
2159                engineChannels[iChannel]->ResetDimRegionsInUse();
2160            }
2161    
2162            try {
2163                pVoicePool->resizePool(iVoices);
2164            } catch (...) {
2165                throw Exception("FATAL: Could not resize voice pool!");
2166            }
2167    
2168            for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2169                iterVoice->SetEngine(this);
2170                iterVoice->pDiskThread = this->pDiskThread;
2171            }
2172            pVoicePool->clear();
2173    
2174            ResumeAll();
2175        }
2176    
2177      bool Engine::DiskStreamSupported() {      bool Engine::DiskStreamSupported() {
2178          return true;          return true;
2179      }      }
2180    
2181      uint Engine::DiskStreamCount() {      uint Engine::DiskStreamCount() {
2182          return (pDiskThread) ? pDiskThread->ActiveStreamCount : 0;          return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0;
2183      }      }
2184    
2185      uint Engine::DiskStreamCountMax() {      uint Engine::DiskStreamCountMax() {
2186          return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;          return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;
2187      }      }
2188    
2189        int Engine::MaxDiskStreams() {
2190            return iMaxDiskStreams;
2191        }
2192    
2193        void Engine::SetMaxDiskStreams(int iStreams) throw (Exception) {
2194            if (iStreams < 0)
2195                throw Exception("Maximum disk streams for an engine cannot be set lower than 0");
2196    
2197            SuspendAll();
2198    
2199            iMaxDiskStreams = iStreams;
2200    
2201            // reconnect to audio output device, because that will automatically
2202            // recreate the disk thread with the required amount of streams
2203            if (pAudioOutputDevice) Connect(pAudioOutputDevice);
2204    
2205            ResumeAll();
2206        }
2207    
2208      String Engine::DiskStreamBufferFillBytes() {      String Engine::DiskStreamBufferFillBytes() {
2209          return pDiskThread->GetBufferFillBytes();          return pDiskThread->GetBufferFillBytes();
2210      }      }
# Line 2088  namespace LinuxSampler { namespace gig { Line 2222  namespace LinuxSampler { namespace gig {
2222      }      }
2223    
2224      String Engine::Version() {      String Engine::Version() {
2225          String s = "$Revision: 1.93 $";          String s = "$Revision: 1.102 $";
2226          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
2227      }      }
2228    

Legend:
Removed from v.1748  
changed lines
  Added in v.1893

  ViewVC Help
Powered by ViewVC