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