/[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 2448 - (hide annotations) (download)
Fri May 3 14:26:32 2013 UTC (10 years, 11 months ago) by schoenebeck
File size: 30448 byte(s)
* Immediately apply scale tuning changes to active voices.
* Exposed scale tuning to C++ API (along to the already existing standard
  SysEx way).
* Bumped version to 1.0.0.svn21

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

  ViewVC Help
Powered by ViewVC