From e5ffc7847cb70f792b4658aa032959949e849669 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Wed, 4 Aug 2010 16:53:09 +0000 Subject: AUDIO: Implement volume and balance control for the AudioCD manager (needed for music fading in Kyra 1 FM-Towns and probably other FM-Towns games). This addition applies to emulated CD audio only for now. I haven't found a way to implement this for real CDs yet. SDL doesn't seem to support this (but it might be just me? If anyone knows more about this, just tell me). svn-id: r51741 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 90 +++++++++++++++++++++----- sound/softsynth/fmtowns_pc98/towns_audio.h | 3 + sound/softsynth/fmtowns_pc98/towns_euphony.cpp | 8 +-- sound/softsynth/fmtowns_pc98/towns_euphony.h | 4 +- 4 files changed, 81 insertions(+), 24 deletions(-) (limited to 'sound/softsynth/fmtowns_pc98') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp index 773c5a8067..42b9be804e 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -24,6 +24,7 @@ */ #include "sound/softsynth/fmtowns_pc98/towns_audio.h" +#include "sound/audiocd.h" #include "common/endian.h" @@ -101,8 +102,9 @@ private: TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns), _fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0), - _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), _pcmSfxChanMask(0), - _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), _ready(false) { + _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), + _pcmSfxChanMask(0), _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), + _cdaVolFlags(0), _ready(false) { #define INTCB(x) &TownsAudioInterface::intf_##x static const TownsAudioIntfCallback intfCb[] = { @@ -147,7 +149,7 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac INTCB(notImpl), INTCB(notImpl), // 32 - INTCB(notImpl), + INTCB(loadSamples), INTCB(reserveEffectChannels), INTCB(loadWaveTable), INTCB(unloadWaveTable), @@ -268,7 +270,6 @@ int TownsAudioInterface::callback(int command, ...) { return 4; } - Common::StackLock lock(_mutex); int res = (this->*_intfOpcodes[command])(args); va_end(args); @@ -350,11 +351,9 @@ void TownsAudioInterface::timerCallbackA() { void TownsAudioInterface::timerCallbackB() { Common::StackLock lock(_mutex); - if (_ready) { - if (_drv) - _drv->timerCallback(1); - for (int i = 0; i < 8; i++) - pcmUpdateEnvelopeGenerator(i); + if (_drv && _ready) { + _drv->timerCallback(1); + callback(80); } } @@ -489,6 +488,29 @@ int TownsAudioInterface::intf_enableTimerB(va_list &args) { return 0; } +int TownsAudioInterface::intf_loadSamples(va_list &args) { + uint32 dest = va_arg(args, uint32); + int size = va_arg(args, int); + uint8 *src = va_arg(args, uint8*); + + if (dest >= 65536 || size == 0 || size > 65536) + return 3; + if (size + dest > 65536) + return 5; + + int dwIndex = _numWaveTables - 1; + for (uint32 t = _waveTablesTotalDataSize; dwIndex && (dest < t); dwIndex--) + t -= _waveTables[dwIndex].size; + + TownsAudio_WaveTable *s = &_waveTables[dwIndex]; + _waveTablesTotalDataSize -= s->size; + s->size = size; + s->readData(src); + _waveTablesTotalDataSize += s->size; + + return 0; +} + int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) { int numChan = va_arg(args, int); if (numChan > 8) @@ -541,9 +563,9 @@ int TownsAudioInterface::intf_loadWaveTable(va_list &args) { TownsAudio_WaveTable *s = &_waveTables[_numWaveTables++]; s->readHeader(data); - s->readData(data + 32); - - _waveTablesTotalDataSize += w.size; + + _waveTablesTotalDataSize += s->size; + callback(32, _waveTablesTotalDataSize, s->size, data + 32); return 0; } @@ -698,9 +720,44 @@ int TownsAudioInterface::intf_pcmUpdateEnvelopeGenerator(va_list &args) { } int TownsAudioInterface::intf_cdaSetVolume(va_list &args) { - /*int unk = va_arg(args, int); - int volume1 = va_arg(args, int); - int volume2 = va_arg(args, int);*/ + int mode = va_arg(args, int); + int left = va_arg(args, int); + int right = va_arg(args, int); + + // calculate mixer balance value + int8 balance = right - left; + + if (left & 0xff80 || right & 0xff80) + return 3; + + static const uint8 flags[] = { 0x0C, 0x30, 0x40, 0x80 }; + + //int a = (mode & 0x40) ? 4 : 0; + int b = mode & 3; + left = (left & 0x7e) >> 1; + right = (right & 0x7e) >> 1; + + if (mode & 0x40) + _cdaVolFlags |= flags[b]; + else + _cdaVolFlags &= ~flags[b]; + + if (mode > 1) { + // Unknown purpose / TODO + + } else if (mode == 1) { + // FM Towns seems to support volumes of 0 - 63 for each channel. + // We recalculate sane values for out 0 to 255 volume range. + + int vl = (int)(((float)left * 255.0f) / 63.0f); + int vr = (int)(((float)right * 255.0f) / 63.0f); + AudioCD.setVolume((vl + vr) >> 1); + AudioCD.setBalance(balance); + + } else { + // Unknown purpose / TODO + } + return 0; } @@ -1402,8 +1459,7 @@ void TownsAudio_PcmChannel::clear() { panLeft = panRight = 0; - envTotalLevel = envAttackRate = envDecayRate = envSustainLevel = - envSustainRate = envReleaseRate = 0; + envTotalLevel = envAttackRate = envDecayRate = envSustainLevel = envSustainRate = envReleaseRate = 0; envStep = envCurrentLevel = 0; envState = kEnvReady; diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h index 707c9e6bd4..212c00c40f 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.h +++ b/sound/softsynth/fmtowns_pc98/towns_audio.h @@ -77,6 +77,7 @@ private: int intf_setTimerB(va_list &args); int intf_enableTimerA(va_list &args); int intf_enableTimerB(va_list &args); + int intf_loadSamples(va_list &args); int intf_reserveEffectChannels(va_list &args); int intf_loadWaveTable(va_list &args); int intf_unloadWaveTable(va_list &args); @@ -148,6 +149,8 @@ private: void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w); void cdaReset(); + + uint8 _cdaVolFlags; const float _baserate; uint32 _timerBase; diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp index 13120df17a..e23d5bcb36 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp @@ -66,8 +66,6 @@ bool TownsEuphonyDriver::init() { reset(); - cdaSetVolume(1, 118, 118); - return true; } @@ -194,7 +192,7 @@ bool TownsEuphonyDriver::soundEffectIsPlaying(int chan) { return _intf->callback(40, chan) ? true : false; } -void TownsEuphonyDriver::chanStereo(int chan, int mode) { +void TownsEuphonyDriver::chanPanPos(int chan, int mode) { _intf->callback(3, chan, mode); } @@ -206,8 +204,8 @@ void TownsEuphonyDriver::chanVolume(int chan, int vol) { _intf->callback(8, chan, vol); } -void TownsEuphonyDriver::cdaSetVolume(int a, int vol1, int vol2) { - _intf->callback(67, a, vol1, vol2); +void TownsEuphonyDriver::cdaSetVolume(int mode, int volLeft, int volRight) { + _intf->callback(67, mode, volLeft, volRight); } int TownsEuphonyDriver::chanEnable(int tableEntry, int val) { diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.h b/sound/softsynth/fmtowns_pc98/towns_euphony.h index 47cfdcb2b9..2026a299c1 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.h +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.h @@ -50,11 +50,11 @@ public: void stopSoundEffect(int chan); bool soundEffectIsPlaying(int chan); - void chanStereo(int chan, int mode); + void chanPanPos(int chan, int mode); void chanPitch(int chan, int pitch); void chanVolume(int chan, int vol); - void cdaSetVolume(int a, int vol1, int vol2); + void cdaSetVolume(int mode, int volLeft, int volRight); int chanEnable(int tableEntry, int val); int chanMode(int tableEntry, int val); -- cgit v1.2.3