diff options
author | Kari Salminen | 2008-04-21 04:04:24 +0000 |
---|---|---|
committer | Kari Salminen | 2008-04-21 04:04:24 +0000 |
commit | 38b2fb132222a8dcc841000d3ef99ef8b9674671 (patch) | |
tree | be26ff2f3e1fc43c588197222e83cd3cf08f9bf8 | |
parent | 3996b76aeb17922dd52f9a72392f61d6afa911bb (diff) | |
download | scummvm-rg350-38b2fb132222a8dcc841000d3ef99ef8b9674671.tar.gz scummvm-rg350-38b2fb132222a8dcc841000d3ef99ef8b9674671.tar.bz2 scummvm-rg350-38b2fb132222a8dcc841000d3ef99ef8b9674671.zip |
Fix timing in Apple IIGS MIDI parsing. Now sounds should get triggered at the correct times without the previously observed time jitter effect.
svn-id: r31636
-rw-r--r-- | engines/agi/sound.cpp | 47 | ||||
-rw-r--r-- | engines/agi/sound.h | 14 |
2 files changed, 27 insertions, 34 deletions
diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp index 9db8ba1b65..77f79272f8 100644 --- a/engines/agi/sound.cpp +++ b/engines/agi/sound.cpp @@ -61,6 +61,7 @@ IIgsMidi::IIgsMidi(uint8 *data, uint32 len, int resnum, SoundMgr &manager) : Agi _ptr = _data + 2; // Set current position to just after the header _len = len; // Save the resource's length _type = READ_LE_UINT16(data); // Read sound resource's type + _midiTicks = _soundBufTicks = 0; _isValid = (_type == AGI_SOUND_MIDI) && (_data != NULL) && (_len >= 2); if (!_isValid) // Check for errors @@ -276,11 +277,6 @@ static const IIgsExeInfo IIgsExeInfos[] = { {GID_GOLDRUSH, "GR", 0x3003, 148268, 0x8979, instSetV2} }; -// Time (In milliseconds) in Apple IIGS mixing buffer time granularity -// (i.e. in IIGS_BUFFER_SIZE / getRate() seconds granularity) -static uint32 g_IIgsBufGranMillis = 0; -static uint32 g_midiMillis = 0; // Time position (In milliseconds) in currently playing MIDI sound - static const int16 waveformRamp[WAVEFORM_SIZE] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, @@ -367,22 +363,7 @@ void SoundMgr::startSound(int resnum, int flag) { break; } case AGI_SOUND_MIDI: - g_IIgsBufGranMillis = g_midiMillis = 0; -#if 0 - debugC(3, kDebugLevelSound, "IIGS MIDI sequence"); - - for (i = 0; i < NUM_CHANNELS; i++) { - _chn[i].type = type; - _chn[i].flags = AGI_SOUND_LOOP | AGI_SOUND_ENVELOPE; - _chn[i].ins = _waveform; - _chn[i].size = WAVEFORM_SIZE; - _chn[i].vol = 0; - _chn[i].end = 0; - } - - _chn[0].timer = *(song + 2); - _chn[0].ptr = (struct AgiNote *)(song + 3); -#endif + ((IIgsMidi *) _vm->_game.sounds[_playingSound])->rewind(); break; case AGI_SOUND_4CHN: PCjrSound *pcjrSound = (PCjrSound *) _vm->_game.sounds[resnum]; @@ -552,31 +533,33 @@ void SoundMgr::playMidiSound() { _playing = true; p = midiObj->getPtr(); - g_IIgsBufGranMillis += (IIGS_BUFFER_SIZE * 1000) / getRate(); + midiObj->_soundBufTicks++; - while (g_midiMillis < g_IIgsBufGranMillis) { - uint8 readByte = *p++; + while (true) { + uint8 readByte = *p; // Check for end of MIDI sequence marker (Can also be here before delta-time) if (readByte == MIDI_BYTE_STOP_SEQUENCE) { debugC(3, kDebugLevelSound, "End of MIDI sequence (Before reading delta-time)"); - g_IIgsBufGranMillis = g_midiMillis = 0; _playing = false; midiObj->rewind(); return; } else if (readByte == MIDI_BYTE_TIMER_SYNC) { debugC(3, kDebugLevelSound, "Timer sync"); + p++; // Jump over the timer sync byte as it's not needed continue; } uint8 deltaTime = readByte; - uint32 ticksPerSec = 60; // Approximation based on tests with Apple IIGS KQ1 and SQ1 under MESS 0.124a - g_midiMillis += (deltaTime * 1000) / ticksPerSec; + if (midiObj->_midiTicks + deltaTime > midiObj->_soundBufTicks) { + break; + } + midiObj->_midiTicks += deltaTime; + p++; // Jump over the delta-time byte as it was already taken care of // Check for end of MIDI sequence marker (This time it after reading delta-time) if (*p == MIDI_BYTE_STOP_SEQUENCE) { debugC(3, kDebugLevelSound, "End of MIDI sequence (After reading delta-time)"); - g_IIgsBufGranMillis = g_midiMillis = 0; _playing = false; midiObj->rewind(); return; @@ -921,10 +904,10 @@ uint32 SoundMgr::mixSound(void) { if (channel.envSeg < ENVELOPE_SEGMENT_COUNT) { const IIgsEnvelopeSegment &seg = channel.ins->env.seg[channel.envSeg]; - double bufSecLen = IIGS_BUFFER_SIZE / (double) getRate(); - double ticksPerSec = 60; // Currently a guess, 1000 would be way too much - double bufTickLen = bufSecLen / (1.0/ticksPerSec); - frac_t envVolDelta = doubleToFrac((seg.inc/256.0)*bufTickLen); + // I currently assume enveloping works with the same speed as the MIDI + // (i.e. with 1/60ths of a second ticks). + // TODO: Check if enveloping really works with the same speed as MIDI + frac_t envVolDelta = doubleToFrac(seg.inc/256.0); if (intToFrac(seg.bp) >= channel.envVol) { channel.envVol += envVolDelta; if (channel.envVol >= intToFrac(seg.bp)) { diff --git a/engines/agi/sound.h b/engines/agi/sound.h index 6b268edb92..f1c2782421 100644 --- a/engines/agi/sound.h +++ b/engines/agi/sound.h @@ -36,7 +36,14 @@ namespace Agi { #define BUFFER_SIZE 410 -#define IIGS_BUFFER_SIZE 200 + +// Apple IIGS MIDI uses 60 ticks per second (Based on tests with Apple IIGS +// KQ1 and SQ1 under MESS 0.124a). So we make the audio buffer size to be a +// 1/60th of a second in length. That should be getSampleRate() / 60 samples +// in length but as getSampleRate() is always 22050 at the moment we just use +// the hardcoded value of 368 (22050/60 = 367.5 which rounds up to 368). +// FIXME: Use getSampleRate() / 60 rather than a hardcoded value +#define IIGS_BUFFER_SIZE 368 #define SOUND_EMU_NONE 0 #define SOUND_EMU_PC 1 @@ -309,12 +316,15 @@ public: virtual uint16 type() { return _type; } virtual const uint8 *getPtr() { return _ptr; } virtual void setPtr(const uint8 *ptr) { _ptr = ptr; } - virtual void rewind() { _ptr = _data + 2; } + virtual void rewind() { _ptr = _data + 2; _midiTicks = _soundBufTicks = 0; } protected: uint8 *_data; ///< Raw sound resource data const uint8 *_ptr; ///< Pointer to the current position in the MIDI data uint32 _len; ///< Length of the raw sound resource uint16 _type; ///< Sound resource type +public: + uint _midiTicks; ///< MIDI song position in ticks (1/60ths of a second) + uint _soundBufTicks; ///< Sound buffer position in ticks (1/60ths of a second) }; class IIgsSample : public AgiSound { |