/[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 2559 - (hide annotations) (download)
Sun May 18 17:38:25 2014 UTC (9 years, 11 months ago) by schoenebeck
File size: 31031 byte(s)
* Aftertouch: extended API to explicitly handle channel pressure and
  polyphonic key pressure events (so far polyphonic pressure was not
  supported at all, and channel pressure was rerouted as CC128 but not
  used so far).
* Gig Engine: Fixed support for 'aftertouch' attenuation controller.
* Bumped version (1.0.0.svn39).

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

  ViewVC Help
Powered by ViewVC