358 |
this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle(); |
this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle(); |
359 |
this->SampleRate = pAudioOutputDevice->SampleRate(); |
this->SampleRate = pAudioOutputDevice->SampleRate(); |
360 |
|
|
361 |
// FIXME: audio drivers with varying fragment sizes might be a problem here |
MinFadeOutSamples = int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1; |
362 |
MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1; |
if (MaxSamplesPerCycle < MinFadeOutSamples) { |
|
if (MaxFadeOutPos < 0) { |
|
363 |
std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME " |
std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME " |
364 |
<< "too big for current audio fragment size & sampling rate! " |
<< "too big for current audio fragment size & sampling rate! " |
365 |
<< "May lead to click sounds if voice stealing chimes in!\n" << std::flush; |
<< "May lead to click sounds if voice stealing chimes in!\n" << std::flush; |
366 |
// force volume ramp downs at the beginning of each fragment |
// force volume ramp downs at the beginning of each fragment |
367 |
MaxFadeOutPos = 0; |
MinFadeOutSamples = MaxSamplesPerCycle; |
368 |
// lower minimum release time |
// lower minimum release time |
369 |
const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate; |
const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate; |
370 |
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()) { |
573 |
// return if engine disabled |
// return if engine disabled |
574 |
if (EngineDisabled.Pop()) { |
if (EngineDisabled.Pop()) { |
575 |
dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe())); |
dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe())); |
576 |
|
EngineDisabled.RttDone(); |
577 |
return 0; |
return 0; |
578 |
} |
} |
579 |
|
|
699 |
} |
} |
700 |
FrameTime += Samples; |
FrameTime += Samples; |
701 |
|
|
702 |
|
EngineDisabled.RttDone(); |
703 |
return 0; |
return 0; |
704 |
} |
} |
705 |
|
|
858 |
* this audio fragment cycle |
* this audio fragment cycle |
859 |
*/ |
*/ |
860 |
void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) { |
void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) { |
861 |
// route master signal |
// route dry signal |
862 |
{ |
{ |
863 |
AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft); |
AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft); |
864 |
AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight); |
AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight); |
869 |
{ |
{ |
870 |
for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) { |
for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) { |
871 |
FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend); |
FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend); |
872 |
// left channel |
for (int iChan = 0; iChan < 2; ++iChan) { |
873 |
const int iDstL = pFxSend->DestinationChannel(0); |
AudioChannel* pSource = |
874 |
if (iDstL < 0) { |
(iChan) |
875 |
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel")); |
? pEngineChannel->pChannelRight |
876 |
} else { |
: pEngineChannel->pChannelLeft; |
877 |
AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL); |
const int iDstChan = pFxSend->DestinationChannel(iChan); |
878 |
if (!pDstL) { |
if (iDstChan < 0) { |
879 |
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel")); |
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan)); |
880 |
} else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level()); |
goto channel_cleanup; |
881 |
} |
} |
882 |
// right channel |
AudioChannel* pDstChan = NULL; |
883 |
const int iDstR = pFxSend->DestinationChannel(1); |
if (pFxSend->DestinationMasterEffectChain() >= 0) { // fx send routed to an internal master effect |
884 |
if (iDstR < 0) { |
EffectChain* pEffectChain = |
885 |
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel")); |
pAudioOutputDevice->MasterEffectChain( |
886 |
} else { |
pFxSend->DestinationMasterEffectChain() |
887 |
AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR); |
); |
888 |
if (!pDstR) { |
if (!pEffectChain) { |
889 |
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel")); |
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffectChain())); |
890 |
} else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level()); |
goto channel_cleanup; |
891 |
|
} |
892 |
|
Effect* pEffect = |
893 |
|
pEffectChain->GetEffect( |
894 |
|
pFxSend->DestinationMasterEffect() |
895 |
|
); |
896 |
|
if (!pEffect) { |
897 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffect(), pFxSend->DestinationMasterEffectChain())); |
898 |
|
goto channel_cleanup; |
899 |
|
} |
900 |
|
pDstChan = pEffect->InputChannel(iDstChan); |
901 |
|
} else { // FX send routed directly to an audio output channel |
902 |
|
pDstChan = pAudioOutputDevice->Channel(iDstChan); |
903 |
|
} |
904 |
|
if (!pDstChan) { |
905 |
|
dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan)); |
906 |
|
goto channel_cleanup; |
907 |
|
} |
908 |
|
pSource->MixTo(pDstChan, Samples, pFxSend->Level()); |
909 |
} |
} |
910 |
} |
} |
911 |
} |
} |
912 |
|
channel_cleanup: |
913 |
// reset buffers with silence (zero out) for the next audio cycle |
// reset buffers with silence (zero out) for the next audio cycle |
914 |
pEngineChannel->pChannelLeft->Clear(); |
pEngineChannel->pChannelLeft->Clear(); |
915 |
pEngineChannel->pChannelRight->Clear(); |
pEngineChannel->pChannelRight->Clear(); |
955 |
* |
* |
956 |
* @param pData - pointer to sysex data |
* @param pData - pointer to sysex data |
957 |
* @param Size - lenght of sysex data (in bytes) |
* @param Size - lenght of sysex data (in bytes) |
958 |
|
* @param pSender - the MIDI input port on which the SysEx message was |
959 |
|
* received |
960 |
*/ |
*/ |
961 |
void Engine::SendSysex(void* pData, uint Size) { |
void Engine::SendSysex(void* pData, uint Size, MidiInputPort* pSender) { |
962 |
Event event = pEventGenerator->CreateEvent(); |
Event event = pEventGenerator->CreateEvent(); |
963 |
event.Type = Event::type_sysex; |
event.Type = Event::type_sysex; |
964 |
event.Param.Sysex.Size = Size; |
event.Param.Sysex.Size = Size; |
965 |
event.pEngineChannel = NULL; // as Engine global event |
event.pEngineChannel = NULL; // as Engine global event |
966 |
|
event.pMidiInputPort = pSender; |
967 |
if (pEventQueue->write_space() > 0) { |
if (pEventQueue->write_space() > 0) { |
968 |
if (pSysexBuffer->write_space() >= Size) { |
if (pSysexBuffer->write_space() >= Size) { |
969 |
// copy sysex data to input buffer |
// copy sysex data to input buffer |
1732 |
//TODO: not sample accurate yet |
//TODO: not sample accurate yet |
1733 |
pEngineChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value]; |
pEngineChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value]; |
1734 |
pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value]; |
pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value]; |
1735 |
|
pEngineChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value; |
1736 |
break; |
break; |
1737 |
} |
} |
1738 |
case 64: { // sustain |
case 64: { // sustain |
1873 |
if (!pEngineChannel->fxSends.empty()) { |
if (!pEngineChannel->fxSends.empty()) { |
1874 |
for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) { |
for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) { |
1875 |
FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend); |
FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend); |
1876 |
if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) |
if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) { |
1877 |
pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value); |
pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value); |
1878 |
pFxSend->SetInfoChanged(true); |
pFxSend->SetInfoChanged(true); |
1879 |
|
} |
1880 |
} |
} |
1881 |
} |
} |
1882 |
} |
} |
1895 |
if (exclusive_status != 0xF0) goto free_sysex_data; |
if (exclusive_status != 0xF0) goto free_sysex_data; |
1896 |
|
|
1897 |
switch (id) { |
switch (id) { |
1898 |
|
case 0x7f: { // (Realtime) Universal Sysex (GM Standard) |
1899 |
|
uint8_t sysex_channel, sub_id1, sub_id2, val_msb, val_lsb;; |
1900 |
|
if (!reader.pop(&sysex_channel)) goto free_sysex_data; |
1901 |
|
if (!reader.pop(&sub_id1)) goto free_sysex_data; |
1902 |
|
if (!reader.pop(&sub_id2)) goto free_sysex_data; |
1903 |
|
if (!reader.pop(&val_lsb)) goto free_sysex_data; |
1904 |
|
if (!reader.pop(&val_msb)) goto free_sysex_data; |
1905 |
|
//TODO: for now we simply ignore the sysex channel, seldom used anyway |
1906 |
|
switch (sub_id1) { |
1907 |
|
case 0x04: // Device Control |
1908 |
|
switch (sub_id2) { |
1909 |
|
case 0x01: { // Master Volume |
1910 |
|
const double volume = |
1911 |
|
double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0; |
1912 |
|
#if CONFIG_MASTER_VOLUME_SYSEX_BY_PORT |
1913 |
|
// apply volume to all sampler channels that |
1914 |
|
// are connected to the same MIDI input port |
1915 |
|
// this sysex message arrived on |
1916 |
|
for (int i = 0; i < engineChannels.size(); ++i) { |
1917 |
|
EngineChannel* pEngineChannel = engineChannels[i]; |
1918 |
|
if (pEngineChannel->GetMidiInputPort() == |
1919 |
|
itSysexEvent->pMidiInputPort) |
1920 |
|
{ |
1921 |
|
pEngineChannel->Volume(volume); |
1922 |
|
} |
1923 |
|
} |
1924 |
|
#else |
1925 |
|
// apply volume globally to the whole sampler |
1926 |
|
GLOBAL_VOLUME = volume; |
1927 |
|
#endif // CONFIG_MASTER_VOLUME_SYSEX_BY_PORT |
1928 |
|
break; |
1929 |
|
} |
1930 |
|
} |
1931 |
|
break; |
1932 |
|
} |
1933 |
|
break; |
1934 |
|
} |
1935 |
case 0x41: { // Roland |
case 0x41: { // Roland |
1936 |
dmsg(3,("Roland Sysex\n")); |
dmsg(3,("Roland Sysex\n")); |
1937 |
uint8_t device_id, model_id, cmd_id; |
uint8_t device_id, model_id, cmd_id; |
1968 |
dmsg(3,("\t\t\tNew scale applied.\n")); |
dmsg(3,("\t\t\tNew scale applied.\n")); |
1969 |
break; |
break; |
1970 |
} |
} |
1971 |
|
case 0x15: { // chromatic / drumkit mode |
1972 |
|
dmsg(3,("\t\tMIDI Instrument Map Switch\n")); |
1973 |
|
uint8_t part = addr[1] & 0x0f; |
1974 |
|
uint8_t map; |
1975 |
|
if (!reader.pop(&map)) goto free_sysex_data; |
1976 |
|
for (int i = 0; i < engineChannels.size(); ++i) { |
1977 |
|
EngineChannel* pEngineChannel = engineChannels[i]; |
1978 |
|
if ( |
1979 |
|
(pEngineChannel->midiChannel == part || |
1980 |
|
pEngineChannel->midiChannel == midi_chan_all) && |
1981 |
|
pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort |
1982 |
|
) { |
1983 |
|
try { |
1984 |
|
pEngineChannel->SetMidiInstrumentMap(map); |
1985 |
|
} catch (Exception e) { |
1986 |
|
dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d: %s\n", map, part, e.Message().c_str())); |
1987 |
|
goto free_sysex_data; |
1988 |
|
} catch (...) { |
1989 |
|
dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d (unknown exception)\n", map, part)); |
1990 |
|
goto free_sysex_data; |
1991 |
|
} |
1992 |
|
} |
1993 |
|
} |
1994 |
|
dmsg(3,("\t\t\tApplied MIDI instrument map %d to part %d.\n", map, part)); |
1995 |
|
break; |
1996 |
|
} |
1997 |
} |
} |
1998 |
} |
} |
1999 |
else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2) |
else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2) |
2136 |
} |
} |
2137 |
|
|
2138 |
String Engine::Version() { |
String Engine::Version() { |
2139 |
String s = "$Revision: 1.88 $"; |
String s = "$Revision: 1.97 $"; |
2140 |
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 |
2141 |
} |
} |
2142 |
|
|