/[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 1248 by persson, Fri Jun 22 10:10:06 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 132  namespace LinuxSampler { namespace gig { Line 141  namespace LinuxSampler { namespace gig {
141          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
142          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
143          if (pSysexBuffer) delete pSysexBuffer;          if (pSysexBuffer) delete pSysexBuffer;
144            if (pGlobalEvents) delete pGlobalEvents;
145            if (InstrumentChangeQueue) delete InstrumentChangeQueue;
146            if (InstrumentChangeReplyQueue) delete InstrumentChangeReplyQueue;
147            if (pDimRegionsInUse) delete[] pDimRegionsInUse;
148          Unregister();          Unregister();
149      }      }
150    
# Line 257  namespace LinuxSampler { namespace gig { Line 270  namespace LinuxSampler { namespace gig {
270              delete this->pDiskThread;              delete this->pDiskThread;
271              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
272          }          }
273          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
274                                               &instruments);
275          if (!pDiskThread) {          if (!pDiskThread) {
276              dmsg(0,("gig::Engine  new diskthread = NULL\n"));              dmsg(0,("gig::Engine  new diskthread = NULL\n"));
277              exit(EXIT_FAILURE);              exit(EXIT_FAILURE);
# Line 377  namespace LinuxSampler { namespace gig { Line 391  namespace LinuxSampler { namespace gig {
391          // reset internal voice counter (just for statistic of active voices)          // reset internal voice counter (just for statistic of active voices)
392          ActiveVoiceCountTemp = 0;          ActiveVoiceCountTemp = 0;
393    
394            // handle instrument change commands
395            instrument_change_command_t command;
396            if (InstrumentChangeQueue->pop(&command) > 0) {
397                EngineChannel* pEngineChannel = command.pEngineChannel;
398                pEngineChannel->pInstrument = command.pInstrument;
399    
400                // iterate through all active voices and mark their
401                // dimension regions as "in use". The instrument resource
402                // manager may delete all of the instrument except the
403                // dimension regions and samples that are in use.
404                int i = 0;
405                RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
406                RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
407                while (iuiKey != end) { // iterate through all active keys
408                    midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
409                    ++iuiKey;
410    
411                    RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
412                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
413                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
414                        if (!itVoice->Orphan) {
415                            itVoice->Orphan = true;
416                            pDimRegionsInUse[i++] = itVoice->pDimRgn;
417                        }
418                    }
419                }
420                pDimRegionsInUse[i] = 0; // end of list
421    
422                // send a reply to the calling thread, which is waiting
423                instrument_change_reply_t reply;
424                InstrumentChangeReplyQueue->push(&reply);
425            }
426    
427          // handle events on all engine channels          // handle events on all engine channels
428          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  
429              ProcessEvents(engineChannels[i], Samples);              ProcessEvents(engineChannels[i], Samples);
430          }          }
431    
432          // render all 'normal', active voices on all engine channels          // render all 'normal', active voices on all engine channels
433          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  
434              RenderActiveVoices(engineChannels[i], Samples);              RenderActiveVoices(engineChannels[i], Samples);
435          }          }
436    
# Line 400  namespace LinuxSampler { namespace gig { Line 445  namespace LinuxSampler { namespace gig {
445    
446          // handle cleanup on all engine channels for the next audio fragment          // handle cleanup on all engine channels for the next audio fragment
447          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  
448              PostProcess(engineChannels[i]);              PostProcess(engineChannels[i]);
449          }          }
450    
# Line 519  namespace LinuxSampler { namespace gig { Line 563  namespace LinuxSampler { namespace gig {
563          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();
564          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
565              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
566                if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
567              Pool<Voice>::Iterator itNewVoice =              Pool<Voice>::Iterator itNewVoice =
568                  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);
569              if (itNewVoice) {              if (itNewVoice) {
# Line 555  namespace LinuxSampler { namespace gig { Line 600  namespace LinuxSampler { namespace gig {
600          {          {
601              AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);              AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
602              AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);              AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
603              pEngineChannel->pChannelLeft->CopyTo(pDstL, Samples);              pEngineChannel->pChannelLeft->MixTo(pDstL, Samples);
604              pEngineChannel->pChannelRight->CopyTo(pDstR, Samples);              pEngineChannel->pChannelRight->MixTo(pDstR, Samples);
605          }          }
606          // route FX send signal          // route FX send signal
607          {          {
# Line 570  namespace LinuxSampler { namespace gig { Line 615  namespace LinuxSampler { namespace gig {
615                      AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);                      AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);
616                      if (!pDstL) {                      if (!pDstL) {
617                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
618                      } else pEngineChannel->pChannelLeft->CopyTo(pDstL, Samples, pFxSend->Level());                      } else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level());
619                  }                  }
620                  // right channel                  // right channel
621                  const int iDstR = pFxSend->DestinationChannel(1);                  const int iDstR = pFxSend->DestinationChannel(1);
# Line 580  namespace LinuxSampler { namespace gig { Line 625  namespace LinuxSampler { namespace gig {
625                      AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);                      AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);
626                      if (!pDstR) {                      if (!pDstR) {
627                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
628                      } else pEngineChannel->pChannelRight->CopyTo(pDstR, Samples, pFxSend->Level());                      } else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level());
629                  }                  }
630              }              }
631          }          }
# Line 666  namespace LinuxSampler { namespace gig { Line 711  namespace LinuxSampler { namespace gig {
711          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
712          #endif          #endif
713    
714            if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
715    
716            //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
717            itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
718    
719          const int key = itNoteOnEvent->Param.Note.Key;          const int key = itNoteOnEvent->Param.Note.Key;
720          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
721    
# Line 753  namespace LinuxSampler { namespace gig { Line 803  namespace LinuxSampler { namespace gig {
803          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
804          #endif          #endif
805    
806            //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
807            itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
808    
809          const int iKey = itNoteOffEvent->Param.Note.Key;          const int iKey = itNoteOffEvent->Param.Note.Key;
810          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
811          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 816  namespace LinuxSampler { namespace gig {
816          bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);          bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
817    
818          // 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)
819          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
820              bool bOtherKeysPressed = false;              bool bOtherKeysPressed = false;
821              if (iKey == pEngineChannel->SoloKey) {              if (iKey == pEngineChannel->SoloKey) {
822                  pEngineChannel->SoloKey = -1;                  pEngineChannel->SoloKey = -1;
# Line 826  namespace LinuxSampler { namespace gig { Line 879  namespace LinuxSampler { namespace gig {
879              itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type              itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
880    
881              // spawn release triggered voice(s) if needed              // spawn release triggered voice(s) if needed
882              if (pKey->ReleaseTrigger) {              if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
883                  // first, get total amount of required voices (dependant on amount of layers)                  // first, get total amount of required voices (dependant on amount of layers)
884                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
885                  if (pRegion) {                  if (pRegion) {
# Line 1021  namespace LinuxSampler { namespace gig { Line 1074  namespace LinuxSampler { namespace gig {
1074                      std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;                      std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1075              }              }
1076          }          }
1077    
1078            // return if this is a release triggered voice and there is no
1079            // releasetrigger dimension (could happen if an instrument
1080            // change has occured between note on and off)
1081            if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1082    
1083          ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);          ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1084    
1085          // no need to continue if sample is silent          // no need to continue if sample is silent
# Line 1250  namespace LinuxSampler { namespace gig { Line 1309  namespace LinuxSampler { namespace gig {
1309    
1310              uint keygroup = itVoice->KeyGroup;              uint keygroup = itVoice->KeyGroup;
1311    
1312                // if the sample and dimension region belong to an
1313                // instrument that is unloaded, tell the disk thread to
1314                // release them
1315                if (itVoice->Orphan) {
1316                    pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1317                }
1318    
1319              // free the voice object              // free the voice object
1320              pVoicePool->free(itVoice);              pVoicePool->free(itVoice);
1321    
# Line 1300  namespace LinuxSampler { namespace gig { Line 1366  namespace LinuxSampler { namespace gig {
1366                  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;
1367                  break;                  break;
1368              }              }
1369                case 6: { // data entry (currently only used for RPN controllers)
1370                    if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1371                        int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1372                        // limit to +- two octaves for now
1373                        transpose = RTMath::Min(transpose,  24);
1374                        transpose = RTMath::Max(transpose, -24);
1375                        pEngineChannel->GlobalTranspose = transpose;
1376                        // workaround, so we won't have hanging notes
1377                        ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1378                    }
1379                    // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1380                    pEngineChannel->ResetMidiRpnController();
1381                    break;
1382                }
1383              case 7: { // volume              case 7: { // volume
1384                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1385                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
# Line 1404  namespace LinuxSampler { namespace gig { Line 1484  namespace LinuxSampler { namespace gig {
1484                  }                  }
1485                  break;                  break;
1486              }              }
1487                case 100: { // RPN controller LSB
1488                    pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1489                    break;
1490                }
1491                case 101: { // RPN controller MSB
1492                    pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1493                    break;
1494                }
1495    
1496    
1497              // Channel Mode Messages              // Channel Mode Messages
# Line 1440  namespace LinuxSampler { namespace gig { Line 1528  namespace LinuxSampler { namespace gig {
1528                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1529                  if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)                  if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)
1530                      pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);                      pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1531                        pFxSend->SetInfoChanged(true);
1532              }              }
1533          }          }
1534      }      }
# Line 1636  namespace LinuxSampler { namespace gig { Line 1725  namespace LinuxSampler { namespace gig {
1725      }      }
1726    
1727      String Engine::Version() {      String Engine::Version() {
1728          String s = "$Revision: 1.69 $";          String s = "$Revision: 1.77 $";
1729          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
1730      }      }
1731    
# Line 1686  namespace LinuxSampler { namespace gig { Line 1775  namespace LinuxSampler { namespace gig {
1775          return y;          return y;
1776      }      }
1777    
1778        /**
1779         * Changes the instrument for an engine channel.
1780         *
1781         * @param pEngineChannel - engine channel on which the instrument
1782         *                         should be changed
1783         * @param pInstrument - new instrument
1784         * @returns a list of dimension regions from the old instrument
1785         *          that are still in use
1786         */
1787        ::gig::DimensionRegion** Engine::ChangeInstrument(EngineChannel* pEngineChannel, ::gig::Instrument* pInstrument) {
1788            instrument_change_command_t command;
1789            command.pEngineChannel = pEngineChannel;
1790            command.pInstrument = pInstrument;
1791            InstrumentChangeQueue->push(&command);
1792    
1793            // wait for the audio thread to confirm that the instrument
1794            // change has been done
1795            instrument_change_reply_t reply;
1796            while (InstrumentChangeReplyQueue->pop(&reply) == 0) {
1797                usleep(10000);
1798            }
1799            return pDimRegionsInUse;
1800        }
1801    
1802  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

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

  ViewVC Help
Powered by ViewVC