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 "agos/drivers/accolade/mididriver.h"
24 #include "agos/drivers/accolade/adlib.h"
25 
26 #include "audio/fmopl.h"
27 #include "audio/mididrv.h"
28 
29 namespace AGOS {
30 
31 #define AGOS_ADLIB_VOICES_MELODIC_COUNT 6
32 #define AGOS_ADLIB_VOICES_PERCUSSION_START 6
33 #define AGOS_ADLIB_VOICES_PERCUSSION_COUNT 5
34 #define AGOS_ADLIB_VOICES_PERCUSSION_CYMBAL 9
35 
36 // 5 instruments on top of the regular MIDI ones
37 // used by the MUSIC.DRV variant for percussion instruments
38 #define AGOS_ADLIB_EXTRA_INSTRUMENT_COUNT 5
39 
40 const byte operator1Register[AGOS_ADLIB_VOICES_COUNT] = {
41 	0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x14, 0x12, 0x15, 0x11
42 };
43 
44 const byte operator2Register[AGOS_ADLIB_VOICES_COUNT] = {
45 	0x03, 0x04, 0x05, 0x0B, 0x0C, 0x0D, 0x13, 0xFF, 0xFF, 0xFF, 0xFF
46 };
47 
48 // percussion:
49 //  voice  6 - base drum - also uses operator 13h
50 //  voice  7 - snare drum
51 //  voice  8 - tom tom
52 //  voice  9 - cymbal
53 //  voice 10 - hi hat
54 const byte percussionBits[AGOS_ADLIB_VOICES_PERCUSSION_COUNT] = {
55 	0x10, 0x08, 0x04, 0x02, 0x01
56 };
57 
58 // hardcoded, dumped from Accolade music system
59 // same for INSTR.DAT + MUSIC.DRV, except that MUSIC.DRV does the lookup differently
60 const byte percussionKeyNoteChannelTable[] = {
61 	0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x0A, 0x08, 0x0A, 0x08,
62 	0x0A, 0x08, 0x08, 0x09, 0x08, 0x09, 0x0F, 0x0F, 0x0A, 0x0F,
63 	0x0A, 0x0F, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
64 	0x08, 0x08, 0x08, 0x08, 0x0A, 0x0F, 0x0F, 0x08, 0x0F, 0x08
65 };
66 
67 // hardcoded, dumped from Accolade music system (INSTR.DAT variant)
68 const uint16 frequencyLookUpTable[12] = {
69 	0x02B2, 0x02DB, 0x0306, 0x0334, 0x0365, 0x0399, 0x03CF,
70 	0xFE05, 0xFE23, 0xFE44, 0xFE67, 0xFE8B
71 };
72 
73 // hardcoded, dumped from Accolade music system (MUSIC.DRV variant)
74 const uint16 frequencyLookUpTableMusicDrv[12] = {
75 	0x0205, 0x0223, 0x0244, 0x0267, 0x028B, 0x02B2, 0x02DB,
76 	0x0306, 0x0334, 0x0365, 0x0399, 0x03CF
77 };
78 
79 //
80 // Accolade adlib music driver
81 //
82 // Remarks:
83 //
84 // There are at least 2 variants of this sound system.
85 // One for the games Elvira 1 + Elvira 2
86 // It seems it was also used for the game "Altered Destiny"
87 // Another one for the games Waxworks + Simon, the Sorcerer 1 Demo
88 //
89 // First one uses the file INSTR.DAT for instrument data, channel mapping etc.
90 // Second one uses the file MUSIC.DRV, which actually contains driver code + instrument data + channel mapping, etc.
91 //
92 // The second variant supported dynamic channel allocation for the FM voice channels, but this
93 // feature was at least definitely disabled for Simon, the Sorcerer 1 demo and for the Waxworks demo too.
94 //
95 // I have currently not implemented dynamic channel allocation.
96 
MidiDriver_Accolade_AdLib()97 MidiDriver_Accolade_AdLib::MidiDriver_Accolade_AdLib()
98 		: _masterVolume(15), _opl(0),
99 		  _adlibTimerProc(0), _adlibTimerParam(0), _isOpen(false) {
100 	memset(_channelMapping, 0, sizeof(_channelMapping));
101 	memset(_instrumentMapping, 0, sizeof(_instrumentMapping));
102 	memset(_instrumentVolumeAdjust, 0, sizeof(_instrumentVolumeAdjust));
103 	memset(_percussionKeyNoteMapping, 0, sizeof(_percussionKeyNoteMapping));
104 
105 	_instrumentTable = NULL;
106 	_instrumentCount = 0;
107 	_musicDrvMode = false;
108 	_percussionReg = 0x20;
109 }
110 
~MidiDriver_Accolade_AdLib()111 MidiDriver_Accolade_AdLib::~MidiDriver_Accolade_AdLib() {
112 	if (_instrumentTable) {
113 		delete[] _instrumentTable;
114 		_instrumentCount = 0;
115 	}
116 }
117 
open()118 int MidiDriver_Accolade_AdLib::open() {
119 //	debugC(kDebugLevelAdLibDriver, "AdLib: starting driver");
120 
121 	_opl = OPL::Config::create(OPL::Config::kOpl2);
122 
123 	if (!_opl)
124 		return -1;
125 
126 	_opl->init();
127 
128 	_isOpen = true;
129 
130 	_opl->start(new Common::Functor0Mem<void, MidiDriver_Accolade_AdLib>(this, &MidiDriver_Accolade_AdLib::onTimer));
131 
132 	resetAdLib();
133 
134 	// Finally set up default instruments
135 	for (byte FMvoiceNr = 0; FMvoiceNr < AGOS_ADLIB_VOICES_COUNT; FMvoiceNr++) {
136 		if (FMvoiceNr < AGOS_ADLIB_VOICES_PERCUSSION_START) {
137 			// Regular FM voices with instrument 0
138 			programChangeSetInstrument(FMvoiceNr, 0, 0);
139 		} else {
140 			byte percussionInstrument;
141 			if (!_musicDrvMode) {
142 				// INSTR.DAT: percussion voices with instrument 1, 2, 3, 4 and 5
143 				percussionInstrument = FMvoiceNr - AGOS_ADLIB_VOICES_PERCUSSION_START + 1;
144 			} else {
145 				// MUSIC.DRV: percussion voices with instrument 0x80, 0x81, 0x82, 0x83 and 0x84
146 				percussionInstrument = FMvoiceNr - AGOS_ADLIB_VOICES_PERCUSSION_START + 0x80;
147 			}
148 			programChangeSetInstrument(FMvoiceNr, percussionInstrument, percussionInstrument);
149 		}
150 	}
151 
152 	// driver initialization does this here:
153 	// INSTR.DAT
154 	// noteOn(9, 0x29, 0);
155 	// noteOff(9, 0x26, false);
156 	// MUSIC.DRV
157 	// noteOn(9, 0x26, 0);
158 	// noteOff(9, 0x26, false);
159 
160 	return 0;
161 }
162 
close()163 void MidiDriver_Accolade_AdLib::close() {
164 	delete _opl;
165 	_isOpen = false;
166 }
167 
setVolume(byte volume)168 void MidiDriver_Accolade_AdLib::setVolume(byte volume) {
169 	// Set the master volume in range from -128 to 127
170 	_masterVolume = CLIP<int>(-128 + volume, -128, 127);
171 	for (int i = 0; i < AGOS_ADLIB_VOICES_COUNT; i++) {
172 		// Adjust channel volume with the master volume and re-set registers
173 		byte adjustedVelocity = _channels[i].velocity * ((float) (128 + _masterVolume) / 128);
174 		noteOnSetVolume(i, 1, adjustedVelocity);
175 		if (i <= AGOS_ADLIB_VOICES_PERCUSSION_START) {
176 			// Set second operator for FM voices + first percussion
177 			noteOnSetVolume(i, 2, adjustedVelocity);
178 		}
179 	}
180 }
181 
onTimer()182 void MidiDriver_Accolade_AdLib::onTimer() {
183 	if (_adlibTimerProc)
184 		(*_adlibTimerProc)(_adlibTimerParam);
185 }
186 
resetAdLib()187 void MidiDriver_Accolade_AdLib::resetAdLib() {
188 	// The original driver sent 0x00 to register 0x00 up to 0xF5
189 	setRegister(0xBD, 0x00); // Disable rhythm
190 
191 	// reset FM voice instrument data
192 	resetAdLibOperatorRegisters(0x20, 0);
193 	resetAdLibOperatorRegisters(0x60, 0);
194 	resetAdLibOperatorRegisters(0x80, 0);
195 	resetAdLibFMVoiceChannelRegisters(0xA0, 0);
196 	resetAdLibFMVoiceChannelRegisters(0xB0, 0);
197 	resetAdLibFMVoiceChannelRegisters(0xC0, 0);
198 	resetAdLibOperatorRegisters(0xE0, 0);
199 	resetAdLibOperatorRegisters(0x40, 0x3F); // original driver sent 0x00
200 
201 	setRegister(0x01, 0x20); // enable waveform control on both operators
202 	setRegister(0x04, 0x60); // Timer control
203 
204 	setRegister(0x08, 0);    // select FM music mode
205 	setRegister(0xBD, 0x20); // Enable rhythm
206 
207 	// reset our percussion register
208 	_percussionReg = 0x20;
209 }
210 
resetAdLibOperatorRegisters(byte baseRegister,byte value)211 void MidiDriver_Accolade_AdLib::resetAdLibOperatorRegisters(byte baseRegister, byte value) {
212 	byte operatorIndex;
213 
214 	for (operatorIndex = 0; operatorIndex < 0x16; operatorIndex++) {
215 		switch (operatorIndex) {
216 		case 0x06:
217 		case 0x07:
218 		case 0x0E:
219 		case 0x0F:
220 			break;
221 		default:
222 			setRegister(baseRegister + operatorIndex, value);
223 		}
224 	}
225 }
226 
resetAdLibFMVoiceChannelRegisters(byte baseRegister,byte value)227 void MidiDriver_Accolade_AdLib::resetAdLibFMVoiceChannelRegisters(byte baseRegister, byte value) {
228 	byte FMvoiceChannel;
229 
230 	for (FMvoiceChannel = 0; FMvoiceChannel < AGOS_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
231 		setRegister(baseRegister + FMvoiceChannel, value);
232 	}
233 }
234 
235 // MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php
send(uint32 b)236 void MidiDriver_Accolade_AdLib::send(uint32 b) {
237 	byte command = b & 0xf0;
238 	byte channel = b & 0xf;
239 	byte op1 = (b >> 8) & 0xff;
240 	byte op2 = (b >> 16) & 0xff;
241 
242 	byte mappedChannel    = _channelMapping[channel];
243 	byte mappedInstrument = 0;
244 
245 	// Ignore everything that is outside of our channel range
246 	if (mappedChannel >= AGOS_ADLIB_VOICES_COUNT)
247 		return;
248 
249 	switch (command) {
250 	case 0x80:
251 		noteOff(mappedChannel, op1, false);
252 		break;
253 	case 0x90:
254 		// Convert noteOn with velocity 0 to a noteOff
255 		if (op2 == 0)
256 			return noteOff(mappedChannel, op1, false);
257 
258 		noteOn(mappedChannel, op1, op2);
259 		break;
260 	case 0xb0: // Control change
261 		// Doesn't seem to be implemented
262 		break;
263 	case 0xc0: // Program Change
264 		mappedInstrument = _instrumentMapping[op1];
265 		programChange(mappedChannel, mappedInstrument, op1);
266 		break;
267 	case 0xa0: // Polyphonic key pressure (aftertouch)
268 	case 0xd0: // Channel pressure (aftertouch)
269 		// Aftertouch doesn't seem to be implemented
270 		break;
271 	case 0xe0:
272 		// No pitch bend change
273 		break;
274 	case 0xf0: // SysEx
275 		warning("ADLIB: SysEx: %x", b);
276 		break;
277 	default:
278 		warning("ADLIB: Unknown event %02x", command);
279 	}
280 }
281 
setTimerCallback(void * timerParam,Common::TimerManager::TimerProc timerProc)282 void MidiDriver_Accolade_AdLib::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
283 	_adlibTimerProc = timerProc;
284 	_adlibTimerParam = timerParam;
285 }
286 
noteOn(byte FMvoiceChannel,byte note,byte velocity)287 void MidiDriver_Accolade_AdLib::noteOn(byte FMvoiceChannel, byte note, byte velocity) {
288 	byte adjustedNote     = note;
289 	byte adjustedVelocity = velocity;
290 	byte regValueA0h      = 0;
291 	byte regValueB0h      = 0;
292 
293 	// adjust velocity
294 	int16 channelVolumeAdjust = _channels[FMvoiceChannel].volumeAdjust;
295 	channelVolumeAdjust += adjustedVelocity;
296 	channelVolumeAdjust = CLIP<int16>(channelVolumeAdjust, 0, 0x7F);
297 
298 	// adjust velocity with the master volume
299 	byte volumeAdjust = adjustedVelocity * ((float) (128 + _masterVolume) / 128);
300 
301 	adjustedVelocity = volumeAdjust;
302 
303 	if (!_musicDrvMode) {
304 		// INSTR.DAT
305 		// force note-off
306 		noteOff(FMvoiceChannel, note, true);
307 
308 	} else {
309 		// MUSIC.DRV
310 		if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_START) {
311 			// force note-off, but only for actual FM voice channels
312 			noteOff(FMvoiceChannel, note, true);
313 		}
314 	}
315 
316 	if (FMvoiceChannel != 9) {
317 		// regular FM voice
318 
319 		if (!_musicDrvMode) {
320 			// INSTR.DAT: adjust key note
321 			while (adjustedNote < 24)
322 				adjustedNote += 12;
323 			adjustedNote -= 12;
324 		}
325 
326 	} else {
327 		// percussion channel
328 		// MUSIC.DRV variant didn't do this adjustment, it directly used a pointer
329 		adjustedNote -= 36;
330 		if (adjustedNote > 40) { // Security check
331 			warning("ADLIB: bad percussion channel note");
332 			return;
333 		}
334 
335 		byte percussionChannel = percussionKeyNoteChannelTable[adjustedNote];
336 		if (percussionChannel >= AGOS_ADLIB_VOICES_COUNT)
337 			return; // INSTR.DAT variant checked for ">" instead of ">=", which seems to have been a bug
338 
339 		// Map the keynote accordingly
340 		adjustedNote = _percussionKeyNoteMapping[adjustedNote];
341 		// Now overwrite the FM voice channel
342 		FMvoiceChannel = percussionChannel;
343 	}
344 
345 	if (!_musicDrvMode) {
346 		// INSTR.DAT
347 
348 		// Save this key note
349 		_channels[FMvoiceChannel].currentNote = adjustedNote;
350 
351 		adjustedVelocity += 24;
352 		if (adjustedVelocity > 120)
353 			adjustedVelocity = 120;
354 		adjustedVelocity = adjustedVelocity >> 1; // divide by 2
355 
356 	} else {
357 		// MUSIC.DRV
358 		adjustedVelocity = adjustedVelocity >> 1; // divide by 2
359 	}
360 
361 	// Save velocity in the case volume will need to be changed
362 	_channels[FMvoiceChannel].velocity = adjustedVelocity;
363 	// Set volume of voice channel
364 	noteOnSetVolume(FMvoiceChannel, 1, adjustedVelocity);
365 	if (FMvoiceChannel <= AGOS_ADLIB_VOICES_PERCUSSION_START) {
366 		// Set second operator for FM voices + first percussion
367 		noteOnSetVolume(FMvoiceChannel, 2, adjustedVelocity);
368 	}
369 
370 	if (FMvoiceChannel >= AGOS_ADLIB_VOICES_PERCUSSION_START) {
371 		// Percussion
372 		byte percussionIdx = FMvoiceChannel - AGOS_ADLIB_VOICES_PERCUSSION_START;
373 
374 		// Enable bit of the requested percussion type
375 		assert(percussionIdx < AGOS_ADLIB_VOICES_PERCUSSION_COUNT);
376 		_percussionReg |= percussionBits[percussionIdx];
377 		setRegister(0xBD, _percussionReg);
378 	}
379 
380 	if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_CYMBAL) {
381 		// FM voice, Base Drum, Snare Drum + Tom Tom
382 		byte adlibNote = adjustedNote;
383 		byte adlibOctave = 0;
384 		byte adlibFrequencyIdx = 0;
385 		uint16 adlibFrequency = 0;
386 
387 		if (!_musicDrvMode) {
388 			// INSTR.DAT
389 			if (adlibNote >= 0x60)
390 				adlibNote = 0x5F;
391 
392 			adlibOctave = (adlibNote / 12) - 1;
393 			adlibFrequencyIdx = adlibNote % 12;
394 			adlibFrequency = frequencyLookUpTable[adlibFrequencyIdx];
395 
396 			if (adlibFrequency & 0x8000)
397 				adlibOctave++;
398 			if (adlibOctave & 0x80) {
399 				adlibOctave++;
400 				adlibFrequency = adlibFrequency >> 1;
401 			}
402 
403 		} else {
404 			// MUSIC.DRV variant
405 			if (adlibNote >= 19)
406 				adlibNote -= 19;
407 
408 			adlibOctave = (adlibNote / 12);
409 			adlibFrequencyIdx = adlibNote % 12;
410 			// additional code, that will lookup octave and do a multiplication with it
411 			// noteOn however calls the frequency calculation in a way that it multiplies with 0
412 			adlibFrequency = frequencyLookUpTableMusicDrv[adlibFrequencyIdx];
413 		}
414 
415 		regValueA0h = adlibFrequency & 0xFF;
416 		regValueB0h = ((adlibFrequency & 0x300) >> 8) | (adlibOctave << 2);
417 		if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_START) {
418 			// set Key-On flag for regular FM voices, but not for percussion
419 			regValueB0h |= 0x20;
420 		}
421 
422 		setRegister(0xA0 + FMvoiceChannel, regValueA0h);
423 		setRegister(0xB0 + FMvoiceChannel, regValueB0h);
424 		_channels[FMvoiceChannel].currentA0hReg = regValueA0h;
425 		_channels[FMvoiceChannel].currentB0hReg = regValueB0h;
426 
427 		if (_musicDrvMode) {
428 			// MUSIC.DRV
429 			if (FMvoiceChannel < AGOS_ADLIB_VOICES_MELODIC_COUNT) {
430 				_channels[FMvoiceChannel].currentNote = adjustedNote;
431 			}
432 		}
433 	}
434 }
435 
436 // 100% the same for INSTR.DAT and MUSIC.DRV variants
437 // except for a bug, that was introduced for MUSIC.DRV
noteOnSetVolume(byte FMvoiceChannel,byte operatorNr,byte adjustedVelocity)438 void MidiDriver_Accolade_AdLib::noteOnSetVolume(byte FMvoiceChannel, byte operatorNr, byte adjustedVelocity) {
439 	byte operatorReg = 0;
440 	byte regValue40h = 0;
441 	const InstrumentEntry *curInstrument = NULL;
442 
443 	regValue40h = (63 - adjustedVelocity) & 0x3F;
444 
445 	if ((operatorNr == 1) && (FMvoiceChannel <= AGOS_ADLIB_VOICES_PERCUSSION_START)) {
446 		// first operator of FM voice channels or first percussion channel
447 		curInstrument = _channels[FMvoiceChannel].currentInstrumentPtr;
448 		if (!(curInstrument->regC0 & 0x01)) { // check, if both operators produce sound
449 			// only one does, instrument wants fixed volume
450 			if (operatorNr == 1) {
451 				regValue40h = curInstrument->reg40op1;
452 			} else {
453 				regValue40h = curInstrument->reg40op2;
454 			}
455 
456 			// not sure, if we are supposed to implement these bugs, or not
457 #if 0
458 			if (!_musicDrvMode) {
459 				// Table is 16 bytes instead of 18 bytes
460 				if ((FMvoiceChannel == 7) || (FMvoiceChannel == 9)) {
461 					regValue40h = 0;
462 					warning("volume set bug (original)");
463 				}
464 			}
465 			if (_musicDrvMode) {
466 				// MUSIC.DRV variant has a bug, which will overwrite these registers
467 				// for all operators above 11 / 0Bh, which means percussion will always
468 				// get a value of 0 (the table holding those bytes was 12 bytes instead of 18
469 				if (FMvoiceChannel >= AGOS_ADLIB_VOICES_PERCUSSION_START) {
470 					regValue40h = 0;
471 					warning("volume set bug (original)");
472 				}
473 			}
474 #endif
475 		}
476 	}
477 
478 	if (operatorNr == 1) {
479 		operatorReg = operator1Register[FMvoiceChannel];
480 	} else {
481 		operatorReg = operator2Register[FMvoiceChannel];
482 	}
483 	assert(operatorReg != 0xFF); // Security check
484 	setRegister(0x40 + operatorReg, regValue40h);
485 }
486 
noteOff(byte FMvoiceChannel,byte note,bool dontCheckNote)487 void MidiDriver_Accolade_AdLib::noteOff(byte FMvoiceChannel, byte note, bool dontCheckNote) {
488 	byte adjustedNote = note;
489 	byte regValueB0h = 0;
490 
491 	if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_START) {
492 		// regular FM voice
493 
494 		if (!_musicDrvMode) {
495 			// INSTR.DAT: adjust key note
496 			while (adjustedNote < 24)
497 				adjustedNote += 12;
498 			adjustedNote -= 12;
499 		}
500 
501 		if (!dontCheckNote) {
502 			// check, if current note is also the current actually playing channel note
503 			if (_channels[FMvoiceChannel].currentNote != adjustedNote)
504 				return; // not the same -> ignore this note off command
505 		}
506 
507 		regValueB0h = _channels[FMvoiceChannel].currentB0hReg & 0xDF; // Remove "key on" bit
508 		setRegister(0xB0 + FMvoiceChannel, regValueB0h);
509 
510 	} else {
511 		// percussion
512 		adjustedNote -= 36;
513 		if (adjustedNote > 40) { // Security check
514 			warning("ADLIB: bad percussion channel note");
515 			return;
516 		}
517 
518 		byte percussionChannel = percussionKeyNoteChannelTable[adjustedNote];
519 		if (percussionChannel > AGOS_ADLIB_VOICES_COUNT)
520 			return;
521 
522 		byte percussionIdx = percussionChannel - AGOS_ADLIB_VOICES_PERCUSSION_START;
523 
524 		// Disable bit of the requested percussion type
525 		assert(percussionIdx < AGOS_ADLIB_VOICES_PERCUSSION_COUNT);
526 		_percussionReg &= ~percussionBits[percussionIdx];
527 		setRegister(0xBD, _percussionReg);
528 	}
529 }
530 
programChange(byte FMvoiceChannel,byte mappedInstrumentNr,byte MIDIinstrumentNr)531 void MidiDriver_Accolade_AdLib::programChange(byte FMvoiceChannel, byte mappedInstrumentNr, byte MIDIinstrumentNr) {
532 	if (mappedInstrumentNr >= _instrumentCount) {
533 		warning("ADLIB: tried to set non-existent instrument");
534 		return; // out of range
535 	}
536 
537 	// setup instrument
538 	//warning("ADLIB: program change for FM voice channel %d, instrument id %d", FMvoiceChannel, mappedInstrumentNr);
539 
540 	if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_START) {
541 		// Regular FM voice
542 		programChangeSetInstrument(FMvoiceChannel, mappedInstrumentNr, MIDIinstrumentNr);
543 
544 	} else {
545 		// Percussion
546 		// set default instrument (again)
547 		byte percussionInstrumentNr = 0;
548 		const InstrumentEntry *instrumentPtr;
549 
550 		if (!_musicDrvMode) {
551 			// INSTR.DAT: percussion default instruments start at instrument 1
552 			percussionInstrumentNr = FMvoiceChannel - AGOS_ADLIB_VOICES_PERCUSSION_START + 1;
553 		} else {
554 			// MUSIC.DRV: percussion default instruments start at instrument 0x80
555 			percussionInstrumentNr = FMvoiceChannel - AGOS_ADLIB_VOICES_PERCUSSION_START + 0x80;
556 		}
557 		if (percussionInstrumentNr >= _instrumentCount) {
558 			warning("ADLIB: tried to set non-existent instrument");
559 			return;
560 		}
561 		instrumentPtr = &_instrumentTable[percussionInstrumentNr];
562 		_channels[FMvoiceChannel].currentInstrumentPtr = instrumentPtr;
563 		_channels[FMvoiceChannel].volumeAdjust         = _instrumentVolumeAdjust[percussionInstrumentNr];
564 	}
565 }
566 
programChangeSetInstrument(byte FMvoiceChannel,byte mappedInstrumentNr,byte MIDIinstrumentNr)567 void MidiDriver_Accolade_AdLib::programChangeSetInstrument(byte FMvoiceChannel, byte mappedInstrumentNr, byte MIDIinstrumentNr) {
568 	const InstrumentEntry *instrumentPtr;
569 	byte op1Reg = 0;
570 	byte op2Reg = 0;
571 
572 	if (mappedInstrumentNr >= _instrumentCount) {
573 		warning("ADLIB: tried to set non-existent instrument");
574 		return; // out of range
575 	}
576 
577 	// setup instrument
578 	instrumentPtr = &_instrumentTable[mappedInstrumentNr];
579 	//warning("set instrument for FM voice channel %d, instrument id %d", FMvoiceChannel, mappedInstrumentNr);
580 
581 	op1Reg = operator1Register[FMvoiceChannel];
582 	op2Reg = operator2Register[FMvoiceChannel];
583 
584 	setRegister(0x20 + op1Reg, instrumentPtr->reg20op1);
585 	setRegister(0x40 + op1Reg, instrumentPtr->reg40op1);
586 	setRegister(0x60 + op1Reg, instrumentPtr->reg60op1);
587 	setRegister(0x80 + op1Reg, instrumentPtr->reg80op1);
588 
589 	if (FMvoiceChannel <= AGOS_ADLIB_VOICES_PERCUSSION_START) {
590 		// set 2nd operator as well for FM voices and first percussion voice
591 		setRegister(0x20 + op2Reg, instrumentPtr->reg20op2);
592 		setRegister(0x40 + op2Reg, instrumentPtr->reg40op2);
593 		setRegister(0x60 + op2Reg, instrumentPtr->reg60op2);
594 		setRegister(0x80 + op2Reg, instrumentPtr->reg80op2);
595 
596 		if (!_musicDrvMode) {
597 			// set Feedback / Algorithm as well
598 			setRegister(0xC0 + FMvoiceChannel, instrumentPtr->regC0);
599 		} else {
600 			if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_START) {
601 				// set Feedback / Algorithm as well for regular FM voices only
602 				setRegister(0xC0 + FMvoiceChannel, instrumentPtr->regC0);
603 			}
604 		}
605 	}
606 
607 	// Remember instrument
608 	_channels[FMvoiceChannel].currentInstrumentPtr = instrumentPtr;
609 	_channels[FMvoiceChannel].volumeAdjust         = _instrumentVolumeAdjust[MIDIinstrumentNr];
610 }
611 
setRegister(int reg,int value)612 void MidiDriver_Accolade_AdLib::setRegister(int reg, int value) {
613 	_opl->writeReg(reg, value);
614 	//warning("OPL %x %x (%d)", reg, value, value);
615 }
616 
property(int prop,uint32 param)617 uint32 MidiDriver_Accolade_AdLib::property(int prop, uint32 param) {
618 	return 0;
619 }
620 
621 // Called right at the start, we get an INSTR.DAT entry
setupInstruments(byte * driverData,uint16 driverDataSize,bool useMusicDrvFile)622 bool MidiDriver_Accolade_AdLib::setupInstruments(byte *driverData, uint16 driverDataSize, bool useMusicDrvFile) {
623 	uint16 channelMappingOffset         = 0;
624 	uint16 channelMappingSize           = 0;
625 	uint16 instrumentMappingOffset      = 0;
626 	uint16 instrumentMappingSize        = 0;
627 	uint16 instrumentVolumeAdjustOffset = 0;
628 	uint16 instrumentVolumeAdjustSize   = 0;
629 	uint16 keyNoteMappingOffset         = 0;
630 	uint16 keyNoteMappingSize           = 0;
631 	uint16 instrumentCount              = 0;
632 	uint16 instrumentDataOffset         = 0;
633 	uint16 instrumentDataSize           = 0;
634 	uint16 instrumentEntrySize          = 0;
635 
636 	if (!useMusicDrvFile) {
637 		// INSTR.DAT: we expect at least 354 bytes
638 		if (driverDataSize < 354)
639 			return false;
640 
641 		// Data is like this:
642 		// 128 bytes  instrument mapping
643 		// 128 bytes  instrument volume adjust (signed!)
644 		//  16 bytes  unknown
645 		//  16 bytes  channel mapping
646 		//  64 bytes  key note mapping (not used for MT32)
647 		//   1 byte   instrument count
648 		//   1 byte   bytes per instrument
649 		//   x bytes  no instruments used for MT32
650 
651 		channelMappingOffset         = 256 + 16;
652 		channelMappingSize           = 16;
653 		instrumentMappingOffset      = 0;
654 		instrumentMappingSize        = 128;
655 		instrumentVolumeAdjustOffset = 128;
656 		instrumentVolumeAdjustSize   = 128;
657 		keyNoteMappingOffset         = 256 + 16 + 16;
658 		keyNoteMappingSize           = 64;
659 
660 		byte instrDatInstrumentCount    = driverData[256 + 16 + 16 + 64];
661 		byte instrDatBytesPerInstrument = driverData[256 + 16 + 16 + 64 + 1];
662 
663 		// We expect 9 bytes per instrument
664 		if (instrDatBytesPerInstrument != 9)
665 			return false;
666 		// And we also expect at least one adlib instrument
667 		if (!instrDatInstrumentCount)
668 			return false;
669 
670 		instrumentCount      = instrDatInstrumentCount;
671 		instrumentDataOffset = 256 + 16 + 16 + 64 + 2;
672 		instrumentDataSize   = instrDatBytesPerInstrument * instrDatInstrumentCount;
673 		instrumentEntrySize  = instrDatBytesPerInstrument;
674 
675 	} else {
676 		// MUSIC.DRV: we expect at least 468 bytes
677 		if (driverDataSize < 468)
678 			return false;
679 
680 		// music.drv is basically a driver, but with a few fixed locations for certain data
681 
682 		channelMappingOffset         = 396;
683 		channelMappingSize           = 16;
684 		instrumentMappingOffset      = 140;
685 		instrumentMappingSize        = 128;
686 		instrumentVolumeAdjustOffset = 140 + 128;
687 		instrumentVolumeAdjustSize   = 128;
688 		keyNoteMappingOffset         = 376 + 36; // adjust by 36, because we adjust keyNote before mapping (see noteOn)
689 		keyNoteMappingSize           = 64;
690 
691 		// seems to have used 128 + 5 instruments
692 		// 128 regular ones and an additional 5 for percussion
693 		instrumentCount         = 128 + AGOS_ADLIB_EXTRA_INSTRUMENT_COUNT;
694 		instrumentDataOffset    = 722;
695 		instrumentEntrySize     = 9;
696 		instrumentDataSize      = instrumentCount * instrumentEntrySize;
697 	}
698 
699 	// Channel mapping
700 	if (channelMappingSize) {
701 		// Get these 16 bytes for MIDI channel mapping
702 		if (channelMappingSize != sizeof(_channelMapping))
703 			return false;
704 
705 		memcpy(_channelMapping, driverData + channelMappingOffset, sizeof(_channelMapping));
706 	} else {
707 		// Set up straight mapping
708 		for (uint16 channelNr = 0; channelNr < sizeof(_channelMapping); channelNr++) {
709 			_channelMapping[channelNr] = channelNr;
710 		}
711 	}
712 
713 	if (instrumentMappingSize) {
714 		// And these for instrument mapping
715 		if (instrumentMappingSize > sizeof(_instrumentMapping))
716 			return false;
717 
718 		memcpy(_instrumentMapping, driverData + instrumentMappingOffset, instrumentMappingSize);
719 	}
720 	// Set up straight mapping for the remaining data
721 	for (uint16 instrumentNr = instrumentMappingSize; instrumentNr < sizeof(_instrumentMapping); instrumentNr++) {
722 		_instrumentMapping[instrumentNr] = instrumentNr;
723 	}
724 
725 	if (instrumentVolumeAdjustSize) {
726 		if (instrumentVolumeAdjustSize != sizeof(_instrumentVolumeAdjust))
727 			return false;
728 
729 		memcpy(_instrumentVolumeAdjust, driverData + instrumentVolumeAdjustOffset, instrumentVolumeAdjustSize);
730 	}
731 
732 	// Get key note mapping, if available
733 	if (keyNoteMappingSize) {
734 		if (keyNoteMappingSize != sizeof(_percussionKeyNoteMapping))
735 			return false;
736 
737 		memcpy(_percussionKeyNoteMapping, driverData + keyNoteMappingOffset, keyNoteMappingSize);
738 	}
739 
740 	// Check, if there are enough bytes left to hold all instrument data
741 	if (driverDataSize < (instrumentDataOffset + instrumentDataSize))
742 		return false;
743 
744 	// We release previous instrument data, just in case
745 	if (_instrumentTable)
746 		delete[] _instrumentTable;
747 
748 	_instrumentTable = new InstrumentEntry[instrumentCount];
749 	_instrumentCount = instrumentCount;
750 
751 	byte            *instrDATReadPtr    = driverData + instrumentDataOffset;
752 	InstrumentEntry *instrumentWritePtr = _instrumentTable;
753 
754 	for (uint16 instrumentNr = 0; instrumentNr < _instrumentCount; instrumentNr++) {
755 		memcpy(instrumentWritePtr, instrDATReadPtr, sizeof(InstrumentEntry));
756 		instrDATReadPtr += instrumentEntrySize;
757 		instrumentWritePtr++;
758 	}
759 
760 	// Enable MUSIC.DRV-Mode (slightly different behaviour)
761 	if (useMusicDrvFile)
762 		_musicDrvMode = true;
763 
764 	if (_musicDrvMode) {
765 		// Extra code for MUSIC.DRV
766 
767 		// This was done during "programChange" in the original driver
768 		instrumentWritePtr = _instrumentTable;
769 		for (uint16 instrumentNr = 0; instrumentNr < _instrumentCount; instrumentNr++) {
770 			instrumentWritePtr->reg80op1 |= 0x03; // set release rate
771 			instrumentWritePtr->reg80op2 |= 0x03;
772 			instrumentWritePtr++;
773 		}
774 	}
775 	return true;
776 }
777 
MidiDriver_Accolade_AdLib_create(Common::String driverFilename)778 MidiDriver *MidiDriver_Accolade_AdLib_create(Common::String driverFilename) {
779 	byte  *driverData = NULL;
780 	uint16 driverDataSize = 0;
781 	bool   isMusicDrvFile = false;
782 
783 	MidiDriver_Accolade_readDriver(driverFilename, MT_ADLIB, driverData, driverDataSize, isMusicDrvFile);
784 	if (!driverData)
785 		error("ACCOLADE-ADLIB: error during readDriver()");
786 
787 	MidiDriver_Accolade_AdLib *driver = new MidiDriver_Accolade_AdLib();
788 	if (driver) {
789 		if (!driver->setupInstruments(driverData, driverDataSize, isMusicDrvFile)) {
790 			delete driver;
791 			driver = nullptr;
792 		}
793 	}
794 
795 	delete[] driverData;
796 	return driver;
797 }
798 
799 } // End of namespace AGOS
800