/[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 3707 - (hide annotations) (download)
Wed Jan 8 21:21:58 2020 UTC (5 months, 3 weeks ago) by schoenebeck
File size: 33427 byte(s)
Fixed compiler warnings about format specifiers:

Use portable format specifiers like PRId64 from inttypes.h
instead of assuming a particular word size.

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 3707 * Copyright (C) 2005-2020 Christian Schoenebeck *
7     * Copyright (C) 2009-2012 Grigor Iliev *
8     * Copyright (C) 2013-2016 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     /**
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 schoenebeck 2611 pEngine->CreateInstrumentScriptVM();
65 iliev 2012 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 schoenebeck 3707 dmsg(4,("This Engine has now %" PRId64 " EngineChannels.\n", (int64_t)pEngine->engineChannels.size()));
73 iliev 2012 return pEngine;
74     }
75    
76 schoenebeck 2611 AbstractEngine::AbstractEngine() {
77 iliev 2012 pAudioOutputDevice = NULL;
78 schoenebeck 3283 pEventGenerator = new EventGenerator(44100);
79 iliev 2012 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 schoenebeck 2879 pEventPool->setPoolElementIDsReservedBits(INSTR_SCRIPT_EVENT_ID_RESERVED_BITS);
83 iliev 2012 pGlobalEvents = new RTList<Event>(pEventPool);
84     FrameTime = 0;
85 persson 2091 RandomSeed = 0;
86 schoenebeck 2121 pDedicatedVoiceChannelLeft = pDedicatedVoiceChannelRight = NULL;
87 schoenebeck 2611 pScriptVM = NULL;
88 iliev 2012 }
89    
90     AbstractEngine::~AbstractEngine() {
91     if (pEventQueue) delete pEventQueue;
92     if (pEventPool) delete pEventPool;
93     if (pEventGenerator) delete pEventGenerator;
94     if (pGlobalEvents) delete pGlobalEvents;
95     if (pSysexBuffer) delete pSysexBuffer;
96 schoenebeck 2121 if (pDedicatedVoiceChannelLeft) delete pDedicatedVoiceChannelLeft;
97     if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
98 schoenebeck 2594 if (pScriptVM) delete pScriptVM;
99 iliev 2012 Unregister();
100     }
101    
102 schoenebeck 2611 void AbstractEngine::CreateInstrumentScriptVM() {
103     dmsg(2,("Created sampler format independent instrument script VM.\n"));
104     if (pScriptVM) return;
105     pScriptVM = new InstrumentScriptVM; // format independent script runner
106 schoenebeck 2600 }
107    
108     /**
109 iliev 2012 * 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 schoenebeck 3707 else dmsg(4,("This Engine has now %" PRId64 " EngineChannels.\n", (int64_t)pEngine->engineChannels.size()));
131 iliev 2012 }
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 schoenebeck 3501 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)\n",
318     ((iChan) ? "R" : "L"), iChan, iDstChan));
319 schoenebeck 2121 return false; // error
320     }
321     AudioChannel* pDstChan = NULL;
322 schoenebeck 3501 Effect* pEffect = NULL;
323 schoenebeck 2137 if (pFxSend->DestinationEffectChain() >= 0) { // fx send routed to an internal send effect
324 schoenebeck 2121 EffectChain* pEffectChain =
325 iliev 2198 pAudioOutputDevice->SendEffectChainByID(
326 schoenebeck 2137 pFxSend->DestinationEffectChain()
327 schoenebeck 2121 );
328     if (!pEffectChain) {
329 schoenebeck 3501 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d\n",
330     ((iChan) ? "R" : "L"), pFxSend->DestinationEffectChain()));
331 schoenebeck 2121 return false; // error
332     }
333 schoenebeck 3501 pEffect =
334 schoenebeck 2121 pEffectChain->GetEffect(
335 schoenebeck 2137 pFxSend->DestinationEffectChainPosition()
336 schoenebeck 2121 );
337     if (!pEffect) {
338 schoenebeck 3501 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d\n",
339     ((iChan) ? "R" : "L"), pFxSend->DestinationEffectChainPosition(), pFxSend->DestinationEffectChain()));
340 schoenebeck 2121 return false; // error
341     }
342     pDstChan = pEffect->InputChannel(iDstChan);
343 schoenebeck 3501 } else { // FX send routed directly to audio output device channel(s)
344 schoenebeck 2121 pDstChan = pAudioOutputDevice->Channel(iDstChan);
345     }
346     if (!pDstChan) {
347 schoenebeck 3501 if (pFxSend->DestinationEffectChain() >= 0) { // fx send routed to an internal send effect
348     const int iEffectChannels = pEffect ? pEffect->InputChannelCount() : 0;
349     dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d): "
350     "FX send is routed to effect %d of effect chain %d and that effect has %d input channels\n",
351     ((iChan) ? "R" : "L"), iChan, iDstChan,
352     pFxSend->DestinationEffectChainPosition(),
353     pFxSend->DestinationEffectChain(), iEffectChannels));
354     } else { // FX send routed directly to audio output device channel(s)
355     dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d): "
356     "FX send is directly routed to audio output device which has %d output channels\n",
357     ((iChan) ? "R" : "L"), iChan, iDstChan,
358     (pAudioOutputDevice ? pAudioOutputDevice->ChannelCount() : 0)));
359     }
360 schoenebeck 2121 return false; // error
361     }
362     ppSource[iChan]->MixTo(pDstChan, Samples, FxSendLevel);
363     }
364     return true; // success
365     }
366 iliev 2012
367     /**
368     * Calculates the Roland GS sysex check sum.
369     *
370     * @param AddrReader - reader which currently points to the first GS
371     * command address byte of the GS sysex message in
372     * question
373     * @param DataSize - size of the GS message data (in bytes)
374     */
375     uint8_t AbstractEngine::GSCheckSum(const RingBuffer<uint8_t,false>::NonVolatileReader AddrReader, uint DataSize) {
376     RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
377 schoenebeck 2500 uint bytes = 3 /*addr*/ + DataSize;
378 iliev 2012 uint8_t sum = 0;
379 schoenebeck 2500 uint8_t c;
380     for (uint i = 0; i < bytes; ++i) {
381     if (!reader.pop(&c)) break;
382     sum += c;
383     }
384 iliev 2012 return 128 - sum % 128;
385     }
386    
387     /**
388     * Allows to tune each of the twelve semitones of an octave.
389     *
390     * @param ScaleTunes - detuning of all twelve semitones (in cents)
391     */
392 schoenebeck 2448 void AbstractEngine::AdjustScaleTuning(const int8_t ScaleTunes[12]) {
393     memcpy(&this->ScaleTuning[0], &ScaleTunes[0], 12);
394     ScaleTuningChanged.raise();
395 iliev 2012 }
396 schoenebeck 2448
397     void AbstractEngine::GetScaleTuning(int8_t* pScaleTunes) {
398     memcpy(pScaleTunes, &this->ScaleTuning[0], 12);
399     }
400 iliev 2012
401     uint AbstractEngine::VoiceCount() {
402     return atomic_read(&ActiveVoiceCount);
403     }
404    
405     void AbstractEngine::SetVoiceCount(uint Count) {
406     atomic_set(&ActiveVoiceCount, Count);
407     }
408    
409     uint AbstractEngine::VoiceCountMax() {
410     return ActiveVoiceCountMax;
411     }
412    
413     /**
414 schoenebeck 2559 * Stores the latest pitchbend event as current pitchbend scalar value.
415 iliev 2012 *
416     * @param pEngineChannel - engine channel on which this event occured on
417     * @param itPitchbendEvent - absolute pitch value and time stamp of the event
418     */
419     void AbstractEngine::ProcessPitchbend(AbstractEngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
420     pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value
421     }
422    
423     void AbstractEngine::ProcessFxSendControllers (
424     AbstractEngineChannel* pEngineChannel,
425     Pool<Event>::Iterator& itControlChangeEvent
426     ) {
427     if (!pEngineChannel->fxSends.empty()) {
428     for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
429     FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
430     if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) {
431     pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
432     pFxSend->SetInfoChanged(true);
433     }
434     }
435     }
436     }
437    
438     /**
439     * Will be called by the MIDI input device whenever a MIDI system
440     * exclusive message has arrived.
441     *
442     * @param pData - pointer to sysex data
443     * @param Size - lenght of sysex data (in bytes)
444     * @param pSender - the MIDI input port on which the SysEx message was
445     * received
446     */
447     void AbstractEngine::SendSysex(void* pData, uint Size, MidiInputPort* pSender) {
448     Event event = pEventGenerator->CreateEvent();
449     event.Type = Event::type_sysex;
450     event.Param.Sysex.Size = Size;
451     event.pEngineChannel = NULL; // as Engine global event
452     event.pMidiInputPort = pSender;
453     if (pEventQueue->write_space() > 0) {
454     if (pSysexBuffer->write_space() >= Size) {
455     // copy sysex data to input buffer
456     uint toWrite = Size;
457     uint8_t* pPos = (uint8_t*) pData;
458     while (toWrite) {
459     const uint writeNow = RTMath::Min(toWrite, pSysexBuffer->write_space_to_end());
460     pSysexBuffer->write(pPos, writeNow);
461     toWrite -= writeNow;
462     pPos += writeNow;
463    
464     }
465     // finally place sysex event into input event queue
466     pEventQueue->push(&event);
467     }
468     else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,CONFIG_SYSEX_BUFFER_SIZE));
469     }
470     else dmsg(1,("Engine: Input event queue full!"));
471     }
472    
473     /**
474     * Reacts on MIDI system exclusive messages.
475     *
476     * @param itSysexEvent - sysex data size and time stamp of the sysex event
477     */
478     void AbstractEngine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
479     RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
480    
481     uint8_t exclusive_status, id;
482     if (!reader.pop(&exclusive_status)) goto free_sysex_data;
483     if (!reader.pop(&id)) goto free_sysex_data;
484     if (exclusive_status != 0xF0) goto free_sysex_data;
485    
486     switch (id) {
487     case 0x7f: { // (Realtime) Universal Sysex (GM Standard)
488     uint8_t sysex_channel, sub_id1, sub_id2, val_msb, val_lsb;;
489     if (!reader.pop(&sysex_channel)) goto free_sysex_data;
490     if (!reader.pop(&sub_id1)) goto free_sysex_data;
491     if (!reader.pop(&sub_id2)) goto free_sysex_data;
492     if (!reader.pop(&val_lsb)) goto free_sysex_data;
493     if (!reader.pop(&val_msb)) goto free_sysex_data;
494     //TODO: for now we simply ignore the sysex channel, seldom used anyway
495     switch (sub_id1) {
496     case 0x04: // Device Control
497     switch (sub_id2) {
498     case 0x01: { // Master Volume
499     const double volume =
500     double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0;
501     #if CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
502     // apply volume to all sampler channels that
503     // are connected to the same MIDI input port
504     // this sysex message arrived on
505     for (int i = 0; i < engineChannels.size(); ++i) {
506     EngineChannel* pEngineChannel = engineChannels[i];
507     if (pEngineChannel->GetMidiInputPort() ==
508     itSysexEvent->pMidiInputPort)
509     {
510     pEngineChannel->Volume(volume);
511     }
512     }
513     #else
514     // apply volume globally to the whole sampler
515     GLOBAL_VOLUME = volume;
516     #endif // CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
517     break;
518     }
519     }
520     break;
521     }
522     break;
523     }
524     case 0x41: { // Roland
525     dmsg(3,("Roland Sysex\n"));
526     uint8_t device_id, model_id, cmd_id;
527     if (!reader.pop(&device_id)) goto free_sysex_data;
528     if (!reader.pop(&model_id)) goto free_sysex_data;
529     if (!reader.pop(&cmd_id)) goto free_sysex_data;
530     if (model_id != 0x42 /*GS*/) goto free_sysex_data;
531     if (cmd_id != 0x12 /*DT1*/) goto free_sysex_data;
532    
533     // command address
534     uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB)
535 schoenebeck 3034 //const RingBuffer<uint8_t,false>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later
536 iliev 2012 if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
537     if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
538     dmsg(3,("\tSystem Parameter\n"));
539     if (addr[2] == 0x7f) { // GS reset
540     for (int i = 0; i < engineChannels.size(); ++i) {
541     AbstractEngineChannel* pEngineChannel
542     = static_cast<AbstractEngineChannel*>(engineChannels[i]);
543 schoenebeck 2500 Sync< ArrayList<MidiInputPort*> > midiInputs = pEngineChannel->midiInputs.front();
544     for (int k = 0; k < midiInputs->size(); ++k) {
545     if ((*midiInputs)[k] == itSysexEvent->pMidiInputPort) {
546     KillAllVoices(pEngineChannel, itSysexEvent);
547     pEngineChannel->ResetControllers();
548     break;
549     }
550 iliev 2012 }
551     }
552     }
553     }
554     else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
555     dmsg(3,("\tCommon Parameter\n"));
556     }
557     else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)
558     dmsg(3,("\tPart Parameter\n"));
559     switch (addr[2]) {
560     case 0x40: { // scale tuning
561     dmsg(3,("\t\tScale Tuning\n"));
562     uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave
563     if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;
564     uint8_t checksum;
565     if (!reader.pop(&checksum)) goto free_sysex_data;
566     #if CONFIG_ASSERT_GS_SYSEX_CHECKSUM
567     if (GSCheckSum(checksum_reader, 12)) goto free_sysex_data;
568     #endif // CONFIG_ASSERT_GS_SYSEX_CHECKSUM
569     for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;
570 schoenebeck 2448 AdjustScaleTuning((int8_t*) scale_tunes);
571 iliev 2012 dmsg(3,("\t\t\tNew scale applied.\n"));
572     break;
573     }
574     case 0x15: { // chromatic / drumkit mode
575     dmsg(3,("\t\tMIDI Instrument Map Switch\n"));
576     uint8_t part = addr[1] & 0x0f;
577     uint8_t map;
578     if (!reader.pop(&map)) goto free_sysex_data;
579     for (int i = 0; i < engineChannels.size(); ++i) {
580     AbstractEngineChannel* pEngineChannel
581     = static_cast<AbstractEngineChannel*>(engineChannels[i]);
582 schoenebeck 2500 if (pEngineChannel->midiChannel == part ||
583     pEngineChannel->midiChannel == midi_chan_all)
584     {
585     Sync< ArrayList<MidiInputPort*> > midiInputs = pEngineChannel->midiInputs.front();
586     for (int k = 0; k < midiInputs->size(); ++k) {
587     if ((*midiInputs)[k] == itSysexEvent->pMidiInputPort) {
588     try {
589     pEngineChannel->SetMidiInstrumentMap(map);
590     } catch (Exception e) {
591     dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d: %s\n", map, part, e.Message().c_str()));
592     goto free_sysex_data;
593     } catch (...) {
594     dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d (unknown exception)\n", map, part));
595     goto free_sysex_data;
596     }
597     break;
598     }
599 iliev 2012 }
600     }
601     }
602     dmsg(3,("\t\t\tApplied MIDI instrument map %d to part %d.\n", map, part));
603     break;
604     }
605     }
606     }
607     else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)
608     }
609     else if (addr[0] == 0x41) { // Drum Setup Parameters
610     }
611     break;
612     }
613     }
614    
615     free_sysex_data: // finally free sysex data
616     pSysexBuffer->increment_read_ptr(itSysexEvent->Param.Sysex.Size);
617     }
618    
619     String AbstractEngine::GetFormatString(Format f) {
620     switch(f) {
621     case GIG: return "GIG";
622     case SF2: return "SF2";
623     case SFZ: return "SFZ";
624     default: return "UNKNOWN";
625     }
626     }
627    
628     String AbstractEngine::EngineName() {
629     return GetFormatString(GetEngineFormat());
630     }
631    
632     // static constant initializers
633     const AbstractEngine::FloatTable AbstractEngine::VolumeCurve(InitVolumeCurve());
634     const AbstractEngine::FloatTable AbstractEngine::PanCurve(InitPanCurve());
635     const AbstractEngine::FloatTable AbstractEngine::CrossfadeCurve(InitCrossfadeCurve());
636    
637     float* AbstractEngine::InitVolumeCurve() {
638     // line-segment approximation
639     const float segments[] = {
640     0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
641     64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
642     };
643     return InitCurve(segments);
644     }
645    
646     float* AbstractEngine::InitPanCurve() {
647     // line-segment approximation
648     const float segments[] = {
649     0, 0, 1, 0,
650     2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
651     127, 1.41, 128, 1.41
652     };
653     return InitCurve(segments, 129);
654     }
655    
656     float* AbstractEngine::InitCrossfadeCurve() {
657     // line-segment approximation
658     const float segments[] = {
659     0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
660     };
661     return InitCurve(segments);
662     }
663    
664     float* AbstractEngine::InitCurve(const float* segments, int size) {
665     float* y = new float[size];
666     for (int x = 0 ; x < size ; x++) {
667     if (x > segments[2]) segments += 2;
668     y[x] = segments[1] + (x - segments[0]) *
669     (segments[3] - segments[1]) / (segments[2] - segments[0]);
670     }
671     return y;
672     }
673    
674 schoenebeck 2931 /**
675     * Returns the volume factor to be used for the requested signed,
676     * normalized @a pan value and audio @a channel index.
677     *
678     * @param pan - between -1.0 (most left) and +1.0 (most right)
679     * @param channel - 0: return value for left channel, 1: return value for right channel
680     * @returns final volume factor for the requested audio channel to be applied
681     */
682     float AbstractEngine::PanCurveValueNorm(float pan, int channel) {
683     float pan128 = (pan + 1.f) / 2.f * 128.f;
684     if (channel == 0) pan128 = 128 - pan128;
685     return PanCurve[pan128]; //TODO: interpolation should be done here (float type "pan" argument here allows a much more fine graded result value than those 129 steps of the PanCurve)
686     }
687    
688 iliev 2012 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC