Skip to content

Commit

Permalink
CINE: Implement sfx repeat and volume fade for FW Amiga/AtariST.
Browse files Browse the repository at this point in the history
This fixes bug 3091660 "FW: Looping samples don't loop in Amiga version".
  • Loading branch information
Johannes Schickel committed Sep 7, 2012
1 parent b107454 commit c850eff
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 13 deletions.
78 changes: 68 additions & 10 deletions engines/cine/sound.cpp
Expand Up @@ -998,11 +998,18 @@ void PCSound::stopSound(int channel) {
}

PaulaSound::PaulaSound(Audio::Mixer *mixer, CineEngine *vm)
: Sound(mixer, vm) {
: Sound(mixer, vm), _sfxTimer(0) {
_moduleStream = 0;
// The original is using the following timer frequency:
// 0.709379Mhz / 8000 = 88.672375Hz
// 1000000 / 88.672375Hz = 11277.46944863us
g_system->getTimerManager()->installTimerProc(&PaulaSound::sfxTimerProc, 11277, this, "PaulaSound::sfxTimerProc");
}

PaulaSound::~PaulaSound() {
Common::StackLock lock(_mutex);

g_system->getTimerManager()->removeTimerProc(&PaulaSound::sfxTimerProc);
for (int i = 0; i < NUM_CHANNELS; ++i) {
stopSound(i);
}
Expand All @@ -1011,6 +1018,10 @@ PaulaSound::~PaulaSound() {

void PaulaSound::loadMusic(const char *name) {
debugC(5, kCineDebugSound, "PaulaSound::loadMusic('%s')", name);
for (int i = 0; i < NUM_CHANNELS; ++i) {
stopSound(i);
}

if (_vm->getGameType() == GType_FW) {
// look for separate files
Common::File f;
Expand Down Expand Up @@ -1049,34 +1060,81 @@ void PaulaSound::fadeOutMusic() {
}

void PaulaSound::playSound(int channel, int frequency, const uint8 *data, int size, int volumeStep, int stepCount, int volume, int repeat) {
// TODO: handle volume slides and repeat
debugC(5, kCineDebugSound, "PaulaSound::playSound() channel %d size %d", channel, size);
Common::StackLock lock(_mutex);
assert(frequency > 0);

stopSound(channel);
if (size > 0) {
byte *sound = (byte *)malloc(size);
if (sound) {
// Create the audio stream
memcpy(sound, data, size);
playSoundChannel(channel, frequency, sound, size, volume);

// Clear the first and last 16 bits like in the original.
sound[0] = sound[1] = sound[size - 2] = sound[size - 1] = 0;

Audio::SeekableAudioStream *stream = Audio::makeRawStream(sound, size, PAULA_FREQ / frequency, 0);

// Initialize the volume control
_channelsTable[channel].initialize(volume, volumeStep, stepCount);

// Start the sfx
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_channelsTable[channel].handle,
Audio::makeLoopingAudioStream(stream, repeat ? 0 : 1),
-1, volume * Audio::Mixer::kMaxChannelVolume / 63);
}
}
}

void PaulaSound::stopSound(int channel) {
debugC(5, kCineDebugSound, "PaulaSound::stopSound() channel %d", channel);
_mixer->stopHandle(_channelsTable[channel]);
Common::StackLock lock(_mutex);

_mixer->stopHandle(_channelsTable[channel].handle);
}

void PaulaSound::update() {
// process volume slides and start sound playback
// TODO
}

void PaulaSound::playSoundChannel(int channel, int frequency, uint8 *data, int size, int volume) {
assert(frequency > 0);
frequency = PAULA_FREQ / frequency;
Audio::AudioStream *stream = Audio::makeRawStream(data, size, frequency, 0);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_channelsTable[channel], stream);
_mixer->setChannelVolume(_channelsTable[channel], volume * Audio::Mixer::kMaxChannelVolume / 63);
void PaulaSound::sfxTimerProc(void *param) {
PaulaSound *sound = (PaulaSound *)param;
sound->sfxTimerCallback();
}

void PaulaSound::sfxTimerCallback() {
Common::StackLock lock(_mutex);

if (_sfxTimer < 6) {
++_sfxTimer;

for (int i = 0; i < NUM_CHANNELS; ++i) {
// Only process active channels
if (!_mixer->isSoundHandleActive(_channelsTable[i].handle)) {
continue;
}

if (_channelsTable[i].curStep) {
--_channelsTable[i].curStep;
} else {
_channelsTable[i].curStep = _channelsTable[i].stepCount;
const int volume = CLIP(_channelsTable[i].volume + _channelsTable[i].volumeStep, 0, 63);
_channelsTable[i].volume = volume;
// Unlike the original we stop silent sounds
if (volume) {
_mixer->setChannelVolume(_channelsTable[i].handle, volume * Audio::Mixer::kMaxChannelVolume / 63);
} else {
_mixer->stopHandle(_channelsTable[i].handle);
}
}
}
} else {
_sfxTimer = 0;
// Possible TODO: The original only ever started sounds here. This
// should not be noticable though. So we do not do it for now.
}
}

} // End of namespace Cine
23 changes: 20 additions & 3 deletions engines/cine/sound.h
Expand Up @@ -24,6 +24,7 @@
#define CINE_SOUND_H_

#include "common/util.h"
#include "common/mutex.h"
#include "audio/mixer.h"

namespace Audio {
Expand Down Expand Up @@ -99,10 +100,26 @@ class PaulaSound : public Sound {
};

protected:
Common::Mutex _mutex;

struct SfxChannel {
Audio::SoundHandle handle;
int volume;
int volumeStep;
int curStep;
int stepCount;

void initialize(int vol, int volStep, int stepCnt) {
volume = vol;
volumeStep = volStep;
curStep = stepCount = stepCnt;
}
};
SfxChannel _channelsTable[NUM_CHANNELS];
int _sfxTimer;
static void sfxTimerProc(void *param);
void sfxTimerCallback();

void playSoundChannel(int channel, int frequency, uint8 *data, int size, int volume);

Audio::SoundHandle _channelsTable[NUM_CHANNELS];
Audio::SoundHandle _moduleHandle;
Audio::AudioStream *_moduleStream;
};
Expand Down

0 comments on commit c850eff

Please sign in to comment.