/[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 2612 - (show annotations) (download)
Tue Jun 10 13:32:16 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 44603 byte(s)
* Fixed crashes when exiting the sampler.
* Bumped version (1.0.0.svn47).

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 * Copyright (C) 2013-2014 Christian Schoenebeck and Andreas Persson *
9 * *
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 #include "AbstractEngineChannel.h"
27 #include "../common/global_private.h"
28 #include "../Sampler.h"
29
30 namespace LinuxSampler {
31
32 AbstractEngineChannel::AbstractEngineChannel() :
33 virtualMidiDevicesReader_AudioThread(virtualMidiDevices),
34 virtualMidiDevicesReader_MidiThread(virtualMidiDevices)
35 {
36 pEngine = NULL;
37 pEvents = NULL; // we allocate when we retrieve the right Engine object
38 pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
39 InstrumentIdx = -1;
40 InstrumentStat = -1;
41 pChannelLeft = NULL;
42 pChannelRight = NULL;
43 AudioDeviceChannelLeft = -1;
44 AudioDeviceChannelRight = -1;
45 midiChannel = midi_chan_all;
46 ResetControllers();
47 PortamentoMode = false;
48 PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
49 pScript = NULL;
50 }
51
52 AbstractEngineChannel::~AbstractEngineChannel() {
53 if (pScript) pScript->resetAll(); // unloads script (in case one is loaded)
54 delete pEventQueue;
55 DeleteGroupEventLists();
56 RemoveAllFxSends();
57 }
58
59 Engine* AbstractEngineChannel::GetEngine() {
60 return pEngine;
61 }
62
63 uint AbstractEngineChannel::Channels() {
64 return 2;
65 }
66
67 /**
68 * More or less a workaround to set the instrument name, index and load
69 * status variable to zero percent immediately, that is without blocking
70 * the calling thread. It might be used in future for other preparations
71 * as well though.
72 *
73 * @param FileName - file name of the instrument file
74 * @param Instrument - index of the instrument in the file
75 * @see LoadInstrument()
76 */
77 void AbstractEngineChannel::PrepareLoadInstrument(const char* FileName, uint Instrument) {
78 InstrumentFile = FileName;
79 InstrumentIdx = Instrument;
80 InstrumentStat = 0;
81 }
82
83 String AbstractEngineChannel::InstrumentFileName() {
84 return InstrumentFile;
85 }
86
87 String AbstractEngineChannel::InstrumentName() {
88 return InstrumentIdxName;
89 }
90
91 int AbstractEngineChannel::InstrumentIndex() {
92 return InstrumentIdx;
93 }
94
95 int AbstractEngineChannel::InstrumentStatus() {
96 return InstrumentStat;
97 }
98
99 String AbstractEngineChannel::EngineName() {
100 return AbstractEngine::GetFormatString(GetEngineFormat());
101 }
102
103 void AbstractEngineChannel::Reset() {
104 if (pEngine) pEngine->DisableAndLock();
105 ResetInternal();
106 ResetControllers();
107 if (pEngine) {
108 pEngine->Enable();
109 pEngine->Reset();
110 }
111 }
112
113 void AbstractEngineChannel::ResetControllers() {
114 Pitch = 0;
115 GlobalVolume = 1.0f;
116 MidiVolume = 1.0;
117 iLastPanRequest = 64;
118 GlobalTranspose = 0;
119 // set all MIDI controller values to zero
120 memset(ControllerTable, 0x00, 129);
121 // reset all FX Send levels
122 for (
123 std::vector<FxSend*>::iterator iter = fxSends.begin();
124 iter != fxSends.end(); iter++
125 ) {
126 (*iter)->Reset();
127 }
128 }
129
130 /**
131 * This method is not thread safe!
132 */
133 void AbstractEngineChannel::ResetInternal() {
134 CurrentKeyDimension = 0;
135 PortamentoPos = -1.0f; // no portamento active yet
136
137 // delete all input events
138 pEventQueue->init();
139
140 if (pEngine) pEngine->ResetInternal();
141
142 // status of engine channel has changed, so set notify flag
143 bStatusChanged = true;
144 }
145
146 /**
147 * Implementation of virtual method from abstract EngineChannel interface.
148 * This method will periodically be polled (e.g. by the LSCP server) to
149 * check if some engine channel parameter has changed since the last
150 * StatusChanged() call.
151 *
152 * This method can also be used to mark the engine channel as changed
153 * from outside, e.g. by a MIDI input device. The optional argument
154 * \a nNewStatus can be used for this.
155 *
156 * TODO: This "poll method" is just a lazy solution and might be
157 * replaced in future.
158 * @param bNewStatus - (optional, default: false) sets the new status flag
159 * @returns true if engine channel status has changed since last
160 * StatusChanged() call
161 */
162 bool AbstractEngineChannel::StatusChanged(bool bNewStatus) {
163 bool b = bStatusChanged;
164 bStatusChanged = bNewStatus;
165 return b;
166 }
167
168 float AbstractEngineChannel::Volume() {
169 return GlobalVolume;
170 }
171
172 void AbstractEngineChannel::Volume(float f) {
173 GlobalVolume = f;
174 bStatusChanged = true; // status of engine channel has changed, so set notify flag
175 }
176
177 float AbstractEngineChannel::Pan() {
178 return float(iLastPanRequest - 64) / 64.0f;
179 }
180
181 void AbstractEngineChannel::Pan(float f) {
182 int iMidiPan = int(f * 64.0f) + 64;
183 if (iMidiPan > 127) iMidiPan = 127;
184 else if (iMidiPan < 0) iMidiPan = 0;
185 iLastPanRequest = iMidiPan;
186 }
187
188 AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDevice() {
189 return (pEngine) ? pEngine->pAudioOutputDevice : NULL;
190 }
191
192 /**
193 * Gets thread safe access to the currently connected audio output
194 * device from other threads than the lscp thread.
195 */
196 AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
197 LockGuard lock(EngineMutex);
198 return GetAudioOutputDevice();
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) {
234 if (!pMidiPort) return;
235
236 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
237
238 // check if connection already exists
239 for (int i = 0; i < connections->size(); ++i)
240 if ((*connections)[i] == pMidiPort)
241 return; // to avoid endless recursion
242
243 connections->add(pMidiPort);
244
245 // inform MIDI port about this new connection
246 pMidiPort->Connect(this, MidiChannel());
247 }
248
249 void AbstractEngineChannel::Disconnect(MidiInputPort* pMidiPort) {
250 if (!pMidiPort) return;
251
252 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
253
254 for (int i = 0; i < connections->size(); ++i) {
255 if ((*connections)[i] == pMidiPort) {
256 connections->remove(i);
257 // inform MIDI port about this disconnection
258 pMidiPort->Disconnect(this);
259 return;
260 }
261 }
262 }
263
264 void AbstractEngineChannel::DisconnectAllMidiInputPorts() {
265 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
266 ArrayList<MidiInputPort*> clonedList = *connections;
267 connections->clear();
268 for (int i = 0; i < clonedList.size(); ++i) clonedList[i]->Disconnect(this);
269 }
270
271 uint AbstractEngineChannel::GetMidiInputPortCount() {
272 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
273 return connections->size();
274 }
275
276 MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) {
277 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
278 return (index < connections->size()) ? (*connections)[index] : NULL;
279 }
280
281 // deprecated (just for API backward compatibility) - may be removed in future
282 void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
283 if (!pMidiPort) return;
284
285 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
286
287 // check against endless recursion
288 if (connections->size() == 1 && (*connections)[0] == pMidiPort && this->midiChannel == MidiChannel)
289 return;
290
291 if (!isValidMidiChan(MidiChannel))
292 throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
293
294 this->midiChannel = MidiChannel;
295
296 // disconnect all currently connected MIDI ports
297 ArrayList<MidiInputPort*> clonedList = *connections;
298 connections->clear();
299 for (int i = 0; i < clonedList.size(); ++i)
300 clonedList[i]->Disconnect(this);
301
302 // connect the new port
303 connections->add(pMidiPort);
304 pMidiPort->Connect(this, MidiChannel);
305 }
306
307 // deprecated (just for API backward compatibility) - may be removed in future
308 void AbstractEngineChannel::DisconnectMidiInputPort() {
309 DisconnectAllMidiInputPorts();
310 }
311
312 // deprecated (just for API backward compatibility) - may be removed in future
313 MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {
314 return GetMidiInputPort(0);
315 }
316
317 midi_chan_t AbstractEngineChannel::MidiChannel() {
318 return midiChannel;
319 }
320
321 void AbstractEngineChannel::SetMidiChannel(midi_chan_t MidiChannel) {
322 if (this->midiChannel == MidiChannel) return;
323 if (!isValidMidiChan(MidiChannel))
324 throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
325
326 this->midiChannel = MidiChannel;
327
328 Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
329 ArrayList<MidiInputPort*> clonedList = *connections;
330
331 DisconnectAllMidiInputPorts();
332
333 for (int i = 0; i < clonedList.size(); ++i) Connect(clonedList[i]);
334 }
335
336 void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {
337 // double buffer ... double work ...
338 {
339 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
340 devices.add(pDevice);
341 }
342 {
343 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
344 devices.add(pDevice);
345 }
346 }
347
348 void AbstractEngineChannel::Disconnect(VirtualMidiDevice* pDevice) {
349 // double buffer ... double work ...
350 {
351 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
352 devices.remove(pDevice);
353 }
354 {
355 ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
356 devices.remove(pDevice);
357 }
358 }
359
360 /**
361 * Will be called by the MIDIIn Thread to let the audio thread trigger a new
362 * voice for the given key. This method is meant for real time rendering,
363 * that is an event will immediately be created with the current system
364 * time as time stamp.
365 *
366 * @param Key - MIDI key number of the triggered key
367 * @param Velocity - MIDI velocity value of the triggered key
368 */
369 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
370 if (pEngine) {
371 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
372 LockGuard g;
373 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
374
375 Event event = pEngine->pEventGenerator->CreateEvent();
376 event.Type = Event::type_note_on;
377 event.Param.Note.Key = Key;
378 event.Param.Note.Velocity = Velocity;
379 event.Param.Note.Channel = MidiChannel;
380 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
381 event.pEngineChannel = this;
382 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
383 else dmsg(1,("EngineChannel: Input event queue full!"));
384 // inform connected virtual MIDI devices if any ...
385 // (e.g. virtual MIDI keyboard in instrument editor(s))
386 ArrayList<VirtualMidiDevice*>& devices =
387 const_cast<ArrayList<VirtualMidiDevice*>&>(
388 virtualMidiDevicesReader_MidiThread.Lock()
389 );
390 for (int i = 0; i < devices.size(); i++) {
391 devices[i]->SendNoteOnToDevice(Key, Velocity);
392 }
393 virtualMidiDevicesReader_MidiThread.Unlock();
394 }
395 }
396
397 /**
398 * Will be called by the MIDIIn Thread to let the audio thread trigger a new
399 * voice for the given key. This method is meant for offline rendering
400 * and / or for cases where the exact position of the event in the current
401 * audio fragment is already known.
402 *
403 * @param Key - MIDI key number of the triggered key
404 * @param Velocity - MIDI velocity value of the triggered key
405 * @param FragmentPos - sample point position in the current audio
406 * fragment to which this event belongs to
407 */
408 void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
409 if (FragmentPos < 0) {
410 dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
411 }
412 else if (pEngine) {
413 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
414 LockGuard g;
415 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
416
417 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
418 event.Type = Event::type_note_on;
419 event.Param.Note.Key = Key;
420 event.Param.Note.Velocity = Velocity;
421 event.Param.Note.Channel = MidiChannel;
422 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
423 event.pEngineChannel = this;
424 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
425 else dmsg(1,("EngineChannel: Input event queue full!"));
426 // inform connected virtual MIDI devices if any ...
427 // (e.g. virtual MIDI keyboard in instrument editor(s))
428 ArrayList<VirtualMidiDevice*>& devices =
429 const_cast<ArrayList<VirtualMidiDevice*>&>(
430 virtualMidiDevicesReader_MidiThread.Lock()
431 );
432 for (int i = 0; i < devices.size(); i++) {
433 devices[i]->SendNoteOnToDevice(Key, Velocity);
434 }
435 virtualMidiDevicesReader_MidiThread.Unlock();
436 }
437 }
438
439 /**
440 * Will be called by the MIDIIn Thread to signal the audio thread to release
441 * voice(s) on the given key. This method is meant for real time rendering,
442 * that is an event will immediately be created with the current system
443 * time as time stamp.
444 *
445 * @param Key - MIDI key number of the released key
446 * @param Velocity - MIDI release velocity value of the released key
447 */
448 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
449 if (pEngine) {
450 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
451 LockGuard g;
452 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
453
454 Event event = pEngine->pEventGenerator->CreateEvent();
455 event.Type = Event::type_note_off;
456 event.Param.Note.Key = Key;
457 event.Param.Note.Velocity = Velocity;
458 event.Param.Note.Channel = MidiChannel;
459 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
460 event.pEngineChannel = this;
461 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
462 else dmsg(1,("EngineChannel: Input event queue full!"));
463 // inform connected virtual MIDI devices if any ...
464 // (e.g. virtual MIDI keyboard in instrument editor(s))
465 ArrayList<VirtualMidiDevice*>& devices =
466 const_cast<ArrayList<VirtualMidiDevice*>&>(
467 virtualMidiDevicesReader_MidiThread.Lock()
468 );
469 for (int i = 0; i < devices.size(); i++) {
470 devices[i]->SendNoteOffToDevice(Key, Velocity);
471 }
472 virtualMidiDevicesReader_MidiThread.Unlock();
473 }
474 }
475
476 /**
477 * Will be called by the MIDIIn Thread to signal the audio thread to release
478 * voice(s) on the given key. This method is meant for offline rendering
479 * and / or for cases where the exact position of the event in the current
480 * audio fragment is already known.
481 *
482 * @param Key - MIDI key number of the released key
483 * @param Velocity - MIDI release velocity value of the released key
484 * @param FragmentPos - sample point position in the current audio
485 * fragment to which this event belongs to
486 */
487 void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
488 if (FragmentPos < 0) {
489 dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
490 }
491 else if (pEngine) {
492 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
493 LockGuard g;
494 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
495
496 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
497 event.Type = Event::type_note_off;
498 event.Param.Note.Key = Key;
499 event.Param.Note.Velocity = Velocity;
500 event.Param.Note.Channel = MidiChannel;
501 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
502 event.pEngineChannel = this;
503 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
504 else dmsg(1,("EngineChannel: Input event queue full!"));
505 // inform connected virtual MIDI devices if any ...
506 // (e.g. virtual MIDI keyboard in instrument editor(s))
507 ArrayList<VirtualMidiDevice*>& devices =
508 const_cast<ArrayList<VirtualMidiDevice*>&>(
509 virtualMidiDevicesReader_MidiThread.Lock()
510 );
511 for (int i = 0; i < devices.size(); i++) {
512 devices[i]->SendNoteOffToDevice(Key, Velocity);
513 }
514 virtualMidiDevicesReader_MidiThread.Unlock();
515 }
516 }
517
518 /**
519 * Will be called by the MIDIIn Thread to signal the audio thread to change
520 * the pitch value for all voices. This method is meant for real time
521 * rendering, that is an event will immediately be created with the
522 * current system time as time stamp.
523 *
524 * @param Pitch - MIDI pitch value (-8192 ... +8191)
525 */
526 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
527 if (pEngine) {
528 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
529 LockGuard g;
530 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
531
532 Event event = pEngine->pEventGenerator->CreateEvent();
533 event.Type = Event::type_pitchbend;
534 event.Param.Pitch.Pitch = Pitch;
535 event.Param.Pitch.Channel = MidiChannel;
536 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
537 event.pEngineChannel = this;
538 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
539 else dmsg(1,("EngineChannel: Input event queue full!"));
540 }
541 }
542
543 /**
544 * Will be called by the MIDIIn Thread to signal the audio thread to change
545 * the pitch value for all voices. This method is meant for offline
546 * rendering and / or for cases where the exact position of the event in
547 * the current audio fragment is already known.
548 *
549 * @param Pitch - MIDI pitch value (-8192 ... +8191)
550 * @param FragmentPos - sample point position in the current audio
551 * fragment to which this event belongs to
552 */
553 void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel, int32_t FragmentPos) {
554 if (FragmentPos < 0) {
555 dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
556 }
557 else if (pEngine) {
558 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
559 LockGuard g;
560 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
561
562 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
563 event.Type = Event::type_pitchbend;
564 event.Param.Pitch.Pitch = Pitch;
565 event.Param.Pitch.Channel = MidiChannel;
566 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
567 event.pEngineChannel = this;
568 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
569 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
570 }
571 }
572
573 /**
574 * Will be called by the MIDIIn Thread to signal the audio thread that a
575 * continuous controller value has changed. This method is meant for real
576 * time rendering, that is an event will immediately be created with the
577 * current system time as time stamp.
578 *
579 * @param Controller - MIDI controller number of the occured control change
580 * @param Value - value of the control change
581 */
582 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
583 if (pEngine) {
584 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
585 LockGuard g;
586 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
587
588 Event event = pEngine->pEventGenerator->CreateEvent();
589 event.Type = Event::type_control_change;
590 event.Param.CC.Controller = Controller;
591 event.Param.CC.Value = Value;
592 event.Param.CC.Channel = MidiChannel;
593 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
594 event.pEngineChannel = this;
595 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
596 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
597 }
598 }
599
600 /**
601 * Will be called by the MIDIIn Thread to signal the audio thread that a
602 * continuous controller value has changed. This method is meant for
603 * offline rendering and / or for cases where the exact position of the
604 * event in the current audio fragment is already known.
605 *
606 * @param Controller - MIDI controller number of the occured control change
607 * @param Value - value of the control change
608 * @param FragmentPos - sample point position in the current audio
609 * fragment to which this event belongs to
610 */
611 void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
612 if (FragmentPos < 0) {
613 dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
614 }
615 else if (pEngine) {
616 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
617 LockGuard g;
618 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
619
620 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
621 event.Type = Event::type_control_change;
622 event.Param.CC.Controller = Controller;
623 event.Param.CC.Value = Value;
624 event.Param.CC.Channel = MidiChannel;
625 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
626 event.pEngineChannel = this;
627 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
628 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
629 }
630 }
631
632 void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel) {
633 if (pEngine) {
634 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
635 LockGuard g;
636 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
637
638 Event event = pEngine->pEventGenerator->CreateEvent();
639 event.Type = Event::type_channel_pressure;
640 event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
641 event.Param.ChannelPressure.Value = Value;
642 event.Param.ChannelPressure.Channel = MidiChannel;
643 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
644 event.pEngineChannel = this;
645 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
646 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
647 }
648 }
649
650 void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
651 if (pEngine) {
652 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
653 LockGuard g;
654 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
655
656 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
657 event.Type = Event::type_channel_pressure;
658 event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
659 event.Param.ChannelPressure.Value = Value;
660 event.Param.ChannelPressure.Channel = MidiChannel;
661 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
662 event.pEngineChannel = this;
663 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
664 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
665 }
666 }
667
668 void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel) {
669 if (pEngine) {
670 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
671 LockGuard g;
672 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
673
674 Event event = pEngine->pEventGenerator->CreateEvent();
675 event.Type = Event::type_note_pressure;
676 event.Param.NotePressure.Key = Key;
677 event.Param.NotePressure.Value = Value;
678 event.Param.NotePressure.Channel = MidiChannel;
679 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
680 event.pEngineChannel = this;
681 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
682 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
683 }
684 }
685
686 void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
687 if (pEngine) {
688 // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
689 LockGuard g;
690 if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
691
692 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
693 event.Type = Event::type_note_pressure;
694 event.Param.NotePressure.Key = Key;
695 event.Param.NotePressure.Value = Value;
696 event.Param.NotePressure.Channel = MidiChannel;
697 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
698 event.pEngineChannel = this;
699 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
700 else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
701 }
702 }
703
704 /**
705 * Copy all events from the engine channel's input event queue buffer to
706 * the internal event list. This will be done at the beginning of each
707 * audio cycle (that is each RenderAudio() call) to distinguish all
708 * events which have to be processed in the current audio cycle. Each
709 * EngineChannel has it's own input event queue for the common channel
710 * specific events (like NoteOn, NoteOff and ControlChange events).
711 * Beside that, the engine also has a input event queue for global
712 * events (usually SysEx messages).
713 *
714 * @param Samples - number of sample points to be processed in the
715 * current audio cycle
716 */
717 void AbstractEngineChannel::ImportEvents(uint Samples) {
718 // import events from pure software MIDI "devices"
719 // (e.g. virtual keyboard in instrument editor)
720 {
721 const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
722 const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
723 Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
724 VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
725 // as we're going to (carefully) write some status to the
726 // synchronized struct, we cast away the const
727 ArrayList<VirtualMidiDevice*>& devices =
728 const_cast<ArrayList<VirtualMidiDevice*>&>(virtualMidiDevicesReader_AudioThread.Lock());
729 // iterate through all virtual MIDI devices
730 for (int i = 0; i < devices.size(); i++) {
731 VirtualMidiDevice* pDev = devices[i];
732 // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
733 while (pDev->GetMidiEventFromDevice(devEvent)) {
734 switch (devEvent.Type) {
735 case VirtualMidiDevice::EVENT_TYPE_NOTEON:
736 event.Type = Event::type_note_on;
737 event.Param.Note.Key = devEvent.Arg1;
738 event.Param.Note.Velocity = devEvent.Arg2;
739 event.Param.Note.Channel = channel;
740 break;
741 case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
742 event.Type = Event::type_note_off;
743 event.Param.Note.Key = devEvent.Arg1;
744 event.Param.Note.Velocity = devEvent.Arg2;
745 event.Param.Note.Channel = channel;
746 break;
747 case VirtualMidiDevice::EVENT_TYPE_CC:
748 switch (devEvent.Arg1) {
749 case 0: // bank select MSB ...
750 SetMidiBankMsb(devEvent.Arg2);
751 continue; // don't push this event into FIFO
752 case 32: // bank select LSB ...
753 SetMidiBankLsb(devEvent.Arg2);
754 continue; // don't push this event into FIFO
755 default: // regular MIDI CC ...
756 event.Type = Event::type_control_change;
757 event.Param.CC.Controller = devEvent.Arg1;
758 event.Param.CC.Value = devEvent.Arg2;
759 event.Param.CC.Channel = channel;
760 }
761 break;
762 case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
763 event.Type = Event::type_pitchbend;
764 event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
765 event.Param.Pitch.Channel = channel;
766 break;
767 case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
768 SendProgramChange(devEvent.Arg1);
769 continue; // don't push this event into FIFO
770 default:
771 std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
772 << devEvent.Type << "). This is a bug!";
773 continue;
774 }
775 event.pEngineChannel = this;
776 // copy event to internal event list
777 if (pEvents->poolIsEmpty()) {
778 dmsg(1,("Event pool emtpy!\n"));
779 goto exitVirtualDevicesLoop;
780 }
781 *pEvents->allocAppend() = event;
782 }
783 }
784 }
785 exitVirtualDevicesLoop:
786 virtualMidiDevicesReader_AudioThread.Unlock();
787
788 // import events from the regular MIDI devices
789 RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
790 Event* pEvent;
791 while (true) {
792 // get next event from input event queue
793 if (!(pEvent = eventQueueReader.pop())) break;
794 // if younger event reached, ignore that and all subsequent ones for now
795 if (pEvent->FragmentPos() >= Samples) {
796 eventQueueReader--;
797 dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
798 pEvent->ResetFragmentPos();
799 break;
800 }
801 // copy event to internal event list
802 if (pEvents->poolIsEmpty()) {
803 dmsg(1,("Event pool emtpy!\n"));
804 break;
805 }
806 *pEvents->allocAppend() = *pEvent;
807 }
808 eventQueueReader.free(); // free all copied events from input queue
809 }
810
811 /**
812 * Called by real-time instrument script functions to schedule a new event
813 * somewhere in future.
814 *
815 * @returns unique event ID of scheduled new event
816 */
817 int AbstractEngineChannel::ScheduleEvent(const Event* pEvent, int delay) { //TODO: delay not implemented yet
818 // since delay is not implemented yet, we simply add the new event
819 // to the event list of the current audio fragmet cycle for now
820 RTList<Event>::Iterator itEvent = pEvents->allocAppend();
821 if (itEvent) *itEvent = *pEvent; // copy event
822 return pEvents->getID(itEvent);
823 }
824
825 /**
826 * Called by real-time instrument script functions to ignore the event
827 * reflected by given event ID. The event will be freed immediately to its
828 * pool and cannot be dereferenced by its old ID anymore. Even if its
829 * allocated back from the Pool later on, it will have a different ID.
830 */
831 void AbstractEngineChannel::IgnoreEvent(int id) {
832 RTList<Event>::Iterator it = pEvents->fromID(id);
833 if (it) pEvents->free(it);
834 }
835
836 FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
837 if (pEngine) pEngine->DisableAndLock();
838 FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
839 if (fxSends.empty()) {
840 if (pEngine && pEngine->pAudioOutputDevice) {
841 AudioOutputDevice* pDevice = pEngine->pAudioOutputDevice;
842 // create local render buffers
843 pChannelLeft = new AudioChannel(0, pDevice->MaxSamplesPerCycle());
844 pChannelRight = new AudioChannel(1, pDevice->MaxSamplesPerCycle());
845 } else {
846 // postpone local render buffer creation until audio device is assigned
847 pChannelLeft = NULL;
848 pChannelRight = NULL;
849 }
850 }
851 fxSends.push_back(pFxSend);
852 if (pEngine) pEngine->Enable();
853 fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
854
855 return pFxSend;
856 }
857
858 FxSend* AbstractEngineChannel::GetFxSend(uint FxSendIndex) {
859 return (FxSendIndex < fxSends.size()) ? fxSends[FxSendIndex] : NULL;
860 }
861
862 uint AbstractEngineChannel::GetFxSendCount() {
863 return fxSends.size();
864 }
865
866 void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {
867 if (pEngine) pEngine->DisableAndLock();
868 for (
869 std::vector<FxSend*>::iterator iter = fxSends.begin();
870 iter != fxSends.end(); iter++
871 ) {
872 if (*iter == pFxSend) {
873 delete pFxSend;
874 fxSends.erase(iter);
875 if (fxSends.empty()) {
876 // destroy local render buffers
877 if (pChannelLeft) delete pChannelLeft;
878 if (pChannelRight) delete pChannelRight;
879 // fallback to render directly into AudioOutputDevice's buffers
880 if (pEngine && pEngine->pAudioOutputDevice) {
881 pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
882 pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
883 } else { // we update the pointers later
884 pChannelLeft = NULL;
885 pChannelRight = NULL;
886 }
887 }
888 break;
889 }
890 }
891 if (pEngine) pEngine->Enable();
892 fireFxSendCountChanged(GetSamplerChannel()->Index(), GetFxSendCount());
893 }
894
895 void AbstractEngineChannel::RemoveAllFxSends() {
896 if (pEngine) pEngine->DisableAndLock();
897 if (!fxSends.empty()) { // free local render buffers
898 if (pChannelLeft) {
899 delete pChannelLeft;
900 if (pEngine && pEngine->pAudioOutputDevice) {
901 // fallback to render directly to the AudioOutputDevice's buffer
902 pChannelLeft = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelLeft);
903 } else pChannelLeft = NULL;
904 }
905 if (pChannelRight) {
906 delete pChannelRight;
907 if (pEngine && pEngine->pAudioOutputDevice) {
908 // fallback to render directly to the AudioOutputDevice's buffer
909 pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
910 } else pChannelRight = NULL;
911 }
912 }
913 for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];
914 fxSends.clear();
915 if (pEngine) pEngine->Enable();
916 }
917
918 /**
919 * Add a group number to the set of key groups. Should be called
920 * when an instrument is loaded to make sure there are event lists
921 * for all key groups.
922 */
923 void AbstractEngineChannel::AddGroup(uint group) {
924 if (group) {
925 std::pair<ActiveKeyGroupMap::iterator, bool> p =
926 ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
927 if (p.second) {
928 // If the engine channel is pending deletion (see bug
929 // #113), pEngine will be null, so we can't use
930 // pEngine->pEventPool here. Instead we're using a
931 // specialized RTList that allows specifying the pool
932 // later.
933 (*p.first).second = new LazyList<Event>;
934 }
935 }
936 }
937
938 /**
939 * Handle key group (a.k.a. exclusive group) conflicts.
940 */
941 void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
942 dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
943 if (KeyGroup) {
944 // send a release event to all active voices in the group
945 RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
946 *itEvent = *itNoteOnEvent;
947 }
948 }
949
950 /**
951 * Empty the lists of group events. Should be called from the
952 * audio thread, after all voices have been rendered.
953 */
954 void AbstractEngineChannel::ClearGroupEventLists() {
955 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
956 iter != ActiveKeyGroups.end(); iter++) {
957 if (iter->second) {
958 iter->second->clear();
959 } else {
960 dmsg(1,("EngineChannel: group event list was NULL"));
961 }
962 }
963 }
964
965 /**
966 * Remove all lists with group events.
967 */
968 void AbstractEngineChannel::DeleteGroupEventLists() {
969 for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
970 iter != ActiveKeyGroups.end(); iter++) {
971 delete iter->second;
972 }
973 ActiveKeyGroups.clear();
974 }
975
976 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC