/[svn]/linuxsampler/trunk/src/engines/EngineChannelBase.h
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/EngineChannelBase.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2659 by schoenebeck, Sun Jun 29 19:34:28 2014 UTC revision 3054 by schoenebeck, Thu Dec 15 12:47:45 2016 UTC
# Line 4  Line 4 
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-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2013 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8     *   Copyright (C) 2012-2016 Christian Schoenebeck and Andreas Persson     *
9   *                                                                         *   *                                                                         *
10   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
11   *   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 49  namespace LinuxSampler { Line 50  namespace LinuxSampler {
50      };      };
51    
52      template<class V>      template<class V>
53      class VoicePool {      class NotePool {
54          public:          public:
55              virtual Pool<V>* GetVoicePool() = 0;              virtual Pool<V>* GetVoicePool() = 0;
56                virtual Pool< Note<V> >* GetNotePool() = 0;
57                virtual Pool<note_id_t>* GetNodeIDPool() = 0;
58      };      };
59    
60      template <class V /* Voice */, class R /* Region */, class I /* Instrument */>      template <class V /* Voice */, class R /* Region */, class I /* Instrument */>
61      class EngineChannelBase: public AbstractEngineChannel, public MidiKeyboardManager<V>, public ResourceConsumer<I> {      class EngineChannelBase: public AbstractEngineChannel, public MidiKeyboardManager<V>, public ResourceConsumer<I> {
62          public:          public:
63                typedef typename RTList< Note<V> >::Iterator NoteIterator;
64              typedef typename RTList<R*>::Iterator RTListRegionIterator;              typedef typename RTList<R*>::Iterator RTListRegionIterator;
65              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;
66    
# Line 123  namespace LinuxSampler { Line 127  namespace LinuxSampler {
127                  }                  }
128              }              }
129    
130              virtual void Connect(AudioOutputDevice* pAudioOut) {              virtual void Connect(AudioOutputDevice* pAudioOut) OVERRIDE {
131                  if (pEngine) {                  if (pEngine) {
132                      if (pEngine->pAudioOutputDevice == pAudioOut) return;                      if (pEngine->pAudioOutputDevice == pAudioOut) return;
133                      DisconnectAudioOutputDevice();                      DisconnectAudioOutputDevice();
# Line 133  namespace LinuxSampler { Line 137  namespace LinuxSampler {
137                      LockGuard lock(EngineMutex);                      LockGuard lock(EngineMutex);
138                      pEngine = newEngine;                      pEngine = newEngine;
139                  }                  }
140                  ResetInternal();                  ResetInternal(false/*don't reset engine*/); // 'false' is error prone here, but the danger of recursion with 'true' would be worse, there could be a better solution though
141                  pEvents = new RTList<Event>(pEngine->pEventPool);                  pEvents = new RTList<Event>(pEngine->pEventPool);
142                    delayedEvents.pList = new RTList<Event>(pEngine->pEventPool);
143    
144                  RegionPools<R>* pRegionPool = dynamic_cast<RegionPools<R>*>(pEngine);                  RegionPools<R>* pRegionPool = dynamic_cast<RegionPools<R>*>(pEngine);
145                  // reset the instrument change command struct (need to be done                  // reset the instrument change command struct (need to be done
# Line 161  namespace LinuxSampler { Line 166  namespace LinuxSampler {
166                      bStatusChanged = true;                      bStatusChanged = true;
167                  }                  }
168    
169                  VoicePool<V>* pVoicePool = dynamic_cast<VoicePool<V>*>(pEngine);                  NotePool<V>* pNotePool = dynamic_cast<NotePool<V>*>(pEngine);
170                  MidiKeyboardManager<V>::AllocateActiveVoices(pVoicePool->GetVoicePool());                  MidiKeyboardManager<V>::AllocateActiveNotesLists(
171                  MidiKeyboardManager<V>::AllocateEvents(pEngine->pEventPool);                      pNotePool->GetNotePool(),
172                        pNotePool->GetVoicePool()
173                    );
174                    MidiKeyboardManager<V>::AllocateEventsLists(pEngine->pEventPool);
175    
176                  AudioDeviceChannelLeft  = 0;                  AudioDeviceChannelLeft  = 0;
177                  AudioDeviceChannelRight = 1;                  AudioDeviceChannelRight = 1;
# Line 181  namespace LinuxSampler { Line 189  namespace LinuxSampler {
189                  MidiInputPort::AddSysexListener(pEngine);                  MidiInputPort::AddSysexListener(pEngine);
190              }              }
191    
192              virtual void DisconnectAudioOutputDevice() {              virtual void DisconnectAudioOutputDevice() OVERRIDE {
193                  if (pEngine) { // if clause to prevent disconnect loops                  if (pEngine) { // if clause to prevent disconnect loops
194    
195                      ResetInternal();                      ResetInternal(false/*don't reset engine*/); // 'false' is error prone here, but the danger of recursion with 'true' would be worse, there could be a better solution though
196    
197                      DeleteRegionsInUse();                      DeleteRegionsInUse();
198                      UnloadScriptInUse();                      UnloadScriptInUse();
# Line 199  namespace LinuxSampler { Line 207  namespace LinuxSampler {
207                          delete pEvents;                          delete pEvents;
208                          pEvents = NULL;                          pEvents = NULL;
209                      }                      }
210                        if (delayedEvents.pList) {
211                            delete delayedEvents.pList;
212                            delayedEvents.pList = NULL;
213                        }
214    
215                      MidiKeyboardManager<V>::DeleteActiveVoices();                      MidiKeyboardManager<V>::DeleteActiveNotesLists();
216                      MidiKeyboardManager<V>::DeleteEvents();                      MidiKeyboardManager<V>::DeleteEventsLists();
217                      DeleteGroupEventLists();                      DeleteGroupEventLists();
218    
219                      AudioOutputDevice* oldAudioDevice = pEngine->pAudioOutputDevice;                      AudioOutputDevice* oldAudioDevice = pEngine->pAudioOutputDevice;
# Line 226  namespace LinuxSampler { Line 238  namespace LinuxSampler {
238                      virtual bool Process(MidiKey* pMidiKey) { pMidiKey->pEvents->clear(); return false; }                      virtual bool Process(MidiKey* pMidiKey) { pMidiKey->pEvents->clear(); return false; }
239              };              };
240    
241              void ClearEventLists() {              /**
242                 * Free all events of the current audio fragment cycle. Calling
243                 * this method will @b NOT free events scheduled past the current
244                 * fragment's boundary! (@see AbstractEngineChannel::delayedEvents).
245                 */
246                void ClearEventListsOfCurrentFragment() {
247                  pEvents->clear();                  pEvents->clear();
248                  // empty MIDI key specific event lists                  // empty MIDI key specific event lists
249                  ClearEventListsHandler handler;                  ClearEventListsHandler handler;
# Line 249  namespace LinuxSampler { Line 266  namespace LinuxSampler {
266              virtual void ResourceToBeUpdated(I* pResource, void*& pUpdateArg) OVERRIDE {              virtual void ResourceToBeUpdated(I* pResource, void*& pUpdateArg) OVERRIDE {
267                  dmsg(3,("EngineChannelBase: Received instrument update message.\n"));                  dmsg(3,("EngineChannelBase: Received instrument update message.\n"));
268                  if (pEngine) pEngine->DisableAndLock();                  if (pEngine) pEngine->DisableAndLock();
269                  ResetInternal();                  ResetInternal(false/*don't reset engine*/);
270                  this->pInstrument = NULL;                  this->pInstrument = NULL;
271              }              }
272    
# Line 271  namespace LinuxSampler { Line 288  namespace LinuxSampler {
288               */               */
289              virtual void OnResourceProgress(float fProgress) OVERRIDE {              virtual void OnResourceProgress(float fProgress) OVERRIDE {
290                  this->InstrumentStat = int(fProgress * 100.0f);                  this->InstrumentStat = int(fProgress * 100.0f);
291                  dmsg(7,("EngineChannelBase: progress %d%", InstrumentStat));                  dmsg(7,("EngineChannelBase: progress %d%%", InstrumentStat));
292                  bStatusChanged = true; // status of engine has changed, so set notify flag                  bStatusChanged = true; // status of engine has changed, so set notify flag
293              }              }
294    
295                /**
296                 * Called on sustain pedal up events to check and if required,
297                 * launch release trigger voices on the respective active key.
298                 *
299                 * @param pEngineChannel - engine channel on which this event occurred on
300                 * @param itEvent - release trigger event (contains note number)
301                 */
302                virtual void ProcessReleaseTrigger(RTList<Event>::Iterator& itEvent) OVERRIDE {
303                    if (!pEngine) return;
304                    pEngine->ProcessReleaseTrigger(this, itEvent);
305                }
306    
307              void RenderActiveVoices(uint Samples) {              void RenderActiveVoices(uint Samples) {
308                  RenderVoicesHandler handler(this, Samples);                  RenderVoicesHandler handler(this, Samples);
309                  this->ProcessActiveVoices(&handler);                  this->ProcessActiveVoices(&handler);
# Line 283  namespace LinuxSampler { Line 312  namespace LinuxSampler {
312                  SetDiskStreamCount(handler.StreamCount);                  SetDiskStreamCount(handler.StreamCount);
313              }              }
314    
315                /**
316                 * Called by real-time instrument script functions to schedule a
317                 * new note (new note-on event and a new @c Note object linked to it)
318                 * @a delay microseconds in future.
319                 *
320                 * @b IMPORTANT: for the supplied @a delay to be scheduled
321                 * correctly, the passed @a pEvent must be assigned a valid
322                 * fragment time within the current audio fragment boundaries. That
323                 * fragment time will be used by this method as basis for
324                 * interpreting what "now" acutally is, and thus it will be used as
325                 * basis for calculating the precise scheduling time for @a delay.
326                 * The easiest way to achieve this is by copying a recent event
327                 * which happened within the current audio fragment cycle: i.e. the
328                 * original event which caused calling this method here, or by using
329                 * Event::copyTimefrom() method to only copy the time, without any
330                 * other event data.
331                 *
332                 * @param pEvent - note-on event to be scheduled in future (event
333                 *                 data will be copied)
334                 * @param delay - amount of microseconds in future (from now) when
335                 *                event shall be processed
336                 * @returns unique note ID of scheduled new note, or NULL on error
337                 */
338                note_id_t ScheduleNoteMicroSec(const Event* pEvent, int delay) OVERRIDE {
339                    // add (copied) note-on event into scheduler queue
340                    const event_id_t noteOnEventID = ScheduleEventMicroSec(pEvent, delay);
341                    if (!noteOnEventID) return 0; // error
342                    // get access to (copied) event on the scheduler queue
343                    RTList<Event>::Iterator itEvent = pEvents->fromID(noteOnEventID);
344                    // stick a new note to the (copied) event on the queue
345                    const note_id_t noteID = pEngine->LaunchNewNote(this, &*itEvent);
346                    return noteID;
347                }
348    
349                /**
350                 * Called by real-time instrument script functions to ignore the note
351                 * reflected by given note ID. The note's event will be freed immediately
352                 * to its event pool and this will prevent voices to be launched for the
353                 * note.
354                 *
355                 * NOTE: preventing a note by calling this method works only if the note
356                 * was launched within the current audio fragment cycle.
357                 *
358                 * @param id - unique ID of note to be dropped
359                 */
360                void IgnoreNote(note_id_t id) OVERRIDE {
361                    Pool< Note<V> >* pNotePool =
362                        dynamic_cast<NotePool<V>*>(pEngine)->GetNotePool();
363    
364                    NoteIterator itNote = pNotePool->fromID(id);
365                    if (!itNote) return; // note probably already released
366    
367                    // if the note already got active voices, then it is too late to drop it
368                    if (!itNote->pActiveVoices->isEmpty()) return;
369    
370                    // if the original (note-on) event is not available anymore, then it is too late to drop it
371                    RTList<Event>::Iterator itEvent = pEvents->fromID(itNote->eventID);
372                    if (!itEvent) return;
373    
374                    // drop the note
375                    pNotePool->free(itNote);
376    
377                    // drop the original event
378                    pEvents->free(itEvent);
379                }
380    
381              RTList<R*>* pRegionsInUse;     ///< temporary pointer into the instrument change command, used by the audio thread              RTList<R*>* pRegionsInUse;     ///< temporary pointer into the instrument change command, used by the audio thread
382              I* pInstrument;              I* pInstrument;
383    
# Line 343  namespace LinuxSampler { Line 438  namespace LinuxSampler {
438                      EngineChannelBase<V, R, I>* pChannel;                      EngineChannelBase<V, R, I>* pChannel;
439    
440                      RenderVoicesHandler(EngineChannelBase<V, R, I>* channel, uint samples) :                      RenderVoicesHandler(EngineChannelBase<V, R, I>* channel, uint samples) :
441                          pChannel(channel), Samples(samples), VoiceCount(0), StreamCount(0) { }                          Samples(samples), VoiceCount(0), StreamCount(0), pChannel(channel) { }
442    
443                      virtual void Process(RTListVoiceIterator& itVoice) {                      virtual void Process(RTListVoiceIterator& itVoice) {
444                          // now render current voice                          // now render current voice
# Line 370  namespace LinuxSampler { Line 465  namespace LinuxSampler {
465              SyncConfInstrChangeCmdReader InstrumentChangeCommandReader;              SyncConfInstrChangeCmdReader InstrumentChangeCommandReader;
466    
467              /** This method is not thread safe! */              /** This method is not thread safe! */
468              virtual void ResetInternal() {              virtual void ResetInternal(bool bResetEngine) OVERRIDE {
469                  AbstractEngineChannel::ResetInternal();                  AbstractEngineChannel::ResetInternal(bResetEngine);
470    
471                  MidiKeyboardManager<V>::Reset();                  MidiKeyboardManager<V>::Reset();
472              }              }
473    
474              virtual void ResetControllers() {              virtual void ResetControllers() OVERRIDE {
475                  AbstractEngineChannel::ResetControllers();                  AbstractEngineChannel::ResetControllers();
476    
477                  MidiKeyboardManager<V>::SustainPedal   = false;                  MidiKeyboardManager<V>::SustainPedal   = false;

Legend:
Removed from v.2659  
changed lines
  Added in v.3054

  ViewVC Help
Powered by ViewVC