/[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 2121 - (show 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 /***************************************************************************
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
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 RandomSeed = 0;
82 pDedicatedVoiceChannelLeft = pDedicatedVoiceChannelRight = NULL;
83 }
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 if (pDedicatedVoiceChannelLeft) delete pDedicatedVoiceChannelLeft;
92 if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
93 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 AudioChannel* ppSource[2] = {
228 pChannel->pChannelLeft,
229 pChannel->pChannelRight
230 };
231 // route dry signal
232 {
233 AudioChannel* pDstL = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelLeft);
234 AudioChannel* pDstR = pAudioOutputDevice->Channel(pChannel->AudioDeviceChannelRight);
235 ppSource[0]->MixTo(pDstL, Samples);
236 ppSource[1]->MixTo(pDstR, Samples);
237 }
238 // route FX send signal (wet)
239 {
240 for (int iFxSend = 0; iFxSend < pChannel->GetFxSendCount(); iFxSend++) {
241 FxSend* pFxSend = pChannel->GetFxSend(iFxSend);
242 const bool success = RouteFxSend(pFxSend, ppSource, pFxSend->Level(), Samples);
243 if (!success) goto channel_cleanup;
244 }
245 }
246 channel_cleanup:
247 // reset buffers with silence (zero out) for the next audio cycle
248 ppSource[0]->Clear();
249 ppSource[1]->Clear();
250 }
251
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
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