/[svn]/linuxsampler/trunk/src/engines/AbstractEngine.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/AbstractEngine.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2448 - (show 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 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005-2008 Christian Schoenebeck *
7 * Copyright (C) 2009-2010 Christian Schoenebeck and Grigor Iliev *
8 * *
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 #include "../effects/EffectFactory.h"
30
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 RandomSeed = 0;
83 pDedicatedVoiceChannelLeft = pDedicatedVoiceChannelRight = NULL;
84 }
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 if (pDedicatedVoiceChannelLeft) delete pDedicatedVoiceChannelLeft;
93 if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
94 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 ScaleTuningChanged.raise();
169 }
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 AudioChannel* ppSource[2] = {
230 pChannel->pChannelLeft,
231 pChannel->pChannelRight
232 };
233 // route dry signal
234 {
235 AudioChannel* pDstL = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelLeft);
236 AudioChannel* pDstR = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelRight);
237 ppSource[0]->MixTo(pDstL, Samples);
238 ppSource[1]->MixTo(pDstR, Samples);
239 }
240 // route FX send signal (wet)
241 {
242 for (int iFxSend = 0; iFxSend < pChannel->GetFxSendCount(); iFxSend++) {
243 FxSend* pFxSend = pChannel->GetFxSend(iFxSend);
244 const bool success = RouteFxSend(pFxSend, ppSource, pFxSend->Level(), Samples);
245 if (!success) goto channel_cleanup;
246 }
247 }
248 channel_cleanup:
249 // reset buffers with silence (zero out) for the next audio cycle
250 ppSource[0]->Clear();
251 ppSource[1]->Clear();
252 }
253
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 if (pFxSend->DestinationEffectChain() >= 0) { // fx send routed to an internal send effect
311 EffectChain* pEffectChain =
312 pAudioOutputDevice->SendEffectChainByID(
313 pFxSend->DestinationEffectChain()
314 );
315 if (!pEffectChain) {
316 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationEffectChain()));
317 return false; // error
318 }
319 Effect* pEffect =
320 pEffectChain->GetEffect(
321 pFxSend->DestinationEffectChainPosition()
322 );
323 if (!pEffect) {
324 dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationEffectChainPosition(), pFxSend->DestinationEffectChain()));
325 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
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 void AbstractEngine::AdjustScaleTuning(const int8_t ScaleTunes[12]) {
364 memcpy(&this->ScaleTuning[0], &ScaleTunes[0], 12);
365 ScaleTuningChanged.raise();
366 }
367
368 void AbstractEngine::GetScaleTuning(int8_t* pScaleTunes) {
369 memcpy(pScaleTunes, &this->ScaleTuning[0], 12);
370 }
371
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 AdjustScaleTuning((int8_t*) scale_tunes);
540 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