/[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 2611 - (show annotations) (download)
Mon Jun 9 19:20:37 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 31505 byte(s)
* Fixed crash when loading an instrument script.
* Fixed "init" script handler only to be executed once:
  when the script was loaded.
* Fixed aftertouch script event which always had value zero
  and controller number was set to aftertouch value instead.
* gig Engine: Fixed handling of "smartmidi" dimension, which
  was recognized as "unknown" dimension.
* Fixed script function gig_set_dim_zone(): was accessing
  wrong event.
* ls_instr_script command line tool: is now not limited to
  core language scripts, but can now also parse sampler format
  dependent instrument scripts, with the respective specific
  built-in script variables and functions.
* ScriptVM: Fixed runtime behavior of "and" and "or" binary
  script expressions, which also evaluated the right hand side
  of the expression even if the left hand side already failed
  the overall expression semantic to become true.
* Bumped version (1.0.0.svn46).

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

  ViewVC Help
Powered by ViewVC