/[svn]/linuxsampler/trunk/src/engines/gig/EngineChannel.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/gig/EngineChannel.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1659 - (hide annotations) (download)
Sun Feb 3 00:13:27 2008 UTC (16 years, 2 months ago) by schoenebeck
File size: 37487 byte(s)
* added support for triggering notes by instrument editors
  (still some cleanup / refactoring ahead, but it should work)
* bumped version to 0.5.1.1cvs

1 schoenebeck 411 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 persson 1646 * Copyright (C) 2005 - 2008 Christian Schoenebeck *
7 schoenebeck 411 * *
8     * This program is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This program is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this program; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24     #include "EngineChannel.h"
25    
26 schoenebeck 1424 #include "../../common/global_private.h"
27    
28 persson 438 namespace LinuxSampler { namespace gig {
29 schoenebeck 411
30 persson 1646 EngineChannel::EngineChannel() :
31 schoenebeck 1659 InstrumentChangeCommandReader(InstrumentChangeCommand),
32     virtualMidiDevicesReader(virtualMidiDevices)
33     {
34 schoenebeck 411 pMIDIKeyInfo = new midi_key_info_t[128];
35     pEngine = NULL;
36     pInstrument = NULL;
37 schoenebeck 460 pEvents = NULL; // we allocate when we retrieve the right Engine object
38 schoenebeck 970 pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
39 schoenebeck 411 pActiveKeys = new Pool<uint>(128);
40     for (uint i = 0; i < 128; i++) {
41     pMIDIKeyInfo[i].pActiveVoices = NULL; // we allocate when we retrieve the right Engine object
42     pMIDIKeyInfo[i].KeyPressed = false;
43     pMIDIKeyInfo[i].Active = false;
44     pMIDIKeyInfo[i].ReleaseTrigger = false;
45     pMIDIKeyInfo[i].pEvents = NULL; // we allocate when we retrieve the right Engine object
46 schoenebeck 473 pMIDIKeyInfo[i].VoiceTheftsQueued = 0;
47 persson 438 pMIDIKeyInfo[i].RoundRobinIndex = 0;
48 schoenebeck 411 }
49     InstrumentIdx = -1;
50     InstrumentStat = -1;
51 schoenebeck 1001 pChannelLeft = NULL;
52     pChannelRight = NULL;
53 schoenebeck 411 AudioDeviceChannelLeft = -1;
54     AudioDeviceChannelRight = -1;
55 schoenebeck 675 pMidiInputPort = NULL;
56     midiChannel = midi_chan_all;
57 schoenebeck 670 ResetControllers();
58 schoenebeck 829 SoloMode = false;
59     PortamentoMode = false;
60     PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
61 schoenebeck 411 }
62    
63     EngineChannel::~EngineChannel() {
64 schoenebeck 460 DisconnectAudioOutputDevice();
65 schoenebeck 411 if (pEventQueue) delete pEventQueue;
66     if (pActiveKeys) delete pActiveKeys;
67     if (pMIDIKeyInfo) delete[] pMIDIKeyInfo;
68 schoenebeck 1001 RemoveAllFxSends();
69 schoenebeck 411 }
70    
71     /**
72 schoenebeck 660 * Implementation of virtual method from abstract EngineChannel interface.
73     * This method will periodically be polled (e.g. by the LSCP server) to
74     * check if some engine channel parameter has changed since the last
75     * StatusChanged() call.
76     *
77 schoenebeck 670 * This method can also be used to mark the engine channel as changed
78     * from outside, e.g. by a MIDI input device. The optional argument
79     * \a nNewStatus can be used for this.
80     *
81 schoenebeck 660 * TODO: This "poll method" is just a lazy solution and might be
82     * replaced in future.
83 schoenebeck 670 * @param bNewStatus - (optional, default: false) sets the new status flag
84 schoenebeck 660 * @returns true if engine channel status has changed since last
85     * StatusChanged() call
86     */
87 schoenebeck 670 bool EngineChannel::StatusChanged(bool bNewStatus) {
88 schoenebeck 660 bool b = bStatusChanged;
89 schoenebeck 670 bStatusChanged = bNewStatus;
90 schoenebeck 660 return b;
91     }
92    
93 schoenebeck 670 void EngineChannel::Reset() {
94     if (pEngine) pEngine->DisableAndLock();
95     ResetInternal();
96     ResetControllers();
97     if (pEngine) {
98     pEngine->Enable();
99     pEngine->Reset();
100     }
101     }
102    
103 schoenebeck 660 /**
104 schoenebeck 411 * This method is not thread safe!
105     */
106     void EngineChannel::ResetInternal() {
107     CurrentKeyDimension = 0;
108    
109     // reset key info
110     for (uint i = 0; i < 128; i++) {
111     if (pMIDIKeyInfo[i].pActiveVoices)
112     pMIDIKeyInfo[i].pActiveVoices->clear();
113     if (pMIDIKeyInfo[i].pEvents)
114     pMIDIKeyInfo[i].pEvents->clear();
115     pMIDIKeyInfo[i].KeyPressed = false;
116     pMIDIKeyInfo[i].Active = false;
117     pMIDIKeyInfo[i].ReleaseTrigger = false;
118     pMIDIKeyInfo[i].itSelf = Pool<uint>::Iterator();
119 schoenebeck 473 pMIDIKeyInfo[i].VoiceTheftsQueued = 0;
120 schoenebeck 411 }
121 schoenebeck 829 SoloKey = -1; // no solo key active yet
122     PortamentoPos = -1.0f; // no portamento active yet
123 schoenebeck 411
124     // reset all key groups
125     std::map<uint,uint*>::iterator iter = ActiveKeyGroups.begin();
126     for (; iter != ActiveKeyGroups.end(); iter++) iter->second = NULL;
127    
128     // free all active keys
129     pActiveKeys->clear();
130    
131     // delete all input events
132     pEventQueue->init();
133    
134     if (pEngine) pEngine->ResetInternal();
135 schoenebeck 660
136     // status of engine channel has changed, so set notify flag
137     bStatusChanged = true;
138 schoenebeck 411 }
139    
140     LinuxSampler::Engine* EngineChannel::GetEngine() {
141     return pEngine;
142     }
143    
144     /**
145     * More or less a workaround to set the instrument name, index and load
146     * status variable to zero percent immediately, that is without blocking
147     * the calling thread. It might be used in future for other preparations
148     * as well though.
149     *
150     * @param FileName - file name of the Gigasampler instrument file
151     * @param Instrument - index of the instrument in the .gig file
152     * @see LoadInstrument()
153     */
154     void EngineChannel::PrepareLoadInstrument(const char* FileName, uint Instrument) {
155     InstrumentFile = FileName;
156     InstrumentIdx = Instrument;
157     InstrumentStat = 0;
158     }
159    
160     /**
161     * Load an instrument from a .gig file. PrepareLoadInstrument() has to
162     * be called first to provide the information which instrument to load.
163     * This method will then actually start to load the instrument and block
164     * the calling thread until loading was completed.
165     *
166     * @see PrepareLoadInstrument()
167     */
168     void EngineChannel::LoadInstrument() {
169 persson 1646 // make sure we don't trigger any new notes with an old
170     // instrument
171     instrument_change_command_t& cmd = ChangeInstrument(0);
172     if (cmd.pInstrument) {
173     // give old instrument back to instrument manager, but
174     // keep the dimension regions and samples that are in use
175     Engine::instruments.HandBackInstrument(cmd.pInstrument, this, cmd.pDimRegionsInUse);
176 schoenebeck 411 }
177 persson 1646 cmd.pDimRegionsInUse->clear();
178 schoenebeck 411
179     // delete all key groups
180     ActiveKeyGroups.clear();
181    
182     // request gig instrument from instrument manager
183 persson 1038 ::gig::Instrument* newInstrument;
184 schoenebeck 411 try {
185 schoenebeck 947 InstrumentManager::instrument_id_t instrid;
186     instrid.FileName = InstrumentFile;
187     instrid.Index = InstrumentIdx;
188 persson 1038 newInstrument = Engine::instruments.Borrow(instrid, this);
189     if (!newInstrument) {
190 schoenebeck 1212 throw InstrumentManagerException("resource was not created");
191 schoenebeck 411 }
192     }
193     catch (RIFF::Exception e) {
194     InstrumentStat = -2;
195 iliev 1309 StatusChanged(true);
196 schoenebeck 411 String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;
197 schoenebeck 880 throw Exception(msg);
198 schoenebeck 411 }
199 schoenebeck 1212 catch (InstrumentManagerException e) {
200 schoenebeck 411 InstrumentStat = -3;
201 iliev 1309 StatusChanged(true);
202 schoenebeck 411 String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();
203 schoenebeck 880 throw Exception(msg);
204 schoenebeck 411 }
205     catch (...) {
206     InstrumentStat = -4;
207 iliev 1309 StatusChanged(true);
208 schoenebeck 880 throw Exception("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file.");
209 schoenebeck 411 }
210    
211     // rebuild ActiveKeyGroups map with key groups of current instrument
212 persson 1038 for (::gig::Region* pRegion = newInstrument->GetFirstRegion(); pRegion; pRegion = newInstrument->GetNextRegion())
213 schoenebeck 411 if (pRegion->KeyGroup) ActiveKeyGroups[pRegion->KeyGroup] = NULL;
214    
215 persson 1038 InstrumentIdxName = newInstrument->pInfo->Name;
216 schoenebeck 411 InstrumentStat = 100;
217    
218 persson 1646 ChangeInstrument(newInstrument);
219    
220 iliev 1298 StatusChanged(true);
221 schoenebeck 411 }
222    
223 persson 1646
224 schoenebeck 411 /**
225 persson 1646 * Changes the instrument for an engine channel.
226     *
227     * @param pInstrument - new instrument
228     * @returns the resulting instrument change command after the
229     * command switch, containing the old instrument and
230     * the dimregions it is using
231     */
232     EngineChannel::instrument_change_command_t& EngineChannel::ChangeInstrument(::gig::Instrument* pInstrument) {
233     instrument_change_command_t& cmd = InstrumentChangeCommand.GetConfigForUpdate();
234     cmd.pInstrument = pInstrument;
235     cmd.bChangeInstrument = true;
236    
237     return InstrumentChangeCommand.SwitchConfig();
238     }
239    
240     /**
241 schoenebeck 411 * Will be called by the InstrumentResourceManager when the instrument
242 schoenebeck 517 * we are currently using on this EngineChannel is going to be updated,
243     * so we can stop playback before that happens.
244 schoenebeck 411 */
245     void EngineChannel::ResourceToBeUpdated(::gig::Instrument* pResource, void*& pUpdateArg) {
246     dmsg(3,("gig::Engine: Received instrument update message.\n"));
247     if (pEngine) pEngine->DisableAndLock();
248     ResetInternal();
249     this->pInstrument = NULL;
250     }
251    
252     /**
253     * Will be called by the InstrumentResourceManager when the instrument
254     * update process was completed, so we can continue with playback.
255     */
256     void EngineChannel::ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) {
257     this->pInstrument = pNewResource; //TODO: there are couple of engine parameters we should update here as well if the instrument was updated (see LoadInstrument())
258     if (pEngine) pEngine->Enable();
259 schoenebeck 660 bStatusChanged = true; // status of engine has changed, so set notify flag
260 schoenebeck 411 }
261    
262 schoenebeck 517 /**
263     * Will be called by the InstrumentResourceManager on progress changes
264     * while loading or realoading an instrument for this EngineChannel.
265     *
266     * @param fProgress - current progress as value between 0.0 and 1.0
267     */
268     void EngineChannel::OnResourceProgress(float fProgress) {
269     this->InstrumentStat = int(fProgress * 100.0f);
270     dmsg(7,("gig::EngineChannel: progress %d%", InstrumentStat));
271 schoenebeck 660 bStatusChanged = true; // status of engine has changed, so set notify flag
272 schoenebeck 517 }
273    
274 schoenebeck 412 void EngineChannel::Connect(AudioOutputDevice* pAudioOut) {
275 schoenebeck 460 if (pEngine) {
276     if (pEngine->pAudioOutputDevice == pAudioOut) return;
277 schoenebeck 412 DisconnectAudioOutputDevice();
278     }
279 schoenebeck 411 pEngine = Engine::AcquireEngine(this, pAudioOut);
280 persson 438 ResetInternal();
281 schoenebeck 738 pEvents = new RTList<Event>(pEngine->pEventPool);
282 persson 1646
283     // reset the instrument change command struct (need to be done
284     // twice, as it is double buffered)
285     {
286     instrument_change_command_t& cmd = InstrumentChangeCommand.GetConfigForUpdate();
287     cmd.pDimRegionsInUse = new RTList< ::gig::DimensionRegion*>(pEngine->pDimRegionPool[0]);
288     cmd.pInstrument = 0;
289     cmd.bChangeInstrument = false;
290     }
291     {
292     instrument_change_command_t& cmd = InstrumentChangeCommand.SwitchConfig();
293     cmd.pDimRegionsInUse = new RTList< ::gig::DimensionRegion*>(pEngine->pDimRegionPool[1]);
294     cmd.pInstrument = 0;
295     cmd.bChangeInstrument = false;
296     }
297    
298 schoenebeck 411 for (uint i = 0; i < 128; i++) {
299     pMIDIKeyInfo[i].pActiveVoices = new RTList<Voice>(pEngine->pVoicePool);
300     pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEngine->pEventPool);
301     }
302     AudioDeviceChannelLeft = 0;
303     AudioDeviceChannelRight = 1;
304 schoenebeck 1001 if (fxSends.empty()) { // render directly into the AudioDevice's output buffers
305     pChannelLeft = pAudioOut->Channel(AudioDeviceChannelLeft);
306     pChannelRight = pAudioOut->Channel(AudioDeviceChannelRight);
307     } else { // use local buffers for rendering and copy later
308     // ensure the local buffers have the correct size
309     if (pChannelLeft) delete pChannelLeft;
310     if (pChannelRight) delete pChannelRight;
311     pChannelLeft = new AudioChannel(0, pAudioOut->MaxSamplesPerCycle());
312     pChannelRight = new AudioChannel(1, pAudioOut->MaxSamplesPerCycle());
313     }
314 persson 1039 if (pEngine->EngineDisabled.GetUnsafe()) pEngine->Enable();
315 persson 846 MidiInputPort::AddSysexListener(pEngine);
316 schoenebeck 411 }
317    
318     void EngineChannel::DisconnectAudioOutputDevice() {
319     if (pEngine) { // if clause to prevent disconnect loops
320 persson 1646
321     // delete the structures used for instrument change
322     RTList< ::gig::DimensionRegion*>* d = InstrumentChangeCommand.GetConfigForUpdate().pDimRegionsInUse;
323     if (d) delete d;
324     EngineChannel::instrument_change_command_t& cmd = InstrumentChangeCommand.SwitchConfig();
325     d = cmd.pDimRegionsInUse;
326    
327     if (cmd.pInstrument) {
328     // release the currently loaded instrument
329     Engine::instruments.HandBackInstrument(cmd.pInstrument, this, d);
330     }
331     if (d) delete d;
332    
333     // release all active dimension regions to resource
334     // manager
335     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
336     RTList<uint>::Iterator end = pActiveKeys->end();
337     while (iuiKey != end) { // iterate through all active keys
338     midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];
339     ++iuiKey;
340    
341     RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
342     RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
343     for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
344     Engine::instruments.HandBackDimReg(itVoice->pDimRgn);
345     }
346     }
347    
348 schoenebeck 411 ResetInternal();
349 schoenebeck 460 if (pEvents) {
350     delete pEvents;
351     pEvents = NULL;
352     }
353 schoenebeck 411 for (uint i = 0; i < 128; i++) {
354 schoenebeck 420 if (pMIDIKeyInfo[i].pActiveVoices) {
355     delete pMIDIKeyInfo[i].pActiveVoices;
356     pMIDIKeyInfo[i].pActiveVoices = NULL;
357     }
358     if (pMIDIKeyInfo[i].pEvents) {
359     delete pMIDIKeyInfo[i].pEvents;
360     pMIDIKeyInfo[i].pEvents = NULL;
361     }
362 schoenebeck 411 }
363     Engine* oldEngine = pEngine;
364     AudioOutputDevice* oldAudioDevice = pEngine->pAudioOutputDevice;
365     pEngine = NULL;
366     Engine::FreeEngine(this, oldAudioDevice);
367     AudioDeviceChannelLeft = -1;
368 persson 438 AudioDeviceChannelRight = -1;
369 schoenebeck 1001 if (!fxSends.empty()) { // free the local rendering buffers
370     if (pChannelLeft) delete pChannelLeft;
371     if (pChannelRight) delete pChannelRight;
372     }
373     pChannelLeft = NULL;
374     pChannelRight = NULL;
375 schoenebeck 411 }
376     }
377    
378 schoenebeck 1001 AudioOutputDevice* EngineChannel::GetAudioOutputDevice() {
379     return (pEngine) ? pEngine->pAudioOutputDevice : NULL;
380     }
381    
382 schoenebeck 411 void EngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
383     if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");
384 persson 438
385 schoenebeck 411 AudioChannel* pChannel = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannel);
386     if (!pChannel) throw AudioOutputException("Invalid audio output device channel " + ToString(AudioDeviceChannel));
387     switch (EngineAudioChannel) {
388     case 0: // left output channel
389 schoenebeck 1001 if (fxSends.empty()) pChannelLeft = pChannel;
390 schoenebeck 411 AudioDeviceChannelLeft = AudioDeviceChannel;
391     break;
392     case 1: // right output channel
393 schoenebeck 1001 if (fxSends.empty()) pChannelRight = pChannel;
394 schoenebeck 411 AudioDeviceChannelRight = AudioDeviceChannel;
395     break;
396     default:
397     throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
398     }
399 iliev 1267
400     bStatusChanged = true;
401 schoenebeck 411 }
402    
403     int EngineChannel::OutputChannel(uint EngineAudioChannel) {
404     switch (EngineAudioChannel) {
405     case 0: // left channel
406     return AudioDeviceChannelLeft;
407     case 1: // right channel
408     return AudioDeviceChannelRight;
409     default:
410     throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
411     }
412     }
413    
414 schoenebeck 675 void EngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
415     if (!pMidiPort || pMidiPort == this->pMidiInputPort) return;
416     DisconnectMidiInputPort();
417     this->pMidiInputPort = pMidiPort;
418     this->midiChannel = MidiChannel;
419     pMidiPort->Connect(this, MidiChannel);
420     }
421    
422     void EngineChannel::DisconnectMidiInputPort() {
423     MidiInputPort* pOldPort = this->pMidiInputPort;
424     this->pMidiInputPort = NULL;
425     if (pOldPort) pOldPort->Disconnect(this);
426     }
427    
428     MidiInputPort* EngineChannel::GetMidiInputPort() {
429     return pMidiInputPort;
430     }
431    
432     midi_chan_t EngineChannel::MidiChannel() {
433     return midiChannel;
434     }
435    
436 schoenebeck 1001 FxSend* EngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
437     if (pEngine) pEngine->DisableAndLock();
438     FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
439     if (fxSends.empty()) {
440     if (pEngine && pEngine->pAudioOutputDevice) {
441     AudioOutputDevice* pDevice = pEngine->pAudioOutputDevice;
442     // create local render buffers
443     pChannelLeft = new AudioChannel(0, pDevice->MaxSamplesPerCycle());
444     pChannelRight = new AudioChannel(1, pDevice->MaxSamplesPerCycle());
445     } else {
446     // postpone local render buffer creation until audio device is assigned
447     pChannelLeft = NULL;
448     pChannelRight = NULL;
449     }
450     }
451     fxSends.push_back(pFxSend);
452     if (pEngine) pEngine->Enable();
453 iliev 1130 fireFxSendCountChanged(iSamplerChannelIndex, GetFxSendCount());
454 persson 1646
455 schoenebeck 1001 return pFxSend;
456     }
457    
458     FxSend* EngineChannel::GetFxSend(uint FxSendIndex) {
459     return (FxSendIndex < fxSends.size()) ? fxSends[FxSendIndex] : NULL;
460     }
461    
462     uint EngineChannel::GetFxSendCount() {
463     return fxSends.size();
464     }
465    
466     void EngineChannel::RemoveFxSend(FxSend* pFxSend) {
467     if (pEngine) pEngine->DisableAndLock();
468     for (
469     std::vector<FxSend*>::iterator iter = fxSends.begin();
470     iter != fxSends.end(); iter++
471     ) {
472     if (*iter == pFxSend) {
473     delete pFxSend;
474     fxSends.erase(iter);
475     if (fxSends.empty()) {
476     // destroy local render buffers
477     if (pChannelLeft) delete pChannelLeft;
478     if (pChannelRight) delete pChannelRight;
479     // fallback to render directly into AudioOutputDevice's buffers
480     if (pEngine && pEngine->pAudioOutputDevice) {
481     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
482     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
483     } else { // we update the pointers later
484     pChannelLeft = NULL;
485     pChannelRight = NULL;
486     }
487     }
488     break;
489     }
490     }
491     if (pEngine) pEngine->Enable();
492 iliev 1130 fireFxSendCountChanged(iSamplerChannelIndex, GetFxSendCount());
493 schoenebeck 1001 }
494    
495 schoenebeck 411 /**
496     * Will be called by the MIDIIn Thread to let the audio thread trigger a new
497 schoenebeck 906 * voice for the given key. This method is meant for real time rendering,
498     * that is an event will immediately be created with the current system
499     * time as time stamp.
500 schoenebeck 411 *
501     * @param Key - MIDI key number of the triggered key
502     * @param Velocity - MIDI velocity value of the triggered key
503     */
504     void EngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity) {
505     if (pEngine) {
506     Event event = pEngine->pEventGenerator->CreateEvent();
507     event.Type = Event::type_note_on;
508     event.Param.Note.Key = Key;
509     event.Param.Note.Velocity = Velocity;
510 persson 438 event.pEngineChannel = this;
511 schoenebeck 411 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
512 schoenebeck 412 else dmsg(1,("EngineChannel: Input event queue full!"));
513 schoenebeck 1653 // inform instrument editor(s), if any ...
514     pEngine->instruments.TrySendNoteOnToEditors(Key, Velocity, pInstrument);
515 schoenebeck 411 }
516     }
517    
518     /**
519 schoenebeck 906 * Will be called by the MIDIIn Thread to let the audio thread trigger a new
520     * voice for the given key. This method is meant for offline rendering
521     * and / or for cases where the exact position of the event in the current
522     * audio fragment is already known.
523     *
524     * @param Key - MIDI key number of the triggered key
525     * @param Velocity - MIDI velocity value of the triggered key
526     * @param FragmentPos - sample point position in the current audio
527     * fragment to which this event belongs to
528     */
529     void EngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, int32_t FragmentPos) {
530     if (FragmentPos < 0) {
531     dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
532     }
533     else if (pEngine) {
534     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
535     event.Type = Event::type_note_on;
536     event.Param.Note.Key = Key;
537     event.Param.Note.Velocity = Velocity;
538     event.pEngineChannel = this;
539     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
540     else dmsg(1,("EngineChannel: Input event queue full!"));
541 schoenebeck 1653 // inform instrument editor(s), if any ...
542     pEngine->instruments.TrySendNoteOnToEditors(Key, Velocity, pInstrument);
543 schoenebeck 906 }
544     }
545    
546     /**
547 schoenebeck 411 * Will be called by the MIDIIn Thread to signal the audio thread to release
548 schoenebeck 906 * voice(s) on the given key. This method is meant for real time rendering,
549     * that is an event will immediately be created with the current system
550     * time as time stamp.
551 schoenebeck 411 *
552     * @param Key - MIDI key number of the released key
553     * @param Velocity - MIDI release velocity value of the released key
554     */
555     void EngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity) {
556     if (pEngine) {
557     Event event = pEngine->pEventGenerator->CreateEvent();
558     event.Type = Event::type_note_off;
559     event.Param.Note.Key = Key;
560     event.Param.Note.Velocity = Velocity;
561 schoenebeck 412 event.pEngineChannel = this;
562 schoenebeck 411 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
563 schoenebeck 412 else dmsg(1,("EngineChannel: Input event queue full!"));
564 schoenebeck 1653 // inform instrument editor(s), if any ...
565     pEngine->instruments.TrySendNoteOffToEditors(Key, Velocity, pInstrument);
566 schoenebeck 411 }
567     }
568    
569     /**
570 schoenebeck 906 * Will be called by the MIDIIn Thread to signal the audio thread to release
571     * voice(s) on the given key. This method is meant for offline rendering
572     * and / or for cases where the exact position of the event in the current
573     * audio fragment is already known.
574     *
575     * @param Key - MIDI key number of the released key
576     * @param Velocity - MIDI release velocity value of the released key
577     * @param FragmentPos - sample point position in the current audio
578     * fragment to which this event belongs to
579     */
580     void EngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, int32_t FragmentPos) {
581     if (FragmentPos < 0) {
582     dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
583     }
584     else if (pEngine) {
585     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
586     event.Type = Event::type_note_off;
587     event.Param.Note.Key = Key;
588     event.Param.Note.Velocity = Velocity;
589     event.pEngineChannel = this;
590     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
591     else dmsg(1,("EngineChannel: Input event queue full!"));
592 schoenebeck 1653 // inform instrument editor(s), if any ...
593     pEngine->instruments.TrySendNoteOffToEditors(Key, Velocity, pInstrument);
594 schoenebeck 906 }
595     }
596    
597     /**
598 schoenebeck 411 * Will be called by the MIDIIn Thread to signal the audio thread to change
599 schoenebeck 906 * the pitch value for all voices. This method is meant for real time
600     * rendering, that is an event will immediately be created with the
601     * current system time as time stamp.
602 schoenebeck 411 *
603     * @param Pitch - MIDI pitch value (-8192 ... +8191)
604     */
605     void EngineChannel::SendPitchbend(int Pitch) {
606 persson 438 if (pEngine) {
607 schoenebeck 411 Event event = pEngine->pEventGenerator->CreateEvent();
608     event.Type = Event::type_pitchbend;
609     event.Param.Pitch.Pitch = Pitch;
610 schoenebeck 412 event.pEngineChannel = this;
611 schoenebeck 411 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
612 schoenebeck 412 else dmsg(1,("EngineChannel: Input event queue full!"));
613 schoenebeck 411 }
614     }
615    
616     /**
617 schoenebeck 906 * Will be called by the MIDIIn Thread to signal the audio thread to change
618     * the pitch value for all voices. This method is meant for offline
619     * rendering and / or for cases where the exact position of the event in
620     * the current audio fragment is already known.
621     *
622     * @param Pitch - MIDI pitch value (-8192 ... +8191)
623     * @param FragmentPos - sample point position in the current audio
624     * fragment to which this event belongs to
625     */
626     void EngineChannel::SendPitchbend(int Pitch, int32_t FragmentPos) {
627     if (FragmentPos < 0) {
628     dmsg(1,("EngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
629     }
630     else if (pEngine) {
631     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
632     event.Type = Event::type_pitchbend;
633     event.Param.Pitch.Pitch = Pitch;
634     event.pEngineChannel = this;
635     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
636     else dmsg(1,("EngineChannel: Input event queue full!"));
637     }
638     }
639    
640     /**
641 schoenebeck 411 * Will be called by the MIDIIn Thread to signal the audio thread that a
642 schoenebeck 906 * continuous controller value has changed. This method is meant for real
643     * time rendering, that is an event will immediately be created with the
644     * current system time as time stamp.
645 schoenebeck 411 *
646     * @param Controller - MIDI controller number of the occured control change
647     * @param Value - value of the control change
648     */
649     void EngineChannel::SendControlChange(uint8_t Controller, uint8_t Value) {
650     if (pEngine) {
651     Event event = pEngine->pEventGenerator->CreateEvent();
652     event.Type = Event::type_control_change;
653     event.Param.CC.Controller = Controller;
654     event.Param.CC.Value = Value;
655 schoenebeck 412 event.pEngineChannel = this;
656 schoenebeck 411 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
657 schoenebeck 412 else dmsg(1,("EngineChannel: Input event queue full!"));
658 schoenebeck 411 }
659     }
660    
661 schoenebeck 906 /**
662     * Will be called by the MIDIIn Thread to signal the audio thread that a
663     * continuous controller value has changed. This method is meant for
664     * offline rendering and / or for cases where the exact position of the
665     * event in the current audio fragment is already known.
666     *
667     * @param Controller - MIDI controller number of the occured control change
668     * @param Value - value of the control change
669     * @param FragmentPos - sample point position in the current audio
670     * fragment to which this event belongs to
671     */
672     void EngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, int32_t FragmentPos) {
673     if (FragmentPos < 0) {
674     dmsg(1,("EngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
675     }
676     else if (pEngine) {
677     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
678     event.Type = Event::type_control_change;
679     event.Param.CC.Controller = Controller;
680     event.Param.CC.Value = Value;
681     event.pEngineChannel = this;
682     if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
683     else dmsg(1,("EngineChannel: Input event queue full!"));
684     }
685     }
686    
687 schoenebeck 460 void EngineChannel::ClearEventLists() {
688     pEvents->clear();
689     // empty MIDI key specific event lists
690     {
691     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
692     RTList<uint>::Iterator end = pActiveKeys->end();
693     for(; iuiKey != end; ++iuiKey) {
694     pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key
695     }
696     }
697     }
698    
699 schoenebeck 473 void EngineChannel::ResetControllers() {
700 schoenebeck 670 Pitch = 0;
701     SustainPedal = false;
702 iliev 776 SostenutoPedal = false;
703 schoenebeck 1005 GlobalVolume = 1.0f;
704 schoenebeck 947 MidiVolume = 1.0;
705 schoenebeck 670 GlobalPanLeft = 1.0f;
706     GlobalPanRight = 1.0f;
707 schoenebeck 1041 GlobalTranspose = 0;
708 schoenebeck 473 // set all MIDI controller values to zero
709 persson 903 memset(ControllerTable, 0x00, 129);
710 schoenebeck 1040 // reset all FX Send levels
711     for (
712     std::vector<FxSend*>::iterator iter = fxSends.begin();
713     iter != fxSends.end(); iter++
714     ) {
715     (*iter)->Reset();
716     }
717 schoenebeck 473 }
718    
719 schoenebeck 460 /**
720     * Copy all events from the engine channel's input event queue buffer to
721     * the internal event list. This will be done at the beginning of each
722     * audio cycle (that is each RenderAudio() call) to distinguish all
723     * events which have to be processed in the current audio cycle. Each
724     * EngineChannel has it's own input event queue for the common channel
725     * specific events (like NoteOn, NoteOff and ControlChange events).
726     * Beside that, the engine also has a input event queue for global
727     * events (usually SysEx messages).
728     *
729     * @param Samples - number of sample points to be processed in the
730     * current audio cycle
731     */
732     void EngineChannel::ImportEvents(uint Samples) {
733 schoenebeck 1659 // import events from pure software MIDI "devices"
734     // (e.g. virtual keyboard in instrument editor)
735     {
736     const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
737     Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
738     VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
739     // as we're going to (carefully) write some status to the
740     // synchronized struct, we cast away the const
741     ArrayList<VirtualMidiDevice*>& devices =
742     const_cast<ArrayList<VirtualMidiDevice*>&>(virtualMidiDevicesReader.Lock());
743     // iterate through all virtual MIDI devices
744     for (int i = 0; i < devices.size(); i++) {
745     VirtualMidiDevice* pDev = devices[i];
746     // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
747     while (pDev->GetMidiEventFromDevice(devEvent)) {
748     event.Type =
749     (devEvent.Type == VirtualMidiDevice::EVENT_TYPE_NOTEON) ?
750     Event::type_note_on : Event::type_note_off;
751     event.Param.Note.Key = devEvent.Key;
752     event.Param.Note.Velocity = devEvent.Velocity;
753     event.pEngineChannel = this;
754     // copy event to internal event list
755     if (pEvents->poolIsEmpty()) {
756     dmsg(1,("Event pool emtpy!\n"));
757     goto exitVirtualDevicesLoop;
758     }
759     *pEvents->allocAppend() = event;
760     }
761     }
762     }
763     exitVirtualDevicesLoop:
764     virtualMidiDevicesReader.Unlock();
765    
766     // import events from the regular MIDI devices
767 schoenebeck 970 RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
768 schoenebeck 460 Event* pEvent;
769     while (true) {
770     // get next event from input event queue
771     if (!(pEvent = eventQueueReader.pop())) break;
772     // if younger event reached, ignore that and all subsequent ones for now
773     if (pEvent->FragmentPos() >= Samples) {
774     eventQueueReader--;
775     dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
776     pEvent->ResetFragmentPos();
777     break;
778     }
779     // copy event to internal event list
780     if (pEvents->poolIsEmpty()) {
781     dmsg(1,("Event pool emtpy!\n"));
782     break;
783     }
784     *pEvents->allocAppend() = *pEvent;
785     }
786     eventQueueReader.free(); // free all copied events from input queue
787     }
788    
789 schoenebeck 1001 void EngineChannel::RemoveAllFxSends() {
790     if (pEngine) pEngine->DisableAndLock();
791     if (!fxSends.empty()) { // free local render buffers
792     if (pChannelLeft) {
793     delete pChannelLeft;
794     if (pEngine && pEngine->pAudioOutputDevice) {
795     // fallback to render directly to the AudioOutputDevice's buffer
796     pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
797     } else pChannelLeft = NULL;
798     }
799     if (pChannelRight) {
800     delete pChannelRight;
801     if (pEngine && pEngine->pAudioOutputDevice) {
802     // fallback to render directly to the AudioOutputDevice's buffer
803     pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
804 persson 1646 } else pChannelRight = NULL;
805 schoenebeck 1001 }
806     }
807     for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];
808     fxSends.clear();
809     if (pEngine) pEngine->Enable();
810     }
811    
812 schoenebeck 1659 void EngineChannel::Connect(VirtualMidiDevice* pDevice) {
813     // double buffer ... double work ...
814     {
815     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
816     devices.add(pDevice);
817     }
818     {
819     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
820     devices.add(pDevice);
821     }
822     }
823    
824     void EngineChannel::Disconnect(VirtualMidiDevice* pDevice) {
825     // double buffer ... double work ...
826     {
827     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
828     devices.remove(pDevice);
829     }
830     {
831     ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
832     devices.remove(pDevice);
833     }
834     }
835    
836 schoenebeck 411 float EngineChannel::Volume() {
837     return GlobalVolume;
838     }
839    
840     void EngineChannel::Volume(float f) {
841     GlobalVolume = f;
842 schoenebeck 660 bStatusChanged = true; // status of engine channel has changed, so set notify flag
843 schoenebeck 411 }
844    
845     uint EngineChannel::Channels() {
846     return 2;
847     }
848    
849     String EngineChannel::InstrumentFileName() {
850     return InstrumentFile;
851     }
852    
853     String EngineChannel::InstrumentName() {
854     return InstrumentIdxName;
855     }
856    
857     int EngineChannel::InstrumentIndex() {
858     return InstrumentIdx;
859     }
860    
861     int EngineChannel::InstrumentStatus() {
862     return InstrumentStat;
863 persson 438 }
864 schoenebeck 411
865 schoenebeck 475 String EngineChannel::EngineName() {
866     return LS_GIG_ENGINE_NAME;
867     }
868 schoenebeck 660
869 schoenebeck 411 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC