1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/config-manager.h"
24 #include "common/fs.h"
25 #include "common/archive.h"
26 #include "common/md5.h"
27 #include "common/memstream.h"
28 #include "common/str-array.h"
29 #include "common/textconsole.h"
30 #include "audio/mixer.h"
31 
32 #include "agi/agi.h"
33 #include "agi/sound_2gs.h"
34 
35 namespace Agi {
36 
SoundGen2GS(AgiBase * vm,Audio::Mixer * pMixer)37 SoundGen2GS::SoundGen2GS(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixer) {
38 	// Allocate memory for the wavetable
39 	_wavetable = new int8[SIERRASTANDARD_SIZE];
40 
41 	// Apple IIGS AGI MIDI player advances 60 ticks per second. Strategy
42 	// here is to first generate audio for a 1/60th of a second and then
43 	// advance the MIDI player by one tick. Thus, make the output buffer
44 	// to be a 1/60th of a second in length.
45 	_outSize = _sampleRate / 60;
46 	_out = new int16[2 * _outSize]; // stereo
47 
48 	// Initialize player variables
49 	_nextGen = 0;
50 	_ticks = 0;
51 
52 	// Not playing anything yet
53 	_playingSound = -1;
54 	_playing = false;
55 
56 	// Load instruments
57 	_disableMidi = !loadInstruments();
58 
59 	_mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
60 }
61 
~SoundGen2GS()62 SoundGen2GS::~SoundGen2GS() {
63 	_mixer->stopHandle(*_soundHandle);
64 	delete[] _wavetable;
65 	delete[] _out;
66 }
67 
readBuffer(int16 * buffer,const int numSamples)68 int SoundGen2GS::readBuffer(int16 *buffer, const int numSamples) {
69 	static uint data_available = 0;
70 	static uint data_offset = 0;
71 	uint n = numSamples << 1;
72 	uint8 *p = (uint8 *)buffer;
73 
74 	while (n > data_available) {
75 		memcpy(p, (uint8 *)_out + data_offset, data_available);
76 		p += data_available;
77 		n -= data_available;
78 
79 		advancePlayer();
80 
81 		data_available = generateOutput() << 1;
82 		data_offset = 0;
83 	}
84 
85 	memcpy(p, (uint8 *)_out + data_offset, n);
86 	data_offset += n;
87 	data_available -= n;
88 
89 	return numSamples;
90 }
91 
92 /**
93  * Initiate the playing of a sound resource.
94  * @param resnum Resource number
95  */
play(int resnum)96 void SoundGen2GS::play(int resnum) {
97 	AgiSoundEmuType type;
98 
99 	type = (AgiSoundEmuType)_vm->_game.sounds[resnum]->type();
100 	assert(type == AGI_SOUND_SAMPLE || type == AGI_SOUND_MIDI);
101 
102 	if (_vm->_soundemu != SOUND_EMU_APPLE2GS) {
103 		warning("Trying to play sample or MIDI resource but not using Apple IIGS sound emulation mode");
104 		return;
105 	}
106 
107 	// FIXME: all sorts of things in here are not thread-safe
108 	haltGenerators();
109 
110 	switch (type) {
111 	case AGI_SOUND_SAMPLE: {
112 		IIgsSample *sampleRes = (IIgsSample *) _vm->_game.sounds[resnum];
113 		const IIgsSampleHeader &header = sampleRes->getHeader();
114 		_channels[kSfxMidiChannel].setInstrument(&header.instrument);
115 		_channels[kSfxMidiChannel].setVolume(header.volume);
116 		midiNoteOn(kSfxMidiChannel, header.pitch, 127);
117 		break;
118 	}
119 	case AGI_SOUND_MIDI:
120 		((IIgsMidi *) _vm->_game.sounds[resnum])->rewind();
121 		_ticks = 0;
122 		break;
123 	default:
124 		break;
125 	}
126 
127 	_playingSound = resnum;
128 }
129 
stop()130 void SoundGen2GS::stop() {
131 	haltGenerators();
132 	_playingSound = -1;
133 	_playing = false;
134 }
135 
136 /**
137  * Fill output buffer by advancing the generators for a 1/60th of a second.
138  * @return Number of generated samples
139  */
generateOutput()140 uint SoundGen2GS::generateOutput() {
141 	memset(_out, 0, _outSize * 2 * 2);
142 
143 	if (!_playing || _playingSound == -1)
144 		return _outSize * 2;
145 
146 	int16 *p = _out;
147 	int n = _outSize;
148 	while (n--) {
149 		int outLeft = 0;
150 		int outRight = 0;
151 		for (int k = 0; k < MAX_GENERATORS; k++) {
152 			IIgsGenerator *g = &_generators[k];
153 			if (!g->curInstrument)
154 				continue;
155 			const IIgsInstrumentHeader *curInstrument = g->curInstrument;
156 
157 			// Advance envelope
158 			int vol = fracToInt(g->a);
159 			if (g->a <= curInstrument->env[g->seg].bp) {
160 				g->a += curInstrument->env[g->seg].inc * ENVELOPE_COEF;
161 				if (g->a > curInstrument->env[g->seg].bp) {
162 					g->a = curInstrument->env[g->seg].bp;
163 					g->seg++;
164 				}
165 			} else {
166 				g->a -= curInstrument->env[g->seg].inc * ENVELOPE_COEF;
167 				if (g->a < curInstrument->env[g->seg].bp) {
168 					g->a = curInstrument->env[g->seg].bp;
169 					g->seg++;
170 				}
171 			}
172 
173 			// TODO: Advance vibrato here. The Apple IIGS uses a LFO with
174 			// triangle wave to modulate the frequency of both oscillators.
175 			// In Apple IIGS the vibrato and the envelope are updated at the
176 			// same time, so the vibrato speed depends on ENVELOPE_COEF.
177 
178 			// Advance oscillators
179 			int s0 = 0;
180 			int s1 = 0;
181 			if (!g->osc[0].halt) {
182 				s0 = g->osc[0].base[fracToInt(g->osc[0].p)];
183 				g->osc[0].p += g->osc[0].pd;
184 				if ((uint)fracToInt(g->osc[0].p) >= g->osc[0].size) {
185 					g->osc[0].p -= intToFrac(g->osc[0].size);
186 					if (!g->osc[0].loop)
187 						g->osc[0].halt = true;
188 					if (g->osc[0].swap) {
189 						g->osc[0].halt = true;
190 						g->osc[1].halt = false;
191 					}
192 				}
193 			}
194 			if (!g->osc[1].halt) {
195 				s1 = g->osc[1].base[fracToInt(g->osc[1].p)];
196 				g->osc[1].p += g->osc[1].pd;
197 				if ((uint)fracToInt(g->osc[1].p) >= g->osc[1].size) {
198 					g->osc[1].p -= intToFrac(g->osc[1].size);
199 					if (!g->osc[1].loop)
200 						g->osc[1].halt = true;
201 					if (g->osc[1].swap) {
202 						g->osc[0].halt = false;
203 						g->osc[1].halt = true;
204 					}
205 				}
206 			}
207 
208 			// Take envelope and MIDI volume information into account.
209 			// Also amplify.
210 			s0 *= vol * g->velocity / 127 * 80 / 256;
211 			s1 *= vol * g->velocity / 127 * 80 / 256;
212 
213 			// Select output channel.
214 			if (g->osc[0].rightChannel)
215 				outRight += s0;
216 			else
217 				outLeft += s0;
218 
219 			if (g->osc[1].rightChannel)
220 				outRight += s1;
221 			else
222 				outLeft += s1;
223 		}
224 
225 		if (outLeft > 32768)
226 			outLeft = 32768;
227 		if (outLeft < -32767)
228 			outLeft = -32767;
229 		if (outRight > 32768)
230 			outRight = 32768;
231 		if (outRight < -32767)
232 			outRight = -32767;
233 
234 		*p++ = outLeft;
235 		*p++ = outRight;
236 	}
237 
238 	return _outSize * 2;
239 }
240 
advancePlayer()241 void SoundGen2GS::advancePlayer() {
242 	if (_playingSound == -1)
243 		return;
244 
245 	if (_vm->_game.sounds[_playingSound]->type() == AGI_SOUND_MIDI) {
246 		advanceMidiPlayer();
247 	} else if (_vm->_game.sounds[_playingSound]->type() == AGI_SOUND_SAMPLE) {
248 		_playing = activeGenerators() > 0;
249 	}
250 
251 	if (!_playing) {
252 		_vm->_sound->soundIsFinished();
253 		_playingSound = -1;
254 	}
255 }
256 
advanceMidiPlayer()257 void SoundGen2GS::advanceMidiPlayer() {
258 	if (_disableMidi)
259 		return;
260 
261 	const uint8 *p;
262 	uint8 parm1, parm2;
263 	static uint8 cmd, chn;
264 
265 	if (_playingSound == -1 || _vm->_game.sounds[_playingSound] == NULL) {
266 		warning("Error playing Apple IIGS MIDI sound resource");
267 		_playing = false;
268 		return;
269 	}
270 
271 	IIgsMidi *midiObj = (IIgsMidi *) _vm->_game.sounds[_playingSound];
272 
273 	_ticks++;
274 	_playing = true;
275 	p = midiObj->getPtr();
276 
277 	while (true) {
278 		// Check for end of MIDI sequence marker (Can also be here before delta-time)
279 		if (*p == MIDI_STOP_SEQUENCE) {
280 			debugC(3, kDebugLevelSound, "End of MIDI sequence (Before reading delta-time)");
281 			_playing = false;
282 			midiObj->rewind();
283 			return;
284 		}
285 		if (*p == MIDI_TIMER_SYNC) {
286 			debugC(3, kDebugLevelSound, "Timer sync");
287 			p++; // Jump over the timer sync byte as it's not needed
288 			continue;
289 		}
290 
291 		// Check for delta time
292 		uint8 delta = *p;
293 		if (midiObj->_ticks + delta > _ticks)
294 			break;
295 		midiObj->_ticks += delta;
296 		p++;
297 
298 		// Check for end of MIDI sequence marker (This time it after reading delta-time)
299 		if (*p == MIDI_STOP_SEQUENCE) {
300 			debugC(3, kDebugLevelSound, "End of MIDI sequence (After reading delta-time)");
301 			_playing = false;
302 			midiObj->rewind();
303 			return;
304 		}
305 
306 		// Separate byte into command and channel if it's a command byte.
307 		// Otherwise use running status (i.e. previously set command and channel).
308 		if (*p & 0x80) {
309 			cmd = *p++;
310 			chn = cmd & 0x0f;
311 			cmd >>= 4;
312 		}
313 
314 		switch (cmd) {
315 		case MIDI_NOTE_OFF:
316 			parm1 = *p++;
317 			parm2 = *p++;
318 			debugC(3, kDebugLevelSound, "channel %X: note off (key = %d, velocity = %d)", chn, parm1, parm2);
319 			midiNoteOff(chn, parm1, parm2);
320 			break;
321 		case MIDI_NOTE_ON:
322 			parm1 = *p++;
323 			parm2 = *p++;
324 			debugC(3, kDebugLevelSound, "channel %X: note on (key = %d, velocity = %d)", chn, parm1, parm2);
325 			midiNoteOn(chn, parm1, parm2);
326 			break;
327 		case MIDI_CONTROLLER:
328 			parm1 = *p++;
329 			parm2 = *p++;
330 			debugC(3, kDebugLevelSound, "channel %X: controller %02X = %02X", chn, parm1, parm2);
331 			// The tested Apple IIGS AGI MIDI resources only used
332 			// controllers 0 (Bank select?), 7 (Volume) and 64 (Sustain On/Off).
333 			// Controller 0's parameter was in range 94-127,
334 			// controller 7's parameter was in range 0-127 and
335 			// controller 64's parameter was always 0 (i.e. sustain off).
336 			switch (parm1) {
337 			case 7:
338 				_channels[chn].setVolume(parm2);
339 				break;
340 			default:
341 				break;
342 			}
343 			break;
344 		case MIDI_PROGRAM_CHANGE:
345 			parm1 = *p++;
346 			debugC(3, kDebugLevelSound, "channel %X: program change %02X", chn, parm1);
347 			_channels[chn].setInstrument(getInstrument(parm1));
348 			break;
349 		case MIDI_PITCH_WHEEL:
350 			parm1 = *p++;
351 			parm2 = *p++;
352 			debugC(3, kDebugLevelSound, "channel %X: pitch wheel (unimplemented) %02X, %02X", chn, parm1, parm2);
353 			break;
354 
355 		default:
356 			debugC(3, kDebugLevelSound, "channel %X: unimplemented command %02X", chn, cmd);
357 			break;
358 		}
359 	}
360 
361 	midiObj->setPtr(p);
362 }
363 
midiNoteOff(int channel,int note,int velocity)364 void SoundGen2GS::midiNoteOff(int channel, int note, int velocity) {
365 	// Release keys within the given MIDI channel
366 	for (int i = 0; i < MAX_GENERATORS; i++) {
367 		if (_generators[i].channel == channel && _generators[i].key == note) {
368 			if (_generators[i].curInstrument) {
369 				_generators[i].seg = _generators[i].curInstrument->seg;
370 			}
371 		}
372 	}
373 }
374 
midiNoteOn(int channel,int note,int velocity)375 void SoundGen2GS::midiNoteOn(int channel, int note, int velocity) {
376 	if (!_channels[channel].getInstrument()) {
377 		debugC(3, kDebugLevelSound, "midiNoteOn(): no instrument specified for channel %d", channel);
378 		return;
379 	}
380 
381 	// Allocate a generator for the note.
382 	IIgsGenerator *generator = allocateGenerator();
383 	generator->curInstrument = _channels[channel].getInstrument();
384 	const IIgsInstrumentHeader *curInstrument = generator->curInstrument;
385 
386 	// Pass information from the MIDI channel to the generator. Take
387 	// velocity into account, although simplistically.
388 	velocity *= 5 / 3;
389 	if (velocity > 127)
390 		velocity = 127;
391 
392 	generator->key = note;
393 	generator->velocity = velocity * _channels[channel].getVolume() / 127;
394 	generator->channel = channel;
395 
396 	// Instruments can define different samples to be used based on
397 	// what the key is. Find the correct samples for our key.
398 	int wa = 0;
399 	int wb = 0;
400 	while (wa < curInstrument->waveCount[0] - 1 && note > curInstrument->wave[0][wa].key)
401 		wa++;
402 	while (wb < curInstrument->waveCount[1] - 1 && note > curInstrument->wave[1][wb].key)
403 		wb++;
404 
405 	// Prepare the generator.
406 	generator->osc[0].base  = curInstrument->wavetableBase + curInstrument->wave[0][wa].offset;
407 	generator->osc[0].size  = curInstrument->wave[0][wa].size;
408 	generator->osc[0].pd    = doubleToFrac(midiKeyToFreq(note, (double)curInstrument->wave[0][wa].tune / 256.0) / (double)_sampleRate);
409 	generator->osc[0].p     = 0;
410 	generator->osc[0].halt  = curInstrument->wave[0][wa].halt;
411 	generator->osc[0].loop  = curInstrument->wave[0][wa].loop;
412 	generator->osc[0].swap  = curInstrument->wave[0][wa].swap;
413 	generator->osc[0].rightChannel = curInstrument->wave[0][wa].rightChannel;
414 
415 	generator->osc[1].base  = curInstrument->wavetableBase + curInstrument->wave[1][wb].offset;
416 	generator->osc[1].size  = curInstrument->wave[1][wb].size;
417 	generator->osc[1].pd    = doubleToFrac(midiKeyToFreq(note, (double)curInstrument->wave[1][wb].tune / 256.0) / (double)_sampleRate);
418 	generator->osc[1].p     = 0;
419 	generator->osc[1].halt  = curInstrument->wave[1][wb].halt;
420 	generator->osc[1].loop  = curInstrument->wave[1][wb].loop;
421 	generator->osc[1].swap  = curInstrument->wave[1][wb].swap;
422 	generator->osc[1].rightChannel = curInstrument->wave[1][wb].rightChannel;
423 
424 	generator->seg  = 0;
425 	generator->a    = 0;
426 
427 	// Print debug messages for instruments with swap mode or vibrato enabled
428 	if (generator->osc[0].swap || generator->osc[1].swap)
429 		debugC(2, kDebugLevelSound, "Detected swap mode in a playing instrument. This is rare and is not tested well...");
430 	if (curInstrument->vibDepth > 0)
431 		debugC(2, kDebugLevelSound, "Detected vibrato in a playing instrument. Vibrato is not implemented, playing without...");
432 }
433 
midiKeyToFreq(int key,double finetune)434 double SoundGen2GS::midiKeyToFreq(int key, double finetune) {
435 	return 440.0 * pow(2.0, (15.0 + (double)key + finetune) / 12.0);
436 }
437 
haltGenerators()438 void SoundGen2GS::haltGenerators() {
439 	for (int i = 0; i < MAX_GENERATORS; i++) {
440 		// Reset instrument pointer especially for samples, because samples are deleted on unload/room changes
441 		// and not resetting them here would cause those invalidated samples get accessed during generateOutput()
442 		_generators[i].curInstrument = nullptr;
443 		_generators[i].osc[0].halt = true;
444 		_generators[i].osc[1].halt = true;
445 	}
446 }
447 
activeGenerators()448 uint SoundGen2GS::activeGenerators() {
449 	int n = 0;
450 	for (int i = 0; i < MAX_GENERATORS; i++)
451 		if (!_generators[i].osc[0].halt || !_generators[i].osc[1].halt)
452 			n++;
453 	return n;
454 }
455 
setProgramChangeMapping(const IIgsMidiProgramMapping * mapping)456 void SoundGen2GS::setProgramChangeMapping(const IIgsMidiProgramMapping *mapping) {
457 	_progToInst = mapping;
458 }
459 
IIgsMidi(uint8 * data,uint32 len,int resnum)460 IIgsMidi::IIgsMidi(uint8 *data, uint32 len, int resnum) : AgiSound() {
461 	_data = data; // Save the resource pointer
462 	_ptr = _data + 2; // Set current position to just after the header
463 	_len = len;  // Save the resource's length
464 	_type = READ_LE_UINT16(data); // Read sound resource's type
465 	_ticks = 0;
466 	_isValid = (_type == AGI_SOUND_MIDI) && (_data != NULL) && (_len >= 2);
467 
468 	if (!_isValid) // Check for errors
469 		warning("Error creating Apple IIGS midi sound from resource %d (Type %d, length %d)", resnum, _type, len);
470 }
471 
472 /**
473  * Convert sample from 8-bit unsigned to 8-bit signed format.
474  * @param source  Source stream containing the 8-bit unsigned sample data.
475  * @param dest  Destination buffer for the 8-bit signed sample data.
476  * @param length  Length of the sample data to be converted.
477  */
convertWave(Common::SeekableReadStream & source,int8 * dest,uint length)478 static bool convertWave(Common::SeekableReadStream &source, int8 *dest, uint length) {
479 	// Convert the wave from 8-bit unsigned to 8-bit signed format
480 	for (uint i = 0; i < length; i++)
481 		dest[i] = (int8)((int)source.readByte() - ZERO_OFFSET);
482 	return !(source.eos() || source.err());
483 }
484 
IIgsSample(uint8 * data,uint32 len,int16 resourceNr)485 IIgsSample::IIgsSample(uint8 *data, uint32 len, int16 resourceNr) : AgiSound() {
486 	Common::MemoryReadStream stream(data, len, DisposeAfterUse::YES);
487 
488 	_sample = nullptr;
489 
490 	// Check that the header was read ok and that it's of the correct type
491 	if (_header.read(stream) && _header.type == AGI_SOUND_SAMPLE) { // An Apple IIGS AGI sample resource
492 		uint32 sampleStartPos = stream.pos();
493 		uint32 tailLen = stream.size() - sampleStartPos;
494 
495 		if (tailLen < _header.sampleSize) { // Check if there's no room for the sample data in the stream
496 			// Apple IIGS Manhunter I: Sound resource 16 has only 16074 bytes
497 			// of sample data although header says it should have 16384 bytes.
498 			warning("Apple IIGS sample (%d) expected %d bytes, got %d bytes only",
499 			        resourceNr, _header.sampleSize, tailLen);
500 
501 			_header.sampleSize = (uint16) tailLen; // Use the part that's left
502 		}
503 
504 		if (_header.pitch > 0x7F) { // Check if the pitch is invalid
505 			warning("Apple IIGS sample (%d) has too high pitch (0x%02x)", resourceNr, _header.pitch);
506 
507 			_header.pitch &= 0x7F; // Apple IIGS AGI probably did it this way too
508 		}
509 
510 		// Convert sample data from 8-bit unsigned to 8-bit signed format
511 		stream.seek(sampleStartPos);
512 		_sample = new int8[_header.sampleSize];
513 
514 		if (_sample != NULL) {
515 			_isValid = convertWave(stream, _sample, _header.sampleSize);
516 
517 			if (_isValid) {
518 				// Finalize header info using sample data
519 				_header.finalize(_sample);
520 			}
521 		}
522 	}
523 
524 	if (!_isValid) // Check for errors
525 		warning("Error creating Apple IIGS sample from resource %d (Type %d, length %d)", resourceNr, _header.type, len);
526 }
527 
528 
read(Common::SeekableReadStream & stream,bool ignoreAddr)529 bool IIgsInstrumentHeader::read(Common::SeekableReadStream &stream, bool ignoreAddr) {
530 	for (int i = 0; i < ENVELOPE_SEGMENT_COUNT; i++) {
531 		env[i].bp = intToFrac(stream.readByte());
532 		env[i].inc = intToFrac(stream.readUint16LE()) >> 8;
533 	}
534 	seg         = stream.readByte();
535 	/*priority  =*/ stream.readByte(); // Not needed. 32 in all tested data.
536 	bend        = stream.readByte();
537 	vibDepth    = stream.readByte();
538 	vibSpeed    = stream.readByte();
539 	stream.readByte(); // Not needed? 0 in all tested data.
540 
541 	waveCount[0] = stream.readByte();
542 	waveCount[1] = stream.readByte();
543 	for (int i = 0; i < 2; i++) {
544 		for (int k = 0; k < waveCount[i]; k++) {
545 			wave[i][k].key = stream.readByte();
546 			wave[i][k].offset = stream.readByte() << 8;
547 			wave[i][k].size = 0x100 << (stream.readByte() & 7);
548 			uint8 b = stream.readByte();
549 			wave[i][k].tune = stream.readUint16LE();
550 
551 			// For sample resources we ignore the address.
552 			if (ignoreAddr)
553 				wave[i][k].offset = 0;
554 
555 			// Parse the generator mode byte to separate fields.
556 			wave[i][k].halt = b & 0x1;          // Bit 0     = HALT
557 			wave[i][k].loop = !(b & 0x2);       // Bit 1     =!LOOP
558 			wave[i][k].swap = (b & 0x6) == 0x6; // Bit 1&2   = SWAP
559 			// channels seem to be reversed, verified with emulator + captured apple IIgs music
560 			if (b & 0x10) {
561 				wave[i][k].rightChannel = true; // Bit 4 set = right channel
562 			} else {
563 				wave[i][k].rightChannel = false; // Bit 4 not set = left channel
564 			}
565 		}
566 	}
567 
568 	return !(stream.eos() || stream.err());
569 }
570 
finalize(int8 * wavetable,uint32 wavetableSize)571 bool IIgsInstrumentHeader::finalize(int8 *wavetable, uint32 wavetableSize) {
572 	wavetableBase = wavetable;
573 
574 	// Go through all offsets and sizes and make sure, they point to within wavetable
575 	for (int i = 0; i < 2; i++) {
576 		for (int k = 0; k < waveCount[i]; k++) {
577 			uint32 waveOffset = wave[i][k].offset;
578 			uint32 waveSize   = wave[i][k].size;
579 
580 			if (waveOffset >= wavetableSize) {
581 				error("Apple IIgs sound: sample data points outside of wavetable");
582 			}
583 
584 			if ((waveOffset + waveSize) > wavetableSize) {
585 				// fix up size, it's actually saved in a way in the header, that it can't be correct
586 				// if we don't fix it here, we would do invalid memory access, which results in potential crashes
587 				wave[i][k].size = wavetableSize - waveOffset;
588 			}
589 
590 			// Detect true sample size
591 			int8 *sample = wavetableBase + wave[i][k].offset;
592 			uint32 trueSize;
593 			for (trueSize = 0; trueSize < wave[i][k].size; trueSize++) {
594 				if (sample[trueSize] == -ZERO_OFFSET)
595 					break;
596 			}
597 			wave[i][k].size = trueSize;
598 		}
599 	}
600 
601 	return true;
602 }
603 
read(Common::SeekableReadStream & stream)604 bool IIgsSampleHeader::read(Common::SeekableReadStream &stream) {
605 	type                = stream.readUint16LE();
606 	pitch               = stream.readByte();
607 	unknownByte_Ofs3    = stream.readByte();
608 	volume              = stream.readByte();
609 	unknownByte_Ofs5    = stream.readByte();
610 	instrumentSize      = stream.readUint16LE();
611 	sampleSize          = stream.readUint16LE();
612 	// Read the instrument header *ignoring* its wave address info
613 	return instrument.read(stream, true);
614 }
615 
finalize(int8 * sampleData)616 bool IIgsSampleHeader::finalize(int8 *sampleData) {
617 	return instrument.finalize(sampleData, sampleSize);
618 }
619 
620 //###
621 //### LOADER METHODS
622 //###
623 
loadInstruments()624 bool SoundGen2GS::loadInstruments() {
625 	// Get info on the particular Apple IIGS AGI game's executable
626 	const IIgsExeInfo *exeInfo = getIIgsExeInfo((enum AgiGameID)_vm->getGameID());
627 	if (exeInfo == NULL) {
628 		warning("Unsupported Apple IIGS game, not loading instruments");
629 		return false;
630 	}
631 
632 	// Find the executable file and the wavetable file
633 	Common::ArchiveMemberList exeNames, waveNames;
634 	SearchMan.listMatchingMembers(exeNames, "*.SYS16");
635 	SearchMan.listMatchingMembers(exeNames, "*.SYS");
636 	SearchMan.listMatchingMembers(waveNames, "SIERRASTANDARD");
637 	SearchMan.listMatchingMembers(waveNames, "SIERRAST");
638 
639 	if (exeNames.empty()) {
640 		warning("Couldn't find Apple IIGS game executable (*.SYS16 or *.SYS), not loading instruments");
641 		return false;
642 	}
643 	if (waveNames.empty()) {
644 		warning("Couldn't find Apple IIGS wave file (SIERRASTANDARD or SIERRAST), not loading instruments");
645 		return false;
646 	}
647 
648 	Common::String exeName  = exeNames.front()->getName();
649 	Common::String waveName = waveNames.front()->getName();
650 
651 	// Set the MIDI program change to instrument number mapping and
652 	// load the instrument headers and their sample data.
653 	setProgramChangeMapping(exeInfo->instSet->progToInst);
654 	return loadWaveFile(waveName, *exeInfo) && loadInstrumentHeaders(exeName, *exeInfo);
655 }
656 
657 /** Older Apple IIGS AGI MIDI program change to instrument number mapping. */
658 static const IIgsMidiProgramMapping progToInstMappingV1 = {
659 	{
660 		19, 20, 22, 23, 21, 24, 5, 5, 5, 5,
661 		6, 7, 10, 9, 11, 9, 15, 8, 5, 5,
662 		17, 16, 18, 12, 14, 5, 5, 5, 5, 5,
663 		0, 1, 2, 9, 3, 4, 15, 2, 2, 2,
664 		25, 13, 13, 25
665 	},
666 	5
667 };
668 
669 /** Newer Apple IIGS AGI MIDI program change to instrument number mapping.
670 	FIXME: Some instrument choices sound wrong. */
671 static const IIgsMidiProgramMapping progToInstMappingV2 = {
672 	{
673 		21, 22, 24, 25, 23, 26, 6, 6, 6, 6,
674 		7, 9, 12, 8, 13, 11, 17, 10, 6, 6,
675 		19, 18, 20, 14, 16, 6, 6, 6, 6, 6,
676 		0, 1, 2, 4, 3, 5, 17, 2, 2, 2,
677 		27, 15, 15, 27
678 	},
679 	6
680 };
681 
682 // Older Apple IIGS AGI instrument set. Used only by Space Quest I (AGI v1.002).
683 //
684 // Instrument 0 uses vibrato.
685 // Instrument 1 uses vibrato.
686 // Instrument 3 uses vibrato.
687 // Instrument 5 has swap mode enabled for the first oscillator.
688 // Instruemnt 9 uses vibrato.
689 // Instrument 10 uses vibrato.
690 // Instrument 12 uses vibrato.
691 // Instrument 15 uses vibrato.
692 // Instrument 16 uses vibrato.
693 // Instrument 18 uses vibrato.
694 static const IIgsInstrumentSetInfo instSetV1 = {
695 	1192, 26, "7ee16bbc135171ffd6b9120cc7ff1af2", "edd3bf8905d9c238e02832b732fb2e18", &progToInstMappingV1
696 };
697 
698 // Newer Apple IIGS AGI instrument set (AGI v1.003+). Used by all others than Space Quest I.
699 //
700 // Instrument 0 uses vibrato.
701 // Instrument 1 uses vibrato.
702 // Instrument 3 uses vibrato.
703 // Instrument 6 has swap mode enabled for the first oscillator.
704 // Instrument 11 uses vibrato.
705 // Instrument 12 uses vibrato.
706 // Instrument 14 uses vibrato.
707 // Instrument 17 uses vibrato.
708 // Instrument 18 uses vibrato.
709 // Instrument 20 uses vibrato.
710 //
711 // In KQ1 intro and in LSL intro one (and the same, or at least similar)
712 // instrument is using vibrato. In PQ intro there is also one instrument
713 // using vibrato.
714 static const IIgsInstrumentSetInfo instSetV2 = {
715 	1292, 28, "b7d428955bb90721996de1cbca25e768", "c05fb0b0e11deefab58bc68fbd2a3d07", &progToInstMappingV2
716 };
717 
718 /** Information about different Apple IIGS AGI executables. */
719 static const IIgsExeInfo IIgsExeInfos[] = {
720 	{GID_SQ1,      "SQ",   0x1002, 138496, 0x80AD, &instSetV1},
721 	{GID_LSL1,     "LL",   0x1003, 141003, 0x844E, &instSetV2},
722 	{GID_AGIDEMO,  "DEMO", 0x1005, 141884, 0x8469, &instSetV2},
723 	{GID_KQ1,      "KQ",   0x1006, 141894, 0x8469, &instSetV2},
724 	{GID_PQ1,      "PQ",   0x1007, 141882, 0x8469, &instSetV2},
725 	{GID_MIXEDUP,  "MG",   0x1013, 142552, 0x84B7, &instSetV2},
726 	{GID_KQ2,      "KQ2",  0x1013, 143775, 0x84B7, &instSetV2},
727 	{GID_KQ3,      "KQ3",  0x1014, 144312, 0x84B7, &instSetV2},
728 	{GID_SQ2,      "SQ2",  0x1014, 107882, 0x6563, &instSetV2},
729 	{GID_MH1,      "MH",   0x2004, 147678, 0x8979, &instSetV2},
730 	{GID_KQ4,      "KQ4",  0x2006, 147652, 0x8979, &instSetV2},
731 	{GID_BC,       "BC",   0x3001, 148192, 0x8979, &instSetV2},
732 	{GID_GOLDRUSH, "GR",   0x3003, 148268, 0x8979, &instSetV2}
733 };
734 
735 /**
736  * Finds information about an Apple IIGS AGI executable based on the game ID.
737  * @return A non-null IIgsExeInfo pointer if successful, otherwise NULL.
738  */
getIIgsExeInfo(enum AgiGameID gameid) const739 const IIgsExeInfo *SoundGen2GS::getIIgsExeInfo(enum AgiGameID gameid) const {
740 	for (int i = 0; i < ARRAYSIZE(IIgsExeInfos); i++)
741 		if (IIgsExeInfos[i].gameid == gameid)
742 			return &IIgsExeInfos[i];
743 	return NULL;
744 }
745 
loadInstrumentHeaders(Common::String & exePath,const IIgsExeInfo & exeInfo)746 bool SoundGen2GS::loadInstrumentHeaders(Common::String &exePath, const IIgsExeInfo &exeInfo) {
747 	Common::File file;
748 
749 	// Open the executable file and check that it has correct size
750 	file.open(exePath);
751 	if (file.size() != (int32)exeInfo.exeSize) {
752 		debugC(3, kDebugLevelSound, "Apple IIGS executable (%s) has wrong size (Is %d, should be %d)",
753 		       exePath.c_str(), (int)file.size(), exeInfo.exeSize);
754 	}
755 
756 	// Read the whole executable file into memory
757 	// CHECKME: Why do we read the file into memory first? It does not seem to be
758 	// kept outside of this function. Is the processing of the data too slow
759 	// otherwise?
760 	Common::ScopedPtr<Common::SeekableReadStream> data(file.readStream(file.size()));
761 	file.close();
762 
763 	// Check that we got enough data to be able to parse the instruments
764 	if (!data || data->size() < (int32)(exeInfo.instSetStart + exeInfo.instSet->byteCount)) {
765 		warning("Error loading instruments from Apple IIGS executable (%s)", exePath.c_str());
766 		return false;
767 	}
768 
769 	// Check instrument set's length (The info's saved in the executable)
770 	data->seek(exeInfo.instSetStart - 4);
771 	uint16 instSetByteCount = data->readUint16LE();
772 	if (instSetByteCount != exeInfo.instSet->byteCount) {
773 		debugC(3, kDebugLevelSound, "Wrong instrument set size (Is %d, should be %d) in Apple IIGS executable (%s)",
774 		       instSetByteCount, exeInfo.instSet->byteCount, exePath.c_str());
775 	}
776 
777 	// Check instrument set's md5sum
778 	data->seek(exeInfo.instSetStart);
779 	Common::String md5str = Common::computeStreamMD5AsString(*data, exeInfo.instSet->byteCount);
780 	if (md5str != exeInfo.instSet->md5) {
781 		warning("Unknown Apple IIGS instrument set (md5: %s) in %s, trying to use it nonetheless",
782 		        md5str.c_str(), exePath.c_str());
783 	}
784 
785 	// Read in the instrument set one instrument at a time
786 	data->seek(exeInfo.instSetStart);
787 
788 	_instruments.clear();
789 	_instruments.reserve(exeInfo.instSet->instCount);
790 
791 	IIgsInstrumentHeader instrument;
792 	for (uint i = 0; i < exeInfo.instSet->instCount; i++) {
793 		if (!instrument.read(*data)) {
794 			warning("Error loading Apple IIGS instrument (%d. of %d) from %s, not loading more instruments",
795 			        i + 1, exeInfo.instSet->instCount, exePath.c_str());
796 			break;
797 		}
798 		instrument.finalize(_wavetable, SIERRASTANDARD_SIZE);
799 		_instruments.push_back(instrument);
800 	}
801 
802 	// Loading was successful only if all instruments were loaded successfully
803 	return (_instruments.size() == exeInfo.instSet->instCount);
804 }
805 
loadWaveFile(Common::String & wavePath,const IIgsExeInfo & exeInfo)806 bool SoundGen2GS::loadWaveFile(Common::String &wavePath, const IIgsExeInfo &exeInfo) {
807 	Common::File file;
808 
809 	// Open the wave file and read it into memory
810 	// CHECKME: Why do we read the file into memory first? It does not seem to be
811 	// kept outside of this function. Is the processing of the data too slow
812 	// otherwise?
813 	file.open(wavePath);
814 	Common::ScopedPtr<Common::SeekableReadStream> uint8Wave(file.readStream(file.size()));
815 	file.close();
816 
817 	// Check that we got the whole wave file
818 	if (!uint8Wave || (uint8Wave->size() != SIERRASTANDARD_SIZE)) {
819 		warning("Error loading Apple IIGS wave file (%s), not loading instruments", wavePath.c_str());
820 		return false;
821 	}
822 
823 	// Check wave file's md5sum
824 	Common::String md5str = Common::computeStreamMD5AsString(*uint8Wave, SIERRASTANDARD_SIZE);
825 	if (md5str != exeInfo.instSet->waveFileMd5) {
826 		warning("Unknown Apple IIGS wave file (md5: %s, game: %s).\n" \
827 		        "Please report the information on the previous line to the ScummVM team.\n" \
828 		        "Using the wave file as it is - music may sound weird", md5str.c_str(), exeInfo.exePrefix);
829 	}
830 
831 	// Convert the wave file to 8-bit signed and save the result
832 	uint8Wave->seek(0);
833 	return convertWave(*uint8Wave, _wavetable, SIERRASTANDARD_SIZE);
834 }
835 
836 } // End of namespace Agi
837