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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2606 - (show annotations) (download)
Sun Jun 8 05:42:56 2014 UTC (9 years, 10 months ago) by persson
File size: 31993 byte(s)
* removed usage of c++11 initializer that caused compilation errors on
  older compilers

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 "AbstractEngine.h"
27 #include "AbstractEngineChannel.h"
28 #include "EngineFactory.h"
29 #include "../common/global_private.h"
30 #include "../effects/EffectFactory.h"
31
32 namespace LinuxSampler {
33
34 //InstrumentResourceManager Engine::instruments;
35
36 std::map<AbstractEngine::Format, std::map<AudioOutputDevice*,AbstractEngine*> > AbstractEngine::engines;
37
38 VMParserContext* AbstractEngine::ScriptResourceManager::Create(String Key, ScriptConsumer* pConsumer, void*& pArg) {
39 return parent->pScriptVM->loadScript(Key);
40 }
41
42 void AbstractEngine::ScriptResourceManager::Destroy(VMParserContext* pResource, void* pArg) {
43 delete pResource;
44 }
45
46 /**
47 * Get an AbstractEngine object for the given AbstractEngineChannel and the
48 * given AudioOutputDevice. All engine channels which are connected to
49 * the same audio output device will use the same engine instance. This
50 * method will be called by an EngineChannel whenever it's
51 * connecting to an audio output device.
52 *
53 * @param pChannel - engine channel which acquires an engine object
54 * @param pDevice - the audio output device \a pChannel is connected to
55 */
56 AbstractEngine* AbstractEngine::AcquireEngine(AbstractEngineChannel* pChannel, AudioOutputDevice* pDevice) {
57 AbstractEngine* pEngine = NULL;
58 // check if there's already an engine for the given audio output device
59 std::map<AbstractEngine::Format, std::map<AudioOutputDevice*,AbstractEngine*> >::iterator it;
60 it = engines.find(pChannel->GetEngineFormat());
61 if (it != engines.end() && (*it).second.count(pDevice)) {
62 dmsg(4,("Using existing Engine.\n"));
63 pEngine = (*it).second[pDevice];
64
65 // Disable the engine while the new engine channel is
66 // added and initialized. The engine will be enabled again
67 // in EngineChannel::Connect.
68 pEngine->DisableAndLock();
69 } else { // create a new engine (and disk thread) instance for the given audio output device
70 dmsg(4,("Creating new Engine.\n"));
71 pEngine = (AbstractEngine*) EngineFactory::Create(pChannel->EngineName());
72 pEngine->Connect(pDevice);
73 engines[pChannel->GetEngineFormat()][pDevice] = pEngine;
74 }
75 // register engine channel to the engine instance
76 pEngine->engineChannels.add(pChannel);
77 // remember index in the ArrayList
78 pChannel->iEngineIndexSelf = pEngine->engineChannels.size() - 1;
79 dmsg(4,("This Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
80 return pEngine;
81 }
82
83 AbstractEngine::AbstractEngine() : scripts(this) {
84 pAudioOutputDevice = NULL;
85 pEventGenerator = NULL;
86 pSysexBuffer = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0);
87 pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
88 pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
89 pGlobalEvents = new RTList<Event>(pEventPool);
90 FrameTime = 0;
91 RandomSeed = 0;
92 pDedicatedVoiceChannelLeft = pDedicatedVoiceChannelRight = NULL;
93 pScriptVM = CreateInstrumentScriptVM();
94 }
95
96 AbstractEngine::~AbstractEngine() {
97 if (pEventQueue) delete pEventQueue;
98 if (pEventPool) delete pEventPool;
99 if (pEventGenerator) delete pEventGenerator;
100 if (pGlobalEvents) delete pGlobalEvents;
101 if (pSysexBuffer) delete pSysexBuffer;
102 if (pDedicatedVoiceChannelLeft) delete pDedicatedVoiceChannelLeft;
103 if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
104 if (pScriptVM) delete pScriptVM;
105 Unregister();
106 }
107
108 /**
109 * Allocates a sampler format independent real-time instrument script
110 * runner. This method is overriden by sampler engines in case they have
111 * their own implementation of the script VM, with script feature extensions
112 * required for their sampler format.
113 */
114 InstrumentScriptVM* AbstractEngine::CreateInstrumentScriptVM() {
115 return new InstrumentScriptVM; // format independent script runner
116 }
117
118 /**
119 * Once an engine channel is disconnected from an audio output device,
120 * it will immediately call this method to unregister itself from the
121 * engine instance and if that engine instance is not used by any other
122 * engine channel anymore, then that engine instance will be destroyed.
123 *
124 * @param pChannel - engine channel which wants to disconnect from it's
125 * engine instance
126 * @param pDevice - audio output device \a pChannel was connected to
127 */
128 void AbstractEngine::FreeEngine(AbstractEngineChannel* pChannel, AudioOutputDevice* pDevice) {
129 dmsg(4,("Disconnecting EngineChannel from Engine.\n"));
130 AbstractEngine* pEngine = engines[pChannel->GetEngineFormat()][pDevice];
131 // unregister EngineChannel from the Engine instance
132 pEngine->engineChannels.remove(pChannel);
133 // if the used Engine instance is not used anymore, then destroy it
134 if (pEngine->engineChannels.empty()) {
135 pDevice->Disconnect(pEngine);
136 engines[pChannel->GetEngineFormat()].erase(pDevice);
137 delete pEngine;
138 dmsg(4,("Destroying Engine.\n"));
139 }
140 else dmsg(4,("This Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
141 }
142
143 void AbstractEngine::Enable() {
144 dmsg(3,("AbstractEngine: enabling\n"));
145 EngineDisabled.PushAndUnlock(false, 2, 0, true); // set condition object 'EngineDisabled' to false (wait max. 2s)
146 dmsg(3,("AbstractEngine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
147 }
148
149 /**
150 * Temporarily stop the engine to not do anything. The engine will just be
151 * frozen during that time, that means after enabling it again it will
152 * continue where it was, with all its voices and playback state it had at
153 * the point of disabling. Notice that the engine's (audio) thread will
154 * continue to run, it just remains in an inactive loop during that time.
155 *
156 * If you need to be sure that all voices and disk streams are killed as
157 * well, use @c SuspendAll() instead.
158 *
159 * @see Enable(), SuspendAll()
160 */
161 void AbstractEngine::Disable() {
162 dmsg(3,("AbstractEngine: disabling\n"));
163 bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s
164 if (!pWasDisabled) dmsg(3,("AbstractEngine warning: Timeout waiting to disable engine.\n"));
165 }
166
167 void AbstractEngine::DisableAndLock() {
168 dmsg(3,("AbstractEngine: disabling\n"));
169 bool* pWasDisabled = EngineDisabled.Push(true, 2); // wait max. 2s
170 if (!pWasDisabled) dmsg(3,("AbstractEngine warning: Timeout waiting to disable engine.\n"));
171 }
172
173 /**
174 * Reset all voices and disk thread and clear input event queue and all
175 * control and status variables.
176 */
177 void AbstractEngine::Reset() {
178 DisableAndLock();
179 ResetInternal();
180 ResetScaleTuning();
181 Enable();
182 }
183
184 /**
185 * Reset to normal, chromatic scale (means equal tempered).
186 */
187 void AbstractEngine::ResetScaleTuning() {
188 memset(&ScaleTuning[0], 0x00, 12);
189 ScaleTuningChanged.raise();
190 }
191
192 /**
193 * Copy all events from the engine's global input queue buffer to the
194 * engine's internal event list. This will be done at the beginning of
195 * each audio cycle (that is each RenderAudio() call) to distinguish
196 * all global events which have to be processed in the current audio
197 * cycle. These events are usually just SysEx messages. Every
198 * EngineChannel has it's own input event queue buffer and event list
199 * to handle common events like NoteOn, NoteOff and ControlChange
200 * events.
201 *
202 * @param Samples - number of sample points to be processed in the
203 * current audio cycle
204 */
205 void AbstractEngine::ImportEvents(uint Samples) {
206 RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
207 Event* pEvent;
208 while (true) {
209 // get next event from input event queue
210 if (!(pEvent = eventQueueReader.pop())) break;
211 // if younger event reached, ignore that and all subsequent ones for now
212 if (pEvent->FragmentPos() >= Samples) {
213 eventQueueReader--;
214 dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
215 pEvent->ResetFragmentPos();
216 break;
217 }
218 // copy event to internal event list
219 if (pGlobalEvents->poolIsEmpty()) {
220 dmsg(1,("Event pool emtpy!\n"));
221 break;
222 }
223 *pGlobalEvents->allocAppend() = *pEvent;
224 }
225 eventQueueReader.free(); // free all copied events from input queue
226 }
227
228 /**
229 * Clear all engine global event lists.
230 */
231 void AbstractEngine::ClearEventLists() {
232 pGlobalEvents->clear();
233 }
234
235 /**
236 * Will be called in case the respective engine channel sports FX send
237 * channels. In this particular case, engine channel local buffers are
238 * used to render and mix all voices to. This method is responsible for
239 * copying the audio data from those local buffers to the master audio
240 * output channels as well as to the FX send audio output channels with
241 * their respective FX send levels.
242 *
243 * @param pEngineChannel - engine channel from which audio should be
244 * routed
245 * @param Samples - amount of sample points to be routed in
246 * this audio fragment cycle
247 */
248 void AbstractEngine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
249 AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
250 AudioChannel* ppSource[2] = {
251 pChannel->pChannelLeft,
252 pChannel->pChannelRight
253 };
254 // route dry signal
255 {
256 AudioChannel* pDstL = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelLeft);
257 AudioChannel* pDstR = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelRight);
258 ppSource[0]->MixTo(pDstL, Samples);
259 ppSource[1]->MixTo(pDstR, Samples);
260 }
261 // route FX send signal (wet)
262 {
263 for (int iFxSend = 0; iFxSend < pChannel->GetFxSendCount(); iFxSend++) {
264 FxSend* pFxSend = pChannel->GetFxSend(iFxSend);
265 const bool success = RouteFxSend(pFxSend, ppSource, pFxSend->Level(), Samples);
266 if (!success) goto channel_cleanup;
267 }
268 }
269 channel_cleanup:
270 // reset buffers with silence (zero out) for the next audio cycle
271 ppSource[0]->Clear();
272 ppSource[1]->Clear();
273 }
274
275 /**
276 * Similar to RouteAudio(), but this method is even more special. It is
277 * only called by voices which have dedicated effect send(s) level(s). So
278 * such voices have to be routed separately apart from the other voices
279 * which can just be mixed together and routed afterwards in one turn.
280 */
281 void AbstractEngine::RouteDedicatedVoiceChannels(EngineChannel* pEngineChannel, optional<float> FxSendLevels[2], uint Samples) {
282 AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
283 AudioChannel* ppSource[2] = {
284 pDedicatedVoiceChannelLeft,
285 pDedicatedVoiceChannelRight
286 };
287 // route dry signal
288 {
289 AudioChannel* pDstL = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelLeft);
290 AudioChannel* pDstR = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelRight);
291 ppSource[0]->MixTo(pDstL, Samples);
292 ppSource[1]->MixTo(pDstR, Samples);
293 }
294 // route FX send signals (wet)
295 // (we simply hard code the voices 'reverb send' to the 1st effect
296 // send bus, and the voioces 'chorus send' to the 2nd effect send bus)
297 {
298 for (int iFxSend = 0; iFxSend < 2 && iFxSend < pChannel->GetFxSendCount(); iFxSend++) {
299 // no voice specific FX send level defined for this effect?
300 if (!FxSendLevels[iFxSend]) continue; // ignore this effect then
301
302 FxSend* pFxSend = pChannel->GetFxSend(iFxSend);
303 const bool success = RouteFxSend(pFxSend, ppSource, *FxSendLevels[iFxSend], Samples);
304 if (!success) goto channel_cleanup;
305 }
306 }
307 channel_cleanup:
308 // reset buffers with silence (zero out) for the next dedicated voice rendering/routing process
309 ppSource[0]->Clear();
310 ppSource[1]->Clear();
311 }
312
313 /**
314 * Route the audio signal given by @a ppSource to the effect send bus
315 * defined by @a pFxSend (wet signal only).
316 *
317 * @param pFxSend - definition of effect send bus
318 * @param ppSource - the 2 channels of the audio signal to be routed
319 * @param FxSendLevel - the effect send level to by applied
320 * @param Samples - amount of sample points to be processed
321 * @returns true if signal was routed successfully, false on error
322 */
323 bool AbstractEngine::RouteFxSend(FxSend* pFxSend, AudioChannel* ppSource[2], float FxSendLevel, uint Samples) {
324 for (int iChan = 0; iChan < 2; ++iChan) {
325 const int iDstChan = pFxSend->DestinationChannel(iChan);
326 if (iDstChan < 0) {
327 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
328 return false; // error
329 }
330 AudioChannel* pDstChan = NULL;
331 if (pFxSend->DestinationEffectChain() >= 0) { // fx send routed to an internal send effect
332 EffectChain* pEffectChain =
333 pAudioOutputDevice->SendEffectChainByID(
334 pFxSend->DestinationEffectChain()
335 );
336 if (!pEffectChain) {
337 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationEffectChain()));
338 return false; // error
339 }
340 Effect* pEffect =
341 pEffectChain->GetEffect(
342 pFxSend->DestinationEffectChainPosition()
343 );
344 if (!pEffect) {
345 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationEffectChainPosition(), pFxSend->DestinationEffectChain()));
346 return false; // error
347 }
348 pDstChan = pEffect->InputChannel(iDstChan);
349 } else { // FX send routed directly to an audio output channel
350 pDstChan = pAudioOutputDevice->Channel(iDstChan);
351 }
352 if (!pDstChan) {
353 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
354 return false; // error
355 }
356 ppSource[iChan]->MixTo(pDstChan, Samples, FxSendLevel);
357 }
358 return true; // success
359 }
360
361 /**
362 * Calculates the Roland GS sysex check sum.
363 *
364 * @param AddrReader - reader which currently points to the first GS
365 * command address byte of the GS sysex message in
366 * question
367 * @param DataSize - size of the GS message data (in bytes)
368 */
369 uint8_t AbstractEngine::GSCheckSum(const RingBuffer<uint8_t,false>::NonVolatileReader AddrReader, uint DataSize) {
370 RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
371 uint bytes = 3 /*addr*/ + DataSize;
372 uint8_t sum = 0;
373 uint8_t c;
374 for (uint i = 0; i < bytes; ++i) {
375 if (!reader.pop(&c)) break;
376 sum += c;
377 }
378 return 128 - sum % 128;
379 }
380
381 /**
382 * Allows to tune each of the twelve semitones of an octave.
383 *
384 * @param ScaleTunes - detuning of all twelve semitones (in cents)
385 */
386 void AbstractEngine::AdjustScaleTuning(const int8_t ScaleTunes[12]) {
387 memcpy(&this->ScaleTuning[0], &ScaleTunes[0], 12);
388 ScaleTuningChanged.raise();
389 }
390
391 void AbstractEngine::GetScaleTuning(int8_t* pScaleTunes) {
392 memcpy(pScaleTunes, &this->ScaleTuning[0], 12);
393 }
394
395 uint AbstractEngine::VoiceCount() {
396 return atomic_read(&ActiveVoiceCount);
397 }
398
399 void AbstractEngine::SetVoiceCount(uint Count) {
400 atomic_set(&ActiveVoiceCount, Count);
401 }
402
403 uint AbstractEngine::VoiceCountMax() {
404 return ActiveVoiceCountMax;
405 }
406
407 /**
408 * Stores the latest pitchbend event as current pitchbend scalar value.
409 *
410 * @param pEngineChannel - engine channel on which this event occured on
411 * @param itPitchbendEvent - absolute pitch value and time stamp of the event
412 */
413 void AbstractEngine::ProcessPitchbend(AbstractEngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
414 pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value
415 }
416
417 void AbstractEngine::ProcessFxSendControllers (
418 AbstractEngineChannel* pEngineChannel,
419 Pool<Event>::Iterator& itControlChangeEvent
420 ) {
421 if (!pEngineChannel->fxSends.empty()) {
422 for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
423 FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
424 if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) {
425 pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
426 pFxSend->SetInfoChanged(true);
427 }
428 }
429 }
430 }
431
432 /**
433 * Will be called by the MIDI input device whenever a MIDI system
434 * exclusive message has arrived.
435 *
436 * @param pData - pointer to sysex data
437 * @param Size - lenght of sysex data (in bytes)
438 * @param pSender - the MIDI input port on which the SysEx message was
439 * received
440 */
441 void AbstractEngine::SendSysex(void* pData, uint Size, MidiInputPort* pSender) {
442 Event event = pEventGenerator->CreateEvent();
443 event.Type = Event::type_sysex;
444 event.Param.Sysex.Size = Size;
445 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
446 event.pEngineChannel = NULL; // as Engine global event
447 event.pMidiInputPort = pSender;
448 if (pEventQueue->write_space() > 0) {
449 if (pSysexBuffer->write_space() >= Size) {
450 // copy sysex data to input buffer
451 uint toWrite = Size;
452 uint8_t* pPos = (uint8_t*) pData;
453 while (toWrite) {
454 const uint writeNow = RTMath::Min(toWrite, pSysexBuffer->write_space_to_end());
455 pSysexBuffer->write(pPos, writeNow);
456 toWrite -= writeNow;
457 pPos += writeNow;
458
459 }
460 // finally place sysex event into input event queue
461 pEventQueue->push(&event);
462 }
463 else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,CONFIG_SYSEX_BUFFER_SIZE));
464 }
465 else dmsg(1,("Engine: Input event queue full!"));
466 }
467
468 /**
469 * Reacts on MIDI system exclusive messages.
470 *
471 * @param itSysexEvent - sysex data size and time stamp of the sysex event
472 */
473 void AbstractEngine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
474 RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
475
476 uint8_t exclusive_status, id;
477 if (!reader.pop(&exclusive_status)) goto free_sysex_data;
478 if (!reader.pop(&id)) goto free_sysex_data;
479 if (exclusive_status != 0xF0) goto free_sysex_data;
480
481 switch (id) {
482 case 0x7f: { // (Realtime) Universal Sysex (GM Standard)
483 uint8_t sysex_channel, sub_id1, sub_id2, val_msb, val_lsb;;
484 if (!reader.pop(&sysex_channel)) goto free_sysex_data;
485 if (!reader.pop(&sub_id1)) goto free_sysex_data;
486 if (!reader.pop(&sub_id2)) goto free_sysex_data;
487 if (!reader.pop(&val_lsb)) goto free_sysex_data;
488 if (!reader.pop(&val_msb)) goto free_sysex_data;
489 //TODO: for now we simply ignore the sysex channel, seldom used anyway
490 switch (sub_id1) {
491 case 0x04: // Device Control
492 switch (sub_id2) {
493 case 0x01: { // Master Volume
494 const double volume =
495 double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0;
496 #if CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
497 // apply volume to all sampler channels that
498 // are connected to the same MIDI input port
499 // this sysex message arrived on
500 for (int i = 0; i < engineChannels.size(); ++i) {
501 EngineChannel* pEngineChannel = engineChannels[i];
502 if (pEngineChannel->GetMidiInputPort() ==
503 itSysexEvent->pMidiInputPort)
504 {
505 pEngineChannel->Volume(volume);
506 }
507 }
508 #else
509 // apply volume globally to the whole sampler
510 GLOBAL_VOLUME = volume;
511 #endif // CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
512 break;
513 }
514 }
515 break;
516 }
517 break;
518 }
519 case 0x41: { // Roland
520 dmsg(3,("Roland Sysex\n"));
521 uint8_t device_id, model_id, cmd_id;
522 if (!reader.pop(&device_id)) goto free_sysex_data;
523 if (!reader.pop(&model_id)) goto free_sysex_data;
524 if (!reader.pop(&cmd_id)) goto free_sysex_data;
525 if (model_id != 0x42 /*GS*/) goto free_sysex_data;
526 if (cmd_id != 0x12 /*DT1*/) goto free_sysex_data;
527
528 // command address
529 uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB)
530 const RingBuffer<uint8_t,false>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later
531 if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
532 if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
533 dmsg(3,("\tSystem Parameter\n"));
534 if (addr[2] == 0x7f) { // GS reset
535 for (int i = 0; i < engineChannels.size(); ++i) {
536 AbstractEngineChannel* pEngineChannel
537 = static_cast<AbstractEngineChannel*>(engineChannels[i]);
538 Sync< ArrayList<MidiInputPort*> > midiInputs = pEngineChannel->midiInputs.front();
539 for (int k = 0; k < midiInputs->size(); ++k) {
540 if ((*midiInputs)[k] == itSysexEvent->pMidiInputPort) {
541 KillAllVoices(pEngineChannel, itSysexEvent);
542 pEngineChannel->ResetControllers();
543 break;
544 }
545 }
546 }
547 }
548 }
549 else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
550 dmsg(3,("\tCommon Parameter\n"));
551 }
552 else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)
553 dmsg(3,("\tPart Parameter\n"));
554 switch (addr[2]) {
555 case 0x40: { // scale tuning
556 dmsg(3,("\t\tScale Tuning\n"));
557 uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave
558 if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;
559 uint8_t checksum;
560 if (!reader.pop(&checksum)) goto free_sysex_data;
561 #if CONFIG_ASSERT_GS_SYSEX_CHECKSUM
562 if (GSCheckSum(checksum_reader, 12)) goto free_sysex_data;
563 #endif // CONFIG_ASSERT_GS_SYSEX_CHECKSUM
564 for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;
565 AdjustScaleTuning((int8_t*) scale_tunes);
566 dmsg(3,("\t\t\tNew scale applied.\n"));
567 break;
568 }
569 case 0x15: { // chromatic / drumkit mode
570 dmsg(3,("\t\tMIDI Instrument Map Switch\n"));
571 uint8_t part = addr[1] & 0x0f;
572 uint8_t map;
573 if (!reader.pop(&map)) goto free_sysex_data;
574 for (int i = 0; i < engineChannels.size(); ++i) {
575 AbstractEngineChannel* pEngineChannel
576 = static_cast<AbstractEngineChannel*>(engineChannels[i]);
577 if (pEngineChannel->midiChannel == part ||
578 pEngineChannel->midiChannel == midi_chan_all)
579 {
580 Sync< ArrayList<MidiInputPort*> > midiInputs = pEngineChannel->midiInputs.front();
581 for (int k = 0; k < midiInputs->size(); ++k) {
582 if ((*midiInputs)[k] == itSysexEvent->pMidiInputPort) {
583 try {
584 pEngineChannel->SetMidiInstrumentMap(map);
585 } catch (Exception e) {
586 dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d: %s\n", map, part, e.Message().c_str()));
587 goto free_sysex_data;
588 } catch (...) {
589 dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d (unknown exception)\n", map, part));
590 goto free_sysex_data;
591 }
592 break;
593 }
594 }
595 }
596 }
597 dmsg(3,("\t\t\tApplied MIDI instrument map %d to part %d.\n", map, part));
598 break;
599 }
600 }
601 }
602 else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)
603 }
604 else if (addr[0] == 0x41) { // Drum Setup Parameters
605 }
606 break;
607 }
608 }
609
610 free_sysex_data: // finally free sysex data
611 pSysexBuffer->increment_read_ptr(itSysexEvent->Param.Sysex.Size);
612 }
613
614 String AbstractEngine::GetFormatString(Format f) {
615 switch(f) {
616 case GIG: return "GIG";
617 case SF2: return "SF2";
618 case SFZ: return "SFZ";
619 default: return "UNKNOWN";
620 }
621 }
622
623 String AbstractEngine::EngineName() {
624 return GetFormatString(GetEngineFormat());
625 }
626
627 // static constant initializers
628 const AbstractEngine::FloatTable AbstractEngine::VolumeCurve(InitVolumeCurve());
629 const AbstractEngine::FloatTable AbstractEngine::PanCurve(InitPanCurve());
630 const AbstractEngine::FloatTable AbstractEngine::CrossfadeCurve(InitCrossfadeCurve());
631
632 float* AbstractEngine::InitVolumeCurve() {
633 // line-segment approximation
634 const float segments[] = {
635 0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
636 64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
637 };
638 return InitCurve(segments);
639 }
640
641 float* AbstractEngine::InitPanCurve() {
642 // line-segment approximation
643 const float segments[] = {
644 0, 0, 1, 0,
645 2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
646 127, 1.41, 128, 1.41
647 };
648 return InitCurve(segments, 129);
649 }
650
651 float* AbstractEngine::InitCrossfadeCurve() {
652 // line-segment approximation
653 const float segments[] = {
654 0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
655 };
656 return InitCurve(segments);
657 }
658
659 float* AbstractEngine::InitCurve(const float* segments, int size) {
660 float* y = new float[size];
661 for (int x = 0 ; x < size ; x++) {
662 if (x > segments[2]) segments += 2;
663 y[x] = segments[1] + (x - segments[0]) *
664 (segments[3] - segments[1]) / (segments[2] - segments[0]);
665 }
666 return y;
667 }
668
669 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC