/[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 2121 - (hide annotations) (download)
Tue Sep 14 17:09:08 2010 UTC (9 years, 9 months ago) by schoenebeck
File size: 30238 byte(s)
* implemented Roland GS NRPN 1ArrH which allows to set volume per note
* implemented Roland GS NRPN 1CrrH which allows to set pan per note
* implemented Roland GS NRPN 1DrrH which allows to set reverb send per
  note (in this implementation of the sampler its simply hard routed to
  the 1st effect send of the sampler channel, no matter what the actual
  effect type is)
* implemented Roland GS NRPN 1ErrH which allows to set chorus send per
  note (in this implementation of the sampler its simply hard routed to
  the 2nd effect send of the sampler channel, no matter what the actual
  effect type is)
* bumped version to 1.0.0cvs4

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     if (pFxSend->DestinationMasterEffectChain() >= 0) { // fx send routed to an internal master effect
309     EffectChain* pEffectChain =
310     pAudioOutputDevice->MasterEffectChain(
311     pFxSend->DestinationMasterEffectChain()
312     );
313     if (!pEffectChain) {
314     dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffectChain()));
315     return false; // error
316     }
317     Effect* pEffect =
318     pEffectChain->GetEffect(
319     pFxSend->DestinationMasterEffect()
320     );
321     if (!pEffect) {
322     dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffect(), pFxSend->DestinationMasterEffectChain()));
323     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