/[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 2500 - (hide annotations) (download)
Fri Jan 10 12:20:05 2014 UTC (10 years, 3 months ago) by schoenebeck
File size: 31130 byte(s)
* Added support for multiple MIDI input ports per sampler channel (added
  various new C++ API methods for this new feature/design, old C++ API
  methods are now marked as deprecated but should still provide full
  behavior backward compatibility).
* LSCP Network interface: Added the following new LSCP commands for the new
  feature mentioned above: "ADD CHANNEL MIDI_INPUT",
  "REMOVE CHANNEL MIDI_INPUT" and "LIST CHANNEL MIDI_INPUTS". As with the
  C++ API changes, the old LSCP commands for MIDI input management are now
  marked as deprecated, but are still there and should provide full behavior
  backward compatibility.
* New LSCP specification document (LSCP v1.6).
* AbstractEngine::GSCheckSum(): don't allocate memory on the stack (was
  unsafe and caused compilation error with old clang 2.x).
* Bumped version (1.0.0.svn25).

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     * Moves pitchbend event from the general (input) event list to the engine
389     * channel's event list. It will actually processed later by the
390     * respective voice.
391     *
392     * @param pEngineChannel - engine channel on which this event occured on
393     * @param itPitchbendEvent - absolute pitch value and time stamp of the event
394     */
395     void AbstractEngine::ProcessPitchbend(AbstractEngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
396     pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value
397     }
398    
399     void AbstractEngine::ProcessFxSendControllers (
400     AbstractEngineChannel* pEngineChannel,
401     Pool<Event>::Iterator& itControlChangeEvent
402     ) {
403     if (!pEngineChannel->fxSends.empty()) {
404     for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
405     FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
406     if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) {
407     pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
408     pFxSend->SetInfoChanged(true);
409     }
410     }
411     }
412     }
413    
414     /**
415     * Will be called by the MIDI input device whenever a MIDI system
416     * exclusive message has arrived.
417     *
418     * @param pData - pointer to sysex data
419     * @param Size - lenght of sysex data (in bytes)
420     * @param pSender - the MIDI input port on which the SysEx message was
421     * received
422     */
423     void AbstractEngine::SendSysex(void* pData, uint Size, MidiInputPort* pSender) {
424     Event event = pEventGenerator->CreateEvent();
425     event.Type = Event::type_sysex;
426     event.Param.Sysex.Size = Size;
427     event.pEngineChannel = NULL; // as Engine global event
428     event.pMidiInputPort = pSender;
429     if (pEventQueue->write_space() > 0) {
430     if (pSysexBuffer->write_space() >= Size) {
431     // copy sysex data to input buffer
432     uint toWrite = Size;
433     uint8_t* pPos = (uint8_t*) pData;
434     while (toWrite) {
435     const uint writeNow = RTMath::Min(toWrite, pSysexBuffer->write_space_to_end());
436     pSysexBuffer->write(pPos, writeNow);
437     toWrite -= writeNow;
438     pPos += writeNow;
439    
440     }
441     // finally place sysex event into input event queue
442     pEventQueue->push(&event);
443     }
444     else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,CONFIG_SYSEX_BUFFER_SIZE));
445     }
446     else dmsg(1,("Engine: Input event queue full!"));
447     }
448    
449     /**
450     * Reacts on MIDI system exclusive messages.
451     *
452     * @param itSysexEvent - sysex data size and time stamp of the sysex event
453     */
454     void AbstractEngine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
455     RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
456    
457     uint8_t exclusive_status, id;
458     if (!reader.pop(&exclusive_status)) goto free_sysex_data;
459     if (!reader.pop(&id)) goto free_sysex_data;
460     if (exclusive_status != 0xF0) goto free_sysex_data;
461    
462     switch (id) {
463     case 0x7f: { // (Realtime) Universal Sysex (GM Standard)
464     uint8_t sysex_channel, sub_id1, sub_id2, val_msb, val_lsb;;
465     if (!reader.pop(&sysex_channel)) goto free_sysex_data;
466     if (!reader.pop(&sub_id1)) goto free_sysex_data;
467     if (!reader.pop(&sub_id2)) goto free_sysex_data;
468     if (!reader.pop(&val_lsb)) goto free_sysex_data;
469     if (!reader.pop(&val_msb)) goto free_sysex_data;
470     //TODO: for now we simply ignore the sysex channel, seldom used anyway
471     switch (sub_id1) {
472     case 0x04: // Device Control
473     switch (sub_id2) {
474     case 0x01: { // Master Volume
475     const double volume =
476     double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0;
477     #if CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
478     // apply volume to all sampler channels that
479     // are connected to the same MIDI input port
480     // this sysex message arrived on
481     for (int i = 0; i < engineChannels.size(); ++i) {
482     EngineChannel* pEngineChannel = engineChannels[i];
483     if (pEngineChannel->GetMidiInputPort() ==
484     itSysexEvent->pMidiInputPort)
485     {
486     pEngineChannel->Volume(volume);
487     }
488     }
489     #else
490     // apply volume globally to the whole sampler
491     GLOBAL_VOLUME = volume;
492     #endif // CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
493     break;
494     }
495     }
496     break;
497     }
498     break;
499     }
500     case 0x41: { // Roland
501     dmsg(3,("Roland Sysex\n"));
502     uint8_t device_id, model_id, cmd_id;
503     if (!reader.pop(&device_id)) goto free_sysex_data;
504     if (!reader.pop(&model_id)) goto free_sysex_data;
505     if (!reader.pop(&cmd_id)) goto free_sysex_data;
506     if (model_id != 0x42 /*GS*/) goto free_sysex_data;
507     if (cmd_id != 0x12 /*DT1*/) goto free_sysex_data;
508    
509     // command address
510     uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB)
511     const RingBuffer<uint8_t,false>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later
512     if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
513     if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
514     dmsg(3,("\tSystem Parameter\n"));
515     if (addr[2] == 0x7f) { // GS reset
516     for (int i = 0; i < engineChannels.size(); ++i) {
517     AbstractEngineChannel* pEngineChannel
518     = static_cast<AbstractEngineChannel*>(engineChannels[i]);
519 schoenebeck 2500 Sync< ArrayList<MidiInputPort*> > midiInputs = pEngineChannel->midiInputs.front();
520     for (int k = 0; k < midiInputs->size(); ++k) {
521     if ((*midiInputs)[k] == itSysexEvent->pMidiInputPort) {
522     KillAllVoices(pEngineChannel, itSysexEvent);
523     pEngineChannel->ResetControllers();
524     break;
525     }
526 iliev 2012 }
527     }
528     }
529     }
530     else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
531     dmsg(3,("\tCommon Parameter\n"));
532     }
533     else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)
534     dmsg(3,("\tPart Parameter\n"));
535     switch (addr[2]) {
536     case 0x40: { // scale tuning
537     dmsg(3,("\t\tScale Tuning\n"));
538     uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave
539     if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;
540     uint8_t checksum;
541     if (!reader.pop(&checksum)) goto free_sysex_data;
542     #if CONFIG_ASSERT_GS_SYSEX_CHECKSUM
543     if (GSCheckSum(checksum_reader, 12)) goto free_sysex_data;
544     #endif // CONFIG_ASSERT_GS_SYSEX_CHECKSUM
545     for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;
546 schoenebeck 2448 AdjustScaleTuning((int8_t*) scale_tunes);
547 iliev 2012 dmsg(3,("\t\t\tNew scale applied.\n"));
548     break;
549     }
550     case 0x15: { // chromatic / drumkit mode
551     dmsg(3,("\t\tMIDI Instrument Map Switch\n"));
552     uint8_t part = addr[1] & 0x0f;
553     uint8_t map;
554     if (!reader.pop(&map)) goto free_sysex_data;
555     for (int i = 0; i < engineChannels.size(); ++i) {
556     AbstractEngineChannel* pEngineChannel
557     = static_cast<AbstractEngineChannel*>(engineChannels[i]);
558 schoenebeck 2500 if (pEngineChannel->midiChannel == part ||
559     pEngineChannel->midiChannel == midi_chan_all)
560     {
561     Sync< ArrayList<MidiInputPort*> > midiInputs = pEngineChannel->midiInputs.front();
562     for (int k = 0; k < midiInputs->size(); ++k) {
563     if ((*midiInputs)[k] == itSysexEvent->pMidiInputPort) {
564     try {
565     pEngineChannel->SetMidiInstrumentMap(map);
566     } catch (Exception e) {
567     dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d: %s\n", map, part, e.Message().c_str()));
568     goto free_sysex_data;
569     } catch (...) {
570     dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d (unknown exception)\n", map, part));
571     goto free_sysex_data;
572     }
573     break;
574     }
575 iliev 2012 }
576     }
577     }
578     dmsg(3,("\t\t\tApplied MIDI instrument map %d to part %d.\n", map, part));
579     break;
580     }
581     }
582     }
583     else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)
584     }
585     else if (addr[0] == 0x41) { // Drum Setup Parameters
586     }
587     break;
588     }
589     }
590    
591     free_sysex_data: // finally free sysex data
592     pSysexBuffer->increment_read_ptr(itSysexEvent->Param.Sysex.Size);
593     }
594    
595     String AbstractEngine::GetFormatString(Format f) {
596     switch(f) {
597     case GIG: return "GIG";
598     case SF2: return "SF2";
599     case SFZ: return "SFZ";
600     default: return "UNKNOWN";
601     }
602     }
603    
604     String AbstractEngine::EngineName() {
605     return GetFormatString(GetEngineFormat());
606     }
607    
608     // static constant initializers
609     const AbstractEngine::FloatTable AbstractEngine::VolumeCurve(InitVolumeCurve());
610     const AbstractEngine::FloatTable AbstractEngine::PanCurve(InitPanCurve());
611     const AbstractEngine::FloatTable AbstractEngine::CrossfadeCurve(InitCrossfadeCurve());
612    
613     float* AbstractEngine::InitVolumeCurve() {
614     // line-segment approximation
615     const float segments[] = {
616     0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
617     64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
618     };
619     return InitCurve(segments);
620     }
621    
622     float* AbstractEngine::InitPanCurve() {
623     // line-segment approximation
624     const float segments[] = {
625     0, 0, 1, 0,
626     2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
627     127, 1.41, 128, 1.41
628     };
629     return InitCurve(segments, 129);
630     }
631    
632     float* AbstractEngine::InitCrossfadeCurve() {
633     // line-segment approximation
634     const float segments[] = {
635     0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
636     };
637     return InitCurve(segments);
638     }
639    
640     float* AbstractEngine::InitCurve(const float* segments, int size) {
641     float* y = new float[size];
642     for (int x = 0 ; x < size ; x++) {
643     if (x > segments[2]) segments += 2;
644     y[x] = segments[1] + (x - segments[0]) *
645     (segments[3] - segments[1]) / (segments[2] - segments[0]);
646     }
647     return y;
648     }
649    
650     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC