aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sound
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/sound')
-rw-r--r--engines/sci/sound/audio.cpp15
-rw-r--r--engines/sci/sound/drivers/amigamac.cpp (renamed from engines/sci/sound/drivers/amiga.cpp)562
-rw-r--r--engines/sci/sound/drivers/mididriver.h4
-rw-r--r--engines/sci/sound/midiparser_sci.cpp6
-rw-r--r--engines/sci/sound/music.cpp20
-rw-r--r--engines/sci/sound/music.h2
-rw-r--r--engines/sci/sound/soundcmd.cpp76
-rw-r--r--engines/sci/sound/soundcmd.h2
8 files changed, 504 insertions, 183 deletions
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index d9e9d2e8db..640273c20e 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -35,6 +35,7 @@
#include "sound/audiostream.h"
#include "sound/decoders/aiff.h"
#include "sound/decoders/flac.h"
+#include "sound/decoders/mac_snd.h"
#include "sound/decoders/mp3.h"
#include "sound/decoders/raw.h"
#include "sound/decoders/vorbis.h"
@@ -337,19 +338,9 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
} else if (audioRes->size > 14 && READ_BE_UINT16(audioRes->data) == 1 && READ_BE_UINT16(audioRes->data + 2) == 1
&& READ_BE_UINT16(audioRes->data + 4) == 5 && READ_BE_UINT32(audioRes->data + 10) == 0x00018051) {
// Mac snd detected
- // See http://developer.apple.com/legacy/mac/library/documentation/mac/Sound/Sound-60.html#HEADING60-15 for more details
+ Common::MemoryReadStream *sndStream = new Common::MemoryReadStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
- uint32 soundHeaderOffset = READ_BE_UINT32(audioRes->data + 16);
- assert(READ_BE_UINT32(audioRes->data + soundHeaderOffset) == 0);
- size = READ_BE_UINT32(audioRes->data + soundHeaderOffset + 4);
- _audioRate = READ_BE_UINT16(audioRes->data + soundHeaderOffset + 8); // Really floating point, but we're just truncating
-
- if (*(audioRes->data + soundHeaderOffset + 20) != 0)
- error("Unhandled Mac snd extended/compressed header");
-
- data = (byte *)malloc(size);
- memcpy(data, audioRes->data + soundHeaderOffset + 22, size);
- flags = Audio::FLAG_UNSIGNED;
+ audioSeekStream = Audio::makeMacSndStream(sndStream, DisposeAfterUse::YES);
} else {
// SCI1 raw audio
size = audioRes->size;
diff --git a/engines/sci/sound/drivers/amiga.cpp b/engines/sci/sound/drivers/amigamac.cpp
index 0413dbb79e..4fb9146b53 100644
--- a/engines/sci/sound/drivers/amiga.cpp
+++ b/engines/sci/sound/drivers/amigamac.cpp
@@ -25,6 +25,7 @@
#include "sound/softsynth/emumidi.h"
#include "sci/sound/drivers/mididriver.h"
+#include "sci/resource.h"
#include "common/file.h"
#include "common/frac.h"
@@ -34,35 +35,14 @@ namespace Sci {
/* #define DEBUG */
-// Frequencies for every note
-// FIXME Store only one octave
-static const int freq_table[] = {
- 58, 62, 65, 69, 73, 78, 82, 87,
- 92, 98, 104, 110, 117, 124, 131, 139,
- 147, 156, 165, 175, 185, 196, 208, 220,
- 234, 248, 262, 278, 294, 312, 331, 350,
- 371, 393, 417, 441, 468, 496, 525, 556,
- 589, 625, 662, 701, 743, 787, 834, 883,
- 936, 992, 1051, 1113, 1179, 1250, 1324, 1403,
- 1486, 1574, 1668, 1767, 1872, 1984, 2102, 2227,
- 2359, 2500, 2648, 2806, 2973, 3149, 3337, 3535,
- 3745, 3968, 4204, 4454, 4719, 5000, 5297, 5612,
- 5946, 6299, 6674, 7071, 7491, 7937, 8408, 8908,
- 9438, 10000, 10594, 11224, 11892, 12599, 13348, 14142,
- 14983, 15874, 16817, 17817, 18877, 20000, 21189, 22449,
- 23784, 25198, 26696, 28284, 29966, 31748, 33635, 35635,
- 37754, 40000, 42378, 44898, 47568, 50396, 53393, 56568,
- 59932, 63496, 67271, 71271, 75509, 80000, 84757, 89796
-};
-
-class MidiDriver_Amiga : public MidiDriver_Emulated {
+class MidiDriver_AmigaMac : public MidiDriver_Emulated {
public:
enum {
kVoices = 4
};
- MidiDriver_Amiga(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15) { }
- virtual ~MidiDriver_Amiga() { }
+ MidiDriver_AmigaMac(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15) { }
+ virtual ~MidiDriver_AmigaMac() { }
// MidiDriver
int open();
@@ -99,6 +79,7 @@ private:
int instrument;
int volume;
int pan;
+ uint16 pitch;
};
struct Envelope {
@@ -121,7 +102,7 @@ private:
frac_t rate;
};
- struct Instrument {
+ struct InstrumentSample {
char name[30];
int mode;
int size; // Size of non-looping part in bytes
@@ -130,35 +111,55 @@ private:
Envelope envelope[4]; // Envelope
int8 *samples;
int8 *loop;
+ int16 startNote;
+ int16 endNote;
+ bool isUnsigned;
+ uint16 baseFreq;
+ uint16 baseNote;
+ int16 fixedNote;
+ };
+
+ class Instrument : public Common::Array<InstrumentSample *> {
+ public:
+ char name[30];
};
struct Bank {
char name[30];
uint size;
- Instrument *instruments[256];
+ Common::Array<Instrument> instruments;
};
+ bool _isSci1;
bool _playSwitch;
int _masterVolume;
int _frequency;
Envelope _envDecay;
Bank _bank; // Instrument bank
+ double _freqTable[48];
Channel _channels[MIDI_CHANNELS];
/* Internal channels */
Voice _voices[kChannels];
void setEnvelope(Voice *channel, Envelope *envelope, int phase);
- int interpolate(int8 *samples, frac_t offset);
+ void setOutputFrac(int voice);
+ int interpolate(int8 *samples, frac_t offset, bool isUnsigned);
void playInstrument(int16 *dest, Voice *channel, int count);
void changeInstrument(int channel, int instrument);
void stopChannel(int ch);
void stopNote(int ch, int note);
void startNote(int ch, int note, int velocity);
- Instrument *readInstrument(Common::File &file, int *id);
+ InstrumentSample *findInstrument(int instrument, int note);
+ void pitchWheel(int ch, uint16 pitch);
+
+ bool loadInstrumentsSCI0(Common::File &file);
+ bool loadInstrumentsSCI0Mac(Common::SeekableReadStream &file);
+ InstrumentSample *readInstrumentSCI0(Common::SeekableReadStream &file, int *id);
+ bool loadInstrumentsSCI1(Common::SeekableReadStream &file);
};
-void MidiDriver_Amiga::setEnvelope(Voice *channel, Envelope *envelope, int phase) {
+void MidiDriver_AmigaMac::setEnvelope(Voice *channel, Envelope *envelope, int phase) {
channel->envelope = phase;
channel->envelope_samples = envelope[phase].length;
@@ -168,25 +169,32 @@ void MidiDriver_Amiga::setEnvelope(Voice *channel, Envelope *envelope, int phase
channel->velocity = envelope[phase - 1].target;
}
-int MidiDriver_Amiga::interpolate(int8 *samples, frac_t offset) {
+int MidiDriver_AmigaMac::interpolate(int8 *samples, frac_t offset, bool isUnsigned) {
int x = fracToInt(offset);
- int diff = (samples[x + 1] - samples[x]) << 8;
+ if (isUnsigned) {
+ int s1 = (byte)samples[x] - 0x80;
+ int s2 = (byte)samples[x + 1] - 0x80;
+ int diff = (s2 - s1) << 8;
+ return (s1 << 8) + fracToInt(diff * (offset & FRAC_LO_MASK));
+ }
+
+ int diff = (samples[x + 1] - samples[x]) << 8;
return (samples[x] << 8) + fracToInt(diff * (offset & FRAC_LO_MASK));
}
-void MidiDriver_Amiga::playInstrument(int16 *dest, Voice *channel, int count) {
+void MidiDriver_AmigaMac::playInstrument(int16 *dest, Voice *channel, int count) {
int index = 0;
int vol = _channels[channel->hw_channel].volume;
- Instrument *instrument = _bank.instruments[channel->instrument];
+ InstrumentSample *instrument = findInstrument(channel->instrument, channel->note);
while (1) {
/* Available source samples until end of segment */
frac_t lin_avail;
- int seg_end, rem, i, amount;
+ uint32 seg_end, rem, i, amount;
int8 *samples;
- if (channel->looping) {
+ if (channel->looping && instrument->loop) {
samples = instrument->loop;
seg_end = instrument->loop_size;
} else {
@@ -208,11 +216,11 @@ void MidiDriver_Amiga::playInstrument(int16 *dest, Voice *channel, int count) {
amount = rem;
/* Stop at next envelope event */
- if ((channel->envelope_samples != -1) && (amount > channel->envelope_samples))
+ if ((channel->envelope_samples != -1) && (amount > (uint32)channel->envelope_samples))
amount = channel->envelope_samples;
for (i = 0; i < amount; i++) {
- dest[index++] = interpolate(samples, channel->offset) * channel->velocity / 64 * channel->note_velocity * vol / (127 * 127);
+ dest[index++] = interpolate(samples, channel->offset, instrument->isUnsigned) * channel->velocity / 64 * channel->note_velocity * vol / (127 * 127);
channel->offset += channel->rate;
}
@@ -263,7 +271,7 @@ void MidiDriver_Amiga::playInstrument(int16 *dest, Voice *channel, int count) {
if (index == count)
break;
- if (fracToInt(channel->offset) >= seg_end) {
+ if ((uint32)fracToInt(channel->offset) >= seg_end) {
if (instrument->mode & kModeLoop) {
/* Loop the samples */
channel->offset -= intToFrac(seg_end);
@@ -277,9 +285,9 @@ void MidiDriver_Amiga::playInstrument(int16 *dest, Voice *channel, int count) {
}
}
-void MidiDriver_Amiga::changeInstrument(int channel, int instrument) {
+void MidiDriver_AmigaMac::changeInstrument(int channel, int instrument) {
#ifdef DEBUG
- if (_bank.instruments[instrument])
+ if (_bank.instruments[instrument][0])
printf("[sfx:seq:amiga] Setting channel %i to \"%s\" (%i)\n", channel, _bank.instruments[instrument]->name, instrument);
else
warning("[sfx:seq:amiga] instrument %i does not exist (channel %i)", instrument, channel);
@@ -287,7 +295,7 @@ void MidiDriver_Amiga::changeInstrument(int channel, int instrument) {
_channels[channel].instrument = instrument;
}
-void MidiDriver_Amiga::stopChannel(int ch) {
+void MidiDriver_AmigaMac::stopChannel(int ch) {
int i;
/* Start decay phase for note on this hw channel, if any */
@@ -300,9 +308,16 @@ void MidiDriver_Amiga::stopChannel(int ch) {
}
}
-void MidiDriver_Amiga::stopNote(int ch, int note) {
+void MidiDriver_AmigaMac::pitchWheel(int ch, uint16 pitch) {
+ _channels[ch].pitch = pitch;
+
+ for (int i = 0; i < kChannels; i++)
+ if (_voices[i].note != -1 && _voices[i].hw_channel == ch)
+ setOutputFrac(i);
+}
+
+void MidiDriver_AmigaMac::stopNote(int ch, int note) {
int channel;
- Instrument *instrument;
for (channel = 0; channel < kChannels; channel++)
if (_voices[channel].note == note && _voices[channel].hw_channel == ch && !_voices[channel].decay)
@@ -315,15 +330,75 @@ void MidiDriver_Amiga::stopNote(int ch, int note) {
return;
}
- instrument = _bank.instruments[_voices[channel].instrument];
+ InstrumentSample *instrument = findInstrument(_voices[channel].instrument, note);
+
+ // FIXME: SCI1 envelope support is not perfect yet
/* Start the envelope phases for note-off if looping is on and envelope is enabled */
if ((instrument->mode & kModeLoop) && (instrument->envelope[0].length != 0))
setEnvelope(&_voices[channel], instrument->envelope, 2);
}
-void MidiDriver_Amiga::startNote(int ch, int note, int velocity) {
- Instrument *instrument;
+MidiDriver_AmigaMac::InstrumentSample *MidiDriver_AmigaMac::findInstrument(int instrument, int note) {
+ if ((uint)instrument >= _bank.instruments.size())
+ return 0;
+
+ for (uint32 i = 0; i < _bank.instruments[instrument].size(); i++) {
+ InstrumentSample *sample = _bank.instruments[instrument][i];
+ if (note >= sample->startNote && note <= sample->endNote)
+ return sample;
+ }
+
+ return 0;
+}
+
+void MidiDriver_AmigaMac::setOutputFrac(int voice) {
+ InstrumentSample *instrument = findInstrument(_voices[voice].instrument, _voices[voice].note);
+
+ int fnote = 0;
+
+ if (instrument->fixedNote == -1) {
+ fnote = _voices[voice].note;
+
+ // Handle SCI0-style transposing here
+ if (!_isSci1)
+ fnote += instrument->transpose;
+
+ if (fnote < 0 || fnote > 127) {
+ warning("[sfx:seq:amiga] illegal note %i", fnote);
+ return;
+ }
+ } else
+ fnote = instrument->fixedNote;
+
+ // Compute rate for note
+ int mulFact = 1, divFact = 1;
+
+ fnote -= instrument->baseNote;
+ fnote *= 4;
+ // FIXME: check how SSCI maps this
+ fnote += (_channels[_voices[voice].hw_channel].pitch - 0x2000) / 169;
+
+ while (fnote < 0) {
+ divFact *= 2;
+ fnote += 12 * 4;
+ }
+
+ while (fnote >= 12 * 4) {
+ mulFact *= 2;
+ fnote -= 12 * 4;
+ }
+
+ double freq = _freqTable[fnote] * instrument->baseFreq * mulFact / divFact;
+
+ // Handle SCI1-style transposing here
+ if (instrument->transpose && _isSci1)
+ freq = freq + ((_freqTable[4] - 1.0) * freq * (double)instrument->transpose / (double)16);
+
+ _voices[voice].rate = doubleToFrac(freq / _frequency);
+}
+
+void MidiDriver_AmigaMac::startNote(int ch, int note, int velocity) {
int channel;
if (_channels[ch].instrument < 0 || _channels[ch].instrument > 255) {
@@ -331,7 +406,7 @@ void MidiDriver_Amiga::startNote(int ch, int note, int velocity) {
return;
}
- instrument = _bank.instruments[_channels[ch].instrument];
+ InstrumentSample *instrument = findInstrument(_channels[ch].instrument, note);
if (!instrument) {
warning("[sfx:seq:amiga] instrument %i does not exist", _channels[ch].instrument);
@@ -349,19 +424,6 @@ void MidiDriver_Amiga::startNote(int ch, int note, int velocity) {
stopChannel(ch);
- if (instrument->mode & kModePitch) {
- int fnote = note + instrument->transpose;
-
- if (fnote < 0 || fnote > 127) {
- warning("[sfx:seq:amiga] illegal note %i\n", fnote);
- return;
- }
-
- /* Compute rate for note */
- _voices[channel].rate = doubleToFrac(freq_table[fnote] / (double) _frequency);
- } else
- _voices[channel].rate = doubleToFrac(kBaseFreq / (double) _frequency);
-
_voices[channel].instrument = _channels[ch].instrument;
_voices[channel].note = note;
_voices[channel].note_velocity = velocity;
@@ -377,30 +439,34 @@ void MidiDriver_Amiga::startNote(int ch, int note, int velocity) {
_voices[channel].hw_channel = ch;
_voices[channel].decay = 0;
_voices[channel].looping = 0;
+ setOutputFrac(channel);
}
-MidiDriver_Amiga::Instrument *MidiDriver_Amiga::readInstrument(Common::File &file, int *id) {
- Instrument *instrument;
+MidiDriver_AmigaMac::InstrumentSample *MidiDriver_AmigaMac::readInstrumentSCI0(Common::SeekableReadStream &file, int *id) {
byte header[61];
- int size;
- int seg_size[3];
- int loop_offset;
- int i;
if (file.read(header, 61) < 61) {
warning("[sfx:seq:amiga] failed to read instrument header");
return NULL;
}
- instrument = new Instrument;
-
+ int seg_size[3];
seg_size[0] = READ_BE_UINT16(header + 35) * 2;
seg_size[1] = READ_BE_UINT16(header + 41) * 2;
seg_size[2] = READ_BE_UINT16(header + 47) * 2;
+ InstrumentSample *instrument = new InstrumentSample;
+
+ instrument->startNote = 0;
+ instrument->endNote = 127;
+ instrument->isUnsigned = false;
+ instrument->baseFreq = kBaseFreq;
+ instrument->baseNote = 101;
+ instrument->fixedNote = 101;
+
instrument->mode = header[33];
instrument->transpose = (int8) header[34];
- for (i = 0; i < 4; i++) {
+ for (int i = 0; i < 4; i++) {
int length = (int8) header[49 + i];
if (length == 0 && i > 0)
@@ -413,13 +479,14 @@ MidiDriver_Amiga::Instrument *MidiDriver_Amiga::readInstrument(Common::File &fil
/* Final target must be 0 */
instrument->envelope[3].target = 0;
- loop_offset = READ_BE_UINT32(header + 37) & ~1;
- size = seg_size[0] + seg_size[1] + seg_size[2];
+ int loop_offset = READ_BE_UINT32(header + 37) & ~1;
+ int size = seg_size[0] + seg_size[1] + seg_size[2];
*id = READ_BE_UINT16(header);
strncpy(instrument->name, (char *) header + 2, 29);
instrument->name[29] = 0;
+
#ifdef DEBUG
printf("[sfx:seq:amiga] Reading instrument %i: \"%s\" (%i bytes)\n",
*id, instrument->name, size);
@@ -429,6 +496,7 @@ MidiDriver_Amiga::Instrument *MidiDriver_Amiga::readInstrument(Common::File &fil
printf(" Segment sizes: %i %i %i\n", seg_size[0], seg_size[1], seg_size[2]);
printf(" Segment offsets: 0 %i %i\n", loop_offset, read_int32(header + 43));
#endif
+
instrument->samples = (int8 *) malloc(size + 1);
if (file.read(instrument->samples, size) < (unsigned int)size) {
warning("[sfx:seq:amiga] failed to read instrument samples");
@@ -437,6 +505,9 @@ MidiDriver_Amiga::Instrument *MidiDriver_Amiga::readInstrument(Common::File &fil
return NULL;
}
+ if (instrument->mode & kModePitch)
+ instrument->fixedNote = -1;
+
if (instrument->mode & kModeLoop) {
if (loop_offset + seg_size[1] > size) {
#ifdef DEBUG
@@ -463,6 +534,7 @@ MidiDriver_Amiga::Instrument *MidiDriver_Amiga::readInstrument(Common::File &fil
instrument->loop[instrument->loop_size] = instrument->loop[0];
} else {
instrument->loop = NULL;
+ instrument->loop_size = 0;
instrument->size = size;
instrument->samples[instrument->size] = 0;
}
@@ -470,7 +542,7 @@ MidiDriver_Amiga::Instrument *MidiDriver_Amiga::readInstrument(Common::File &fil
return instrument;
}
-uint32 MidiDriver_Amiga::property(int prop, uint32 param) {
+uint32 MidiDriver_AmigaMac::property(int prop, uint32 param) {
switch(prop) {
case MIDI_PROP_MASTER_VOLUME:
if (param != 0xffff)
@@ -482,28 +554,17 @@ uint32 MidiDriver_Amiga::property(int prop, uint32 param) {
return 0;
}
-int MidiDriver_Amiga::open() {
+int MidiDriver_AmigaMac::open() {
+ _isSci1 = false;
+
+ for (int i = 0; i < 48; i++)
+ _freqTable[i] = pow(2, i / (double)48);
+
_frequency = _mixer->getOutputRate();
_envDecay.length = _frequency / (32 * 64);
_envDecay.delta = 1;
_envDecay.target = 0;
- Common::File file;
- byte header[40];
-
- if (!file.open("bank.001")) {
- warning("[sfx:seq:amiga] file bank.001 not found");
- return Common::kUnknownError;
- }
-
- if (file.read(header, 40) < 40) {
- warning("[sfx:seq:amiga] failed to read header of file bank.001");
- return Common::kUnknownError;
- }
-
- for (uint i = 0; i < 256; i++)
- _bank.instruments[i] = NULL;
-
for (uint i = 0; i < kChannels; i++) {
_voices[i].note = -1;
_voices[i].hw_channel = 0;
@@ -513,32 +574,46 @@ int MidiDriver_Amiga::open() {
_channels[i].instrument = -1;
_channels[i].volume = 127;
_channels[i].pan = (i % 4 == 0 || i % 4 == 3 ? kPanLeft : kPanRight);
+ _channels[i].pitch = 0x2000;
}
- _bank.size = READ_BE_UINT16(header + 38);
- strncpy(_bank.name, (char *) header + 8, 29);
- _bank.name[29] = 0;
-#ifdef DEBUG
- printf("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
-#endif
-
- for (uint i = 0; i < _bank.size; i++) {
- int id;
- Instrument *instrument = readInstrument(file, &id);
+ Common::File file;
- if (!instrument) {
- warning("[sfx:seq:amiga] failed to read bank.001");
+ if (file.open("bank.001")) {
+ if (!loadInstrumentsSCI0(file)) {
+ file.close();
return Common::kUnknownError;
}
+ file.close();
+ } else {
+ ResourceManager *resMan = g_sci->getResMan();
- if (id < 0 || id > 255) {
- warning("[sfx:seq:amiga] Error: instrument ID out of bounds");
+ Resource *resource = resMan->findResource(ResourceId(kResourceTypePatch, 7), false);
+ if (!resource)
+ resource = resMan->findResource(ResourceId(kResourceTypePatch, 9), false);
+
+ // If we have a patch by this point, it's SCI1
+ if (resource)
+ _isSci1 = true;
+
+ // Check for the SCI0 Mac patch
+ if (!resource)
+ resource = resMan->findResource(ResourceId(kResourceTypePatch, 200), false);
+
+ if (!resource) {
+ warning("Could not open patch for Amiga sound driver");
return Common::kUnknownError;
}
- _bank.instruments[id] = instrument;
- }
+ Common::MemoryReadStream stream(resource->data, resource->size);
+ if (_isSci1) {
+ if (!loadInstrumentsSCI1(stream))
+ return Common::kUnknownError;
+ } else if (!loadInstrumentsSCI0Mac(stream))
+ return Common::kUnknownError;
+ }
+
MidiDriver_Emulated::open();
_mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, DisposeAfterUse::NO);
@@ -546,28 +621,30 @@ int MidiDriver_Amiga::open() {
return Common::kNoError;
}
-void MidiDriver_Amiga::close() {
+void MidiDriver_AmigaMac::close() {
_mixer->stopHandle(_mixerSoundHandle);
for (uint i = 0; i < _bank.size; i++) {
- if (_bank.instruments[i]) {
- if (_bank.instruments[i]->loop)
- free(_bank.instruments[i]->loop);
- free(_bank.instruments[i]->samples);
- delete _bank.instruments[i];
+ for (uint32 j = 0; j < _bank.instruments[i].size(); j++) {
+ if (_bank.instruments[i][j]) {
+ if (_bank.instruments[i][j]->loop)
+ free(_bank.instruments[i][j]->loop);
+ free(_bank.instruments[i][j]->samples);
+ delete _bank.instruments[i][j];
+ }
}
}
}
-void MidiDriver_Amiga::playSwitch(bool play) {
+void MidiDriver_AmigaMac::playSwitch(bool play) {
_playSwitch = play;
}
-void MidiDriver_Amiga::setVolume(byte volume_) {
+void MidiDriver_AmigaMac::setVolume(byte volume_) {
_masterVolume = volume_;
}
-void MidiDriver_Amiga::send(uint32 b) {
+void MidiDriver_AmigaMac::send(uint32 b) {
byte command = b & 0xf0;
byte channel = b & 0xf;
byte op1 = (b >> 8) & 0xff;
@@ -603,12 +680,15 @@ void MidiDriver_Amiga::send(uint32 b) {
case 0xc0:
changeInstrument(channel, op1);
break;
+ case 0xe0:
+ pitchWheel(channel, (op2 << 7) | op1);
+ break;
default:
warning("[sfx:seq:amiga] unknown event %02x", command);
}
}
-void MidiDriver_Amiga::generateSamples(int16 *data, int len) {
+void MidiDriver_AmigaMac::generateSamples(int16 *data, int len) {
if (len == 0)
return;
@@ -651,24 +731,256 @@ void MidiDriver_Amiga::generateSamples(int16 *data, int len) {
free(buffers);
}
-class MidiPlayer_Amiga : public MidiPlayer {
+bool MidiDriver_AmigaMac::loadInstrumentsSCI0(Common::File &file) {
+ _isSci1 = false;
+
+ byte header[40];
+
+ if (file.read(header, 40) < 40) {
+ warning("[sfx:seq:amiga] failed to read header of file bank.001");
+ return false;
+ }
+
+ _bank.size = READ_BE_UINT16(header + 38);
+ strncpy(_bank.name, (char *) header + 8, 29);
+ _bank.name[29] = 0;
+#ifdef DEBUG
+ printf("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
+#endif
+
+ for (uint i = 0; i < _bank.size; i++) {
+ int id;
+ InstrumentSample *instrument = readInstrumentSCI0(file, &id);
+
+ if (!instrument) {
+ warning("[sfx:seq:amiga] failed to read bank.001");
+ return false;
+ }
+
+ if (id < 0 || id > 255) {
+ warning("[sfx:seq:amiga] Error: instrument ID out of bounds");
+ return false;
+ }
+
+ if ((uint)id >= _bank.instruments.size())
+ _bank.instruments.resize(id + 1);
+
+ _bank.instruments[id].push_back(instrument);
+ memcpy(_bank.instruments[id].name, instrument->name, sizeof(instrument->name));
+ }
+
+ return true;
+}
+
+bool MidiDriver_AmigaMac::loadInstrumentsSCI0Mac(Common::SeekableReadStream &file) {
+ byte header[40];
+
+ if (file.read(header, 40) < 40) {
+ warning("[sfx:seq:amiga] failed to read header of file patch.200");
+ return false;
+ }
+
+ _bank.size = 128;
+ strncpy(_bank.name, (char *) header + 8, 29);
+ _bank.name[29] = 0;
+#ifdef DEBUG
+ printf("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
+#endif
+
+ Common::Array<uint32> instrumentOffsets;
+ instrumentOffsets.resize(_bank.size);
+ _bank.instruments.resize(_bank.size);
+
+ for (uint32 i = 0; i < _bank.size; i++)
+ instrumentOffsets[i] = file.readUint32BE();
+
+ for (uint i = 0; i < _bank.size; i++) {
+ // 0 signifies it doesn't exist
+ if (instrumentOffsets[i] == 0)
+ continue;
+
+ file.seek(instrumentOffsets[i]);
+
+ uint16 id = file.readUint16BE();
+ if (id != i)
+ error("Instrument number mismatch");
+
+ InstrumentSample *instrument = new InstrumentSample;
+
+ instrument->startNote = 0;
+ instrument->endNote = 127;
+ instrument->isUnsigned = true;
+ instrument->baseFreq = kBaseFreq;
+ instrument->baseNote = 101;
+ instrument->fixedNote = 101;
+ instrument->mode = file.readUint16BE();
+
+ // Read in the offsets
+ int32 seg_size[3];
+ seg_size[0] = file.readUint32BE();
+ seg_size[1] = file.readUint32BE();
+ seg_size[2] = file.readUint32BE();
+
+ instrument->transpose = file.readUint16BE();
+
+ for (byte j = 0; j < 4; j++) {
+ int length = (int8)file.readByte();
+
+ if (length == 0 && j > 0)
+ length = 256;
+
+ instrument->envelope[j].length = length * _frequency / 60;
+ instrument->envelope[j].delta = (int8)file.readByte();
+ instrument->envelope[j].target = file.readByte();
+ }
+
+ // Final target must be 0
+ instrument->envelope[3].target = 0;
+
+ file.read(instrument->name, 30);
+
+ if (instrument->mode & kModePitch)
+ instrument->fixedNote = -1;
+
+ uint32 size = seg_size[2];
+ uint32 loop_offset = seg_size[0];
+
+ instrument->samples = (int8 *)malloc(size + 1);
+ if (file.read(instrument->samples, size) < size) {
+ warning("[sfx:seq:amiga] failed to read instrument sample");
+ free(instrument->samples);
+ delete instrument;
+ continue;
+ }
+
+ if (instrument->mode & kModeLoop) {
+ instrument->size = seg_size[0];
+ instrument->loop_size = seg_size[1] - seg_size[0];
+
+ instrument->loop = (int8*)malloc(instrument->loop_size + 1);
+ memcpy(instrument->loop, instrument->samples + loop_offset, instrument->loop_size);
+
+ instrument->samples[instrument->size] = instrument->loop[0];
+ instrument->loop[instrument->loop_size] = instrument->loop[0];
+ } else {
+ instrument->loop = NULL;
+ instrument->loop_size = 0;
+ instrument->size = size;
+ instrument->samples[instrument->size] = (int8)0x80;
+ }
+
+ _bank.instruments[id].push_back(instrument);
+ memcpy(_bank.instruments[id].name, instrument->name, sizeof(instrument->name));
+ }
+
+ return true;
+}
+
+bool MidiDriver_AmigaMac::loadInstrumentsSCI1(Common::SeekableReadStream &file) {
+ _bank.size = 128;
+
+ Common::Array<uint32> instrumentOffsets;
+ instrumentOffsets.resize(_bank.size);
+ _bank.instruments.resize(_bank.size);
+
+ for (uint32 i = 0; i < _bank.size; i++)
+ instrumentOffsets[i] = file.readUint32BE();
+
+ for (uint32 i = 0; i < _bank.size; i++) {
+ // 0 signifies it doesn't exist
+ if (instrumentOffsets[i] == 0)
+ continue;
+
+ file.seek(instrumentOffsets[i]);
+
+ // Read in the instrument name
+ file.read(_bank.instruments[i].name, 10); // last two bytes are always 0
+
+ for (uint32 j = 0; ; j++) {
+ InstrumentSample *sample = new InstrumentSample;
+ memset(sample, 0, sizeof(InstrumentSample));
+
+ sample->startNote = file.readSint16BE();
+
+ // startNote being -1 signifies we're done with this instrument
+ if (sample->startNote == -1) {
+ delete sample;
+ break;
+ }
+
+ sample->endNote = file.readSint16BE();
+ uint32 samplePtr = file.readUint32BE();
+ sample->transpose = file.readSint16BE();
+ for (int env = 0; env < 3; env++) {
+ sample->envelope[env].length = file.readByte() * _frequency / 60;
+ sample->envelope[env].delta = (env == 0 ? 10 : -10);
+ sample->envelope[env].target = file.readByte();
+ }
+
+ sample->envelope[3].length = 0;
+ sample->fixedNote = file.readSint16BE();
+ int16 loop = file.readSint16BE();
+ uint32 nextSamplePos = file.pos();
+
+ file.seek(samplePtr);
+ file.read(sample->name, 8);
+
+ sample->isUnsigned = file.readUint16BE() == 0;
+ uint16 phase1Offset = file.readUint16BE();
+ uint16 phase1End = file.readUint16BE();
+ uint16 phase2Offset = file.readUint16BE();
+ uint16 phase2End = file.readUint16BE();
+ sample->baseNote = file.readUint16BE();
+ uint32 periodTableOffset = file.readUint32BE();
+ uint32 sampleDataPos = file.pos();
+
+ sample->size = phase1End - phase1Offset + 1;
+ sample->loop_size = phase2End - phase2Offset + 1;
+
+ sample->samples = (int8 *)malloc(sample->size + 1);
+ file.seek(phase1Offset + sampleDataPos);
+ file.read(sample->samples, sample->size);
+ sample->samples[sample->size] = (sample->isUnsigned ? (int8)0x80 : 0);
+
+ if (loop == 0 && sample->loop_size > 1) {
+ sample->loop = (int8 *)malloc(sample->loop_size + 1);
+ file.seek(phase2Offset + sampleDataPos);
+ file.read(sample->loop, sample->loop_size);
+ sample->mode |= kModeLoop;
+ sample->samples[sample->size] = sample->loop[0];
+ sample->loop[sample->loop_size] = sample->loop[0];
+ }
+
+ _bank.instruments[i].push_back(sample);
+
+ file.seek(periodTableOffset + 0xe0);
+ sample->baseFreq = file.readUint16BE();
+
+ file.seek(nextSamplePos);
+ }
+ }
+
+ return true;
+}
+
+class MidiPlayer_AmigaMac : public MidiPlayer {
public:
- MidiPlayer_Amiga(SciVersion version) : MidiPlayer(version) { _driver = new MidiDriver_Amiga(g_system->getMixer()); }
+ MidiPlayer_AmigaMac(SciVersion version) : MidiPlayer(version) { _driver = new MidiDriver_AmigaMac(g_system->getMixer()); }
byte getPlayId();
- int getPolyphony() const { return MidiDriver_Amiga::kVoices; }
+ int getPolyphony() const { return MidiDriver_AmigaMac::kVoices; }
bool hasRhythmChannel() const { return false; }
- void setVolume(byte volume) { static_cast<MidiDriver_Amiga *>(_driver)->setVolume(volume); }
- void playSwitch(bool play) { static_cast<MidiDriver_Amiga *>(_driver)->playSwitch(play); }
+ void setVolume(byte volume) { static_cast<MidiDriver_AmigaMac *>(_driver)->setVolume(volume); }
+ void playSwitch(bool play) { static_cast<MidiDriver_AmigaMac *>(_driver)->playSwitch(play); }
void loadInstrument(int idx, byte *data);
};
-MidiPlayer *MidiPlayer_Amiga_create(SciVersion version) {
- return new MidiPlayer_Amiga(version);
+MidiPlayer *MidiPlayer_AmigaMac_create(SciVersion version) {
+ return new MidiPlayer_AmigaMac(version);
}
-byte MidiPlayer_Amiga::getPlayId() {
- if (_version != SCI_VERSION_0_LATE)
- error("Amiga sound support not available for this SCI version");
+byte MidiPlayer_AmigaMac::getPlayId() {
+ if (_version > SCI_VERSION_0_LATE)
+ return 0x06;
return 0x40;
}
diff --git a/engines/sci/sound/drivers/mididriver.h b/engines/sci/sound/drivers/mididriver.h
index 58803db260..2db6f25c70 100644
--- a/engines/sci/sound/drivers/mididriver.h
+++ b/engines/sci/sound/drivers/mididriver.h
@@ -86,7 +86,7 @@ public:
virtual byte getPlayId() = 0;
virtual int getPolyphony() const = 0;
- virtual int getFirstChannel() { return 0; };
+ virtual int getFirstChannel() { return 0; }
virtual void setVolume(byte volume) {
if(_driver)
@@ -113,7 +113,7 @@ protected:
};
extern MidiPlayer *MidiPlayer_AdLib_create(SciVersion version);
-extern MidiPlayer *MidiPlayer_Amiga_create(SciVersion version);
+extern MidiPlayer *MidiPlayer_AmigaMac_create(SciVersion version);
extern MidiPlayer *MidiPlayer_PCJr_create(SciVersion version);
extern MidiPlayer *MidiPlayer_PCSpeaker_create(SciVersion version);
extern MidiPlayer *MidiPlayer_Midi_create(SciVersion version);
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp
index cc09ba79f0..e58fa5120b 100644
--- a/engines/sci/sound/midiparser_sci.cpp
+++ b/engines/sci/sound/midiparser_sci.cpp
@@ -475,7 +475,7 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
// on tick 0. Signal isn't set at that point by sierra sci and it would cause the castle daventry text to
// get immediately removed, so we currently filter it.
// Sierra SCI ignores them as well at that time
- if (_position._play_tick) {
+ if ((_position._play_tick) || (info.delta)) {
_signalSet = true;
_signalToSet = info.basic.param1;
}
@@ -516,10 +516,11 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
break;
case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
+ case SCI_VERSION_2_1:
_dataincToAdd = 1;
break;
default:
- break;
+ error("unsupported _soundVersion");
}
break;
case kResetOnPause:
@@ -672,6 +673,7 @@ void MidiParser_SCI::setVolume(byte volume) {
case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
+ case SCI_VERSION_2_1:
// Send previous channel volumes again to actually update the volume
for (int i = 0; i < 15; i++)
if (_channelRemap[i] != -1)
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 55a7e1fdc4..c3315bd2b5 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -63,23 +63,15 @@ void SciMusic::init() {
// SCI sound init
_dwTempo = 0;
- // Default to MIDI in SCI32 games, as many don't have AdLib support.
- // WORKAROUND: Default to MIDI in Amiga SCI1_EGA+ games as we don't support
- // those patches yet. We also don't yet support the 7.pat file of SCI1+ Mac
- // games or SCI0 Mac patches, so we default to MIDI in those games to let
- // them run.
+ // Default to MIDI in SCI2.1+ games, as many don't have AdLib support.
Common::Platform platform = g_sci->getPlatform();
- uint32 dev = MidiDriver::detectDevice(
- (getSciVersion() >= SCI_VERSION_2 || platform == Common::kPlatformMacintosh ||
- (platform == Common::kPlatformAmiga && getSciVersion() >= SCI_VERSION_1_EGA))
- ? (MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM)
- : (MDT_PCSPK | MDT_ADLIB | MDT_MIDI));
+ uint32 dev = MidiDriver::detectDevice((getSciVersion() >= SCI_VERSION_2_1) ? (MDT_PCSPK | MDT_PCJR | MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM) : (MDT_PCSPK | MDT_PCJR | MDT_ADLIB | MDT_MIDI));
switch (MidiDriver::getMusicType(dev)) {
case MT_ADLIB:
// FIXME: There's no Amiga sound option, so we hook it up to AdLib
- if (g_sci->getPlatform() == Common::kPlatformAmiga)
- _pMidiDrv = MidiPlayer_Amiga_create(_soundVersion);
+ if (g_sci->getPlatform() == Common::kPlatformAmiga || platform == Common::kPlatformMacintosh)
+ _pMidiDrv = MidiPlayer_AmigaMac_create(_soundVersion);
else
_pMidiDrv = MidiPlayer_AdLib_create(_soundVersion);
break;
@@ -410,6 +402,8 @@ void SciMusic::soundStop(MusicEntry *pSnd) {
pSnd->pMidiParser->mainThreadEnd();
_mutex.unlock();
}
+
+ pSnd->fadeStep = 0; // end fading, if fading was in progress
}
void SciMusic::soundSetVolume(MusicEntry *pSnd, byte volume) {
@@ -604,7 +598,7 @@ MusicEntry::MusicEntry() {
priority = 0;
loop = 0;
volume = MUSIC_VOLUME_DEFAULT;
- hold = 0;
+ hold = -1;
pauseCounter = 0;
sampleLoopCounter = 0;
diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h
index 943a5bd2a8..37e3c30030 100644
--- a/engines/sci/sound/music.h
+++ b/engines/sci/sound/music.h
@@ -71,7 +71,7 @@ public:
byte priority;
uint16 loop;
int16 volume;
- byte hold;
+ int16 hold;
int16 pauseCounter;
uint sampleLoopCounter;
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index 51832af09f..bd88a5fca8 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -33,9 +33,6 @@
namespace Sci {
-#define SCI1_SOUND_FLAG_MAY_PAUSE 1 /* Only here for completeness; The interpreter doesn't touch this bit */
-#define SCI1_SOUND_FLAG_SCRIPTED_PRI 2 /* but does touch this */
-
SoundCommandParser::SoundCommandParser(ResourceManager *resMan, SegManager *segMan, Kernel *kernel, AudioPlayer *audio, SciVersion soundVersion) :
_resMan(resMan), _segMan(segMan), _kernel(kernel), _audio(audio), _soundVersion(soundVersion) {
@@ -48,6 +45,7 @@ SoundCommandParser::~SoundCommandParser() {
}
reg_t SoundCommandParser::kDoSoundInit(int argc, reg_t *argv, reg_t acc) {
+ debugC(2, kDebugLevelSound, "kDoSound(init): %04x:%04x", PRINT_REG(argv[0]));
processInitSound(argv[0]);
return acc;
}
@@ -73,8 +71,8 @@ void SoundCommandParser::processInitSound(reg_t obj) {
if (_soundVersion >= SCI_VERSION_1_EARLY)
newSound->volume = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX);
- debugC(2, kDebugLevelSound, "kDoSound(init): number %d, loop %d, prio %d, vol %d", resourceId,
- newSound->loop, newSound->priority, newSound->volume);
+ debugC(2, kDebugLevelSound, "kDoSound(init): %04x:%04x number %d, loop %d, prio %d, vol %d", PRINT_REG(obj),
+ resourceId, newSound->loop, newSound->priority, newSound->volume);
// In SCI1.1 games, sound effects are started from here. If we can find
// a relevant audio resource, play it, otherwise switch to synthesized
@@ -105,6 +103,7 @@ void SoundCommandParser::processInitSound(reg_t obj) {
}
reg_t SoundCommandParser::kDoSoundPlay(int argc, reg_t *argv, reg_t acc) {
+ debugC(2, kDebugLevelSound, "kDoSound(play): %04x:%04x", PRINT_REG(argv[0]));
processPlaySound(argv[0]);
return acc;
}
@@ -142,8 +141,8 @@ void SoundCommandParser::processPlaySound(reg_t obj) {
if (_soundVersion >= SCI_VERSION_1_EARLY)
musicSlot->volume = readSelectorValue(_segMan, obj, SELECTOR(vol));
- debugC(2, kDebugLevelSound, "kDoSound(play): number %d, loop %d, prio %d, vol %d", resourceId,
- musicSlot->loop, musicSlot->priority, musicSlot->volume);
+ debugC(2, kDebugLevelSound, "kDoSound(play): %04x:%04x number %d, loop %d, prio %d, vol %d", PRINT_REG(obj),
+ resourceId, musicSlot->loop, musicSlot->priority, musicSlot->volume);
_music->soundPlay(musicSlot);
}
@@ -154,6 +153,7 @@ reg_t SoundCommandParser::kDoSoundDummy(int argc, reg_t *argv, reg_t acc) {
}
reg_t SoundCommandParser::kDoSoundDispose(int argc, reg_t *argv, reg_t acc) {
+ debugC(2, kDebugLevelSound, "kDoSound(dispose): %04x:%04x", PRINT_REG(argv[0]));
processDisposeSound(argv[0]);
return acc;
}
@@ -176,6 +176,7 @@ void SoundCommandParser::processDisposeSound(reg_t obj) {
}
reg_t SoundCommandParser::kDoSoundStop(int argc, reg_t *argv, reg_t acc) {
+ debugC(2, kDebugLevelSound, "kDoSound(stop): %04x:%04x", PRINT_REG(argv[0]));
processStopSound(argv[0], false);
return acc;
}
@@ -209,6 +210,11 @@ void SoundCommandParser::processStopSound(reg_t obj, bool sampleFinishedPlaying)
}
reg_t SoundCommandParser::kDoSoundPause(int argc, reg_t *argv, reg_t acc) {
+ if (argc == 1)
+ debugC(2, kDebugLevelSound, "kDoSound(pause): %04x:%04x", PRINT_REG(argv[0]));
+ else
+ debugC(2, kDebugLevelSound, "kDoSound(pause): %04x:%04x, %04x:%04x", PRINT_REG(argv[0]), PRINT_REG(argv[1]));
+
if (_soundVersion <= SCI_VERSION_0_LATE) {
// SCI0 games give us 0/1 for either resuming or pausing the current music
// this one doesn't count, so pausing 2 times and resuming once means here that we are supposed to resume
@@ -250,26 +256,18 @@ reg_t SoundCommandParser::kDoSoundPause(int argc, reg_t *argv, reg_t acc) {
}
// SCI0 only command
-reg_t SoundCommandParser::kDoSoundResume(int argc, reg_t *argv, reg_t acc) {
- // this doesn't seem to do what we think it's doing
- // it's called with no arguments at all (just restore a game in qfg1)
- return acc;
- reg_t obj = argv[0];
-
- MusicEntry *musicSlot = _music->getSlot(obj);
- if (!musicSlot) {
- warning("kDoSound(resume):: Slot not found (%04x:%04x)", PRINT_REG(obj));
- return acc;
- }
-
- writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPlaying);
- _music->soundResume(musicSlot);
+// It's called right after restoring a game - it's responsible to kick off playing music again
+// we don't need this at all, so we don't do anything here
+reg_t SoundCommandParser::kDoSoundResumeAfterRestore(int argc, reg_t *argv, reg_t acc) {
return acc;
}
reg_t SoundCommandParser::kDoSoundMute(int argc, reg_t *argv, reg_t acc) {
- if (argc > 0)
+ if (argc > 0) {
+ debugC(2, kDebugLevelSound, "kDoSound(mute): %d", argv[0].toUint16());
_music->soundSetSoundOn(argv[0].toUint16());
+ }
+
return make_reg(0, _music->soundGetSoundOn());
}
@@ -300,7 +298,7 @@ reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) {
// If sound is not playing currently, set signal directly
if (musicSlot->status != kSoundPlaying) {
- debugC(2, kDebugLevelSound, "kDoSound(fade): fading requested, but sound is currently not playing");
+ debugC(2, kDebugLevelSound, "kDoSound(fade): %04x:%04x fading requested, but sound is currently not playing", PRINT_REG(obj));
writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
return acc;
}
@@ -328,7 +326,7 @@ reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) {
error("kDoSound(fade): unsupported argc %d", argc);
}
- debugC(2, kDebugLevelSound, "kDoSound(fade): to %d, step %d, ticker %d", musicSlot->fadeTo, musicSlot->fadeStep, musicSlot->fadeTickerStep);
+ debugC(2, kDebugLevelSound, "kDoSound(fade): %04x:%04x to %d, step %d, ticker %d", PRINT_REG(obj), musicSlot->fadeTo, musicSlot->fadeStep, musicSlot->fadeTickerStep);
return acc;
}
@@ -339,6 +337,8 @@ reg_t SoundCommandParser::kDoSoundGetPolyphony(int argc, reg_t *argv, reg_t acc)
reg_t SoundCommandParser::kDoSoundUpdate(int argc, reg_t *argv, reg_t acc) {
reg_t obj = argv[0];
+ debugC(2, kDebugLevelSound, "kDoSound(update): %04x:%04x", PRINT_REG(argv[0]));
+
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
warning("kDoSound(update): Slot not found (%04x:%04x)", PRINT_REG(obj));
@@ -379,9 +379,13 @@ void SoundCommandParser::processUpdateCues(reg_t obj) {
musicSlot->loop -= currentLoopCounter - musicSlot->sampleLoopCounter;
musicSlot->sampleLoopCounter = currentLoopCounter;
}
- if ((!_music->soundIsActive(musicSlot)) && (musicSlot->status != kSoundPaused)) {
- processStopSound(obj, true);
- } else {
+ if (musicSlot->status == kSoundPlaying) {
+ if (!_music->soundIsActive(musicSlot)) {
+ processStopSound(obj, true);
+ } else {
+ _music->updateAudioStreamTicker(musicSlot);
+ }
+ } else if (musicSlot->status == kSoundPaused) {
_music->updateAudioStreamTicker(musicSlot);
}
// We get a flag from MusicEntry::doFade() here to set volume for the stream
@@ -443,9 +447,15 @@ reg_t SoundCommandParser::kDoSoundSendMidi(int argc, reg_t *argv, reg_t acc) {
byte channel = argv[1].toUint16() & 0xf;
byte midiCmd = argv[2].toUint16() & 0xff;
+ // TODO: first there is a 4-parameter variant of this call which needs to get reversed
+ // second the current code isn't 100% accurate, sierra sci does checks on the 4th parameter
+ if (argc == 4)
+ return acc;
+
uint16 controller = argv[3].toUint16();
uint16 param = argv[4].toUint16();
+ debugC(2, kDebugLevelSound, "kDoSound(sendMidi): %04x:%04x, %d, %d, %d, %d", PRINT_REG(obj), channel, midiCmd, controller, param);
if (channel)
channel--; // channel is given 1-based, we are using 0-based
@@ -464,6 +474,7 @@ reg_t SoundCommandParser::kDoSoundSendMidi(int argc, reg_t *argv, reg_t acc) {
}
reg_t SoundCommandParser::kDoSoundReverb(int argc, reg_t *argv, reg_t acc) {
+ debugC(2, kDebugLevelSound, "doSoundReverb: %d", argv[0].toUint16() & 0xF);
_music->setReverb(argv[0].toUint16() & 0xF);
return acc;
}
@@ -471,6 +482,8 @@ reg_t SoundCommandParser::kDoSoundReverb(int argc, reg_t *argv, reg_t acc) {
reg_t SoundCommandParser::kDoSoundSetHold(int argc, reg_t *argv, reg_t acc) {
reg_t obj = argv[0];
+ debugC(2, kDebugLevelSound, "doSoundSetHold: %04x:%04x, %d", PRINT_REG(argv[0]), argv[1].toUint16());
+
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
warning("kDoSound(setHold): Slot not found (%04x:%04x)", PRINT_REG(obj));
@@ -488,6 +501,11 @@ reg_t SoundCommandParser::kDoSoundGetAudioCapability(int argc, reg_t *argv, reg_
}
reg_t SoundCommandParser::kDoSoundStopAll(int argc, reg_t *argv, reg_t acc) {
+ // TODO: this can't be right, this gets called in kq1 - e.g. being in witch house, getting the note
+ // now the point jingle plays and after a messagebox they call this - and would stop the background effects with it
+ // this doesn't make sense, so i disable it for now
+ return acc;
+
Common::StackLock(_music->_mutex);
const MusicList::iterator end = _music->getPlayListEnd();
@@ -535,6 +553,8 @@ reg_t SoundCommandParser::kDoSoundSetPriority(int argc, reg_t *argv, reg_t acc)
reg_t obj = argv[0];
int16 value = argv[1].toSint16();
+ debugC(2, kDebugLevelSound, "kDoSound(setPriority): %04x:%04x, %d", PRINT_REG(obj), value);
+
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
warning("kDoSound(setPriority): Slot not found (%04x:%04x)", PRINT_REG(obj));
@@ -565,6 +585,8 @@ reg_t SoundCommandParser::kDoSoundSetLoop(int argc, reg_t *argv, reg_t acc) {
reg_t obj = argv[0];
int16 value = argv[1].toSint16();
+ debugC(2, kDebugLevelSound, "kDoSound(setLoop): %04x:%04x, %d", PRINT_REG(obj), value);
+
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
// Apparently, it's perfectly normal for a game to call cmdSetSoundLoop
diff --git a/engines/sci/sound/soundcmd.h b/engines/sci/sound/soundcmd.h
index a8bc1eb280..10915e8ea9 100644
--- a/engines/sci/sound/soundcmd.h
+++ b/engines/sci/sound/soundcmd.h
@@ -85,7 +85,7 @@ public:
reg_t kDoSoundDummy(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundMute(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundPause(int argc, reg_t *argv, reg_t acc);
- reg_t kDoSoundResume(int argc, reg_t *argv, reg_t acc);
+ reg_t kDoSoundResumeAfterRestore(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundStop(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundStopAll(int argc, reg_t *argv, reg_t acc);
reg_t kDoSoundDispose(int argc, reg_t *argv, reg_t acc);