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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2594 - (hide 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 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 persson 2091 * Copyright (C) 2005-2008 Christian Schoenebeck *
7 schoenebeck 2500 * Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev *
8     * Copyright (C) 2013-2014 Christian Schoenebeck and Andreas Persson *
9 iliev 2012 * *
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 iliev 2296 #include "../effects/EffectFactory.h"
31 iliev 2012
32     namespace LinuxSampler {
33    
34     //InstrumentResourceManager Engine::instruments;
35    
36     std::map<AbstractEngine::Format, std::map<AudioOutputDevice*,AbstractEngine*> > AbstractEngine::engines;
37    
38 schoenebeck 2594 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 iliev 2012 /**
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 schoenebeck 2594 AbstractEngine::AbstractEngine() : scripts(this) {
84 iliev 2012 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 persson 2091 RandomSeed = 0;
92 schoenebeck 2121 pDedicatedVoiceChannelLeft = pDedicatedVoiceChannelRight = NULL;
93 schoenebeck 2594 pScriptVM = new InstrumentScriptVM;
94 iliev 2012 }
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 schoenebeck 2121 if (pDedicatedVoiceChannelLeft) delete pDedicatedVoiceChannelLeft;
103     if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
104 schoenebeck 2594 if (pScriptVM) delete pScriptVM;
105 iliev 2012 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 schoenebeck 2448 ScaleTuningChanged.raise();
180 iliev 2012 }
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 schoenebeck 2121 AudioChannel* ppSource[2] = {
241     pChannel->pChannelLeft,
242     pChannel->pChannelRight
243     };
244 iliev 2012 // route dry signal
245     {
246     AudioChannel* pDstL = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelLeft);
247     AudioChannel* pDstR = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelRight);
248 schoenebeck 2121 ppSource[0]->MixTo(pDstL, Samples);
249     ppSource[1]->MixTo(pDstR, Samples);
250 iliev 2012 }
251 schoenebeck 2121 // route FX send signal (wet)
252 iliev 2012 {
253     for (int iFxSend = 0; iFxSend < pChannel->GetFxSendCount(); iFxSend++) {
254     FxSend* pFxSend = pChannel->GetFxSend(iFxSend);
255 schoenebeck 2121 const bool success = RouteFxSend(pFxSend, ppSource, pFxSend->Level(), Samples);
256     if (!success) goto channel_cleanup;
257 iliev 2012 }
258     }
259     channel_cleanup:
260     // reset buffers with silence (zero out) for the next audio cycle
261 schoenebeck 2121 ppSource[0]->Clear();
262     ppSource[1]->Clear();
263 iliev 2012 }
264 schoenebeck 2121
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 schoenebeck 2137 if (pFxSend->DestinationEffectChain() >= 0) { // fx send routed to an internal send effect
322 schoenebeck 2121 EffectChain* pEffectChain =
323 iliev 2198 pAudioOutputDevice->SendEffectChainByID(
324 schoenebeck 2137 pFxSend->DestinationEffectChain()
325 schoenebeck 2121 );
326     if (!pEffectChain) {
327 schoenebeck 2137 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationEffectChain()));
328 schoenebeck 2121 return false; // error
329     }
330     Effect* pEffect =
331     pEffectChain->GetEffect(
332 schoenebeck 2137 pFxSend->DestinationEffectChainPosition()
333 schoenebeck 2121 );
334     if (!pEffect) {
335 schoenebeck 2137 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationEffectChainPosition(), pFxSend->DestinationEffectChain()));
336 schoenebeck 2121 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 iliev 2012
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 schoenebeck 2500 uint bytes = 3 /*addr*/ + DataSize;
362 iliev 2012 uint8_t sum = 0;
363 schoenebeck 2500 uint8_t c;
364     for (uint i = 0; i < bytes; ++i) {
365     if (!reader.pop(&c)) break;
366     sum += c;
367     }
368 iliev 2012 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 schoenebeck 2448 void AbstractEngine::AdjustScaleTuning(const int8_t ScaleTunes[12]) {
377     memcpy(&this->ScaleTuning[0], &ScaleTunes[0], 12);
378     ScaleTuningChanged.raise();
379 iliev 2012 }
380 schoenebeck 2448
381     void AbstractEngine::GetScaleTuning(int8_t* pScaleTunes) {
382     memcpy(pScaleTunes, &this->ScaleTuning[0], 12);
383     }
384 iliev 2012
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 schoenebeck 2559 * Stores the latest pitchbend event as current pitchbend scalar value.
399 iliev 2012 *
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 schoenebeck 2500 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 iliev 2012 }
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 schoenebeck 2448 AdjustScaleTuning((int8_t*) scale_tunes);
555 iliev 2012 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 schoenebeck 2500 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 iliev 2012 }
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