/[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 2618 - (show annotations) (download)
Wed Jun 11 11:39:44 2014 UTC (7 years, 4 months ago) by schoenebeck
File size: 44519 byte(s)
* Fixed execution of "init" instrument script handler.
* Fixed further crashes.
* Bumped version (1.0.0.svn50).

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

  ViewVC Help
Powered by ViewVC