/[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 2594 - (show annotations) (download)
Thu Jun 5 00:16:25 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 31451 byte(s)
* ScriptVM (WIP): started to integrate real-time instrument script
  support into the sampler engine implementations. The code is
  shared among all sampler engines, however currently only the gig
  file format supports storing instrument scripts (as LinuxSampler
  extension to the original GigaStudio 4 file format).
* gig engine: Added support for loading instrument scripts from .gig
  files.
* ScriptVM (WIP): Implemented built-in script variables %CC, $CC_NUM,
  $EVENT_NOTE, $EVENT_VELOCITY, $VCC_MONO_AT, $VCC_PITCH_BEND.
* ScriptVM (WIP): Implemented execution of script event handler "init".
* ScriptVM (WIP): Implemented execution of script event handler
  "controller".
* Bumped version (1.0.0.svn42).

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 = new InstrumentScriptVM;
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 * Once an engine channel is disconnected from an audio output device,
110 * it will immediately call this method to unregister itself from the
111 * engine instance and if that engine instance is not used by any other
112 * engine channel anymore, then that engine instance will be destroyed.
113 *
114 * @param pChannel - engine channel which wants to disconnect from it's
115 * engine instance
116 * @param pDevice - audio output device \a pChannel was connected to
117 */
118 void AbstractEngine::FreeEngine(AbstractEngineChannel* pChannel, AudioOutputDevice* pDevice) {
119 dmsg(4,("Disconnecting EngineChannel from Engine.\n"));
120 AbstractEngine* pEngine = engines[pChannel->GetEngineFormat()][pDevice];
121 // unregister EngineChannel from the Engine instance
122 pEngine->engineChannels.remove(pChannel);
123 // if the used Engine instance is not used anymore, then destroy it
124 if (pEngine->engineChannels.empty()) {
125 pDevice->Disconnect(pEngine);
126 engines[pChannel->GetEngineFormat()].erase(pDevice);
127 delete pEngine;
128 dmsg(4,("Destroying Engine.\n"));
129 }
130 else dmsg(4,("This Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
131 }
132
133 void AbstractEngine::Enable() {
134 dmsg(3,("AbstractEngine: enabling\n"));
135 EngineDisabled.PushAndUnlock(false, 2, 0, true); // set condition object 'EngineDisabled' to false (wait max. 2s)
136 dmsg(3,("AbstractEngine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
137 }
138
139 /**
140 * Temporarily stop the engine to not do anything. The engine will just be
141 * frozen during that time, that means after enabling it again it will
142 * continue where it was, with all its voices and playback state it had at
143 * the point of disabling. Notice that the engine's (audio) thread will
144 * continue to run, it just remains in an inactive loop during that time.
145 *
146 * If you need to be sure that all voices and disk streams are killed as
147 * well, use @c SuspendAll() instead.
148 *
149 * @see Enable(), SuspendAll()
150 */
151 void AbstractEngine::Disable() {
152 dmsg(3,("AbstractEngine: disabling\n"));
153 bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s
154 if (!pWasDisabled) dmsg(3,("AbstractEngine warning: Timeout waiting to disable engine.\n"));
155 }
156
157 void AbstractEngine::DisableAndLock() {
158 dmsg(3,("AbstractEngine: disabling\n"));
159 bool* pWasDisabled = EngineDisabled.Push(true, 2); // wait max. 2s
160 if (!pWasDisabled) dmsg(3,("AbstractEngine warning: Timeout waiting to disable engine.\n"));
161 }
162
163 /**
164 * Reset all voices and disk thread and clear input event queue and all
165 * control and status variables.
166 */
167 void AbstractEngine::Reset() {
168 DisableAndLock();
169 ResetInternal();
170 ResetScaleTuning();
171 Enable();
172 }
173
174 /**
175 * Reset to normal, chromatic scale (means equal tempered).
176 */
177 void AbstractEngine::ResetScaleTuning() {
178 memset(&ScaleTuning[0], 0x00, 12);
179 ScaleTuningChanged.raise();
180 }
181
182 /**
183 * Copy all events from the engine's global input queue buffer to the
184 * engine's internal event list. This will be done at the beginning of
185 * each audio cycle (that is each RenderAudio() call) to distinguish
186 * all global events which have to be processed in the current audio
187 * cycle. These events are usually just SysEx messages. Every
188 * EngineChannel has it's own input event queue buffer and event list
189 * to handle common events like NoteOn, NoteOff and ControlChange
190 * events.
191 *
192 * @param Samples - number of sample points to be processed in the
193 * current audio cycle
194 */
195 void AbstractEngine::ImportEvents(uint Samples) {
196 RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
197 Event* pEvent;
198 while (true) {
199 // get next event from input event queue
200 if (!(pEvent = eventQueueReader.pop())) break;
201 // if younger event reached, ignore that and all subsequent ones for now
202 if (pEvent->FragmentPos() >= Samples) {
203 eventQueueReader--;
204 dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
205 pEvent->ResetFragmentPos();
206 break;
207 }
208 // copy event to internal event list
209 if (pGlobalEvents->poolIsEmpty()) {
210 dmsg(1,("Event pool emtpy!\n"));
211 break;
212 }
213 *pGlobalEvents->allocAppend() = *pEvent;
214 }
215 eventQueueReader.free(); // free all copied events from input queue
216 }
217
218 /**
219 * Clear all engine global event lists.
220 */
221 void AbstractEngine::ClearEventLists() {
222 pGlobalEvents->clear();
223 }
224
225 /**
226 * Will be called in case the respective engine channel sports FX send
227 * channels. In this particular case, engine channel local buffers are
228 * used to render and mix all voices to. This method is responsible for
229 * copying the audio data from those local buffers to the master audio
230 * output channels as well as to the FX send audio output channels with
231 * their respective FX send levels.
232 *
233 * @param pEngineChannel - engine channel from which audio should be
234 * routed
235 * @param Samples - amount of sample points to be routed in
236 * this audio fragment cycle
237 */
238 void AbstractEngine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
239 AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
240 AudioChannel* ppSource[2] = {
241 pChannel->pChannelLeft,
242 pChannel->pChannelRight
243 };
244 // route dry signal
245 {
246 AudioChannel* pDstL = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelLeft);
247 AudioChannel* pDstR = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelRight);
248 ppSource[0]->MixTo(pDstL, Samples);
249 ppSource[1]->MixTo(pDstR, Samples);
250 }
251 // route FX send signal (wet)
252 {
253 for (int iFxSend = 0; iFxSend < pChannel->GetFxSendCount(); iFxSend++) {
254 FxSend* pFxSend = pChannel->GetFxSend(iFxSend);
255 const bool success = RouteFxSend(pFxSend, ppSource, pFxSend->Level(), Samples);
256 if (!success) goto channel_cleanup;
257 }
258 }
259 channel_cleanup:
260 // reset buffers with silence (zero out) for the next audio cycle
261 ppSource[0]->Clear();
262 ppSource[1]->Clear();
263 }
264
265 /**
266 * Similar to RouteAudio(), but this method is even more special. It is
267 * only called by voices which have dedicated effect send(s) level(s). So
268 * such voices have to be routed separately apart from the other voices
269 * which can just be mixed together and routed afterwards in one turn.
270 */
271 void AbstractEngine::RouteDedicatedVoiceChannels(EngineChannel* pEngineChannel, optional<float> FxSendLevels[2], uint Samples) {
272 AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
273 AudioChannel* ppSource[2] = {
274 pDedicatedVoiceChannelLeft,
275 pDedicatedVoiceChannelRight
276 };
277 // route dry signal
278 {
279 AudioChannel* pDstL = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelLeft);
280 AudioChannel* pDstR = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelRight);
281 ppSource[0]->MixTo(pDstL, Samples);
282 ppSource[1]->MixTo(pDstR, Samples);
283 }
284 // route FX send signals (wet)
285 // (we simply hard code the voices 'reverb send' to the 1st effect
286 // send bus, and the voioces 'chorus send' to the 2nd effect send bus)
287 {
288 for (int iFxSend = 0; iFxSend < 2 && iFxSend < pChannel->GetFxSendCount(); iFxSend++) {
289 // no voice specific FX send level defined for this effect?
290 if (!FxSendLevels[iFxSend]) continue; // ignore this effect then
291
292 FxSend* pFxSend = pChannel->GetFxSend(iFxSend);
293 const bool success = RouteFxSend(pFxSend, ppSource, *FxSendLevels[iFxSend], Samples);
294 if (!success) goto channel_cleanup;
295 }
296 }
297 channel_cleanup:
298 // reset buffers with silence (zero out) for the next dedicated voice rendering/routing process
299 ppSource[0]->Clear();
300 ppSource[1]->Clear();
301 }
302
303 /**
304 * Route the audio signal given by @a ppSource to the effect send bus
305 * defined by @a pFxSend (wet signal only).
306 *
307 * @param pFxSend - definition of effect send bus
308 * @param ppSource - the 2 channels of the audio signal to be routed
309 * @param FxSendLevel - the effect send level to by applied
310 * @param Samples - amount of sample points to be processed
311 * @returns true if signal was routed successfully, false on error
312 */
313 bool AbstractEngine::RouteFxSend(FxSend* pFxSend, AudioChannel* ppSource[2], float FxSendLevel, uint Samples) {
314 for (int iChan = 0; iChan < 2; ++iChan) {
315 const int iDstChan = pFxSend->DestinationChannel(iChan);
316 if (iDstChan < 0) {
317 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
318 return false; // error
319 }
320 AudioChannel* pDstChan = NULL;
321 if (pFxSend->DestinationEffectChain() >= 0) { // fx send routed to an internal send effect
322 EffectChain* pEffectChain =
323 pAudioOutputDevice->SendEffectChainByID(
324 pFxSend->DestinationEffectChain()
325 );
326 if (!pEffectChain) {
327 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationEffectChain()));
328 return false; // error
329 }
330 Effect* pEffect =
331 pEffectChain->GetEffect(
332 pFxSend->DestinationEffectChainPosition()
333 );
334 if (!pEffect) {
335 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationEffectChainPosition(), pFxSend->DestinationEffectChain()));
336 return false; // error
337 }
338 pDstChan = pEffect->InputChannel(iDstChan);
339 } else { // FX send routed directly to an audio output channel
340 pDstChan = pAudioOutputDevice->Channel(iDstChan);
341 }
342 if (!pDstChan) {
343 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
344 return false; // error
345 }
346 ppSource[iChan]->MixTo(pDstChan, Samples, FxSendLevel);
347 }
348 return true; // success
349 }
350
351 /**
352 * Calculates the Roland GS sysex check sum.
353 *
354 * @param AddrReader - reader which currently points to the first GS
355 * command address byte of the GS sysex message in
356 * question
357 * @param DataSize - size of the GS message data (in bytes)
358 */
359 uint8_t AbstractEngine::GSCheckSum(const RingBuffer<uint8_t,false>::NonVolatileReader AddrReader, uint DataSize) {
360 RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
361 uint bytes = 3 /*addr*/ + DataSize;
362 uint8_t sum = 0;
363 uint8_t c;
364 for (uint i = 0; i < bytes; ++i) {
365 if (!reader.pop(&c)) break;
366 sum += c;
367 }
368 return 128 - sum % 128;
369 }
370
371 /**
372 * Allows to tune each of the twelve semitones of an octave.
373 *
374 * @param ScaleTunes - detuning of all twelve semitones (in cents)
375 */
376 void AbstractEngine::AdjustScaleTuning(const int8_t ScaleTunes[12]) {
377 memcpy(&this->ScaleTuning[0], &ScaleTunes[0], 12);
378 ScaleTuningChanged.raise();
379 }
380
381 void AbstractEngine::GetScaleTuning(int8_t* pScaleTunes) {
382 memcpy(pScaleTunes, &this->ScaleTuning[0], 12);
383 }
384
385 uint AbstractEngine::VoiceCount() {
386 return atomic_read(&ActiveVoiceCount);
387 }
388
389 void AbstractEngine::SetVoiceCount(uint Count) {
390 atomic_set(&ActiveVoiceCount, Count);
391 }
392
393 uint AbstractEngine::VoiceCountMax() {
394 return ActiveVoiceCountMax;
395 }
396
397 /**
398 * Stores the latest pitchbend event as current pitchbend scalar value.
399 *
400 * @param pEngineChannel - engine channel on which this event occured on
401 * @param itPitchbendEvent - absolute pitch value and time stamp of the event
402 */
403 void AbstractEngine::ProcessPitchbend(AbstractEngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
404 pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value
405 }
406
407 void AbstractEngine::ProcessFxSendControllers (
408 AbstractEngineChannel* pEngineChannel,
409 Pool<Event>::Iterator& itControlChangeEvent
410 ) {
411 if (!pEngineChannel->fxSends.empty()) {
412 for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
413 FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
414 if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) {
415 pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
416 pFxSend->SetInfoChanged(true);
417 }
418 }
419 }
420 }
421
422 /**
423 * Will be called by the MIDI input device whenever a MIDI system
424 * exclusive message has arrived.
425 *
426 * @param pData - pointer to sysex data
427 * @param Size - lenght of sysex data (in bytes)
428 * @param pSender - the MIDI input port on which the SysEx message was
429 * received
430 */
431 void AbstractEngine::SendSysex(void* pData, uint Size, MidiInputPort* pSender) {
432 Event event = pEventGenerator->CreateEvent();
433 event.Type = Event::type_sysex;
434 event.Param.Sysex.Size = Size;
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