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 }
341 break;
342 case MIDI_PROGRAM_CHANGE:
343 parm1 = *p++;
344 debugC(3, kDebugLevelSound, "channel %X: program change %02X", chn, parm1);
345 _channels[chn].setInstrument(getInstrument(parm1));
346 break;
347 case MIDI_PITCH_WHEEL:
348 parm1 = *p++;
349 parm2 = *p++;
350 debugC(3, kDebugLevelSound, "channel %X: pitch wheel (unimplemented) %02X, %02X", chn, parm1, parm2);
351 break;
352
353 default:
354 debugC(3, kDebugLevelSound, "channel %X: unimplemented command %02X", chn, cmd);
355 break;
356 }
357 }
358
359 midiObj->setPtr(p);
360 }
361
midiNoteOff(int channel,int note,int velocity)362 void SoundGen2GS::midiNoteOff(int channel, int note, int velocity) {
363 // Release keys within the given MIDI channel
364 for (int i = 0; i < MAX_GENERATORS; i++) {
365 if (_generators[i].channel == channel && _generators[i].key == note) {
366 if (_generators[i].curInstrument) {
367 _generators[i].seg = _generators[i].curInstrument->seg;
368 }
369 }
370 }
371 }
372
midiNoteOn(int channel,int note,int velocity)373 void SoundGen2GS::midiNoteOn(int channel, int note, int velocity) {
374 if (!_channels[channel].getInstrument()) {
375 debugC(3, kDebugLevelSound, "midiNoteOn(): no instrument specified for channel %d", channel);
376 return;
377 }
378
379 // Allocate a generator for the note.
380 IIgsGenerator *generator = allocateGenerator();
381 generator->curInstrument = _channels[channel].getInstrument();
382 const IIgsInstrumentHeader *curInstrument = generator->curInstrument;
383
384 // Pass information from the MIDI channel to the generator. Take
385 // velocity into account, although simplistically.
386 velocity *= 5 / 3;
387 if (velocity > 127)
388 velocity = 127;
389
390 generator->key = note;
391 generator->velocity = velocity * _channels[channel].getVolume() / 127;
392 generator->channel = channel;
393
394 // Instruments can define different samples to be used based on
395 // what the key is. Find the correct samples for our key.
396 int wa = 0;
397 int wb = 0;
398 while (wa < curInstrument->waveCount[0] - 1 && note > curInstrument->wave[0][wa].key)
399 wa++;
400 while (wb < curInstrument->waveCount[1] - 1 && note > curInstrument->wave[1][wb].key)
401 wb++;
402
403 // Prepare the generator.
404 generator->osc[0].base = curInstrument->wavetableBase + curInstrument->wave[0][wa].offset;
405 generator->osc[0].size = curInstrument->wave[0][wa].size;
406 generator->osc[0].pd = doubleToFrac(midiKeyToFreq(note, (double)curInstrument->wave[0][wa].tune / 256.0) / (double)_sampleRate);
407 generator->osc[0].p = 0;
408 generator->osc[0].halt = curInstrument->wave[0][wa].halt;
409 generator->osc[0].loop = curInstrument->wave[0][wa].loop;
410 generator->osc[0].swap = curInstrument->wave[0][wa].swap;
411 generator->osc[0].rightChannel = curInstrument->wave[0][wa].rightChannel;
412
413 generator->osc[1].base = curInstrument->wavetableBase + curInstrument->wave[1][wb].offset;
414 generator->osc[1].size = curInstrument->wave[1][wb].size;
415 generator->osc[1].pd = doubleToFrac(midiKeyToFreq(note, (double)curInstrument->wave[1][wb].tune / 256.0) / (double)_sampleRate);
416 generator->osc[1].p = 0;
417 generator->osc[1].halt = curInstrument->wave[1][wb].halt;
418 generator->osc[1].loop = curInstrument->wave[1][wb].loop;
419 generator->osc[1].swap = curInstrument->wave[1][wb].swap;
420 generator->osc[1].rightChannel = curInstrument->wave[1][wb].rightChannel;
421
422 generator->seg = 0;
423 generator->a = 0;
424
425 // Print debug messages for instruments with swap mode or vibrato enabled
426 if (generator->osc[0].swap || generator->osc[1].swap)
427 debugC(2, kDebugLevelSound, "Detected swap mode in a playing instrument. This is rare and is not tested well...");
428 if (curInstrument->vibDepth > 0)
429 debugC(2, kDebugLevelSound, "Detected vibrato in a playing instrument. Vibrato is not implemented, playing without...");
430 }
431
midiKeyToFreq(int key,double finetune)432 double SoundGen2GS::midiKeyToFreq(int key, double finetune) {
433 return 440.0 * pow(2.0, (15.0 + (double)key + finetune) / 12.0);
434 }
435
haltGenerators()436 void SoundGen2GS::haltGenerators() {
437 for (int i = 0; i < MAX_GENERATORS; i++) {
438 // Reset instrument pointer especially for samples, because samples are deleted on unload/room changes
439 // and not resetting them here would cause those invalidated samples get accessed during generateOutput()
440 _generators[i].curInstrument = nullptr;
441 _generators[i].osc[0].halt = true;
442 _generators[i].osc[1].halt = true;
443 }
444 }
445
activeGenerators()446 uint SoundGen2GS::activeGenerators() {
447 int n = 0;
448 for (int i = 0; i < MAX_GENERATORS; i++)
449 if (!_generators[i].osc[0].halt || !_generators[i].osc[1].halt)
450 n++;
451 return n;
452 }
453
setProgramChangeMapping(const IIgsMidiProgramMapping * mapping)454 void SoundGen2GS::setProgramChangeMapping(const IIgsMidiProgramMapping *mapping) {
455 _progToInst = mapping;
456 }
457
IIgsMidi(uint8 * data,uint32 len,int resnum)458 IIgsMidi::IIgsMidi(uint8 *data, uint32 len, int resnum) : AgiSound() {
459 _data = data; // Save the resource pointer
460 _ptr = _data + 2; // Set current position to just after the header
461 _len = len; // Save the resource's length
462 _type = READ_LE_UINT16(data); // Read sound resource's type
463 _ticks = 0;
464 _isValid = (_type == AGI_SOUND_MIDI) && (_data != NULL) && (_len >= 2);
465
466 if (!_isValid) // Check for errors
467 warning("Error creating Apple IIGS midi sound from resource %d (Type %d, length %d)", resnum, _type, len);
468 }
469
470 /**
471 * Convert sample from 8-bit unsigned to 8-bit signed format.
472 * @param source Source stream containing the 8-bit unsigned sample data.
473 * @param dest Destination buffer for the 8-bit signed sample data.
474 * @param length Length of the sample data to be converted.
475 */
convertWave(Common::SeekableReadStream & source,int8 * dest,uint length)476 static bool convertWave(Common::SeekableReadStream &source, int8 *dest, uint length) {
477 // Convert the wave from 8-bit unsigned to 8-bit signed format
478 for (uint i = 0; i < length; i++)
479 dest[i] = (int8)((int)source.readByte() - ZERO_OFFSET);
480 return !(source.eos() || source.err());
481 }
482
IIgsSample(uint8 * data,uint32 len,int16 resourceNr)483 IIgsSample::IIgsSample(uint8 *data, uint32 len, int16 resourceNr) : AgiSound() {
484 Common::MemoryReadStream stream(data, len, DisposeAfterUse::YES);
485
486 _sample = nullptr;
487
488 // Check that the header was read ok and that it's of the correct type
489 if (_header.read(stream) && _header.type == AGI_SOUND_SAMPLE) { // An Apple IIGS AGI sample resource
490 uint32 sampleStartPos = stream.pos();
491 uint32 tailLen = stream.size() - sampleStartPos;
492
493 if (tailLen < _header.sampleSize) { // Check if there's no room for the sample data in the stream
494 // Apple IIGS Manhunter I: Sound resource 16 has only 16074 bytes
495 // of sample data although header says it should have 16384 bytes.
496 warning("Apple IIGS sample (%d) expected %d bytes, got %d bytes only",
497 resourceNr, _header.sampleSize, tailLen);
498
499 _header.sampleSize = (uint16) tailLen; // Use the part that's left
500 }
501
502 if (_header.pitch > 0x7F) { // Check if the pitch is invalid
503 warning("Apple IIGS sample (%d) has too high pitch (0x%02x)", resourceNr, _header.pitch);
504
505 _header.pitch &= 0x7F; // Apple IIGS AGI probably did it this way too
506 }
507
508 // Convert sample data from 8-bit unsigned to 8-bit signed format
509 stream.seek(sampleStartPos);
510 _sample = new int8[_header.sampleSize];
511
512 if (_sample != NULL) {
513 _isValid = convertWave(stream, _sample, _header.sampleSize);
514
515 if (_isValid) {
516 // Finalize header info using sample data
517 _header.finalize(_sample);
518 }
519 }
520 }
521
522 if (!_isValid) // Check for errors
523 warning("Error creating Apple IIGS sample from resource %d (Type %d, length %d)", resourceNr, _header.type, len);
524 }
525
526
read(Common::SeekableReadStream & stream,bool ignoreAddr)527 bool IIgsInstrumentHeader::read(Common::SeekableReadStream &stream, bool ignoreAddr) {
528 for (int i = 0; i < ENVELOPE_SEGMENT_COUNT; i++) {
529 env[i].bp = intToFrac(stream.readByte());
530 env[i].inc = intToFrac(stream.readUint16LE()) >> 8;
531 }
532 seg = stream.readByte();
533 /*priority =*/ stream.readByte(); // Not needed. 32 in all tested data.
534 bend = stream.readByte();
535 vibDepth = stream.readByte();
536 vibSpeed = stream.readByte();
537 stream.readByte(); // Not needed? 0 in all tested data.
538
539 waveCount[0] = stream.readByte();
540 waveCount[1] = stream.readByte();
541 for (int i = 0; i < 2; i++) {
542 for (int k = 0; k < waveCount[i]; k++) {
543 wave[i][k].key = stream.readByte();
544 wave[i][k].offset = stream.readByte() << 8;
545 wave[i][k].size = 0x100 << (stream.readByte() & 7);
546 uint8 b = stream.readByte();
547 wave[i][k].tune = stream.readUint16LE();
548
549 // For sample resources we ignore the address.
550 if (ignoreAddr)
551 wave[i][k].offset = 0;
552
553 // Parse the generator mode byte to separate fields.
554 wave[i][k].halt = b & 0x1; // Bit 0 = HALT
555 wave[i][k].loop = !(b & 0x2); // Bit 1 =!LOOP
556 wave[i][k].swap = (b & 0x6) == 0x6; // Bit 1&2 = SWAP
557 // channels seem to be reversed, verified with emulator + captured apple IIgs music
558 if (b & 0x10) {
559 wave[i][k].rightChannel = true; // Bit 4 set = right channel
560 } else {
561 wave[i][k].rightChannel = false; // Bit 4 not set = left channel
562 }
563 }
564 }
565
566 return !(stream.eos() || stream.err());
567 }
568
finalize(int8 * wavetable,uint32 wavetableSize)569 bool IIgsInstrumentHeader::finalize(int8 *wavetable, uint32 wavetableSize) {
570 wavetableBase = wavetable;
571
572 // Go through all offsets and sizes and make sure, they point to within wavetable
573 for (int i = 0; i < 2; i++) {
574 for (int k = 0; k < waveCount[i]; k++) {
575 uint32 waveOffset = wave[i][k].offset;
576 uint32 waveSize = wave[i][k].size;
577
578 if (waveOffset >= wavetableSize) {
579 error("Apple IIgs sound: sample data points outside of wavetable");
580 }
581
582 if ((waveOffset + waveSize) > wavetableSize) {
583 // fix up size, it's actually saved in a way in the header, that it can't be correct
584 // if we don't fix it here, we would do invalid memory access, which results in potential crashes
585 wave[i][k].size = wavetableSize - waveOffset;
586 }
587
588 // Detect true sample size
589 int8 *sample = wavetableBase + wave[i][k].offset;
590 uint32 trueSize;
591 for (trueSize = 0; trueSize < wave[i][k].size; trueSize++) {
592 if (sample[trueSize] == -ZERO_OFFSET)
593 break;
594 }
595 wave[i][k].size = trueSize;
596 }
597 }
598
599 return true;
600 }
601
read(Common::SeekableReadStream & stream)602 bool IIgsSampleHeader::read(Common::SeekableReadStream &stream) {
603 type = stream.readUint16LE();
604 pitch = stream.readByte();
605 unknownByte_Ofs3 = stream.readByte();
606 volume = stream.readByte();
607 unknownByte_Ofs5 = stream.readByte();
608 instrumentSize = stream.readUint16LE();
609 sampleSize = stream.readUint16LE();
610 // Read the instrument header *ignoring* its wave address info
611 return instrument.read(stream, true);
612 }
613
finalize(int8 * sampleData)614 bool IIgsSampleHeader::finalize(int8 *sampleData) {
615 return instrument.finalize(sampleData, sampleSize);
616 }
617
618 //###
619 //### LOADER METHODS
620 //###
621
loadInstruments()622 bool SoundGen2GS::loadInstruments() {
623 // Get info on the particular Apple IIGS AGI game's executable
624 const IIgsExeInfo *exeInfo = getIIgsExeInfo((enum AgiGameID)_vm->getGameID());
625 if (exeInfo == NULL) {
626 warning("Unsupported Apple IIGS game, not loading instruments");
627 return false;
628 }
629
630 // Find the executable file and the wavetable file
631 Common::ArchiveMemberList exeNames, waveNames;
632 SearchMan.listMatchingMembers(exeNames, "*.SYS16");
633 SearchMan.listMatchingMembers(exeNames, "*.SYS");
634 SearchMan.listMatchingMembers(waveNames, "SIERRASTANDARD");
635 SearchMan.listMatchingMembers(waveNames, "SIERRAST");
636
637 if (exeNames.empty()) {
638 warning("Couldn't find Apple IIGS game executable (*.SYS16 or *.SYS), not loading instruments");
639 return false;
640 }
641 if (waveNames.empty()) {
642 warning("Couldn't find Apple IIGS wave file (SIERRASTANDARD or SIERRAST), not loading instruments");
643 return false;
644 }
645
646 Common::String exeName = exeNames.front()->getName();
647 Common::String waveName = waveNames.front()->getName();
648
649 // Set the MIDI program change to instrument number mapping and
650 // load the instrument headers and their sample data.
651 setProgramChangeMapping(exeInfo->instSet->progToInst);
652 return loadWaveFile(waveName, *exeInfo) && loadInstrumentHeaders(exeName, *exeInfo);
653 }
654
655 /** Older Apple IIGS AGI MIDI program change to instrument number mapping. */
656 static const IIgsMidiProgramMapping progToInstMappingV1 = {
657 {
658 19, 20, 22, 23, 21, 24, 5, 5, 5, 5,
659 6, 7, 10, 9, 11, 9, 15, 8, 5, 5,
660 17, 16, 18, 12, 14, 5, 5, 5, 5, 5,
661 0, 1, 2, 9, 3, 4, 15, 2, 2, 2,
662 25, 13, 13, 25
663 },
664 5
665 };
666
667 /** Newer Apple IIGS AGI MIDI program change to instrument number mapping.
668 FIXME: Some instrument choices sound wrong. */
669 static const IIgsMidiProgramMapping progToInstMappingV2 = {
670 {
671 21, 22, 24, 25, 23, 26, 6, 6, 6, 6,
672 7, 9, 12, 8, 13, 11, 17, 10, 6, 6,
673 19, 18, 20, 14, 16, 6, 6, 6, 6, 6,
674 0, 1, 2, 4, 3, 5, 17, 2, 2, 2,
675 27, 15, 15, 27
676 },
677 6
678 };
679
680 // Older Apple IIGS AGI instrument set. Used only by Space Quest I (AGI v1.002).
681 //
682 // Instrument 0 uses vibrato.
683 // Instrument 1 uses vibrato.
684 // Instrument 3 uses vibrato.
685 // Instrument 5 has swap mode enabled for the first oscillator.
686 // Instruemnt 9 uses vibrato.
687 // Instrument 10 uses vibrato.
688 // Instrument 12 uses vibrato.
689 // Instrument 15 uses vibrato.
690 // Instrument 16 uses vibrato.
691 // Instrument 18 uses vibrato.
692 static const IIgsInstrumentSetInfo instSetV1 = {
693 1192, 26, "7ee16bbc135171ffd6b9120cc7ff1af2", "edd3bf8905d9c238e02832b732fb2e18", &progToInstMappingV1
694 };
695
696 // Newer Apple IIGS AGI instrument set (AGI v1.003+). Used by all others than Space Quest I.
697 //
698 // Instrument 0 uses vibrato.
699 // Instrument 1 uses vibrato.
700 // Instrument 3 uses vibrato.
701 // Instrument 6 has swap mode enabled for the first oscillator.
702 // Instrument 11 uses vibrato.
703 // Instrument 12 uses vibrato.
704 // Instrument 14 uses vibrato.
705 // Instrument 17 uses vibrato.
706 // Instrument 18 uses vibrato.
707 // Instrument 20 uses vibrato.
708 //
709 // In KQ1 intro and in LSL intro one (and the same, or at least similar)
710 // instrument is using vibrato. In PQ intro there is also one instrument
711 // using vibrato.
712 static const IIgsInstrumentSetInfo instSetV2 = {
713 1292, 28, "b7d428955bb90721996de1cbca25e768", "c05fb0b0e11deefab58bc68fbd2a3d07", &progToInstMappingV2
714 };
715
716 /** Information about different Apple IIGS AGI executables. */
717 static const IIgsExeInfo IIgsExeInfos[] = {
718 {GID_SQ1, "SQ", 0x1002, 138496, 0x80AD, &instSetV1},
719 {GID_LSL1, "LL", 0x1003, 141003, 0x844E, &instSetV2},
720 {GID_AGIDEMO, "DEMO", 0x1005, 141884, 0x8469, &instSetV2},
721 {GID_KQ1, "KQ", 0x1006, 141894, 0x8469, &instSetV2},
722 {GID_PQ1, "PQ", 0x1007, 141882, 0x8469, &instSetV2},
723 {GID_MIXEDUP, "MG", 0x1013, 142552, 0x84B7, &instSetV2},
724 {GID_KQ2, "KQ2", 0x1013, 143775, 0x84B7, &instSetV2},
725 {GID_KQ3, "KQ3", 0x1014, 144312, 0x84B7, &instSetV2},
726 {GID_SQ2, "SQ2", 0x1014, 107882, 0x6563, &instSetV2},
727 {GID_MH1, "MH", 0x2004, 147678, 0x8979, &instSetV2},
728 {GID_KQ4, "KQ4", 0x2006, 147652, 0x8979, &instSetV2},
729 {GID_BC, "BC", 0x3001, 148192, 0x8979, &instSetV2},
730 {GID_GOLDRUSH, "GR", 0x3003, 148268, 0x8979, &instSetV2}
731 };
732
733 /**
734 * Finds information about an Apple IIGS AGI executable based on the game ID.
735 * @return A non-null IIgsExeInfo pointer if successful, otherwise NULL.
736 */
getIIgsExeInfo(enum AgiGameID gameid) const737 const IIgsExeInfo *SoundGen2GS::getIIgsExeInfo(enum AgiGameID gameid) const {
738 for (int i = 0; i < ARRAYSIZE(IIgsExeInfos); i++)
739 if (IIgsExeInfos[i].gameid == gameid)
740 return &IIgsExeInfos[i];
741 return NULL;
742 }
743
loadInstrumentHeaders(Common::String & exePath,const IIgsExeInfo & exeInfo)744 bool SoundGen2GS::loadInstrumentHeaders(Common::String &exePath, const IIgsExeInfo &exeInfo) {
745 Common::File file;
746
747 // Open the executable file and check that it has correct size
748 file.open(exePath);
749 if (file.size() != (int32)exeInfo.exeSize) {
750 debugC(3, kDebugLevelSound, "Apple IIGS executable (%s) has wrong size (Is %d, should be %d)",
751 exePath.c_str(), file.size(), exeInfo.exeSize);
752 }
753
754 // Read the whole executable file into memory
755 // CHECKME: Why do we read the file into memory first? It does not seem to be
756 // kept outside of this function. Is the processing of the data too slow
757 // otherwise?
758 Common::ScopedPtr<Common::SeekableReadStream> data(file.readStream(file.size()));
759 file.close();
760
761 // Check that we got enough data to be able to parse the instruments
762 if (!data || data->size() < (int32)(exeInfo.instSetStart + exeInfo.instSet->byteCount)) {
763 warning("Error loading instruments from Apple IIGS executable (%s)", exePath.c_str());
764 return false;
765 }
766
767 // Check instrument set's length (The info's saved in the executable)
768 data->seek(exeInfo.instSetStart - 4);
769 uint16 instSetByteCount = data->readUint16LE();
770 if (instSetByteCount != exeInfo.instSet->byteCount) {
771 debugC(3, kDebugLevelSound, "Wrong instrument set size (Is %d, should be %d) in Apple IIGS executable (%s)",
772 instSetByteCount, exeInfo.instSet->byteCount, exePath.c_str());
773 }
774
775 // Check instrument set's md5sum
776 data->seek(exeInfo.instSetStart);
777 Common::String md5str = Common::computeStreamMD5AsString(*data, exeInfo.instSet->byteCount);
778 if (md5str != exeInfo.instSet->md5) {
779 warning("Unknown Apple IIGS instrument set (md5: %s) in %s, trying to use it nonetheless",
780 md5str.c_str(), exePath.c_str());
781 }
782
783 // Read in the instrument set one instrument at a time
784 data->seek(exeInfo.instSetStart);
785
786 _instruments.clear();
787 _instruments.reserve(exeInfo.instSet->instCount);
788
789 IIgsInstrumentHeader instrument;
790 for (uint i = 0; i < exeInfo.instSet->instCount; i++) {
791 if (!instrument.read(*data)) {
792 warning("Error loading Apple IIGS instrument (%d. of %d) from %s, not loading more instruments",
793 i + 1, exeInfo.instSet->instCount, exePath.c_str());
794 break;
795 }
796 instrument.finalize(_wavetable, SIERRASTANDARD_SIZE);
797 _instruments.push_back(instrument);
798 }
799
800 // Loading was successful only if all instruments were loaded successfully
801 return (_instruments.size() == exeInfo.instSet->instCount);
802 }
803
loadWaveFile(Common::String & wavePath,const IIgsExeInfo & exeInfo)804 bool SoundGen2GS::loadWaveFile(Common::String &wavePath, const IIgsExeInfo &exeInfo) {
805 Common::File file;
806
807 // Open the wave file and read it into memory
808 // CHECKME: Why do we read the file into memory first? It does not seem to be
809 // kept outside of this function. Is the processing of the data too slow
810 // otherwise?
811 file.open(wavePath);
812 Common::ScopedPtr<Common::SeekableReadStream> uint8Wave(file.readStream(file.size()));
813 file.close();
814
815 // Check that we got the whole wave file
816 if (!uint8Wave || (uint8Wave->size() != SIERRASTANDARD_SIZE)) {
817 warning("Error loading Apple IIGS wave file (%s), not loading instruments", wavePath.c_str());
818 return false;
819 }
820
821 // Check wave file's md5sum
822 Common::String md5str = Common::computeStreamMD5AsString(*uint8Wave, SIERRASTANDARD_SIZE);
823 if (md5str != exeInfo.instSet->waveFileMd5) {
824 warning("Unknown Apple IIGS wave file (md5: %s, game: %s).\n" \
825 "Please report the information on the previous line to the ScummVM team.\n" \
826 "Using the wave file as it is - music may sound weird", md5str.c_str(), exeInfo.exePrefix);
827 }
828
829 // Convert the wave file to 8-bit signed and save the result
830 uint8Wave->seek(0);
831 return convertWave(*uint8Wave, _wavetable, SIERRASTANDARD_SIZE);
832 }
833
834 } // End of namespace Agi
835