/[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 2618 by schoenebeck, Wed Jun 11 11:39:44 2014 UTC revision 3073 by schoenebeck, Thu Jan 5 16:04:00 2017 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-2017 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 39  namespace LinuxSampler { Line 40  namespace LinuxSampler {
40              bool bChangeInstrument;       ///< Set to true by the loader when the channel should change instrument.              bool bChangeInstrument;       ///< Set to true by the loader when the channel should change instrument.
41              I* pInstrument;               ///< The new instrument. Also used by the loader to read the previously loaded instrument.              I* pInstrument;               ///< The new instrument. Also used by the loader to read the previously loaded instrument.
42              RTList<R*>* pRegionsInUse; ///< List of dimension regions in use by the currently loaded instrument. Continuously updated by the audio thread.              RTList<R*>* pRegionsInUse; ///< List of dimension regions in use by the currently loaded instrument. Continuously updated by the audio thread.
43              InstrumentScript* pScript; ///< Instrument script to be executed for this instrument, or NULL if instrument does not have a script.              InstrumentScript* pScript; ///< Instrument script to be executed for this instrument. This is never NULL, it is always a valid InstrumentScript pointer. Use InstrumentScript::bHasValidScript whether it reflects a valid instrument script to be executed.
44      };      };
45    
46      template<class R>      template<class R>
# 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                /**
56                 * Pool from where Voice objects are allocated from (and freed back to).
57                 */
58              virtual Pool<V>* GetVoicePool() = 0;              virtual Pool<V>* GetVoicePool() = 0;
59    
60                /**
61                 * Pool from where new Note objects are allocated from (and freed back to).
62                 */
63                virtual Pool< Note<V> >* GetNotePool() = 0;
64    
65                /**
66                 * Pool for saving already existing Note object IDs somewhere.
67                 *
68                 * @b IMPORTANT: This pool is @b NOT used for generating any IDs for
69                 * Note objects! The respective Note objective IDs are emitted by
70                 * the Note object pool (see GetNotePool() above).
71                 */
72                virtual Pool<note_id_t>* GetNoteIDPool() = 0;
73      };      };
74    
75      template <class V /* Voice */, class R /* Region */, class I /* Instrument */>      template <class V /* Voice */, class R /* Region */, class I /* Instrument */>
76      class EngineChannelBase: public AbstractEngineChannel, public MidiKeyboardManager<V>, public ResourceConsumer<I> {      class EngineChannelBase: public AbstractEngineChannel, public MidiKeyboardManager<V>, public ResourceConsumer<I> {
77          public:          public:
78                typedef typename RTList< Note<V> >::Iterator NoteIterator;
79              typedef typename RTList<R*>::Iterator RTListRegionIterator;              typedef typename RTList<R*>::Iterator RTListRegionIterator;
80              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;
81    
# Line 123  namespace LinuxSampler { Line 142  namespace LinuxSampler {
142                  }                  }
143              }              }
144    
145              virtual void Connect(AudioOutputDevice* pAudioOut) {              virtual void Connect(AudioOutputDevice* pAudioOut) OVERRIDE {
146                  if (pEngine) {                  if (pEngine) {
147                      if (pEngine->pAudioOutputDevice == pAudioOut) return;                      if (pEngine->pAudioOutputDevice == pAudioOut) return;
148                      DisconnectAudioOutputDevice();                      DisconnectAudioOutputDevice();
# Line 133  namespace LinuxSampler { Line 152  namespace LinuxSampler {
152                      LockGuard lock(EngineMutex);                      LockGuard lock(EngineMutex);
153                      pEngine = newEngine;                      pEngine = newEngine;
154                  }                  }
155                  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
156                  pEvents = new RTList<Event>(pEngine->pEventPool);                  pEvents = new RTList<Event>(pEngine->pEventPool);
157                    delayedEvents.pList = new RTList<Event>(pEngine->pEventPool);
158    
159                  RegionPools<R>* pRegionPool = dynamic_cast<RegionPools<R>*>(pEngine);                  RegionPools<R>* pRegionPool = dynamic_cast<RegionPools<R>*>(pEngine);
160                  // 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 181  namespace LinuxSampler {
181                      bStatusChanged = true;                      bStatusChanged = true;
182                  }                  }
183    
184                  VoicePool<V>* pVoicePool = dynamic_cast<VoicePool<V>*>(pEngine);                  NotePool<V>* pNotePool = dynamic_cast<NotePool<V>*>(pEngine);
185                  MidiKeyboardManager<V>::AllocateActiveVoices(pVoicePool->GetVoicePool());                  MidiKeyboardManager<V>::AllocateActiveNotesLists(
186                  MidiKeyboardManager<V>::AllocateEvents(pEngine->pEventPool);                      pNotePool->GetNotePool(),
187                        pNotePool->GetVoicePool()
188                    );
189                    MidiKeyboardManager<V>::AllocateEventsLists(pEngine->pEventPool);
190    
191                  AudioDeviceChannelLeft  = 0;                  AudioDeviceChannelLeft  = 0;
192                  AudioDeviceChannelRight = 1;                  AudioDeviceChannelRight = 1;
# Line 181  namespace LinuxSampler { Line 204  namespace LinuxSampler {
204                  MidiInputPort::AddSysexListener(pEngine);                  MidiInputPort::AddSysexListener(pEngine);
205              }              }
206    
207              virtual void DisconnectAudioOutputDevice() {              virtual void DisconnectAudioOutputDevice() OVERRIDE {
208                  if (pEngine) { // if clause to prevent disconnect loops                  if (pEngine) { // if clause to prevent disconnect loops
209    
210                      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
211    
212                      DeleteRegionsInUse();                      DeleteRegionsInUse();
213                      UnloadScriptInUse();                      UnloadScriptInUse();
# Line 199  namespace LinuxSampler { Line 222  namespace LinuxSampler {
222                          delete pEvents;                          delete pEvents;
223                          pEvents = NULL;                          pEvents = NULL;
224                      }                      }
225                        if (delayedEvents.pList) {
226                            delete delayedEvents.pList;
227                            delayedEvents.pList = NULL;
228                        }
229    
230                      MidiKeyboardManager<V>::DeleteActiveVoices();                      MidiKeyboardManager<V>::DeleteActiveNotesLists();
231                      MidiKeyboardManager<V>::DeleteEvents();                      MidiKeyboardManager<V>::DeleteEventsLists();
232                      DeleteGroupEventLists();                      DeleteGroupEventLists();
233    
234                      AudioOutputDevice* oldAudioDevice = pEngine->pAudioOutputDevice;                      AudioOutputDevice* oldAudioDevice = pEngine->pAudioOutputDevice;
# Line 226  namespace LinuxSampler { Line 253  namespace LinuxSampler {
253                      virtual bool Process(MidiKey* pMidiKey) { pMidiKey->pEvents->clear(); return false; }                      virtual bool Process(MidiKey* pMidiKey) { pMidiKey->pEvents->clear(); return false; }
254              };              };
255    
256              void ClearEventLists() {              /**
257                 * Free all events of the current audio fragment cycle. Calling
258                 * this method will @b NOT free events scheduled past the current
259                 * fragment's boundary! (@see AbstractEngineChannel::delayedEvents).
260                 */
261                void ClearEventListsOfCurrentFragment() {
262                  pEvents->clear();                  pEvents->clear();
263                  // empty MIDI key specific event lists                  // empty MIDI key specific event lists
264                  ClearEventListsHandler handler;                  ClearEventListsHandler handler;
# Line 249  namespace LinuxSampler { Line 281  namespace LinuxSampler {
281              virtual void ResourceToBeUpdated(I* pResource, void*& pUpdateArg) OVERRIDE {              virtual void ResourceToBeUpdated(I* pResource, void*& pUpdateArg) OVERRIDE {
282                  dmsg(3,("EngineChannelBase: Received instrument update message.\n"));                  dmsg(3,("EngineChannelBase: Received instrument update message.\n"));
283                  if (pEngine) pEngine->DisableAndLock();                  if (pEngine) pEngine->DisableAndLock();
284                  ResetInternal();                  ResetInternal(false/*don't reset engine*/);
285                  this->pInstrument = NULL;                  this->pInstrument = NULL;
286              }              }
287    
# Line 271  namespace LinuxSampler { Line 303  namespace LinuxSampler {
303               */               */
304              virtual void OnResourceProgress(float fProgress) OVERRIDE {              virtual void OnResourceProgress(float fProgress) OVERRIDE {
305                  this->InstrumentStat = int(fProgress * 100.0f);                  this->InstrumentStat = int(fProgress * 100.0f);
306                  dmsg(7,("EngineChannelBase: progress %d%", InstrumentStat));                  dmsg(7,("EngineChannelBase: progress %d%%", InstrumentStat));
307                  bStatusChanged = true; // status of engine has changed, so set notify flag                  bStatusChanged = true; // status of engine has changed, so set notify flag
308              }              }
309    
310                /**
311                 * Called on sustain pedal up events to check and if required,
312                 * launch release trigger voices on the respective active key.
313                 *
314                 * @param pEngineChannel - engine channel on which this event occurred on
315                 * @param itEvent - release trigger event (contains note number)
316                 */
317                virtual void ProcessReleaseTrigger(RTList<Event>::Iterator& itEvent) OVERRIDE {
318                    if (!pEngine) return;
319                    pEngine->ProcessReleaseTrigger(this, itEvent);
320                }
321    
322              void RenderActiveVoices(uint Samples) {              void RenderActiveVoices(uint Samples) {
323                  RenderVoicesHandler handler(this, Samples);                  RenderVoicesHandler handler(this, Samples);
324                  this->ProcessActiveVoices(&handler);                  this->ProcessActiveVoices(&handler);
# Line 283  namespace LinuxSampler { Line 327  namespace LinuxSampler {
327                  SetDiskStreamCount(handler.StreamCount);                  SetDiskStreamCount(handler.StreamCount);
328              }              }
329    
330                /**
331                 * Called by real-time instrument script functions to schedule a
332                 * new note (new note-on event and a new @c Note object linked to it)
333                 * @a delay microseconds in future.
334                 *
335                 * @b IMPORTANT: for the supplied @a delay to be scheduled
336                 * correctly, the passed @a pEvent must be assigned a valid
337                 * fragment time within the current audio fragment boundaries. That
338                 * fragment time will be used by this method as basis for
339                 * interpreting what "now" acutally is, and thus it will be used as
340                 * basis for calculating the precise scheduling time for @a delay.
341                 * The easiest way to achieve this is by copying a recent event
342                 * which happened within the current audio fragment cycle: i.e. the
343                 * original event which caused calling this method here, or by using
344                 * Event::copyTimefrom() method to only copy the time, without any
345                 * other event data.
346                 *
347                 * @param pEvent - note-on event to be scheduled in future (event
348                 *                 data will be copied)
349                 * @param delay - amount of microseconds in future (from now) when
350                 *                event shall be processed
351                 * @returns unique note ID of scheduled new note, or NULL on error
352                 */
353                note_id_t ScheduleNoteMicroSec(const Event* pEvent, int delay) OVERRIDE {
354                    // add (copied) note-on event into scheduler queue
355                    const event_id_t noteOnEventID = ScheduleEventMicroSec(pEvent, delay);
356                    if (!noteOnEventID) return 0; // error
357                    // get access to (copied) event on the scheduler queue
358                    RTList<Event>::Iterator itEvent = pEvents->fromID(noteOnEventID);
359                    // stick a new note to the (copied) event on the queue
360                    const note_id_t noteID = pEngine->LaunchNewNote(this, &*itEvent);
361                    return noteID;
362                }
363    
364                /**
365                 * Called by real-time instrument script functions to ignore the note
366                 * reflected by given note ID. The note's event will be freed immediately
367                 * to its event pool and this will prevent voices to be launched for the
368                 * note.
369                 *
370                 * NOTE: preventing a note by calling this method works only if the note
371                 * was launched within the current audio fragment cycle.
372                 *
373                 * @param id - unique ID of note to be dropped
374                 */
375                void IgnoreNote(note_id_t id) OVERRIDE {
376                    Pool< Note<V> >* pNotePool =
377                        dynamic_cast<NotePool<V>*>(pEngine)->GetNotePool();
378    
379                    NoteIterator itNote = pNotePool->fromID(id);
380                    if (!itNote) return; // note probably already released
381    
382                    // if the note already got active voices, then it is too late to drop it
383                    if (!itNote->pActiveVoices->isEmpty()) return;
384    
385                    // if the original (note-on) event is not available anymore, then it is too late to drop it
386                    RTList<Event>::Iterator itEvent = pEvents->fromID(itNote->eventID);
387                    if (!itEvent) return;
388    
389                    // drop the note
390                    pNotePool->free(itNote);
391    
392                    // drop the original event
393                    pEvents->free(itEvent);
394                }
395    
396                /**
397                 * Copies the note IDs of all currently active notes on this engine
398                 * channel to the note ID buffer @a dstBuf, and returns the amount
399                 * of note IDs that have been copied to the destination buffer.
400                 *
401                 * @param dstBuf  - destination buffer for note IDs
402                 * @param bufSize - size of destination buffer (as amount of max.
403                 *                  note IDs, not as amount of bytes)
404                 * @returns amount of note IDs that have been copied to buffer
405                 */
406                uint AllNoteIDs(note_id_t* dstBuf, uint bufSize) OVERRIDE {
407                    uint n = 0;
408    
409                    Pool< Note<V> >* pNotePool =
410                        dynamic_cast<NotePool<V>*>(pEngine)->GetNotePool();
411    
412                    RTList<uint>::Iterator iuiKey = this->pActiveKeys->first();
413                    RTList<uint>::Iterator end    = this->pActiveKeys->end();
414                    for(; iuiKey != end; ++iuiKey) {
415                        MidiKey* pKey = &this->pMIDIKeyInfo[*iuiKey];
416                        NoteIterator itNote = pKey->pActiveNotes->first();
417                        for (; itNote; ++itNote) {
418                            if (n >= bufSize) goto done;
419                            dstBuf[n++] = pNotePool->getID(itNote);
420                        }
421                    }
422                    done:
423                    return n;
424                }
425    
426              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
427              I* pInstrument;              I* pInstrument;
428    
429              template<class TV, class TRR, class TR, class TD, class TIM, class TI> friend class EngineBase;              template<class TV, class TRR, class TR, class TD, class TIM, class TI> friend class EngineBase;
430    
431          protected:          protected:
432              EngineChannelBase() : InstrumentChangeCommandReader(InstrumentChangeCommand) {              EngineChannelBase() :
433                    MidiKeyboardManager<V>(this),
434                    InstrumentChangeCommandReader(InstrumentChangeCommand)
435                {
436                  pInstrument = NULL;                  pInstrument = NULL;
437    
438                  // reset the instrument change command struct (need to be done                  // reset the instrument change command struct (need to be done
# Line 340  namespace LinuxSampler { Line 483  namespace LinuxSampler {
483                      EngineChannelBase<V, R, I>* pChannel;                      EngineChannelBase<V, R, I>* pChannel;
484    
485                      RenderVoicesHandler(EngineChannelBase<V, R, I>* channel, uint samples) :                      RenderVoicesHandler(EngineChannelBase<V, R, I>* channel, uint samples) :
486                          pChannel(channel), Samples(samples), VoiceCount(0), StreamCount(0) { }                          Samples(samples), VoiceCount(0), StreamCount(0), pChannel(channel) { }
487    
488                      virtual void Process(RTListVoiceIterator& itVoice) {                      virtual void Process(RTListVoiceIterator& itVoice) {
489                          // now render current voice                          // now render current voice
# Line 367  namespace LinuxSampler { Line 510  namespace LinuxSampler {
510              SyncConfInstrChangeCmdReader InstrumentChangeCommandReader;              SyncConfInstrChangeCmdReader InstrumentChangeCommandReader;
511    
512              /** This method is not thread safe! */              /** This method is not thread safe! */
513              virtual void ResetInternal() {              virtual void ResetInternal(bool bResetEngine) OVERRIDE {
514                  AbstractEngineChannel::ResetInternal();                  AbstractEngineChannel::ResetInternal(bResetEngine);
515    
516                  MidiKeyboardManager<V>::Reset();                  MidiKeyboardManager<V>::Reset();
517              }              }
518    
519              virtual void ResetControllers() {              virtual void ResetControllers() OVERRIDE {
520                  AbstractEngineChannel::ResetControllers();                  AbstractEngineChannel::ResetControllers();
521    
522                  MidiKeyboardManager<V>::SustainPedal   = false;                  MidiKeyboardManager<V>::SustainPedal   = false;

Legend:
Removed from v.2618  
changed lines
  Added in v.3073

  ViewVC Help
Powered by ViewVC