/[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 2606 - (hide 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 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 2600 pScriptVM = CreateInstrumentScriptVM();
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 schoenebeck 2600 * 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 iliev 2012 * 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 schoenebeck 2448 ScaleTuningChanged.raise();
190 iliev 2012 }
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 schoenebeck 2121 AudioChannel* ppSource[2] = {
251     pChannel->pChannelLeft,
252     pChannel->pChannelRight
253     };
254 iliev 2012 // route dry signal
255     {
256     AudioChannel* pDstL = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelLeft);
257     AudioChannel* pDstR = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelRight);
258 schoenebeck 2121 ppSource[0]->MixTo(pDstL, Samples);
259     ppSource[1]->MixTo(pDstR, Samples);
260 iliev 2012 }
261 schoenebeck 2121 // route FX send signal (wet)
262 iliev 2012 {
263     for (int iFxSend = 0; iFxSend < pChannel->GetFxSendCount(); iFxSend++) {
264     FxSend* pFxSend = pChannel->GetFxSend(iFxSend);
265 schoenebeck 2121 const bool success = RouteFxSend(pFxSend, ppSource, pFxSend->Level(), Samples);
266     if (!success) goto channel_cleanup;
267 iliev 2012 }
268     }
269     channel_cleanup:
270     // reset buffers with silence (zero out) for the next audio cycle
271 schoenebeck 2121 ppSource[0]->Clear();
272     ppSource[1]->Clear();
273 iliev 2012 }
274 schoenebeck 2121
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 schoenebeck 2137 if (pFxSend->DestinationEffectChain() >= 0) { // fx send routed to an internal send effect
332 schoenebeck 2121 EffectChain* pEffectChain =
333 iliev 2198 pAudioOutputDevice->SendEffectChainByID(
334 schoenebeck 2137 pFxSend->DestinationEffectChain()
335 schoenebeck 2121 );
336     if (!pEffectChain) {
337 schoenebeck 2137 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationEffectChain()));
338 schoenebeck 2121 return false; // error
339     }
340     Effect* pEffect =
341     pEffectChain->GetEffect(
342 schoenebeck 2137 pFxSend->DestinationEffectChainPosition()
343 schoenebeck 2121 );
344     if (!pEffect) {
345 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()));
346 schoenebeck 2121 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 iliev 2012
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 schoenebeck 2500 uint bytes = 3 /*addr*/ + DataSize;
372 iliev 2012 uint8_t sum = 0;
373 schoenebeck 2500 uint8_t c;
374     for (uint i = 0; i < bytes; ++i) {
375     if (!reader.pop(&c)) break;
376     sum += c;
377     }
378 iliev 2012 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 schoenebeck 2448 void AbstractEngine::AdjustScaleTuning(const int8_t ScaleTunes[12]) {
387     memcpy(&this->ScaleTuning[0], &ScaleTunes[0], 12);
388     ScaleTuningChanged.raise();
389 iliev 2012 }
390 schoenebeck 2448
391     void AbstractEngine::GetScaleTuning(int8_t* pScaleTunes) {
392     memcpy(pScaleTunes, &this->ScaleTuning[0], 12);
393     }
394 iliev 2012
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 schoenebeck 2559 * Stores the latest pitchbend event as current pitchbend scalar value.
409 iliev 2012 *
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 persson 2606 memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
446 iliev 2012 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 schoenebeck 2500 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 iliev 2012 }
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 schoenebeck 2448 AdjustScaleTuning((int8_t*) scale_tunes);
566 iliev 2012 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 schoenebeck 2500 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 iliev 2012 }
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