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 "audio/softsynth/fmtowns_pc98/pc98_audio.h"
24 #include "audio/mididrv.h"
25 #include "audio/mixer.h"
26 #include "engines/engine.h"
27 #include "common/func.h"
28
29 namespace AGOS {
30
31 class PC98CommonDriver : public MidiDriver {
32 public:
33 enum PC98DriverProperties {
34 kPropMusicVolume = 0x10,
35 kPropSfxVolume = 0x20,
36 kPropPause = 0x30
37 };
38 public:
39 PC98CommonDriver();
~PC98CommonDriver()40 virtual ~PC98CommonDriver() override {};
41
isOpen() const42 bool isOpen() const override { return _isOpen; }
43 void send(uint32 b) override;
44 void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) override;
45 uint32 property(int prop, uint32 param) override;
getBaseTempo()46 uint32 getBaseTempo() override { return _baseTempo; }
allocateChannel()47 MidiChannel *allocateChannel() override { return 0; }
getPercussionChannel()48 MidiChannel *getPercussionChannel() override { return 0; }
49
50 protected:
51 void updateSounds();
52 void updateParser();
53 void reset();
54
55 uint32 _baseTempo;
56 bool _isOpen;
57
58 Audio::Mixer *_mixer;
59
60 const uint8 *_instrumentsRemap;
61 const int8 *_instrumentLevelAdjust;
62 const uint8 *_partsRemap;
63
64 uint8 _chanUse[16];
65 uint8 _ngDelay;
66 bool _allNotes;
67 bool _programLock;
68 bool _noFadeRemap;
69 bool _delayedProgramChange;
70
71 private:
72 virtual void noteOn(uint8 part, uint8 note, uint8 velo) = 0;
73 virtual void noteOff(uint8 part, uint8 note) = 0;
74 virtual void programChange(uint8 part, uint8 prog) = 0;
75 virtual void processSounds() = 0;
76 virtual void setVolume(int musicVolume, int sfxVolume) = 0;
77 virtual void pause(bool paused) = 0;
78
79 class TimerCb {
80 public:
81 typedef void(*FuncType)(void*);
TimerCb(const FuncType func,void * arg)82 TimerCb(const FuncType func, void *arg) : _func(func), _arg(arg) {}
isValid() const83 bool isValid() const { return _func && _arg; }
operator ()() const84 void operator()() const { (*_func)(_arg); }
85 private:
86 const FuncType _func;
87 void *_arg;
88 } *_timerCb;
89
90 uint32 _internalUpdateTimer;
91
92 uint16 _musicVolume;
93 uint16 _sfxVolume;
94 int8 _fadeVolumeAdjust;
95 uint8 _partPrograms[16];
96 };
97
98 class PC98FMDriver : public PC98CommonDriver, private PC98AudioPluginDriver {
99 public:
100 PC98FMDriver();
101 ~PC98FMDriver() override;
102
103 int open() override;
104 void close() override;
105
106 private:
107 void noteOn(uint8 part, uint8 note, uint8 velo) override;
108 void noteOff(uint8 part, uint8 note) override;
109 void programChange(uint8 part, uint8 prog) override;
110 void processSounds() override;
111 void setVolume(int musicVolume, int sfxVolume) override;
pause(bool paused)112 void pause(bool paused) override {}
113
114 void loadInstrument(uint8 chan, uint8 prg);
115 void startNote(uint8 chan, uint8 note, uint8 velo);
116 void stopNote(uint8 chan, uint8 note);
117
timerCallbackA()118 void timerCallbackA() override {}
119 void timerCallbackB() override;
120
121 PC98AudioCore *_pc98a;
122
123 uint8 _chanAssign[3];
124 uint8 _chanNotes[3];
125 uint8 _partProgramsInternal[16];
126 uint8 _partNotes[16];
127
128 static const uint8 _instrumentsRemapFM[128];
129 static const uint8 _instrumentLevelAdjustFM[128];
130 static const uint8 _partsRemapFM[16];
131 static const uint8 _instrumentPatches[16][25];
132 static const uint8 _ngMapping[76];
133 static const uint8 _carrier[8];
134 static const uint16 _frequency[12];
135 };
136
137 class PC98MidiDriver : public PC98CommonDriver {
138 public:
139 PC98MidiDriver(DeviceHandle dev);
140 ~PC98MidiDriver() override;
141
142 int open() override;
143 void close() override;
144
145 static void timerCallback(void *obj);
146
147 private:
148 void noteOn(uint8 part, uint8 note, uint8 velo) override;
149 void noteOff(uint8 part, uint8 note) override;
150 void programChange(uint8 part, uint8 prog) override;
processSounds()151 void processSounds() override {}
152 void setVolume(int musicVolume, int sfxVolume) override;
153 void pause(bool paused) override;
154 void sendSysexWithCheckSum(uint8 *data);
155
156 MidiDriver *_drv;
157 DeviceHandle _dev;
158
159 uint8 _volSysex[9];
160 uint8 _partAssignSysexGS[9];
161 uint8 _partAssignSysexMT32[9];
162
163 static const uint8 _instrumentsRemapMT32[128];
164 static const uint8 _instrumentsRemapGM[128];
165 static const uint8 _partsRemapMidi[16];
166 static const uint8 _sysexMsg[3][9];
167 };
168
PC98CommonDriver()169 PC98CommonDriver::PC98CommonDriver() : _mixer(g_engine->_mixer), _baseTempo(0), _fadeVolumeAdjust(0), _allNotes(false), _programLock(false), _isOpen(false), _noFadeRemap(false), _delayedProgramChange(false), _ngDelay(0), _timerCb(0), _musicVolume(0xff), _sfxVolume(0xff), _internalUpdateTimer(0) {
170 memset(_partPrograms, 0, sizeof(_partPrograms));
171 memset(_chanUse, 0, sizeof(_chanUse));
172 }
173
send(uint32 b)174 void PC98CommonDriver::send(uint32 b) {
175 if (!_isOpen)
176 return;
177
178 byte para2 = (b >> 16) & 0xFF;
179 byte para1 = (b >> 8) & 0xFF;
180 byte ch = b & 0x0F;
181
182 switch (b & 0xF0) {
183 case 0x80:
184 noteOff(ch, para1);
185 break;
186 case 0x90:
187 if (para2) {
188 int16 velo = para2;
189 if (ch != 9)
190 velo = CLIP<int16>(velo + _instrumentLevelAdjust[_partPrograms[ch]], 0, 127);
191 velo = CLIP<int16>(velo + _fadeVolumeAdjust, 0, 127);
192 noteOn(ch, para1, velo);
193 } else {
194 noteOff(ch, para1);
195 }
196 break;
197 case 0xC0:
198 _partPrograms[ch] = para1;
199 programChange(ch, ch == 9 ? 0 : _instrumentsRemap[para1 & 0x07F]);
200 break;
201 default:
202 // 0xA0 and 0xB0 are parsing related and will be filtered and handled in MidiParser_S1D.
203 if (!((b & 0xF0) == 0xB0 && (para1 == 0x7b || para1 == 0x07)))
204 warning("PC98CommonDriver::send(): Unsupported Midi Message: 0x%02x 0x%02x 0x%02x", b & 0xFF, para1, para2);
205 break;
206 }
207 }
208
setTimerCallback(void * timerParam,Common::TimerManager::TimerProc timerProc)209 void PC98CommonDriver::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
210 delete _timerCb;
211 _timerCb = (_isOpen && timerParam && timerProc) ? new TimerCb(timerProc, timerParam) : 0;
212 }
213
property(int prop,uint32 param)214 uint32 PC98CommonDriver::property(int prop, uint32 param) {
215 uint32 res = 0;
216 switch (prop) {
217 case kPropMusicVolume:
218 case kPropSfxVolume: {
219 uint16 &v = (prop == kPropMusicVolume) ? _musicVolume : _sfxVolume;
220 res = v;
221 if ((int32)param != -1)
222 v = param & 0x1ff;
223 if (_isOpen)
224 setVolume(_musicVolume, _sfxVolume);
225 break;
226 }
227 case kPropPause: {
228 if (_isOpen)
229 pause(param);
230 break;
231 }
232 default:
233 break;
234 }
235 return res;
236 }
237
updateSounds()238 void PC98CommonDriver::updateSounds() {
239 if (!_isOpen)
240 return;
241
242 _internalUpdateTimer += _baseTempo;
243 if (_internalUpdateTimer >= 16667) {
244 _internalUpdateTimer -= 16667;
245
246 // I haven't implemented music fading in and out, since Elvira 1 (the
247 // only game for this sound driver) does not use the feature at all.
248 // The fade volume would have to be updated here...
249
250 for (int i = 0; i < 16; ++i)
251 _chanUse[i] = 0;
252
253 processSounds();
254 }
255 }
256
updateParser()257 void PC98CommonDriver::updateParser() {
258 if (_isOpen && _timerCb && _timerCb->isValid())
259 (*_timerCb)();
260 }
261
reset()262 void PC98CommonDriver::reset() {
263 memset(_partPrograms, 0, sizeof(_partPrograms));
264 memset(_chanUse, 0, sizeof(_chanUse));
265 _allNotes = false;
266 _programLock = false;
267 _noFadeRemap = false;
268 _delayedProgramChange = false;
269 _ngDelay = 0;
270 }
271
PC98FMDriver()272 PC98FMDriver::PC98FMDriver() : PC98CommonDriver(), _pc98a(0) {
273 _baseTempo = 10080;
274 _instrumentsRemap = _instrumentsRemapFM;
275 _instrumentLevelAdjust = (const int8*)_instrumentLevelAdjustFM;
276 _partsRemap = _partsRemapFM;
277 memset(_partProgramsInternal, 0, sizeof(_partProgramsInternal));
278 memset(_partNotes, 0, sizeof(_partNotes));
279 memset(_chanAssign, 0, sizeof(_chanAssign));
280 memset(_chanNotes, 0, sizeof(_chanNotes));
281 }
282
~PC98FMDriver()283 PC98FMDriver::~PC98FMDriver() {
284 _mixer->stopAll();
285 close();
286 }
287
open()288 int PC98FMDriver::open() {
289 if (_isOpen)
290 return MERR_ALREADY_OPEN;
291
292 delete _pc98a;
293
294 _pc98a = new PC98AudioCore(g_engine->_mixer, this, kType26);
295 if (_pc98a && _pc98a->init()) {
296 _pc98a->writeReg(0, 0x06, 0x0a);
297 _pc98a->writeReg(0, 0x07, 0x9c);
298 for (int i = 8; i < 11; ++i)
299 _pc98a->writeReg(0, i, 0);
300 _pc98a->writeReg(0, 0x27, 0x3a);
301 } else {
302 return MERR_DEVICE_NOT_AVAILABLE;
303 }
304
305 memset(_partProgramsInternal, 0, sizeof(_partProgramsInternal));
306 memset(_partNotes, 0, sizeof(_partNotes));
307 memset(_chanAssign, 0, sizeof(_chanAssign));
308 memset(_chanNotes, 0, sizeof(_chanNotes));
309
310 reset();
311
312 _isOpen = true;
313
314 return 0;
315 }
316
close()317 void PC98FMDriver::close() {
318 _isOpen = false;
319 delete _pc98a;
320 _pc98a = 0;
321 setTimerCallback(0, 0);
322 }
323
noteOn(uint8 part,uint8 note,uint8 velo)324 void PC98FMDriver::noteOn(uint8 part, uint8 note, uint8 velo) {
325 if (_delayedProgramChange && part != 9) {
326 int ch = 0x80;
327 uint8 high = 0x80;
328 for (int i = 2; i >= 0; --i) {
329 if (_chanAssign[i] == 0x80) {
330 ch = i;
331 break;
332 }
333 if (part < _chanAssign[i] && high > _chanAssign[i]) {
334 ch = i;
335 high = _chanAssign[i];
336 }
337 }
338 if (ch == 0x80)
339 return;
340
341 loadInstrument(ch, _partProgramsInternal[part]);
342
343 _partNotes[ch] = note;
344 _chanAssign[ch] = part;
345 part = ch;
346 }
347 startNote(part, note, velo);
348 }
349
noteOff(uint8 part,uint8 note)350 void PC98FMDriver::noteOff(uint8 part, uint8 note) {
351 if (_delayedProgramChange) {
352 if (part == 9) {
353 _pc98a->writeReg(0, 6, 0);
354 stopNote(part, note);
355 } else {
356 for (int i = 2; i >= 0; --i) {
357 if (_chanAssign[i] != part || (note != _partNotes[i] && !_allNotes))
358 continue;
359 _chanAssign[i] = 0x80;
360 _partNotes[i] = 0;
361 stopNote(i, note);
362 }
363 }
364 } else {
365 stopNote(part, note);
366 }
367 }
368
programChange(uint8 part,uint8 prog)369 void PC98FMDriver::programChange(uint8 part, uint8 prog) {
370 if (!_delayedProgramChange)
371 loadInstrument(part, prog);
372 _partProgramsInternal[part] = prog;
373 }
374
processSounds()375 void PC98FMDriver::processSounds() {
376 if (_ngDelay)
377 --_ngDelay;
378 if (!_ngDelay)
379 _pc98a->writeReg(0, 0x0a, 0);
380 }
381
setVolume(int musicVolume,int sfxVolume)382 void PC98FMDriver::setVolume(int musicVolume, int sfxVolume) {
383 _pc98a->setMusicVolume(musicVolume);
384 _pc98a->setSoundEffectVolume(sfxVolume);
385 }
386
loadInstrument(uint8 chan,uint8 prg)387 void PC98FMDriver::loadInstrument(uint8 chan, uint8 prg) {
388 if (chan > 2)
389 return;
390
391 assert(prg < ARRAYSIZE(_instrumentPatches));
392 const uint8 *src = _instrumentPatches[prg];
393 _pc98a->writeReg(0, 0xB0 | chan, *src++);
394
395 for (uint8 reg = 0x30 | chan; reg < 0x40; reg += 4) {
396 _pc98a->writeReg(0, reg, *src++);
397 _pc98a->writeReg(0, reg + 0x10, *src++);
398 _pc98a->writeReg(0, reg + 0x20, *src++);
399 _pc98a->writeReg(0, reg + 0x30, (*src++) & 0x1F);
400 _pc98a->writeReg(0, reg + 0x40, (*src++) & 0x1F);
401 _pc98a->writeReg(0, reg + 0x50, *src++);
402 }
403 }
404
startNote(uint8 chan,uint8 note,uint8 velo)405 void PC98FMDriver::startNote(uint8 chan, uint8 note, uint8 velo) {
406 if (chan == 9) {
407 if (note >= sizeof(_ngMapping) || _ngMapping[note] == 0xff)
408 return;
409 _pc98a->writeReg(0, 0x06, _ngMapping[note]);
410 _pc98a->writeReg(0, 0x0a, 0x0a);
411 _ngDelay = 3;
412 }
413
414 if (chan > 2)
415 return;
416
417 if (_chanUse[chan] && note < _chanNotes[chan])
418 return;
419
420 _allNotes = true;
421 stopNote(chan, 0);
422 _allNotes = false;
423 _chanNotes[chan] = note;
424 _chanUse[chan]++;
425
426 const uint8 *instr = _instrumentPatches[_partProgramsInternal[chan]];
427 uint8 c = _carrier[*instr & 7];
428
429 instr += 2;
430 const uint8 *pos = instr;
431 uint8 instvl = 0x7F;
432 for (int i = 0; i < 4; ++i) {
433 if (((c >> i) & 1) && *pos < instvl)
434 instvl = *pos;
435 pos += 6;
436 }
437
438 pos = instr;
439 velo = 0x7f - (0x57 + (velo >> 2)) - instvl;
440 for (uint8 i = 0x40 | chan; i < 0x50; i += 4) {
441 if (c & 1)
442 _pc98a->writeReg(0, i, MIN<uint8>(*pos + velo, 0x7f));
443 pos += 6;
444 c >>= 1;
445 }
446
447 if (note > 18)
448 note -= 12;
449 uint16 frq = _frequency[note % 12];
450 uint8 bl = (note / 12) << 3;
451 _pc98a->writeReg(0, 0xa4 | chan, (frq >> 8) | bl);
452 _pc98a->writeReg(0, 0xa0 | chan, frq & 0xff);
453
454 _pc98a->writeReg(0, 0x28, 0xF0 | chan);
455 }
456
stopNote(uint8 chan,uint8 note)457 void PC98FMDriver::stopNote(uint8 chan, uint8 note) {
458 if (chan > 2)
459 return;
460
461 if (_allNotes || note == _chanNotes[chan])
462 _pc98a->writeReg(0, 0x28, chan);
463 }
464
timerCallbackB()465 void PC98FMDriver::timerCallbackB() {
466 updateSounds();
467 PC98AudioCore::MutexLock tempUnlock = _pc98a->stackUnlockMutex();
468 updateParser();
469 }
470
471 const uint8 PC98FMDriver::_instrumentsRemapFM[128] = {
472 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x01, 0x02, 0x0f,
473 0x0f, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x19, 0x1b, 0x1c, 0x1d, 0x1e, 0x03,
474 0x04, 0x21, 0x22, 0x23, 0x05, 0x25, 0x06, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2e,
475 0x30, 0x31, 0x35, 0x07, 0x35, 0x35, 0x36, 0x37, 0x38, 0x08, 0x3a, 0x3b, 0x3c, 0x3e, 0x3e, 0x3f,
476 0x40, 0x41, 0x42, 0x44, 0x44, 0x45, 0x09, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x0a, 0x51, 0x51,
477 0x51, 0x54, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5a, 0x5a, 0x5e, 0x5f,
478 0x60, 0x61, 0x67, 0x63, 0x0c, 0x65, 0x66, 0x67, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c,
479 0x0c, 0x0c, 0x0c, 0x0d, 0x0e, 0x0f, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
480 };
481
482 const uint8 PC98FMDriver::_instrumentLevelAdjustFM[128] = {
483 0x28, 0x0f, 0x28, 0x1d, 0x14, 0x14, 0x23, 0x19, 0x28, 0x13, 0x23, 0x23, 0x30, 0x23, 0x17, 0x16,
484 0x23, 0x14, 0x15, 0x13, 0x23, 0x23, 0x19, 0x19, 0x32, 0x19, 0x16, 0x23, 0x05, 0x0a, 0x05, 0x0a,
485 0x35, 0x28, 0x2d, 0x23, 0x19, 0x1c, 0x22, 0x23, 0x23, 0x1a, 0x2d, 0x23, 0x23, 0x23, 0x23, 0x1e,
486 0x32, 0x1e, 0x37, 0x23, 0x18, 0x2e, 0x2b, 0x32, 0x11, 0x14, 0x0f, 0x0f, 0x14, 0x14, 0x14, 0x14,
487 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x0a, 0x28, 0x0d, 0x14, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
488 0x23, 0x0a, 0x19, 0x19, 0x14, 0x14, 0x12, 0x14, 0x2b, 0x2c, 0x34, 0x2e, 0x30, 0x31, 0x15, 0x29,
489 0x32, 0x23, 0x23, 0x23, 0x23, 0x0b, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x14, 0x14, 0x1e, 0x23,
490 0x23, 0x23, 0x23, 0x23, 0x2c, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x00, 0x23, 0x23, 0x23
491 };
492
493 const uint8 PC98FMDriver::_partsRemapFM[16] = {
494 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
495 };
496
497 const uint8 PC98FMDriver::_instrumentPatches[16][25] = {
498 { 0x3f, 0x06, 0x6b, 0x1f, 0x0e, 0x00, 0xff, 0x03, 0x0a, 0x1f, 0x02, 0x01, 0x0f, 0x03, 0x0a, 0x1f, 0x02, 0x01, 0x0f, 0x02, 0x00, 0x1f, 0x02, 0x01, 0x0f },
499 { 0x3f, 0x38, 0x75, 0x1f, 0x81, 0x01, 0x0a, 0x01, 0x00, 0x14, 0x82, 0x01, 0x0a, 0x73, 0x00, 0x14, 0x82, 0x01, 0x0a, 0x62, 0x00, 0x14, 0x82, 0x01, 0x0a },
500 { 0x07, 0x08, 0x3e, 0xdf, 0x15, 0x00, 0x0f, 0x03, 0x11, 0x5f, 0x1f, 0x00, 0x0a, 0x02, 0x25, 0x5d, 0x1f, 0x00, 0x0a, 0x02, 0x00, 0x92, 0x1f, 0x00, 0x0a },
501 { 0x3d, 0x4a, 0x23, 0x1b, 0x11, 0x00, 0xfa, 0x41, 0x00, 0x14, 0x00, 0x00, 0x0a, 0x42, 0x00, 0x14, 0x00, 0x00, 0x0a, 0x40, 0x00, 0x14, 0x00, 0x00, 0x0a },
502 { 0x3c, 0x0b, 0x2b, 0x5a, 0x02, 0x01, 0x35, 0x63, 0x2a, 0x55, 0x01, 0x00, 0x24, 0x03, 0x19, 0x5c, 0x09, 0x05, 0x44, 0x21, 0x00, 0x4d, 0x06, 0x00, 0x44 },
503 { 0x3c, 0x01, 0x20, 0x52, 0x0c, 0x01, 0x5a, 0x22, 0x17, 0x4f, 0x0a, 0x01, 0x2a, 0x26, 0x05, 0x45, 0x0a, 0x00, 0x0f, 0x31, 0x00, 0x47, 0x02, 0x00, 0x0f },
504 { 0x2c, 0x3a, 0x2d, 0x58, 0x0e, 0x00, 0xf7, 0x05, 0x39, 0x5a, 0x0e, 0x00, 0xf4, 0x02, 0x00, 0x58, 0x08, 0x00, 0xf4, 0x01, 0x05, 0x9a, 0x08, 0x00, 0xf4 },
505 { 0x3c, 0x01, 0x20, 0x52, 0x0c, 0x01, 0x2a, 0x21, 0x17, 0x4f, 0x0a, 0x01, 0x5a, 0x11, 0x00, 0x12, 0x8a, 0x01, 0x3a, 0x61, 0x07, 0x14, 0x82, 0x01, 0x3a },
506 { 0x00, 0x01, 0x7f, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x23, 0x5f, 0x05, 0x00, 0xf3, 0x71, 0x1b, 0x5f, 0x0c, 0x01, 0xf5, 0x01, 0x07, 0x5f, 0x0c, 0x00, 0xf5 },
507 { 0x18, 0x37, 0x2c, 0x9e, 0x0d, 0x08, 0xb6, 0x31, 0x18, 0x1c, 0x04, 0x03, 0x36, 0x30, 0x22, 0xdc, 0x06, 0x0a, 0xb6, 0x32, 0x00, 0x9c, 0x01, 0x05, 0x26 },
508 { 0x3b, 0x0a, 0x00, 0x1f, 0x00, 0x00, 0x0a, 0x02, 0x22, 0x18, 0x0e, 0x00, 0x0a, 0x60, 0x3a, 0x18, 0x0c, 0x00, 0xfa, 0x31, 0x00, 0x51, 0x0b, 0x00, 0x38 },
509 { 0x2c, 0x34, 0x21, 0x58, 0x0e, 0x00, 0xf7, 0x76, 0x2f, 0x58, 0x14, 0x00, 0xfa, 0x30, 0x00, 0xd8, 0x84, 0x00, 0xf2, 0x72, 0x0b, 0x98, 0x8c, 0x00, 0xf6 },
510 { 0x3b, 0x08, 0x06, 0x5f, 0x00, 0x00, 0x1a, 0x01, 0x19, 0x4e, 0x0e, 0x00, 0x0a, 0x61, 0x30, 0x58, 0x18, 0x00, 0x5a, 0x30, 0x00, 0x50, 0x0b, 0x00, 0x38 },
511 { 0x3b, 0x0a, 0x0d, 0x16, 0x00, 0x00, 0x0a, 0x00, 0x0b, 0x1a, 0x16, 0x40, 0xfb, 0x0d, 0x13, 0x1a, 0x1a, 0xc0, 0xfa, 0x01, 0x00, 0x5e, 0x8e, 0x00, 0xf7 },
512 { 0x3b, 0x0e, 0x0c, 0x1f, 0x00, 0x00, 0x05, 0x0a, 0x25, 0x1b, 0x1b, 0x80, 0xfa, 0x00, 0x31, 0x1f, 0x0a, 0xc0, 0xf5, 0x00, 0x00, 0x5c, 0x8e, 0x40, 0xf7 },
513 { 0x32, 0x02, 0x15, 0x58, 0x14, 0x00, 0xfa, 0x31, 0x25, 0x5f, 0x0a, 0x40, 0xf4, 0x01, 0x17, 0x5a, 0x0c, 0x80, 0xf6, 0x01, 0x00, 0x9a, 0x8b, 0x00, 0xf5 }
514 };
515
516 const uint8 PC98FMDriver::_ngMapping[76] = {
517 0x18, 0x1c, 0x3c, 0x20, 0x3e, 0x24, 0x40, 0x28, 0x2c, 0x38, 0x30, 0x3c, 0x00, 0x00, 0x36, 0x00, 0x38, 0x00, 0x00,
518 0x00, 0x16, 0x11, 0x16, 0x16, 0x11, 0x16, 0x11, 0x16, 0x11, 0x0f, 0x32, 0x00, 0x00, 0x0d, 0x00, 0x10, 0x1f, 0x1f,
519 0x0a, 0x08, 0x0a, 0x19, 0x04, 0x19, 0x04, 0x14, 0x04, 0x14, 0x0f, 0x0c, 0x0f, 0x0c, 0xff, 0xff, 0x0d, 0xff, 0x12,
520 0xff, 0xff, 0xff, 0x0f, 0x19, 0x0f, 0x0f, 0x19, 0x0f, 0x19, 0x0f, 0x19, 0x14, 0x06, 0xff, 0xff, 0x0f, 0xff, 0x00
521 };
522
523 const uint8 PC98FMDriver::_carrier[8] = {
524 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F
525 };
526
527 const uint16 PC98FMDriver::_frequency[12] = {
528 0x0267, 0x028d, 0x02b3, 0x02dd, 0x0308, 0x0337, 0x0368, 0x039c, 0x03d3, 0x040e, 0x044b, 0x048b
529 };
530
531 #define MIDIMSG32(s, p1, p2) (p2 << 16 | p1 << 8 | s)
532
PC98MidiDriver(MidiDriver::DeviceHandle dev)533 PC98MidiDriver::PC98MidiDriver(MidiDriver::DeviceHandle dev) : _dev(dev), _drv(0) {
534 _instrumentsRemap = (getMusicType(dev) == MT_MT32) ? _instrumentsRemapMT32 : (getMusicType(dev) == MT_GM ? _instrumentsRemapGM : 0);
535 int8 *tbl2 = new int8[128];
536 memset(tbl2, 0, 128);
537 _instrumentLevelAdjust = tbl2;
538 _partsRemap = _partsRemapMidi;
539 memcpy(_volSysex, _sysexMsg[0], 9);
540 memcpy(_partAssignSysexGS, _sysexMsg[1], 9);
541 memcpy(_partAssignSysexMT32, _sysexMsg[2], 9);
542 }
543
~PC98MidiDriver()544 PC98MidiDriver::~PC98MidiDriver() {
545 close();
546 delete[] _instrumentLevelAdjust;
547 }
548
open()549 int PC98MidiDriver::open() {
550 if (_isOpen)
551 return MERR_ALREADY_OPEN;
552
553 delete _drv;
554
555 _drv = MidiDriver::createMidi(_dev);
556 if (!_drv || !_instrumentsRemap)
557 return MERR_DEVICE_NOT_AVAILABLE;
558
559 _baseTempo = _drv->getBaseTempo();
560 int res = _drv->open();
561
562 if (!res) {
563 _drv->setTimerCallback(this, &timerCallback);
564
565 for (byte i = 0xB1; i < 0xBA; ++i)
566 _drv->send(MIDIMSG32(i, 0x79, 0));
567
568 property(kPropMusicVolume, Audio::Mixer::kMaxChannelVolume);
569
570 if (getMusicType(_dev) == MT_MT32) {
571 _partAssignSysexGS[7] = 0x10;
572 for (uint8 i = 0x10; i < 0x20; ++i) {
573 _partAssignSysexGS[5] = i;
574 sendSysexWithCheckSum(_partAssignSysexGS);
575 }
576
577 for (uint8 i = 0x01; i < 0x0A; ++i) {
578 _partAssignSysexMT32[6] = 0x0C + i;
579 _partAssignSysexMT32[7] = i;
580 sendSysexWithCheckSum(_partAssignSysexMT32);
581 }
582
583 } else if (getMusicType(_dev) == MT_GM) {
584 _partAssignSysexGS[5] = 0x10;
585 _partAssignSysexGS[7] = 9;
586 sendSysexWithCheckSum(_partAssignSysexGS);
587 uint8 p = 0;
588 for (uint8 i = 0x11; i < 0x20; ++i) {
589 _partAssignSysexGS[5] = i;
590 _partAssignSysexGS[7] = p++;
591 if (p == 9)
592 p++;
593 sendSysexWithCheckSum(_partAssignSysexGS);
594 }
595
596 _partAssignSysexMT32[7] = 0x10;
597 for (uint8 i = 0x0D; i < 0x16; ++i) {
598 _partAssignSysexMT32[6] = i;
599 sendSysexWithCheckSum(_partAssignSysexMT32);
600 }
601
602 _drv->send(MIDIMSG32(0xB9, 0x07, 0x46));
603 }
604
605 reset();
606 _isOpen = true;
607 }
608
609 return res;
610 }
611
close()612 void PC98MidiDriver::close() {
613 _isOpen = false;
614
615 if (_drv) {
616 _drv->setTimerCallback(0, 0);
617 _mixer->stopAll();
618 _drv->close();
619 delete _drv;
620 _drv = 0;
621 }
622
623 setTimerCallback(0, 0);
624 }
625
timerCallback(void * obj)626 void PC98MidiDriver::timerCallback(void *obj) {
627 PC98MidiDriver *drv = static_cast<PC98MidiDriver*>(obj);
628 drv->updateSounds();
629 drv->updateParser();
630 }
631
noteOn(uint8 part,uint8 note,uint8 velo)632 void PC98MidiDriver::noteOn(uint8 part, uint8 note, uint8 velo) {
633 _drv->send(MIDIMSG32(0x90 | _partsRemap[part & 0x0F], note, velo));
634 }
635
noteOff(uint8 part,uint8 note)636 void PC98MidiDriver::noteOff(uint8 part, uint8 note) {
637 if (_allNotes)
638 _drv->send(MIDIMSG32(0xB0 | _partsRemap[part & 0x0F], 0x7B, 0));
639 else
640 _drv->send(MIDIMSG32(0x80 | _partsRemap[part & 0x0F], note, 0));
641 }
642
programChange(uint8 part,uint8 prog)643 void PC98MidiDriver::programChange(uint8 part, uint8 prog) {
644 if (!_programLock)
645 _drv->send(MIDIMSG32(0xC0 | _partsRemap[part & 0x0F], prog, 0));
646 }
647
setVolume(int musicVolume,int sfxVolume)648 void PC98MidiDriver::setVolume(int musicVolume, int sfxVolume) {
649 if (!_isOpen)
650 return;
651
652 if (getMusicType(_dev) == MT_MT32) {
653 _volSysex[7] = musicVolume * 100 / Audio::Mixer::kMaxChannelVolume;
654 sendSysexWithCheckSum(_volSysex);
655 } else {
656 uint8 vol = musicVolume * 127 / Audio::Mixer::kMaxChannelVolume;
657 for (int i = 0; i < 16; ++i)
658 _drv->send(MIDIMSG32(0xB0 | _partsRemap[i], 0x07, vol));
659 }
660 }
661
pause(bool paused)662 void PC98MidiDriver::pause(bool paused) {
663 if (paused) {
664 _allNotes = true;
665 for (int i = 0; i < 16; ++i)
666 noteOff(i, 0);
667 _allNotes = false;
668 }
669 }
670
sendSysexWithCheckSum(uint8 * data)671 void PC98MidiDriver::sendSysexWithCheckSum(uint8 *data) {
672 uint8 chk = 0;
673 for (int i = 4; i < 8; ++i)
674 chk += data[i];
675 data[8] = 0x80 - (chk & 0x7f);
676 _drv->sysEx(data, 9);
677 }
678
679 const uint8 PC98MidiDriver::_instrumentsRemapMT32[128] = {
680 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
681 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
682 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
683 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
684 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
685 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
686 0x60, 0x61, 0x62, 0x63, 0x6e, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
687 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
688 };
689
690 const uint8 PC98MidiDriver::_instrumentsRemapGM[128] = {
691 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x09, 0x0a, 0x0b, 0x0c, 0x10, 0x10, 0x0f,
692 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x26,
693 0x58, 0x21, 0x22, 0x23, 0x61, 0x25, 0x0b, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
694 0x30, 0x31, 0x32, 0x2d, 0x34, 0x35, 0x36, 0x37, 0x38, 0x2e, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
695 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x23, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4c, 0x4e, 0x4f,
696 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
697 0x60, 0x61, 0x62, 0x63, 0x4c, 0x65, 0x66, 0x67, 0x0c, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
698 0x70, 0x71, 0x72, 0x75, 0x76, 0x74, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
699 };
700
701 const uint8 PC98MidiDriver::_partsRemapMidi[16] = {
702 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0f, 0x09, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f
703 };
704
705 const uint8 PC98MidiDriver::_sysexMsg[3][9] = {
706 { 0x41, 0x10, 0x16, 0x12, 0x10, 0x00, 0x16, 0x64, 0x00 },
707 { 0x41, 0x10, 0x42, 0x12, 0x40, 0x10, 0x02, 0x10, 0x00 },
708 { 0x41, 0x10, 0x16, 0x12, 0x10, 0x00, 0x00, 0x00, 0x00 }
709 };
710
MidiDriverPC98_create(MidiDriver::DeviceHandle dev)711 MidiDriver *MidiDriverPC98_create(MidiDriver::DeviceHandle dev) {
712 MusicType type = MidiDriver::getMusicType(dev);
713 if (type == MT_PC98)
714 return new PC98FMDriver();
715 else if (type == MT_GM || type == MT_MT32)
716 return new PC98MidiDriver(dev);
717 return 0;
718 }
719
720 #undef MIDIMSG32
721
722 } // End of namespace AGOS
723