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