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

Contents of /linuxsampler/trunk/src/engines/AbstractEngineChannel.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2382 - (show annotations) (download)
Sun Dec 2 16:30:42 2012 UTC (11 years, 4 months ago) by persson
File size: 32540 byte(s)
* all engines: add pan CC value to instrument pan parameter before
  applying panning, instead of using two separate pan functions in
  series (#182)
* sfz parser: allow -200 to 200 for pan_oncc opcode (#182)
* gig engine: handle special case when pan parameter in gig file has
  max or min value
* CoreMIDI: fixed memory deallocation error

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005-2008 Christian Schoenebeck *
7 * Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev *
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License *
20 * along with this program; if not, write to the Free Software *
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22 * MA 02111-1307 USA *
23 ***************************************************************************/
24
25 #include "AbstractEngineChannel.h"
26 #include "../common/global_private.h"
27 #include "../Sampler.h"
28
29 namespace LinuxSampler {
30
31 AbstractEngineChannel::AbstractEngineChannel() :
32 virtualMidiDevicesReader_AudioThread(virtualMidiDevices),
33 virtualMidiDevicesReader_MidiThread(virtualMidiDevices)
34 {
35 pEngine = NULL;
36 pEvents = NULL; // we allocate when we retrieve the right Engine object
37 pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
38 InstrumentIdx = -1;
39 InstrumentStat = -1;
40 pChannelLeft = NULL;
41 pChannelRight = NULL;
42 AudioDeviceChannelLeft = -1;
43 AudioDeviceChannelRight = -1;
44 pMidiInputPort = NULL;
45 midiChannel = midi_chan_all;
46 ResetControllers();
47 PortamentoMode = false;
48 PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
49 }
50
51 AbstractEngineChannel::~AbstractEngineChannel() {
52 delete pEventQueue;
53 DeleteGroupEventLists();
54 RemoveAllFxSends();
55 }
56
57 Engine* AbstractEngineChannel::GetEngine() {
58 return pEngine;
59 }
60
61 uint AbstractEngineChannel::Channels() {
62 return 2;
63 }
64
65 /**
66 * More or less a workaround to set the instrument name, index and load
67 * status variable to zero percent immediately, that is without blocking
68 * the calling thread. It might be used in future for other preparations
69 * as well though.
70 *
71 * @param FileName - file name of the instrument file
72 * @param Instrument - index of the instrument in the file
73 * @see LoadInstrument()
74 */
75 void AbstractEngineChannel::PrepareLoadInstrument(const char* FileName, uint Instrument) {
76 InstrumentFile = FileName;
77 InstrumentIdx = Instrument;
78 InstrumentStat = 0;
79 }
80
81 String AbstractEngineChannel::InstrumentFileName() {
82 return InstrumentFile;
83 }
84
85 String AbstractEngineChannel::InstrumentName() {
86 return InstrumentIdxName;
87 }
88
89 int AbstractEngineChannel::InstrumentIndex() {
90 return InstrumentIdx;
91 }
92
93 int AbstractEngineChannel::InstrumentStatus() {
94 return InstrumentStat;
95 }
96
97 String AbstractEngineChannel::EngineName() {
98 return AbstractEngine::GetFormatString(GetEngineFormat());
99 }
100
101 void AbstractEngineChannel::Reset() {
102 if (pEngine) pEngine->DisableAndLock();
103 ResetInternal();
104 ResetControllers();
105 if (pEngine) {
106 pEngine->Enable();
107 pEngine->Reset();
108 }
109 }
110
111 void AbstractEngineChannel::ResetControllers() {
112 Pitch = 0;
113 GlobalVolume = 1.0f;
114 MidiVolume = 1.0;
115 iLastPanRequest = 64;
116 GlobalTranspose = 0;
117 // set all MIDI controller values to zero
118 memset(ControllerTable, 0x00, 129);
119 // reset all FX Send levels
120 for (
121 std::vector<FxSend*>::iterator iter = fxSends.begin();
122 iter != fxSends.end(); iter++
123 ) {
124 (*iter)->Reset();
125 }
126 }
127
128 /**
129 * This method is not thread safe!
130 */
131 void AbstractEngineChannel::ResetInternal() {
132 CurrentKeyDimension = 0;
133 PortamentoPos = -1.0f; // no portamento active yet
134
135 // delete all input events
136 pEventQueue->init();
137
138 if (pEngine) pEngine->ResetInternal();
139
140 // status of engine channel has changed, so set notify flag
141 bStatusChanged = true;
142 }
143
144 /**
145 * Implementation of virtual method from abstract EngineChannel interface.
146 * This method will periodically be polled (e.g. by the LSCP server) to
147 * check if some engine channel parameter has changed since the last
148 * StatusChanged() call.
149 *
150 * This method can also be used to mark the engine channel as changed
151 * from outside, e.g. by a MIDI input device. The optional argument
152 * \a nNewStatus can be used for this.
153 *
154 * TODO: This "poll method" is just a lazy solution and might be
155 * replaced in future.
156 * @param bNewStatus - (optional, default: false) sets the new status flag
157 * @returns true if engine channel status has changed since last
158 * StatusChanged() call
159 */
160 bool AbstractEngineChannel::StatusChanged(bool bNewStatus) {
161 bool b = bStatusChanged;
162 bStatusChanged = bNewStatus;
163 return b;
164 }
165
166 float AbstractEngineChannel::Volume() {
167 return GlobalVolume;
168 }
169
170 void AbstractEngineChannel::Volume(float f) {
171 GlobalVolume = f;
172 bStatusChanged = true; // status of engine channel has changed, so set notify flag
173 }
174
175 float AbstractEngineChannel::Pan() {
176 return float(iLastPanRequest - 64) / 64.0f;
177 }
178
179 void AbstractEngineChannel::Pan(float f) {
180 int iMidiPan = int(f * 64.0f) + 64;
181 if (iMidiPan > 127) iMidiPan = 127;
182 else if (iMidiPan < 0) iMidiPan = 0;
183 iLastPanRequest = iMidiPan;
184 }
185
186 AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDevice() {
187 return (pEngine) ? pEngine->pAudioOutputDevice : NULL;
188 }
189
190 /**
191 * Gets thread safe access to the currently connected audio output
192 * device from other threads than the lscp thread.
193 */
194 AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
195 EngineMutex.Lock();
196 AudioOutputDevice* res = GetAudioOutputDevice();
197 EngineMutex.Unlock();
198 return res;
199 }
200
201 void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
202 if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");
203
204 AudioChannel* pChannel = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannel);
205 if (!pChannel) throw AudioOutputException("Invalid audio output device channel " + ToString(AudioDeviceChannel));
206 switch (EngineAudioChannel) {
207 case 0: // left output channel
208 if (fxSends.empty()) pChannelLeft = pChannel;
209 AudioDeviceChannelLeft = AudioDeviceChannel;
210 break;
211 case 1: // right output channel
212 if (fxSends.empty()) pChannelRight = pChannel;
213 AudioDeviceChannelRight = AudioDeviceChannel;
214 break;
215 default:
216 throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
217 }
218
219 bStatusChanged = true;
220 }
221
222 int AbstractEngineChannel::OutputChannel(uint EngineAudioChannel) {
223 switch (EngineAudioChannel) {
224 case 0: // left channel
225 return AudioDeviceChannelLeft;
226 case 1: // right channel
227 return AudioDeviceChannelRight;
228 default:
229 throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
230 }
231 }
232
233 void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
234 if (!pMidiPort || pMidiPort == this->pMidiInputPort) return;
235 DisconnectMidiInputPort();
236 this->pMidiInputPort = pMidiPort;
237 this->midiChannel = MidiChannel;
238 pMidiPort->Connect(this, MidiChannel);
239 }
240
241 void AbstractEngineChannel::DisconnectMidiInputPort() {
242 MidiInputPort* pOldPort = this->pMidiInputPort;
243 this->pMidiInputPort = NULL;
244 if (pOldPort) pOldPort->Disconnect(this);
245 }
246
247 MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {
248 return pMidiInputPort;
249 }
250
251 midi_chan_t AbstractEngineChannel::MidiChannel() {
252 return midiChannel;
253 }
254
255 void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {
256 // double buffer ... double work ...
257 {
258 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
259 devices.add(pDevice);
260 }
261 {
262 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
263 devices.add(pDevice);
264 }
265 }
266
267 void AbstractEngineChannel::Disconnect(VirtualMidiDevice* pDevice) {
268 // double buffer ... double work ...
269 {
270 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
271 devices.remove(pDevice);
272 }
273 {
274 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
275 devices.remove(pDevice);
276 }
277 }
278
279 /**
280 * Will be called by the MIDIIn Thread to let the audio thread trigger a new
281 * voice for the given key. This method is meant for real time rendering,
282 * that is an event will immediately be created with the current system
283 * time as time stamp.
284 *
285 * @param Key - MIDI key number of the triggered key
286 * @param Velocity - MIDI velocity value of the triggered key
287 */
288 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
289 if (pEngine) {
290 Event event = pEngine->pEventGenerator->CreateEvent();
291 event.Type = Event::type_note_on;
292 event.Param.Note.Key = Key;
293 event.Param.Note.Velocity = Velocity;
294 event.Param.Note.Channel = MidiChannel;
295 event.pEngineChannel = this;
296 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
297 else dmsg(1,("EngineChannel: Input event queue full!"));
298 // inform connected virtual MIDI devices if any ...
299 // (e.g. virtual MIDI keyboard in instrument editor(s))
300 ArrayList<VirtualMidiDevice*>& devices =
301 const_cast<ArrayList<VirtualMidiDevice*>&>(
302 virtualMidiDevicesReader_MidiThread.Lock()
303 );
304 for (int i = 0; i < devices.size(); i++) {
305 devices[i]->SendNoteOnToDevice(Key, Velocity);
306 }
307 virtualMidiDevicesReader_MidiThread.Unlock();
308 }
309 }
310
311 /**
312 * Will be called by the MIDIIn Thread to let the audio thread trigger a new
313 * voice for the given key. This method is meant for offline rendering
314 * and / or for cases where the exact position of the event in the current
315 * audio fragment is already known.
316 *
317 * @param Key - MIDI key number of the triggered key
318 * @param Velocity - MIDI velocity value of the triggered key
319 * @param FragmentPos - sample point position in the current audio
320 * fragment to which this event belongs to
321 */
322 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
323 if (FragmentPos < 0) {
324 dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
325 }
326 else if (pEngine) {
327 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
328 event.Type = Event::type_note_on;
329 event.Param.Note.Key = Key;
330 event.Param.Note.Velocity = Velocity;
331 event.Param.Note.Channel = MidiChannel;
332 event.pEngineChannel = this;
333 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
334 else dmsg(1,("EngineChannel: Input event queue full!"));
335 // inform connected virtual MIDI devices if any ...
336 // (e.g. virtual MIDI keyboard in instrument editor(s))
337 ArrayList<VirtualMidiDevice*>& devices =
338 const_cast<ArrayList<VirtualMidiDevice*>&>(
339 virtualMidiDevicesReader_MidiThread.Lock()
340 );
341 for (int i = 0; i < devices.size(); i++) {
342 devices[i]->SendNoteOnToDevice(Key, Velocity);
343 }
344 virtualMidiDevicesReader_MidiThread.Unlock();
345 }
346 }
347
348 /**
349 * Will be called by the MIDIIn Thread to signal the audio thread to release
350 * voice(s) on the given key. This method is meant for real time rendering,
351 * that is an event will immediately be created with the current system
352 * time as time stamp.
353 *
354 * @param Key - MIDI key number of the released key
355 * @param Velocity - MIDI release velocity value of the released key
356 */
357 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
358 if (pEngine) {
359 Event event = pEngine->pEventGenerator->CreateEvent();
360 event.Type = Event::type_note_off;
361 event.Param.Note.Key = Key;
362 event.Param.Note.Velocity = Velocity;
363 event.Param.Note.Channel = MidiChannel;
364 event.pEngineChannel = this;
365 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
366 else dmsg(1,("EngineChannel: Input event queue full!"));
367 // inform connected virtual MIDI devices if any ...
368 // (e.g. virtual MIDI keyboard in instrument editor(s))
369 ArrayList<VirtualMidiDevice*>& devices =
370 const_cast<ArrayList<VirtualMidiDevice*>&>(
371 virtualMidiDevicesReader_MidiThread.Lock()
372 );
373 for (int i = 0; i < devices.size(); i++) {
374 devices[i]->SendNoteOffToDevice(Key, Velocity);
375 }
376 virtualMidiDevicesReader_MidiThread.Unlock();
377 }
378 }
379
380 /**
381 * Will be called by the MIDIIn Thread to signal the audio thread to release
382 * voice(s) on the given key. This method is meant for offline rendering
383 * and / or for cases where the exact position of the event in the current
384 * audio fragment is already known.
385 *
386 * @param Key - MIDI key number of the released key
387 * @param Velocity - MIDI release velocity value of the released key
388 * @param FragmentPos - sample point position in the current audio
389 * fragment to which this event belongs to
390 */
391 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
392 if (FragmentPos < 0) {
393 dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
394 }
395 else if (pEngine) {
396 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
397 event.Type = Event::type_note_off;
398 event.Param.Note.Key = Key;
399 event.Param.Note.Velocity = Velocity;
400 event.Param.Note.Channel = MidiChannel;
401 event.pEngineChannel = this;
402 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
403 else dmsg(1,("EngineChannel: Input event queue full!"));
404 // inform connected virtual MIDI devices if any ...
405 // (e.g. virtual MIDI keyboard in instrument editor(s))
406 ArrayList<VirtualMidiDevice*>& devices =
407 const_cast<ArrayList<VirtualMidiDevice*>&>(
408 virtualMidiDevicesReader_MidiThread.Lock()
409 );
410 for (int i = 0; i < devices.size(); i++) {
411 devices[i]->SendNoteOffToDevice(Key, Velocity);
412 }
413 virtualMidiDevicesReader_MidiThread.Unlock();
414 }
415 }
416
417 /**
418 * Will be called by the MIDIIn Thread to signal the audio thread to change
419 * the pitch value for all voices. This method is meant for real time
420 * rendering, that is an event will immediately be created with the
421 * current system time as time stamp.
422 *
423 * @param Pitch - MIDI pitch value (-8192 ... +8191)
424 */
425 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
426 if (pEngine) {
427 Event event = pEngine->pEventGenerator->CreateEvent();
428 event.Type = Event::type_pitchbend;
429 event.Param.Pitch.Pitch = Pitch;
430 event.Param.Pitch.Channel = MidiChannel;
431 event.pEngineChannel = this;
432 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
433 else dmsg(1,("EngineChannel: Input event queue full!"));
434 }
435 }
436
437 /**
438 * Will be called by the MIDIIn Thread to signal the audio thread to change
439 * the pitch value for all voices. This method is meant for offline
440 * rendering and / or for cases where the exact position of the event in
441 * the current audio fragment is already known.
442 *
443 * @param Pitch - MIDI pitch value (-8192 ... +8191)
444 * @param FragmentPos - sample point position in the current audio
445 * fragment to which this event belongs to
446 */
447 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel, int32_t FragmentPos) {
448 if (FragmentPos < 0) {
449 dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
450 }
451 else if (pEngine) {
452 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
453 event.Type = Event::type_pitchbend;
454 event.Param.Pitch.Pitch = Pitch;
455 event.Param.Pitch.Channel = MidiChannel;
456 event.pEngineChannel = this;
457 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
458 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
459 }
460 }
461
462 /**
463 * Will be called by the MIDIIn Thread to signal the audio thread that a
464 * continuous controller value has changed. This method is meant for real
465 * time rendering, that is an event will immediately be created with the
466 * current system time as time stamp.
467 *
468 * @param Controller - MIDI controller number of the occured control change
469 * @param Value - value of the control change
470 */
471 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
472 if (pEngine) {
473 Event event = pEngine->pEventGenerator->CreateEvent();
474 event.Type = Event::type_control_change;
475 event.Param.CC.Controller = Controller;
476 event.Param.CC.Value = Value;
477 event.Param.CC.Channel = MidiChannel;
478 event.pEngineChannel = this;
479 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
480 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
481 }
482 }
483
484 /**
485 * Will be called by the MIDIIn Thread to signal the audio thread that a
486 * continuous controller value has changed. This method is meant for
487 * offline rendering and / or for cases where the exact position of the
488 * event in the current audio fragment is already known.
489 *
490 * @param Controller - MIDI controller number of the occured control change
491 * @param Value - value of the control change
492 * @param FragmentPos - sample point position in the current audio
493 * fragment to which this event belongs to
494 */
495 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
496 if (FragmentPos < 0) {
497 dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
498 }
499 else if (pEngine) {
500 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
501 event.Type = Event::type_control_change;
502 event.Param.CC.Controller = Controller;
503 event.Param.CC.Value = Value;
504 event.Param.CC.Channel = MidiChannel;
505 event.pEngineChannel = this;
506 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
507 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
508 }
509 }
510
511 /**
512 * Copy all events from the engine channel's input event queue buffer to
513 * the internal event list. This will be done at the beginning of each
514 * audio cycle (that is each RenderAudio() call) to distinguish all
515 * events which have to be processed in the current audio cycle. Each
516 * EngineChannel has it's own input event queue for the common channel
517 * specific events (like NoteOn, NoteOff and ControlChange events).
518 * Beside that, the engine also has a input event queue for global
519 * events (usually SysEx messages).
520 *
521 * @param Samples - number of sample points to be processed in the
522 * current audio cycle
523 */
524 void AbstractEngineChannel::ImportEvents(uint Samples) {
525 // import events from pure software MIDI "devices"
526 // (e.g. virtual keyboard in instrument editor)
527 {
528 const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
529 const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
530 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
531 VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
532 // as we're going to (carefully) write some status to the
533 // synchronized struct, we cast away the const
534 ArrayList<VirtualMidiDevice*>& devices =
535 const_cast<ArrayList<VirtualMidiDevice*>&>(virtualMidiDevicesReader_AudioThread.Lock());
536 // iterate through all virtual MIDI devices
537 for (int i = 0; i < devices.size(); i++) {
538 VirtualMidiDevice* pDev = devices[i];
539 // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
540 while (pDev->GetMidiEventFromDevice(devEvent)) {
541 switch (devEvent.Type) {
542 case VirtualMidiDevice::EVENT_TYPE_NOTEON:
543 event.Type = Event::type_note_on;
544 event.Param.Note.Key = devEvent.Arg1;
545 event.Param.Note.Velocity = devEvent.Arg2;
546 event.Param.Note.Channel = channel;
547 break;
548 case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
549 event.Type = Event::type_note_off;
550 event.Param.Note.Key = devEvent.Arg1;
551 event.Param.Note.Velocity = devEvent.Arg2;
552 event.Param.Note.Channel = channel;
553 break;
554 case VirtualMidiDevice::EVENT_TYPE_CC:
555 event.Type = Event::type_control_change;
556 event.Param.CC.Controller = devEvent.Arg1;
557 event.Param.CC.Value = devEvent.Arg2;
558 event.Param.CC.Channel = channel;
559 break;
560 default:
561 std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
562 << devEvent.Type << "). This is a bug!";
563 continue;
564 }
565 event.pEngineChannel = this;
566 // copy event to internal event list
567 if (pEvents->poolIsEmpty()) {
568 dmsg(1,("Event pool emtpy!\n"));
569 goto exitVirtualDevicesLoop;
570 }
571 *pEvents->allocAppend() = event;
572 }
573 }
574 }
575 exitVirtualDevicesLoop:
576 virtualMidiDevicesReader_AudioThread.Unlock();
577
578 // import events from the regular MIDI devices
579 RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
580 Event* pEvent;
581 while (true) {
582 // get next event from input event queue
583 if (!(pEvent = eventQueueReader.pop())) break;
584 // if younger event reached, ignore that and all subsequent ones for now
585 if (pEvent->FragmentPos() >= Samples) {
586 eventQueueReader--;
587 dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
588 pEvent->ResetFragmentPos();
589 break;
590 }
591 // copy event to internal event list
592 if (pEvents->poolIsEmpty()) {
593 dmsg(1,("Event pool emtpy!\n"));
594 break;
595 }
596 *pEvents->allocAppend() = *pEvent;
597 }
598 eventQueueReader.free(); // free all copied events from input queue
599 }
600
601 FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
602 if (pEngine) pEngine->DisableAndLock();
603 FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
604 if (fxSends.empty()) {
605 if (pEngine && pEngine->pAudioOutputDevice) {
606 AudioOutputDevice* pDevice = pEngine->pAudioOutputDevice;
607 // create local render buffers
608 pChannelLeft = new AudioChannel(0, pDevice->MaxSamplesPerCycle());
609 pChannelRight = new AudioChannel(1, pDevice->MaxSamplesPerCycle());
610 } else {
611 // postpone local render buffer creation until audio device is assigned
612 pChannelLeft = NULL;
613 pChannelRight = NULL;
614 }
615 }
616 fxSends.push_back(pFxSend);
617 if (pEngine) pEngine->Enable();
618 fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
619
620 return pFxSend;
621 }
622
623 FxSend* AbstractEngineChannel::GetFxSend(uint FxSendIndex) {
624 return (FxSendIndex < fxSends.size()) ? fxSends[FxSendIndex] : NULL;
625 }
626
627 uint AbstractEngineChannel::GetFxSendCount() {
628 return fxSends.size();
629 }
630
631 void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {
632 if (pEngine) pEngine->DisableAndLock();
633 for (
634 std::vector<FxSend*>::iterator iter = fxSends.begin();
635 iter != fxSends.end(); iter++
636 ) {
637 if (*iter == pFxSend) {
638 delete pFxSend;
639 fxSends.erase(iter);
640 if (fxSends.empty()) {
641 // destroy local render buffers
642 if (pChannelLeft) delete pChannelLeft;
643 if (pChannelRight) delete pChannelRight;
644 // fallback to render directly into AudioOutputDevice's buffers
645 if (pEngine && pEngine->pAudioOutputDevice) {
646 pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
647 pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
648 } else { // we update the pointers later
649 pChannelLeft = NULL;
650 pChannelRight = NULL;
651 }
652 }
653 break;
654 }
655 }
656 if (pEngine) pEngine->Enable();
657 fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
658 }
659
660 void AbstractEngineChannel::RemoveAllFxSends() {
661 if (pEngine) pEngine->DisableAndLock();
662 if (!fxSends.empty()) { // free local render buffers
663 if (pChannelLeft) {
664 delete pChannelLeft;
665 if (pEngine && pEngine->pAudioOutputDevice) {
666 // fallback to render directly to the AudioOutputDevice's buffer
667 pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
668 } else pChannelLeft = NULL;
669 }
670 if (pChannelRight) {
671 delete pChannelRight;
672 if (pEngine && pEngine->pAudioOutputDevice) {
673 // fallback to render directly to the AudioOutputDevice's buffer
674 pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
675 } else pChannelRight = NULL;
676 }
677 }
678 for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];
679 fxSends.clear();
680 if (pEngine) pEngine->Enable();
681 }
682
683 /**
684 * Add a group number to the set of key groups. Should be called
685 * when an instrument is loaded to make sure there are event lists
686 * for all key groups.
687 */
688 void AbstractEngineChannel::AddGroup(uint group) {
689 if (group) {
690 std::pair<ActiveKeyGroupMap::iterator, bool> p =
691 ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
692 if (p.second) {
693 // If the engine channel is pending deletion (see bug
694 // #113), pEngine will be null, so we can't use
695 // pEngine->pEventPool here. Instead we're using a
696 // specialized RTList that allows specifying the pool
697 // later.
698 (*p.first).second = new LazyList<Event>;
699 }
700 }
701 }
702
703 /**
704 * Handle key group (a.k.a. exclusive group) conflicts.
705 */
706 void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
707 dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
708 if (KeyGroup) {
709 // send a release event to all active voices in the group
710 RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
711 *itEvent = *itNoteOnEvent;
712 }
713 }
714
715 /**
716 * Empty the lists of group events. Should be called from the
717 * audio thread, after all voices have been rendered.
718 */
719 void AbstractEngineChannel::ClearGroupEventLists() {
720 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
721 iter != ActiveKeyGroups.end(); iter++) {
722 if (iter->second) {
723 iter->second->clear();
724 } else {
725 dmsg(1,("EngineChannel: group event list was NULL"));
726 }
727 }
728 }
729
730 /**
731 * Remove all lists with group events.
732 */
733 void AbstractEngineChannel::DeleteGroupEventLists() {
734 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
735 iter != ActiveKeyGroups.end(); iter++) {
736 delete iter->second;
737 }
738 ActiveKeyGroups.clear();
739 }
740
741 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC