/[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 2137 - (hide annotations) (download)
Mon Oct 4 12:20:23 2010 UTC (9 years, 9 months ago) by schoenebeck
File size: 30224 byte(s)
* revised previously added new LSCP commands regarding effect handling:
  renamed "master effects" to "send effects", since this is the actual
  correct common term for those effects
* also corrected the names regarding "send effects" in the respective
  methods of the "FxSsnd" class and "AudioOutputDevice" class of the
  sampler's C++ API, the old methods are still available but marked as
  deprecated and scheduled for removal
* added LSCP command "SET FX_SEND SEND_EFFECT <sampler_channel>
  <fx_send_id> <effect_chain> <chain_pos>"
* added LSCP command "REMOVE FX_SEND SEND_EFFECT <sampler_channel>
  <fx_send_id>"
* added a list of common known LADSPA paths (for Windows and POSIX) which
  will be automatically checked for being used as LADSPA plugin directory
  (if the user did not set the LADSPA_PATH environment variable explicitly)
* bumped version to 1.0.0.cvs8

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

  ViewVC Help
Powered by ViewVC