aboutsummaryrefslogtreecommitdiff
path: root/sound/softsynth
diff options
context:
space:
mode:
authorFlorian Kagerer2010-08-04 16:53:09 +0000
committerFlorian Kagerer2010-08-04 16:53:09 +0000
commite5ffc7847cb70f792b4658aa032959949e849669 (patch)
tree0bba686f2c68bc0c15b5b03e532741299253d842 /sound/softsynth
parentfbd7c8456705442f12c9c798c58ec146f0a85063 (diff)
downloadscummvm-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
Diffstat (limited to 'sound/softsynth')
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_audio.cpp90
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_audio.h3
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_euphony.cpp8
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_euphony.h4
4 files changed, 81 insertions, 24 deletions
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);