[Scummvm-cvs-logs] SF.net SVN: scummvm:[51001] scummvm/trunk/engines/sci/sound

mthreepwood at users.sourceforge.net mthreepwood at users.sourceforge.net
Sun Jul 18 20:14:57 CEST 2010


Revision: 51001
          http://scummvm.svn.sourceforge.net/scummvm/?rev=51001&view=rev
Author:   mthreepwood
Date:     2010-07-18 18:14:56 +0000 (Sun, 18 Jul 2010)

Log Message:
-----------
SCI: Add initial support for SCI0 Mac and SCI1 Amiga/Mac sound.

SCI1 sound is pretty much done, but envelope support is still not 100% complete. SCI0 Mac sound is not complete, but sounds "ok" for now.

Much thanks to Walter, who did a ton of work on this.

Modified Paths:
--------------
    scummvm/trunk/engines/sci/sound/drivers/amiga.cpp
    scummvm/trunk/engines/sci/sound/music.cpp

Modified: scummvm/trunk/engines/sci/sound/drivers/amiga.cpp
===================================================================
--- scummvm/trunk/engines/sci/sound/drivers/amiga.cpp	2010-07-18 18:11:37 UTC (rev 51000)
+++ scummvm/trunk/engines/sci/sound/drivers/amiga.cpp	2010-07-18 18:14:56 UTC (rev 51001)
@@ -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,27 +35,6 @@
 
 /* #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 {
 public:
 	enum {
@@ -99,6 +79,7 @@
 		int instrument;
 		int volume;
 		int pan;
+		uint16 pitch;
 	};
 
 	struct Envelope {
@@ -121,7 +102,7 @@
 		frac_t rate;
 	};
 
-	struct Instrument {
+	struct InstrumentSample {
 		char name[30];
 		int mode;
 		int size; // Size of non-looping part in bytes
@@ -130,32 +111,52 @@
 		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) {
@@ -168,25 +169,32 @@
 		channel->velocity = envelope[phase - 1].target;
 }
 
-int MidiDriver_Amiga::interpolate(int8 *samples, frac_t offset) {
+int MidiDriver_Amiga::interpolate(int8 *samples, frac_t offset, bool isUnsigned) {
 	int x = fracToInt(offset);
+
+	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) {
 	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 @@
 			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 @@
 		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);
@@ -279,7 +287,7 @@
 
 void MidiDriver_Amiga::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);
@@ -300,9 +308,16 @@
 		}
 }
 
+void MidiDriver_Amiga::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_Amiga::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 @@
 		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);
 }
 
+MidiDriver_Amiga::InstrumentSample *MidiDriver_Amiga::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_Amiga::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_Amiga::startNote(int ch, int note, int velocity) {
-	Instrument *instrument;
 	int channel;
 
 	if (_channels[ch].instrument < 0 || _channels[ch].instrument > 255) {
@@ -331,7 +406,7 @@
 		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 @@
 
 	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 @@
 	_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_Amiga::InstrumentSample *MidiDriver_Amiga::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 @@
 	/* 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 @@
 	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 @@
 		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 @@
 		instrument->loop[instrument->loop_size] = instrument->loop[0];
 	} else {
 		instrument->loop = NULL;
+		instrument->loop_size = 0;
 		instrument->size = size;
 		instrument->samples[instrument->size] = 0;
 	}
@@ -483,27 +555,16 @@
 }
 
 int MidiDriver_Amiga::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 @@
 		_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
+	Common::File file;
 
-	for (uint i = 0; i < _bank.size; i++) {
-		int id;
-		Instrument *instrument = readInstrument(file, &id);
-
-		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);
@@ -550,11 +625,13 @@
 	_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];
+			}
 		}
 	}
 }
@@ -603,6 +680,9 @@
 	case 0xc0:
 		changeInstrument(channel, op1);
 		break;
+	case 0xe0:
+		pitchWheel(channel, (op2 << 7) | op1);
+		break;
 	default:
 		warning("[sfx:seq:amiga] unknown event %02x", command);
 	}
@@ -651,6 +731,239 @@
 	free(buffers);
 }
 
+bool MidiDriver_Amiga::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_Amiga::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);
+		uint32 startPos = file.pos();
+		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_Amiga::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_Amiga : public MidiPlayer {
 public:
 	MidiPlayer_Amiga(SciVersion version) : MidiPlayer(version) { _driver = new MidiDriver_Amiga(g_system->getMixer()); }
@@ -667,8 +980,8 @@
 }
 
 byte MidiPlayer_Amiga::getPlayId() {
-	if (_version != SCI_VERSION_0_LATE)
-		error("Amiga sound support not available for this SCI version");
+	if (_version > SCI_VERSION_0_LATE)
+		return 0x06;
 
 	return 0x40;
 }

Modified: scummvm/trunk/engines/sci/sound/music.cpp
===================================================================
--- scummvm/trunk/engines/sci/sound/music.cpp	2010-07-18 18:11:37 UTC (rev 51000)
+++ scummvm/trunk/engines/sci/sound/music.cpp	2010-07-18 18:14:56 UTC (rev 51001)
@@ -63,22 +63,14 @@
 	// 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_ADLIB | MDT_MIDI | MDT_PREFER_GM) : (MDT_PCSPK | 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)
+		if (g_sci->getPlatform() == Common::kPlatformAmiga || platform == Common::kPlatformMacintosh)
 			_pMidiDrv = MidiPlayer_Amiga_create(_soundVersion);
 		else
 			_pMidiDrv = MidiPlayer_AdLib_create(_soundVersion);


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list