51 |
if (engines.count(pDevice)) { |
if (engines.count(pDevice)) { |
52 |
dmsg(4,("Using existing gig::Engine.\n")); |
dmsg(4,("Using existing gig::Engine.\n")); |
53 |
pEngine = engines[pDevice]; |
pEngine = engines[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 |
} else { // create a new engine (and disk thread) instance for the given audio output device |
60 |
dmsg(4,("Creating new gig::Engine.\n")); |
dmsg(4,("Creating new gig::Engine.\n")); |
61 |
pEngine = (Engine*) EngineFactory::Create("gig"); |
pEngine = (Engine*) EngineFactory::Create("gig"); |
106 |
pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); |
pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); |
107 |
pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT); |
pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT); |
108 |
pVoicePool = new Pool<Voice>(CONFIG_MAX_VOICES); |
pVoicePool = new Pool<Voice>(CONFIG_MAX_VOICES); |
109 |
|
pDimRegionsInUse = new ::gig::DimensionRegion*[CONFIG_MAX_VOICES + 1]; |
110 |
pVoiceStealingQueue = new RTList<Event>(pEventPool); |
pVoiceStealingQueue = new RTList<Event>(pEventPool); |
111 |
pGlobalEvents = new RTList<Event>(pEventPool); |
pGlobalEvents = new RTList<Event>(pEventPool); |
112 |
|
InstrumentChangeQueue = new RingBuffer<instrument_change_command_t,false>(1, 0); |
113 |
|
InstrumentChangeReplyQueue = new RingBuffer<instrument_change_reply_t,false>(1, 0); |
114 |
|
|
115 |
for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { |
for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { |
116 |
iterVoice->SetEngine(this); |
iterVoice->SetEngine(this); |
117 |
} |
} |
266 |
delete this->pDiskThread; |
delete this->pDiskThread; |
267 |
dmsg(1,("OK\n")); |
dmsg(1,("OK\n")); |
268 |
} |
} |
269 |
this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6); //FIXME: assuming stereo |
this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo |
270 |
|
&instruments); |
271 |
if (!pDiskThread) { |
if (!pDiskThread) { |
272 |
dmsg(0,("gig::Engine new diskthread = NULL\n")); |
dmsg(0,("gig::Engine new diskthread = NULL\n")); |
273 |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
387 |
// reset internal voice counter (just for statistic of active voices) |
// reset internal voice counter (just for statistic of active voices) |
388 |
ActiveVoiceCountTemp = 0; |
ActiveVoiceCountTemp = 0; |
389 |
|
|
390 |
|
// handle instrument change commands |
391 |
|
instrument_change_command_t command; |
392 |
|
if (InstrumentChangeQueue->pop(&command) > 0) { |
393 |
|
EngineChannel* pEngineChannel = command.pEngineChannel; |
394 |
|
pEngineChannel->pInstrument = command.pInstrument; |
395 |
|
|
396 |
|
// iterate through all active voices and mark their |
397 |
|
// dimension regions as "in use". The instrument resource |
398 |
|
// manager may delete all of the instrument except the |
399 |
|
// dimension regions and samples that are in use. |
400 |
|
int i = 0; |
401 |
|
RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first(); |
402 |
|
RTList<uint>::Iterator end = pEngineChannel->pActiveKeys->end(); |
403 |
|
while (iuiKey != end) { // iterate through all active keys |
404 |
|
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey]; |
405 |
|
++iuiKey; |
406 |
|
|
407 |
|
RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first(); |
408 |
|
RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end(); |
409 |
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
410 |
|
if (!itVoice->Orphan) { |
411 |
|
itVoice->Orphan = true; |
412 |
|
pDimRegionsInUse[i++] = itVoice->pDimRgn; |
413 |
|
} |
414 |
|
} |
415 |
|
} |
416 |
|
pDimRegionsInUse[i] = 0; // end of list |
417 |
|
|
418 |
|
// send a reply to the calling thread, which is waiting |
419 |
|
instrument_change_reply_t reply; |
420 |
|
InstrumentChangeReplyQueue->push(&reply); |
421 |
|
} |
422 |
|
|
423 |
// handle events on all engine channels |
// handle events on all engine channels |
424 |
for (int i = 0; i < engineChannels.size(); i++) { |
for (int i = 0; i < engineChannels.size(); i++) { |
|
if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded |
|
425 |
ProcessEvents(engineChannels[i], Samples); |
ProcessEvents(engineChannels[i], Samples); |
426 |
} |
} |
427 |
|
|
428 |
// render all 'normal', active voices on all engine channels |
// render all 'normal', active voices on all engine channels |
429 |
for (int i = 0; i < engineChannels.size(); i++) { |
for (int i = 0; i < engineChannels.size(); i++) { |
|
if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded |
|
430 |
RenderActiveVoices(engineChannels[i], Samples); |
RenderActiveVoices(engineChannels[i], Samples); |
431 |
} |
} |
432 |
|
|
441 |
|
|
442 |
// handle cleanup on all engine channels for the next audio fragment |
// handle cleanup on all engine channels for the next audio fragment |
443 |
for (int i = 0; i < engineChannels.size(); i++) { |
for (int i = 0; i < engineChannels.size(); i++) { |
|
if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded |
|
444 |
PostProcess(engineChannels[i]); |
PostProcess(engineChannels[i]); |
445 |
} |
} |
446 |
|
|
559 |
RTList<Event>::Iterator end = pVoiceStealingQueue->end(); |
RTList<Event>::Iterator end = pVoiceStealingQueue->end(); |
560 |
for (; itVoiceStealEvent != end; ++itVoiceStealEvent) { |
for (; itVoiceStealEvent != end; ++itVoiceStealEvent) { |
561 |
EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel; |
EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel; |
562 |
|
if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded |
563 |
Pool<Voice>::Iterator itNewVoice = |
Pool<Voice>::Iterator itNewVoice = |
564 |
LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false); |
LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false); |
565 |
if (itNewVoice) { |
if (itNewVoice) { |
707 |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
708 |
#endif |
#endif |
709 |
|
|
710 |
|
if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded |
711 |
|
|
712 |
|
//HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing |
713 |
|
itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose; |
714 |
|
|
715 |
const int key = itNoteOnEvent->Param.Note.Key; |
const int key = itNoteOnEvent->Param.Note.Key; |
716 |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key]; |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key]; |
717 |
|
|
799 |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted |
800 |
#endif |
#endif |
801 |
|
|
802 |
|
//HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing |
803 |
|
itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose; |
804 |
|
|
805 |
const int iKey = itNoteOffEvent->Param.Note.Key; |
const int iKey = itNoteOffEvent->Param.Note.Key; |
806 |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey]; |
midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey]; |
807 |
pKey->KeyPressed = false; // the MIDI key was now released |
pKey->KeyPressed = false; // the MIDI key was now released |
812 |
bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key); |
bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key); |
813 |
|
|
814 |
// in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any) |
// in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any) |
815 |
if (pEngineChannel->SoloMode) { //TODO: this feels like too much code just for handling solo mode :P |
if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P |
816 |
bool bOtherKeysPressed = false; |
bool bOtherKeysPressed = false; |
817 |
if (iKey == pEngineChannel->SoloKey) { |
if (iKey == pEngineChannel->SoloKey) { |
818 |
pEngineChannel->SoloKey = -1; |
pEngineChannel->SoloKey = -1; |
875 |
itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type |
itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type |
876 |
|
|
877 |
// spawn release triggered voice(s) if needed |
// spawn release triggered voice(s) if needed |
878 |
if (pKey->ReleaseTrigger) { |
if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) { |
879 |
// first, get total amount of required voices (dependant on amount of layers) |
// first, get total amount of required voices (dependant on amount of layers) |
880 |
::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key); |
::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key); |
881 |
if (pRegion) { |
if (pRegion) { |
1070 |
std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush; |
std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush; |
1071 |
} |
} |
1072 |
} |
} |
1073 |
|
|
1074 |
|
// return if this is a release triggered voice and there is no |
1075 |
|
// releasetrigger dimension (could happen if an instrument |
1076 |
|
// change has occured between note on and off) |
1077 |
|
if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator(); |
1078 |
|
|
1079 |
::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues); |
::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues); |
1080 |
|
|
1081 |
// no need to continue if sample is silent |
// no need to continue if sample is silent |
1305 |
|
|
1306 |
uint keygroup = itVoice->KeyGroup; |
uint keygroup = itVoice->KeyGroup; |
1307 |
|
|
1308 |
|
// if the sample and dimension region belong to an |
1309 |
|
// instrument that is unloaded, tell the disk thread to |
1310 |
|
// release them |
1311 |
|
if (itVoice->Orphan) { |
1312 |
|
pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn); |
1313 |
|
} |
1314 |
|
|
1315 |
// free the voice object |
// free the voice object |
1316 |
pVoicePool->free(itVoice); |
pVoicePool->free(itVoice); |
1317 |
|
|
1362 |
pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN; |
pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN; |
1363 |
break; |
break; |
1364 |
} |
} |
1365 |
|
case 6: { // data entry (currently only used for RPN controllers) |
1366 |
|
if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones |
1367 |
|
int transpose = (int) itControlChangeEvent->Param.CC.Value - 64; |
1368 |
|
// limit to +- two octaves for now |
1369 |
|
transpose = RTMath::Min(transpose, 24); |
1370 |
|
transpose = RTMath::Max(transpose, -24); |
1371 |
|
pEngineChannel->GlobalTranspose = transpose; |
1372 |
|
// workaround, so we won't have hanging notes |
1373 |
|
ReleaseAllVoices(pEngineChannel, itControlChangeEvent); |
1374 |
|
} |
1375 |
|
break; |
1376 |
|
} |
1377 |
case 7: { // volume |
case 7: { // volume |
1378 |
//TODO: not sample accurate yet |
//TODO: not sample accurate yet |
1379 |
pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value]; |
pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value]; |
1478 |
} |
} |
1479 |
break; |
break; |
1480 |
} |
} |
1481 |
|
case 100: { // RPN controller LSB |
1482 |
|
pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value); |
1483 |
|
break; |
1484 |
|
} |
1485 |
|
case 101: { // RPN controller MSB |
1486 |
|
pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value); |
1487 |
|
break; |
1488 |
|
} |
1489 |
|
|
1490 |
|
|
1491 |
// Channel Mode Messages |
// Channel Mode Messages |
1718 |
} |
} |
1719 |
|
|
1720 |
String Engine::Version() { |
String Engine::Version() { |
1721 |
String s = "$Revision: 1.70 $"; |
String s = "$Revision: 1.74 $"; |
1722 |
return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword |
return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword |
1723 |
} |
} |
1724 |
|
|
1768 |
return y; |
return y; |
1769 |
} |
} |
1770 |
|
|
1771 |
|
/** |
1772 |
|
* Changes the instrument for an engine channel. |
1773 |
|
* |
1774 |
|
* @param pEngineChannel - engine channel on which the instrument |
1775 |
|
* should be changed |
1776 |
|
* @param pInstrument - new instrument |
1777 |
|
* @returns a list of dimension regions from the old instrument |
1778 |
|
* that are still in use |
1779 |
|
*/ |
1780 |
|
::gig::DimensionRegion** Engine::ChangeInstrument(EngineChannel* pEngineChannel, ::gig::Instrument* pInstrument) { |
1781 |
|
instrument_change_command_t command; |
1782 |
|
command.pEngineChannel = pEngineChannel; |
1783 |
|
command.pInstrument = pInstrument; |
1784 |
|
InstrumentChangeQueue->push(&command); |
1785 |
|
|
1786 |
|
// wait for the audio thread to confirm that the instrument |
1787 |
|
// change has been done |
1788 |
|
instrument_change_reply_t reply; |
1789 |
|
while (InstrumentChangeReplyQueue->pop(&reply) == 0) { |
1790 |
|
usleep(10000); |
1791 |
|
} |
1792 |
|
return pDimRegionsInUse; |
1793 |
|
} |
1794 |
|
|
1795 |
}} // namespace LinuxSampler::gig |
}} // namespace LinuxSampler::gig |