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