diff options
author | Florian Kagerer | 2010-08-04 16:53:09 +0000 |
---|---|---|
committer | Florian Kagerer | 2010-08-04 16:53:09 +0000 |
commit | e5ffc7847cb70f792b4658aa032959949e849669 (patch) | |
tree | 0bba686f2c68bc0c15b5b03e532741299253d842 | |
parent | fbd7c8456705442f12c9c798c58ec146f0a85063 (diff) | |
download | scummvm-rg350-e5ffc7847cb70f792b4658aa032959949e849669.tar.gz scummvm-rg350-e5ffc7847cb70f792b4658aa032959949e849669.tar.bz2 scummvm-rg350-e5ffc7847cb70f792b4658aa032959949e849669.zip |
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
-rw-r--r-- | engines/kyra/sound_towns.cpp | 5 | ||||
-rw-r--r-- | sound/audiocd.cpp | 37 | ||||
-rw-r--r-- | sound/audiocd.h | 5 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_audio.cpp | 90 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_audio.h | 3 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_euphony.cpp | 8 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_euphony.h | 4 |
7 files changed, 126 insertions, 26 deletions
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 5f877f7d8a..95e2a5e63f 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -66,6 +66,8 @@ bool SoundTowns::init() { if (!loadInstruments()) return false; + _driver->cdaSetVolume(1, 118, 118); + return true; } @@ -90,6 +92,7 @@ void SoundTowns::playTrack(uint8 track) { beginFadeOut(); if (_musicEnabled == 2 && trackNum != -1) { + _driver->cdaSetVolume(1, 118, 118); AudioCD.play(trackNum+1, loop ? -1 : 1, 0, 0); AudioCD.updateCD(); _cdaPlaying = true; @@ -198,7 +201,7 @@ void SoundTowns::playSoundEffect(uint8 track) { } _driver->chanVolume(_sfxChannel, 127); - _driver->chanStereo(_sfxChannel, 0x40); + _driver->chanPanPos(_sfxChannel, 0x40); _driver->chanPitch(_sfxChannel, 0); _driver->playSoundEffect(_sfxChannel, note, 127, sfxPlaybackBuffer); } diff --git a/sound/audiocd.cpp b/sound/audiocd.cpp index 7afbd12d03..625def58fe 100644 --- a/sound/audiocd.cpp +++ b/sound/audiocd.cpp @@ -42,6 +42,8 @@ AudioCDManager::AudioCDManager() { _cd.start = 0; _cd.duration = 0; _cd.numLoops = 0; + _cd.volume = Mixer::kMaxChannelVolume; + _cd.balance = 0; _mixer = g_system->getMixer(); _emulating = false; assert(_mixer); @@ -79,7 +81,8 @@ void AudioCDManager::play(int track, int numLoops, int startFrame, int duration, */ _emulating = true; _mixer->playStream(Mixer::kMusicSoundType, &_handle, - makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops)); + makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops), -1, _cd.volume, _cd.balance); + } else { _emulating = false; if (!only_emulate) @@ -109,6 +112,38 @@ bool AudioCDManager::isPlaying() const { } } +void AudioCDManager::setVolume(byte volume) { + _cd.volume = volume; + if (_emulating) { + // Audio CD emulation + if (_mixer->isSoundHandleActive(_handle)) + _mixer->setChannelVolume(_handle, _cd.volume); + } else { + // Real Audio CD + + // Unfortunately I can't implement this atm + // since SDL doesn't seem to offer an interface method for this. + + // g_system->setVolumeCD(_cd.volume); + } +} + +void AudioCDManager::setBalance(int8 balance) { + _cd.balance = balance; + if (_emulating) { + // Audio CD emulation + if (isPlaying()) + _mixer->setChannelBalance(_handle, _cd.balance); + } else { + // Real Audio CD + + // Unfortunately I can't implement this atm + // since SDL doesn't seem to offer an interface method for this. + + // g_system->setBalanceCD(_cd.balance); + } +} + void AudioCDManager::updateCD() { if (_emulating) { // Check whether the audio track stopped playback diff --git a/sound/audiocd.h b/sound/audiocd.h index 3ef4a1ac09..abc45a1640 100644 --- a/sound/audiocd.h +++ b/sound/audiocd.h @@ -42,6 +42,8 @@ public: int start; int duration; int numLoops; + int volume; + int balance; }; /** @@ -59,6 +61,9 @@ public: void stop(); bool isPlaying() const; + void setVolume(byte volume); + void setBalance(int8 balance); + void updateCD(); Status getStatus() const; 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); |