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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3205 - (hide annotations) (download) (as text)
Wed May 24 20:05:38 2017 UTC (6 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 27453 byte(s)
* Fixed invalid (note-on) event ID being assigned to new Note
  objects.
* Fixed a bunch of scheduler time related bugs.
* Bumped version (2.0.0.svn47).

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 persson 2072 * Copyright (C) 2005-2008 Christian Schoenebeck *
7 schoenebeck 2871 * Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev *
8 schoenebeck 3073 * Copyright (C) 2012-2017 Christian Schoenebeck and Andreas Persson *
9 iliev 2012 * *
10     * 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 *
12     * the Free Software Foundation; either version 2 of the License, or *
13     * (at your option) any later version. *
14     * *
15     * This program is distributed in the hope that it will be useful, *
16     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18     * GNU General Public License for more details. *
19     * *
20     * You should have received a copy of the GNU General Public License *
21     * along with this program; if not, write to the Free Software *
22     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
23     * MA 02111-1307 USA *
24     ***************************************************************************/
25    
26     #ifndef __LS_ENGINECHANNELBASE_H__
27     #define __LS_ENGINECHANNELBASE_H__
28    
29     #include "AbstractEngineChannel.h"
30     #include "common/MidiKeyboardManager.h"
31     #include "common/Voice.h"
32     #include "../common/ResourceManager.h"
33    
34     namespace LinuxSampler {
35     /// Command used by the instrument loader thread to
36     /// request an instrument change on a channel.
37     template <class R /* Region */, class I /* Instrument */>
38     class InstrumentChangeCmd {
39     public:
40     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.
42     RTList<R*>* pRegionsInUse; ///< List of dimension regions in use by the currently loaded instrument. Continuously updated by the audio thread.
43 schoenebeck 2659 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 iliev 2012 };
45    
46     template<class R>
47     class RegionPools {
48     public:
49     virtual Pool<R*>* GetRegionPool(int index) = 0;
50     };
51    
52     template<class V>
53 schoenebeck 2879 class NotePool {
54 iliev 2012 public:
55 schoenebeck 3073 /**
56     * Pool from where Voice objects are allocated from (and freed back to).
57     */
58 iliev 2012 virtual Pool<V>* GetVoicePool() = 0;
59 schoenebeck 3073
60     /**
61     * Pool from where new Note objects are allocated from (and freed back to).
62     */
63 schoenebeck 2879 virtual Pool< Note<V> >* GetNotePool() = 0;
64 schoenebeck 3073
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 iliev 2012 };
74    
75     template <class V /* Voice */, class R /* Region */, class I /* Instrument */>
76     class EngineChannelBase: public AbstractEngineChannel, public MidiKeyboardManager<V>, public ResourceConsumer<I> {
77     public:
78 schoenebeck 2884 typedef typename RTList< Note<V> >::Iterator NoteIterator;
79 iliev 2012 typedef typename RTList<R*>::Iterator RTListRegionIterator;
80     typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;
81    
82 schoenebeck 2613 virtual MidiKeyboardManagerBase* GetMidiKeyboardManager() OVERRIDE {
83     return this;
84     }
85    
86 iliev 2012 virtual void HandBack(I* Instrument) {
87     ResourceManager<InstrumentManager::instrument_id_t, I>* mgr =
88     dynamic_cast<ResourceManager<InstrumentManager::instrument_id_t, I>*>(pEngine->GetInstrumentManager());
89     mgr->HandBack(Instrument, this);
90     }
91    
92     virtual void ClearRegionsInUse() {
93     {
94     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate();
95 persson 2165 if (cmd.pRegionsInUse) cmd.pRegionsInUse->clear();
96     cmd.bChangeInstrument = false;
97 iliev 2012 }
98     {
99     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig();
100 persson 2165 if (cmd.pRegionsInUse) cmd.pRegionsInUse->clear();
101     cmd.bChangeInstrument = false;
102 iliev 2012 }
103     }
104    
105     virtual void ResetRegionsInUse(Pool<R*>* pRegionPool[]) {
106     DeleteRegionsInUse();
107     AllocateRegionsInUse(pRegionPool);
108     }
109    
110     virtual void DeleteRegionsInUse() {
111 schoenebeck 2612 RTList<R*>* previous = NULL; // prevent double free
112 iliev 2012 {
113     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate();
114 persson 2165 if (cmd.pRegionsInUse) {
115 schoenebeck 2612 previous = cmd.pRegionsInUse;
116 iliev 2012 delete cmd.pRegionsInUse;
117     cmd.pRegionsInUse = NULL;
118     }
119 persson 2165 cmd.bChangeInstrument = false;
120 iliev 2012 }
121     {
122     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig();
123 persson 2165 if (cmd.pRegionsInUse) {
124 schoenebeck 2612 if (cmd.pRegionsInUse != previous)
125     delete cmd.pRegionsInUse;
126 iliev 2012 cmd.pRegionsInUse = NULL;
127     }
128 persson 2165 cmd.bChangeInstrument = false;
129 iliev 2012 }
130     }
131    
132     virtual void AllocateRegionsInUse(Pool<R*>* pRegionPool[]) {
133     {
134     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate();
135     cmd.pRegionsInUse = new RTList<R*>(pRegionPool[0]);
136 persson 2165 cmd.bChangeInstrument = false;
137 iliev 2012 }
138     {
139     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig();
140     cmd.pRegionsInUse = new RTList<R*>(pRegionPool[1]);
141 persson 2165 cmd.bChangeInstrument = false;
142 iliev 2012 }
143     }
144    
145 schoenebeck 3054 virtual void Connect(AudioOutputDevice* pAudioOut) OVERRIDE {
146 iliev 2012 if (pEngine) {
147     if (pEngine->pAudioOutputDevice == pAudioOut) return;
148     DisconnectAudioOutputDevice();
149     }
150 persson 2326 AbstractEngine* newEngine = AbstractEngine::AcquireEngine(this, pAudioOut);
151 persson 2427 {
152     LockGuard lock(EngineMutex);
153     pEngine = newEngine;
154     }
155 schoenebeck 2871 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 iliev 2012 pEvents = new RTList<Event>(pEngine->pEventPool);
157 schoenebeck 2871 delayedEvents.pList = new RTList<Event>(pEngine->pEventPool);
158 iliev 2012
159     RegionPools<R>* pRegionPool = dynamic_cast<RegionPools<R>*>(pEngine);
160     // reset the instrument change command struct (need to be done
161     // twice, as it is double buffered)
162     {
163     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate();
164     cmd.pRegionsInUse = new RTList<R*>(pRegionPool->GetRegionPool(0));
165     cmd.pInstrument = 0;
166     cmd.bChangeInstrument = false;
167     }
168     {
169     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig();
170     cmd.pRegionsInUse = new RTList<R*>(pRegionPool->GetRegionPool(1));
171     cmd.pInstrument = 0;
172     cmd.bChangeInstrument = false;
173     }
174    
175     if (pInstrument != NULL) {
176     pInstrument = NULL;
177     InstrumentStat = -1;
178     InstrumentIdx = -1;
179     InstrumentIdxName = "";
180     InstrumentFile = "";
181     bStatusChanged = true;
182     }
183    
184 schoenebeck 2879 NotePool<V>* pNotePool = dynamic_cast<NotePool<V>*>(pEngine);
185     MidiKeyboardManager<V>::AllocateActiveNotesLists(
186     pNotePool->GetNotePool(),
187     pNotePool->GetVoicePool()
188     );
189     MidiKeyboardManager<V>::AllocateEventsLists(pEngine->pEventPool);
190 iliev 2012
191     AudioDeviceChannelLeft = 0;
192     AudioDeviceChannelRight = 1;
193     if (fxSends.empty()) { // render directly into the AudioDevice's output buffers
194     pChannelLeft = pAudioOut->Channel(AudioDeviceChannelLeft);
195     pChannelRight = pAudioOut->Channel(AudioDeviceChannelRight);
196     } else { // use local buffers for rendering and copy later
197     // ensure the local buffers have the correct size
198     if (pChannelLeft) delete pChannelLeft;
199     if (pChannelRight) delete pChannelRight;
200     pChannelLeft = new AudioChannel(0, pAudioOut->MaxSamplesPerCycle());
201     pChannelRight = new AudioChannel(1, pAudioOut->MaxSamplesPerCycle());
202     }
203     if (pEngine->EngineDisabled.GetUnsafe()) pEngine->Enable();
204     MidiInputPort::AddSysexListener(pEngine);
205     }
206    
207 schoenebeck 3054 virtual void DisconnectAudioOutputDevice() OVERRIDE {
208 iliev 2012 if (pEngine) { // if clause to prevent disconnect loops
209    
210 schoenebeck 2871 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 iliev 2012
212     DeleteRegionsInUse();
213 schoenebeck 2612 UnloadScriptInUse();
214 iliev 2012
215     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate();
216     if (cmd.pInstrument) {
217     // release the currently loaded instrument
218     HandBack(cmd.pInstrument);
219     }
220    
221     if (pEvents) {
222     delete pEvents;
223     pEvents = NULL;
224     }
225 schoenebeck 2871 if (delayedEvents.pList) {
226     delete delayedEvents.pList;
227     delayedEvents.pList = NULL;
228     }
229 iliev 2012
230 schoenebeck 2879 MidiKeyboardManager<V>::DeleteActiveNotesLists();
231     MidiKeyboardManager<V>::DeleteEventsLists();
232 persson 2114 DeleteGroupEventLists();
233 iliev 2012
234     AudioOutputDevice* oldAudioDevice = pEngine->pAudioOutputDevice;
235 persson 2427 {
236     LockGuard lock(EngineMutex);
237     pEngine = NULL;
238     }
239 iliev 2012 AbstractEngine::FreeEngine(this, oldAudioDevice);
240     AudioDeviceChannelLeft = -1;
241     AudioDeviceChannelRight = -1;
242     if (!fxSends.empty()) { // free the local rendering buffers
243     if (pChannelLeft) delete pChannelLeft;
244     if (pChannelRight) delete pChannelRight;
245     }
246     pChannelLeft = NULL;
247     pChannelRight = NULL;
248     }
249     }
250    
251     class ClearEventListsHandler : public MidiKeyboardManager<V>::VoiceHandlerBase {
252     public:
253     virtual bool Process(MidiKey* pMidiKey) { pMidiKey->pEvents->clear(); return false; }
254     };
255    
256 schoenebeck 2871 /**
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 iliev 2012 pEvents->clear();
263     // empty MIDI key specific event lists
264     ClearEventListsHandler handler;
265 persson 2335 this->ProcessActiveVoices(&handler);
266 persson 2114
267     // empty exclusive group specific event lists
268 persson 2352 // (pInstrument == 0 could mean that LoadInstrument is
269     // building new group event lists, so we must check
270     // for that)
271     if (pInstrument) ClearGroupEventLists();
272 iliev 2012 }
273    
274     // implementation of abstract methods derived from interface class 'InstrumentConsumer'
275    
276     /**
277     * Will be called by the InstrumentResourceManager when the instrument
278     * we are currently using on this EngineChannel is going to be updated,
279     * so we can stop playback before that happens.
280     */
281 schoenebeck 2434 virtual void ResourceToBeUpdated(I* pResource, void*& pUpdateArg) OVERRIDE {
282 iliev 2012 dmsg(3,("EngineChannelBase: Received instrument update message.\n"));
283     if (pEngine) pEngine->DisableAndLock();
284 schoenebeck 2871 ResetInternal(false/*don't reset engine*/);
285 iliev 2012 this->pInstrument = NULL;
286     }
287    
288     /**
289     * Will be called by the InstrumentResourceManager when the instrument
290     * update process was completed, so we can continue with playback.
291     */
292 schoenebeck 2434 virtual void ResourceUpdated(I* pOldResource, I* pNewResource, void* pUpdateArg) OVERRIDE {
293 iliev 2012 this->pInstrument = pNewResource; //TODO: there are couple of engine parameters we should update here as well if the instrument was updated (see LoadInstrument())
294     if (pEngine) pEngine->Enable();
295     bStatusChanged = true; // status of engine has changed, so set notify flag
296     }
297    
298     /**
299     * Will be called by the InstrumentResourceManager on progress changes
300     * while loading or realoading an instrument for this EngineChannel.
301     *
302     * @param fProgress - current progress as value between 0.0 and 1.0
303     */
304 schoenebeck 2434 virtual void OnResourceProgress(float fProgress) OVERRIDE {
305 iliev 2012 this->InstrumentStat = int(fProgress * 100.0f);
306 persson 2837 dmsg(7,("EngineChannelBase: progress %d%%", InstrumentStat));
307 iliev 2012 bStatusChanged = true; // status of engine has changed, so set notify flag
308     }
309    
310 schoenebeck 2927 /**
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 iliev 2012 void RenderActiveVoices(uint Samples) {
323     RenderVoicesHandler handler(this, Samples);
324 persson 2335 this->ProcessActiveVoices(&handler);
325 iliev 2012
326     SetVoiceCount(handler.VoiceCount);
327     SetDiskStreamCount(handler.StreamCount);
328     }
329    
330 schoenebeck 2879 /**
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 schoenebeck 3205 const note_id_t noteID = pEngine->LaunchNewNote(this, itEvent);
361 schoenebeck 2879 return noteID;
362     }
363    
364 schoenebeck 2884 /**
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 schoenebeck 3073 /**
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 iliev 2012 RTList<R*>* pRegionsInUse; ///< temporary pointer into the instrument change command, used by the audio thread
427     I* pInstrument;
428    
429     template<class TV, class TRR, class TR, class TD, class TIM, class TI> friend class EngineBase;
430    
431     protected:
432 schoenebeck 2645 EngineChannelBase() :
433     MidiKeyboardManager<V>(this),
434     InstrumentChangeCommandReader(InstrumentChangeCommand)
435     {
436 iliev 2012 pInstrument = NULL;
437    
438     // reset the instrument change command struct (need to be done
439     // twice, as it is double buffered)
440     {
441     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate();
442     cmd.pRegionsInUse = NULL;
443     cmd.pInstrument = NULL;
444 schoenebeck 2611 cmd.pScript = new InstrumentScript(this);
445 iliev 2012 cmd.bChangeInstrument = false;
446     }
447     {
448     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig();
449     cmd.pRegionsInUse = NULL;
450     cmd.pInstrument = NULL;
451 schoenebeck 2611 cmd.pScript = new InstrumentScript(this);
452 iliev 2012 cmd.bChangeInstrument = false;
453     }
454     }
455    
456 schoenebeck 2611 virtual ~EngineChannelBase() {
457 schoenebeck 2612 InstrumentScript* previous = NULL; // prevent double free
458 schoenebeck 2611 {
459     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate();
460 schoenebeck 2612 if (cmd.pScript) {
461     previous = cmd.pScript;
462     delete cmd.pScript;
463     cmd.pScript = NULL;
464     }
465 schoenebeck 2611 }
466     {
467     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig();
468 schoenebeck 2612 if (cmd.pScript) {
469     if (previous != cmd.pScript)
470     delete cmd.pScript;
471     cmd.pScript = NULL;
472     }
473 schoenebeck 2611 }
474     }
475 iliev 2012
476     typedef typename RTList<V>::Iterator RTListVoiceIterator;
477    
478     class RenderVoicesHandler : public MidiKeyboardManager<V>::VoiceHandlerBase {
479     public:
480     uint Samples;
481     uint VoiceCount;
482     uint StreamCount;
483     EngineChannelBase<V, R, I>* pChannel;
484    
485     RenderVoicesHandler(EngineChannelBase<V, R, I>* channel, uint samples) :
486 schoenebeck 3034 Samples(samples), VoiceCount(0), StreamCount(0), pChannel(channel) { }
487 iliev 2012
488     virtual void Process(RTListVoiceIterator& itVoice) {
489     // now render current voice
490     itVoice->Render(Samples);
491     if (itVoice->IsActive()) { // still active
492     if (!itVoice->Orphan) {
493     *(pChannel->pRegionsInUse->allocAppend()) = itVoice->GetRegion();
494     }
495     VoiceCount++;
496    
497     if (itVoice->PlaybackState == Voice::playback_state_disk) {
498     if ((itVoice->DiskStreamRef).State != Stream::state_unused) StreamCount++;
499     }
500     } else { // voice reached end, is now inactive
501 iliev 2244 itVoice->VoiceFreed();
502 iliev 2012 pChannel->FreeVoice(itVoice); // remove voice from the list of active voices
503     }
504     }
505     };
506    
507     typedef typename SynchronizedConfig<InstrumentChangeCmd<R, I> >::Reader SyncConfInstrChangeCmdReader;
508    
509     SynchronizedConfig<InstrumentChangeCmd<R, I> > InstrumentChangeCommand;
510     SyncConfInstrChangeCmdReader InstrumentChangeCommandReader;
511    
512     /** This method is not thread safe! */
513 schoenebeck 2871 virtual void ResetInternal(bool bResetEngine) OVERRIDE {
514     AbstractEngineChannel::ResetInternal(bResetEngine);
515 iliev 2012
516     MidiKeyboardManager<V>::Reset();
517     }
518    
519 schoenebeck 3054 virtual void ResetControllers() OVERRIDE {
520 iliev 2012 AbstractEngineChannel::ResetControllers();
521    
522     MidiKeyboardManager<V>::SustainPedal = false;
523     MidiKeyboardManager<V>::SostenutoPedal = false;
524     }
525    
526     /**
527 schoenebeck 2612 * Unload the currently used and loaded real-time instrument script.
528     * The source code of the script is retained, so that it can still
529     * be reloaded.
530     */
531     void UnloadScriptInUse() {
532     {
533     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate();
534 schoenebeck 2618 if (cmd.pScript) cmd.pScript->unload();
535 schoenebeck 2612 }
536     {
537     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.SwitchConfig();
538 schoenebeck 2618 if (cmd.pScript) cmd.pScript->unload();
539 schoenebeck 2612 }
540 schoenebeck 2614 InstrumentChangeCommand.SwitchConfig(); // switch back to original one
541 schoenebeck 2612 }
542    
543     /**
544 schoenebeck 2611 * Load real-time instrument script and all its resources required
545     * for the upcoming instrument change.
546     *
547     * @param text - source code of script
548     */
549     void LoadInstrumentScript(const String& text) {
550     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate();
551     // load the new script
552     cmd.pScript->load(text);
553     }
554    
555     /**
556 iliev 2012 * Changes the instrument for an engine channel.
557     *
558     * @param pInstrument - new instrument
559     * @returns the resulting instrument change command after the
560     * command switch, containing the old instrument and
561     * the dimregions it is using
562     */
563     InstrumentChangeCmd<R, I>& ChangeInstrument(I* pInstrument) {
564     InstrumentChangeCmd<R, I>& cmd = InstrumentChangeCommand.GetConfigForUpdate();
565     cmd.pInstrument = pInstrument;
566     cmd.bChangeInstrument = true;
567    
568     return InstrumentChangeCommand.SwitchConfig();
569     }
570    
571     virtual void ProcessKeySwitchChange(int key) = 0;
572     };
573    
574     } // namespace LinuxSampler
575    
576     #endif /* __LS_ENGINECHANNELBASE_H__ */

  ViewVC Help
Powered by ViewVC