/[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 1012 by capela, Sun Jan 7 15:52:36 2007 UTC revision 1044 by schoenebeck, Wed Feb 7 21:51:19 2007 UTC
# Line 51  namespace LinuxSampler { namespace gig { Line 51  namespace LinuxSampler { namespace gig {
51          if (engines.count(pDevice)) {          if (engines.count(pDevice)) {
52              dmsg(4,("Using existing gig::Engine.\n"));              dmsg(4,("Using existing gig::Engine.\n"));
53              pEngine = engines[pDevice];              pEngine = engines[pDevice];
54    
55                // Disable the engine while the new engine channel is
56                // added and initialized. The engine will be enabled again
57                // in EngineChannel::Connect.
58                pEngine->DisableAndLock();
59          } else { // create a new engine (and disk thread) instance for the given audio output device          } else { // create a new engine (and disk thread) instance for the given audio output device
60              dmsg(4,("Creating new gig::Engine.\n"));              dmsg(4,("Creating new gig::Engine.\n"));
61              pEngine = (Engine*) EngineFactory::Create("gig");              pEngine = (Engine*) EngineFactory::Create("gig");
# Line 101  namespace LinuxSampler { namespace gig { Line 106  namespace LinuxSampler { namespace gig {
106          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
107          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
108          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);
109            pDimRegionsInUse   = new ::gig::DimensionRegion*[CONFIG_MAX_VOICES + 1];
110          pVoiceStealingQueue = new RTList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
111          pGlobalEvents      = new RTList<Event>(pEventPool);          pGlobalEvents      = new RTList<Event>(pEventPool);
112            InstrumentChangeQueue      = new RingBuffer<instrument_change_command_t,false>(1, 0);
113            InstrumentChangeReplyQueue = new RingBuffer<instrument_change_reply_t,false>(1, 0);
114    
115          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()) {
116              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
117          }          }
# Line 257  namespace LinuxSampler { namespace gig { Line 266  namespace LinuxSampler { namespace gig {
266              delete this->pDiskThread;              delete this->pDiskThread;
267              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
268          }          }
269          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6); //FIXME: assuming stereo          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
270                                               &instruments);
271          if (!pDiskThread) {          if (!pDiskThread) {
272              dmsg(0,("gig::Engine  new diskthread = NULL\n"));              dmsg(0,("gig::Engine  new diskthread = NULL\n"));
273              exit(EXIT_FAILURE);              exit(EXIT_FAILURE);
# Line 377  namespace LinuxSampler { namespace gig { Line 387  namespace LinuxSampler { namespace gig {
387          // reset internal voice counter (just for statistic of active voices)          // reset internal voice counter (just for statistic of active voices)
388          ActiveVoiceCountTemp = 0;          ActiveVoiceCountTemp = 0;
389    
390            // handle instrument change commands
391            instrument_change_command_t command;
392            if (InstrumentChangeQueue->pop(&command) > 0) {
393                EngineChannel* pEngineChannel = command.pEngineChannel;
394                pEngineChannel->pInstrument = command.pInstrument;
395    
396                // iterate through all active voices and mark their
397                // dimension regions as "in use". The instrument resource
398                // manager may delete all of the instrument except the
399                // dimension regions and samples that are in use.
400                int i = 0;
401                RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
402                RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
403                while (iuiKey != end) { // iterate through all active keys
404                    midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
405                    ++iuiKey;
406    
407                    RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
408                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
409                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
410                        if (!itVoice->Orphan) {
411                            itVoice->Orphan = true;
412                            pDimRegionsInUse[i++] = itVoice->pDimRgn;
413                        }
414                    }
415                }
416                pDimRegionsInUse[i] = 0; // end of list
417    
418                // send a reply to the calling thread, which is waiting
419                instrument_change_reply_t reply;
420                InstrumentChangeReplyQueue->push(&reply);
421            }
422    
423          // handle events on all engine channels          // handle events on all engine channels
424          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
425              ProcessEvents(engineChannels[i], Samples);              ProcessEvents(engineChannels[i], Samples);
426          }          }
427    
428          // render all 'normal', active voices on all engine channels          // render all 'normal', active voices on all engine channels
429          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
430              RenderActiveVoices(engineChannels[i], Samples);              RenderActiveVoices(engineChannels[i], Samples);
431          }          }
432    
# Line 400  namespace LinuxSampler { namespace gig { Line 441  namespace LinuxSampler { namespace gig {
441    
442          // handle cleanup on all engine channels for the next audio fragment          // handle cleanup on all engine channels for the next audio fragment
443          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
444              PostProcess(engineChannels[i]);              PostProcess(engineChannels[i]);
445          }          }
446    
# Line 519  namespace LinuxSampler { namespace gig { Line 559  namespace LinuxSampler { namespace gig {
559          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();
560          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
561              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
562                if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
563              Pool<Voice>::Iterator itNewVoice =              Pool<Voice>::Iterator itNewVoice =
564                  LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);                  LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
565              if (itNewVoice) {              if (itNewVoice) {
# Line 555  namespace LinuxSampler { namespace gig { Line 596  namespace LinuxSampler { namespace gig {
596          {          {
597              AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);              AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
598              AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);              AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
599              pEngineChannel->pChannelLeft->CopyTo(pDstL, Samples);              pEngineChannel->pChannelLeft->MixTo(pDstL, Samples);
600              pEngineChannel->pChannelRight->CopyTo(pDstR, Samples);              pEngineChannel->pChannelRight->MixTo(pDstR, Samples);
601          }          }
602          // route FX send signal          // route FX send signal
603          {          {
# Line 570  namespace LinuxSampler { namespace gig { Line 611  namespace LinuxSampler { namespace gig {
611                      AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);                      AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);
612                      if (!pDstL) {                      if (!pDstL) {
613                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
614                      } else pEngineChannel->pChannelLeft->CopyTo(pDstL, Samples, pFxSend->Level());                      } else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level());
615                  }                  }
616                  // right channel                  // right channel
617                  const int iDstR = pFxSend->DestinationChannel(1);                  const int iDstR = pFxSend->DestinationChannel(1);
# Line 580  namespace LinuxSampler { namespace gig { Line 621  namespace LinuxSampler { namespace gig {
621                      AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);                      AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);
622                      if (!pDstR) {                      if (!pDstR) {
623                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
624                      } else pEngineChannel->pChannelRight->CopyTo(pDstR, Samples, pFxSend->Level());                      } else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level());
625                  }                  }
626              }              }
627          }          }
# Line 666  namespace LinuxSampler { namespace gig { Line 707  namespace LinuxSampler { namespace gig {
707          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
708          #endif          #endif
709    
710            if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
711    
712            //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing
713            itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
714    
715          const int key = itNoteOnEvent->Param.Note.Key;          const int key = itNoteOnEvent->Param.Note.Key;
716          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
717    
# Line 753  namespace LinuxSampler { namespace gig { Line 799  namespace LinuxSampler { namespace gig {
799          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
800          #endif          #endif
801    
802            //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing
803            itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
804    
805          const int iKey = itNoteOffEvent->Param.Note.Key;          const int iKey = itNoteOffEvent->Param.Note.Key;
806          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
807          pKey->KeyPressed = false; // the MIDI key was now released          pKey->KeyPressed = false; // the MIDI key was now released
# Line 763  namespace LinuxSampler { namespace gig { Line 812  namespace LinuxSampler { namespace gig {
812          bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);          bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
813    
814          // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)          // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
815          if (pEngineChannel->SoloMode) { //TODO: this feels like too much code just for handling solo mode :P          if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
816              bool bOtherKeysPressed = false;              bool bOtherKeysPressed = false;
817              if (iKey == pEngineChannel->SoloKey) {              if (iKey == pEngineChannel->SoloKey) {
818                  pEngineChannel->SoloKey = -1;                  pEngineChannel->SoloKey = -1;
# Line 826  namespace LinuxSampler { namespace gig { Line 875  namespace LinuxSampler { namespace gig {
875              itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type              itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
876    
877              // spawn release triggered voice(s) if needed              // spawn release triggered voice(s) if needed
878              if (pKey->ReleaseTrigger) {              if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
879                  // first, get total amount of required voices (dependant on amount of layers)                  // first, get total amount of required voices (dependant on amount of layers)
880                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
881                  if (pRegion) {                  if (pRegion) {
# Line 1021  namespace LinuxSampler { namespace gig { Line 1070  namespace LinuxSampler { namespace gig {
1070                      std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;                      std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1071              }              }
1072          }          }
1073    
1074            // return if this is a release triggered voice and there is no
1075            // releasetrigger dimension (could happen if an instrument
1076            // change has occured between note on and off)
1077            if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1078    
1079          ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);          ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1080    
1081          // no need to continue if sample is silent          // no need to continue if sample is silent
# Line 1250  namespace LinuxSampler { namespace gig { Line 1305  namespace LinuxSampler { namespace gig {
1305    
1306              uint keygroup = itVoice->KeyGroup;              uint keygroup = itVoice->KeyGroup;
1307    
1308                // if the sample and dimension region belong to an
1309                // instrument that is unloaded, tell the disk thread to
1310                // release them
1311                if (itVoice->Orphan) {
1312                    pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1313                }
1314    
1315              // free the voice object              // free the voice object
1316              pVoicePool->free(itVoice);              pVoicePool->free(itVoice);
1317    
# Line 1300  namespace LinuxSampler { namespace gig { Line 1362  namespace LinuxSampler { namespace gig {
1362                  pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;                  pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1363                  break;                  break;
1364              }              }
1365                case 6: { // data entry (currently only used for RPN controllers)
1366                    if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1367                        int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1368                        // limit to +- two octaves for now
1369                        transpose = RTMath::Min(transpose,  24);
1370                        transpose = RTMath::Max(transpose, -24);
1371                        pEngineChannel->GlobalTranspose = transpose;
1372                        // workaround, so we won't have hanging notes
1373                        ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1374                    }
1375                    // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1376                    pEngineChannel->ResetMidiRpnController();
1377                    break;
1378                }
1379              case 7: { // volume              case 7: { // volume
1380                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1381                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
# Line 1404  namespace LinuxSampler { namespace gig { Line 1480  namespace LinuxSampler { namespace gig {
1480                  }                  }
1481                  break;                  break;
1482              }              }
1483                case 100: { // RPN controller LSB
1484                    pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1485                    break;
1486                }
1487                case 101: { // RPN controller MSB
1488                    pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1489                    break;
1490                }
1491    
1492    
1493              // Channel Mode Messages              // Channel Mode Messages
# Line 1636  namespace LinuxSampler { namespace gig { Line 1720  namespace LinuxSampler { namespace gig {
1720      }      }
1721    
1722      String Engine::Version() {      String Engine::Version() {
1723          String s = "$Revision: 1.69 $";          String s = "$Revision: 1.75 $";
1724          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
1725      }      }
1726    
# Line 1686  namespace LinuxSampler { namespace gig { Line 1770  namespace LinuxSampler { namespace gig {
1770          return y;          return y;
1771      }      }
1772    
1773        /**
1774         * Changes the instrument for an engine channel.
1775         *
1776         * @param pEngineChannel - engine channel on which the instrument
1777         *                         should be changed
1778         * @param pInstrument - new instrument
1779         * @returns a list of dimension regions from the old instrument
1780         *          that are still in use
1781         */
1782        ::gig::DimensionRegion** Engine::ChangeInstrument(EngineChannel* pEngineChannel, ::gig::Instrument* pInstrument) {
1783            instrument_change_command_t command;
1784            command.pEngineChannel = pEngineChannel;
1785            command.pInstrument = pInstrument;
1786            InstrumentChangeQueue->push(&command);
1787    
1788            // wait for the audio thread to confirm that the instrument
1789            // change has been done
1790            instrument_change_reply_t reply;
1791            while (InstrumentChangeReplyQueue->pop(&reply) == 0) {
1792                usleep(10000);
1793            }
1794            return pDimRegionsInUse;
1795        }
1796    
1797  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.1012  
changed lines
  Added in v.1044

  ViewVC Help
Powered by ViewVC