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 "sci/sci.h"
24
25 #include "common/file.h"
26 #include "common/system.h"
27 #include "common/textconsole.h"
28
29 #include "audio/softsynth/fmtowns_pc98/pc98_audio.h"
30
31 #include "sci/resource/resource.h"
32 #include "sci/sound/drivers/mididriver.h"
33
34 /* PC-98 sound driver for:
35 Quest for Glory 1 SCI_VERSION_0_LATE first driver type
36 Police Quest 2 SCI_VERSION_0_LATE second driver type
37 Castle of Dr. Brain SCI_VERSION_1_LATE third driver type
38 Space Quest IV SCI_VERSION_1_LATE third driver type
39 King's Quest V SCI_VERSION_1_LATE latest driver type
40 */
41
42 namespace Sci {
43
44 class MidiPart_PC9801;
45 class SoundChannel_PC9801 {
46 public:
47 SoundChannel_PC9801(PC98AudioCore *pc98a, MidiPart_PC9801 **parts, SciVersion version, int type, SciSpan<const uint8> instrumentData, bool &soundOn);
48 virtual ~SoundChannel_PC9801();
49
50 void noteOff();
51 void noteOn(uint8 note, uint8 velo);
52
53 virtual void processNoteEvent(uint8 note, bool soundOn);
54 void update();
55 void setVolume(uint8 volume);
56
57 virtual void reset();
toggleNoiseGenerator(bool)58 virtual void toggleNoiseGenerator(bool) {}
59
getType() const60 int getType() const { return _type; }
61
62 uint8 _assign;
63 uint8 _note;
64 uint8 _sustain;
65 uint16 _duration;
66
67 protected:
68 enum ChannelStatusFlags {
69 kChanVbrEnable = 0x01,
70 kChanVbrRestartEnv = 0x02,
71 kChanKeyOn = 0x04,
72 kChanNgEnable = 0x08,
73 kChanNgRestartEnv = 0x10,
74 kChanNgDecrease = 0x20,
75 kChanVbrMode = 0x40,
76 kChanVbrDecrease = 0x80
77 };
78
79 int recalculateFrequency(uint16 note, uint16 modifier, uint8 *destOctaveBlock, uint16 *destFrequency, uint8 *destVbrFrequencyModifier);
80 uint8 getVolume();
81 virtual void processSounds();
82 void programChangeInit(SciSpan<const uint8> &data);
83 void writeReg(uint8 part, uint8 reg, uint8 val);
84
85 int8 _transpose;
86 uint8 _vbrInitialDelay;
87 uint8 _vbrEnvelopeTimer;
88 uint8 _vbrEnvelopeSpeed;
89
90 uint16 _frequencyCourse;
91 uint8 _frequencyBlock;
92 uint8 _frequencyNoteModifier;
93
94 uint8 _vbrDepthIncr;
95 uint8 _vbrDecrTime;
96 uint8 _vbrDepthDecr;
97 uint8 _vbrIncrTime;
98 uint8 _vbrSensitivity;
99 uint16 _vbrIncrStep;
100 uint16 _vbrDecrStep;
101 uint8 _vbrModulationTimer;
102 uint16 _vbrFrequencyModifier;
103 uint8 _vbrCur;
104 uint8 _flags;
105
106 const uint16 *_noteFrequency;
107 const uint16 *_noteFrequencyModifier;
108
109 SciSpan<const uint8> _instrumentData;
110 const SciVersion _version;
111
112 private:
113 virtual void programChange(uint8 program) = 0;
114 virtual bool prepareFrequencyAndVolume(bool updateVolume);
115 virtual void sendSoundOnOff(bool soundOn) = 0;
116 virtual void sendFrequency() = 0;
117 virtual void sendVolume() = 0;
118
119 uint8 _velo;
120 uint8 _volume;
121 uint8 _program;
122 bool &_soundOn;
123
124 MidiPart_PC9801 **_parts;
125 PC98AudioCore *_pc98a;
126 const int _type;
127 };
128
129 class SoundChannel_PC9801_FM4OP : public SoundChannel_PC9801 {
130 public:
131 SoundChannel_PC9801_FM4OP(uint8 id, PC98AudioCore *pc98a, MidiPart_PC9801 **parts, SciVersion version, SciSpan<const uint8> instrumentData, uint8 patchSize, bool &soundOn);
~SoundChannel_PC9801_FM4OP()132 ~SoundChannel_PC9801_FM4OP() override {}
133
134 private:
135 void programChange(uint8 program) override;
136 void sendSoundOnOff(bool soundOn) override;
137 void sendVolume() override;
138 void sendFrequency() override;
139
140 uint8 _operatorLevel[4];
141 uint8 _carrier;
142 uint8 _operatorFlags;
143
144 const uint8 _regPrt;
145 const uint8 _regOffs;
146 const uint8 _patchSize;
147 };
148
149 class SoundChannel_PC9801_FM2OP : public SoundChannel_PC9801 {
150 public:
151 SoundChannel_PC9801_FM2OP(uint8 id, PC98AudioCore *pc98a, MidiPart_PC9801 **parts, SciVersion version, SciSpan<const uint8> instrumentData, uint8 patchSize, bool &soundOn);
~SoundChannel_PC9801_FM2OP()152 ~SoundChannel_PC9801_FM2OP() override {}
153
154 void processNoteEvent(uint8 note, bool soundOn) override;
155 void reset() override;
156
157 private:
158 void programChange(uint8 program) override;
159 bool prepareFrequencyAndVolume(bool updateVolume) override;
160 void processSounds() override;
161 void sendSoundOnOff(bool soundOn) override;
162 void sendVolume() override;
163 void sendFrequency() override;
164
165 uint8 _operatorLevel[2];
166 uint8 _operatorFrqIndex[2];
167 uint16 _frequencyCourse2;
168 uint8 _frequencyNoteModifier2;
169 int16 _vbrFrequencyModifier2;
170 uint16 _vbrIncrStep2;
171 uint16 _vbrDecrStep2;
172 uint8 _vbrCur2;
173 static uint8 _activeOperators;
174
175 const uint16 *_opFreqOffset;
176 const uint8 _patchOffset;
177 const uint8 _regPrt;
178 const uint8 _regOffs;
179 const uint8 _patchSize;
180 };
181
182 class SoundChannel_PC9801_SSG : public SoundChannel_PC9801 {
183 public:
184 SoundChannel_PC9801_SSG(uint8 id, PC98AudioCore *pc98a, MidiPart_PC9801 **parts, SciVersion version, SciSpan<const uint8> instrumentData, uint8 patchOffset, uint8 patchSize, bool &soundOn);
~SoundChannel_PC9801_SSG()185 ~SoundChannel_PC9801_SSG() override {}
186 void reset() override;
187 void toggleNoiseGenerator(bool enable) override;
188
189 private:
190 enum {
191 kEnvSSG_silent = 0x00,
192 kEnvSSG_decay = 0x01,
193 kEnvSSG_sustain = 0x02,
194 kEnvSSG_attack = 0x03,
195 kEnvSSG_keyOn = 0x10
196 };
197
198 void programChange(uint8 program) override;
199 void processSounds() override;
200 void sendSoundOnOff(bool soundOn) override;
201 void sendVolume() override;
202 void sendFrequency() override;
203 void updateNg();
204 void sendActiveChannelsStatus();
205
206 uint8 _instrumentChanMask;
207 uint8 _chanDisableMask;
208 uint8 _chanEnableMask1;
209 uint8 _chanEnableMask2;
210 uint8 _currentLevel;
211 uint8 _ngPhaseStep;
212 uint8 _ngPhase;
213 uint8 _ngEnvelopeTimer;
214 uint8 _ngSpeed;
215 uint8 _ssgEnvelopeTimer;
216 uint8 _ssgLevel;
217 uint8 _ssgSpeed;
218 uint8 _ssgEnvelopeState;
219 bool _ccngEnabled;
220
221 static uint8 _activeChannnelsStatus;
222 SciSpan<const uint8> _selectedInstrument;
223
224 const uint8 *_ngFreq;
225 const uint8 _regOffs;
226 const uint8 _patchOffset;
227 const uint8 _patchSize;
228 };
229
230 class MidiPart_PC9801 {
231 public:
232 MidiPart_PC9801(uint8 id, SoundChannel_PC9801 **channels, uint8 numChan, SciVersion version);
~MidiPart_PC9801()233 ~MidiPart_PC9801() {}
234
235 void noteOff(uint8 note);
236 void noteOn(uint8 note, uint8 velo);
237 void controlChangeVolume(uint8 vol);
238 void controlChangeSustain(uint8 sus);
239 void controlChangePolyphony(uint8 numChan);
240 void controlChangeNoiseGenerator(uint8 status);
241 void controlChangeAllNotesOff();
242 void programChange(uint8 prg);
243 void pitchBend(int16 val);
244
245 void addChannels(int num, int resetMissingChannels = -1, int channelType = -1);
246 void dropChannels(int num);
247
getCurrentProgram() const248 uint8 getCurrentProgram() const { return _program; }
getCurrentVolume() const249 uint8 getCurrentVolume() const { return _volume; }
getCurrentPitchBend() const250 uint16 getCurrentPitchBend() const { return _pitchBend; }
getMissingChannels() const251 uint8 getMissingChannels() const { return _chanMissing; }
252
253 private:
254 int allocateChannel();
255 void assignFreeChannels();
256
257 uint8 _id;
258 uint8 _program;
259 uint8 _volume;
260 uint8 _sustain;
261 uint16 _pitchBend;
262 uint8 _outChan;
263 uint8 _chanMissing;
264
265 SoundChannel_PC9801 **_chan;
266 const SciVersion _version;
267 const int _numChan;
268 const uint8 _noteRangeLow;
269 const uint8 _noteRangeHigh;
270 };
271
272 class MidiDriver_PC9801 : public MidiDriver, public PC98AudioPluginDriver {
273 public:
274 enum {
275 MIDI_PROP_PLAYSWITCH = 1,
276 MIDI_PROP_POLYPHONY = 2,
277 MIDI_PROP_CHANNEL_ID = 3
278 };
279
280 MidiDriver_PC9801(Audio::Mixer *mixer, SciVersion version);
281 ~MidiDriver_PC9801() override;
282
283 int open() override;
isOpen() const284 bool isOpen() const override { return _isOpen; }
285 void close() override;
286
287 void send(uint32 b) override;
288 static void assignFreeChannels(int num);
289 uint32 property(int prop, uint32 param) override;
290 void initTrack(SciSpan<const byte> &header);
291
292 void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) override;
293 uint32 getBaseTempo() override;
allocateChannel()294 MidiChannel *allocateChannel() override { return 0; }
getPercussionChannel()295 MidiChannel *getPercussionChannel() override { return 0; }
296
297 void timerCallbackB() override;
298
299 private:
300 bool loadInstruments(const SciSpan<const uint8> &data);
301 void updateParser();
302 void updateChannels();
303 void reset();
304
305 Common::TimerManager::TimerProc _timerProc;
306 void *_timerProcPara;
307
308 static MidiPart_PC9801 **_parts;
309 SoundChannel_PC9801 **_chan;
310 Common::SpanOwner<SciSpan<uint8> > _instrumentData;
311
312 uint8 _masterVolume;
313 bool _soundOn;
314
315 uint8 _numChan;
316 uint8 _ssgPatchOffset;
317 uint8 _patchSize;
318
319 uint8 _internalVersion;
320 const uint8 _playID;
321 const uint8 _channelMask1;
322 uint8 _channelMask2;
323 uint8 _polyphony;
324
325 bool _isOpen;
326 bool _ready;
327
328 const uint16 _baseTempo;
329
330 PC98AudioCore *_pc98a;
331 Audio::Mixer *_mixer;
332 const SciVersion _version;
333 };
334
335 class MidiPlayer_PC9801 : public MidiPlayer {
336 public:
337 enum {
338 MIDI_PROP_PLAYSWITCH = 1,
339 MIDI_PROP_POLYPHONY = 2,
340 MIDI_PROP_CHANNEL_ID = 3
341 };
342
343 MidiPlayer_PC9801(SciVersion version);
344 ~MidiPlayer_PC9801() override;
345
346 bool hasRhythmChannel() const override;
347 byte getPlayId() const override;
348 int getPolyphony() const override;
349 void playSwitch(bool play) override;
350
351 void initTrack(SciSpan<const byte> &trackData) override;
352 };
353
SoundChannel_PC9801(PC98AudioCore * pc98a,MidiPart_PC9801 ** parts,SciVersion version,int type,SciSpan<const uint8> instrumentData,bool & soundOn)354 SoundChannel_PC9801::SoundChannel_PC9801(PC98AudioCore *pc98a, MidiPart_PC9801 **parts, SciVersion version, int type, SciSpan<const uint8> instrumentData, bool &soundOn)
355 : _pc98a(pc98a), _parts(parts), _version(version), _type(type), _instrumentData(instrumentData), _soundOn(soundOn), _assign(0xff), _note(0xff), _velo(0),
356 _volume(0), _transpose(0), _sustain(0), _duration(0), _program(0xff), _vbrInitialDelay(0), _vbrEnvelopeTimer(0),
357 _vbrEnvelopeSpeed(0), _vbrDepthIncr(0), _vbrDecrTime(0), _vbrDepthDecr(0), _vbrIncrTime(0), _vbrSensitivity(0),
358 _vbrFrequencyModifier(0), _vbrIncrStep(0), _vbrDecrStep(0), _vbrModulationTimer(0), _flags(0), _vbrCur(0x80),
359 _frequencyBlock(0), _frequencyCourse(0), _frequencyNoteModifier(0) {
360
361 static const uint16 courseV0[] = { 0x269, 0x28D, 0x2B5, 0x2DE, 0x30A, 0x339, 0x368, 0x39D, 0x3D4, 0x40E, 0x44A, 0x48C };
362 static const uint16 courseV1[] = { 0x26A, 0x28E, 0x2B5, 0x2DF, 0x30A, 0x339, 0x36A, 0x39E, 0x3D5, 0x40F, 0x44D, 0x48F };
363 static const uint16 fine[] = { 0x24, 0x27, 0x2A, 0x2B, 0x2F, 0x31, 0x34, 0x37, 0x3A, 0x3E, 0x42, 0x45 };
364
365 _noteFrequency = (version > SCI_VERSION_0_LATE) ? courseV1 : courseV0;
366 _noteFrequencyModifier = fine;
367 }
368
~SoundChannel_PC9801()369 SoundChannel_PC9801::~SoundChannel_PC9801() {
370 _instrumentData.clear();
371 }
372
noteOff()373 void SoundChannel_PC9801::noteOff() {
374 if (_sustain)
375 return;
376
377 processNoteEvent(_note, false);
378
379 _note = 0xFF;
380 _duration = 0;
381 }
382
noteOn(uint8 note,uint8 velo)383 void SoundChannel_PC9801::noteOn(uint8 note, uint8 velo) {
384 _duration = 0;
385
386 if (_program != _parts[_assign]->getCurrentProgram() && _soundOn) {
387 _program = _parts[_assign]->getCurrentProgram();
388 programChange(_program);
389 }
390
391 if (_version > SCI_VERSION_0_LATE) {
392 velo >>= 1;
393 if (velo > 63)
394 velo = 63;
395 _velo = velo;
396 }
397
398 processNoteEvent(note, true);
399 }
400
processNoteEvent(uint8 note,bool soundOn)401 void SoundChannel_PC9801::processNoteEvent(uint8 note, bool soundOn) {
402 if (_note != note) {
403 _note = note;
404 _vbrEnvelopeTimer = _vbrInitialDelay;
405 _vbrFrequencyModifier = 0;
406 _vbrCur = 0x80;
407 _flags |= kChanVbrRestartEnv;
408 }
409
410 if (!prepareFrequencyAndVolume(soundOn))
411 soundOn = false;
412
413 sendSoundOnOff(soundOn);
414 }
415
update()416 void SoundChannel_PC9801::update() {
417 processSounds();
418 if (_note != 0xFF)
419 _duration++;
420 }
421
setVolume(uint8 volume)422 void SoundChannel_PC9801::setVolume(uint8 volume) {
423 static const uint8 volumeTable[] = { 0x7F, 0x7F, 0x30, 0x30, 0x28, 0x28, 0x20, 0x20, 0x18, 0x18, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00 };
424 assert(volume < 16);
425 _volume = volumeTable[volume];
426 }
427
reset()428 void SoundChannel_PC9801::reset() {
429 _assign = 0xFF;
430 _note = 0xFF;
431 _volume = 0;
432 }
433
recalculateFrequency(uint16 note,uint16 modifier,uint8 * destOctaveBlock,uint16 * destFrequency,uint8 * destVbrFrequencyModifier)434 int SoundChannel_PC9801::recalculateFrequency(uint16 note, uint16 modifier, uint8 *destOctaveBlock, uint16 *destFrequency, uint8 *destVbrFrequencyModifier) {
435 note += _transpose;
436 uint16 pb = _parts[_assign]->getCurrentPitchBend();
437
438 if (pb == 0x2000) {
439 pb = 0;
440 } else {
441 int dir = 1;
442 if (pb > 0x2000) {
443 pb -= 0x2000;
444 } else if (pb < 0x2000) {
445 pb = 0x2000 - pb;
446 dir = -1;
447 }
448
449 uint8 noteDiff = pb / 684;
450 note += (noteDiff * dir);
451
452 pb %= 684;
453 if (pb > 682)
454 pb = 682;
455 pb = ((pb * 6) >> 4);
456 pb *= dir;
457 }
458
459 note += (modifier >> 8);
460 pb += (modifier & 0xff);
461 if ((pb >> 8) == 1) {
462 pb &= 0xFF;
463 note++;
464 }
465
466 if (_version == SCI_VERSION_0_LATE)
467 note -= 12;
468
469 if (note < 12 || note > 107)
470 return -1;
471
472 if (_version == SCI_VERSION_0_LATE && _type == 2) {
473 uint16 rs = _noteFrequency[note - 12];
474 if (destFrequency)
475 *destFrequency = rs;
476 return rs;
477 }
478
479 uint8 block = (note / 12) - 1;
480 note %= 12;
481 uint16 res =_noteFrequency[note];
482 uint16 pitchVbrMultiplier = _noteFrequencyModifier[note];
483
484 if (_type != 2)
485 res |= (block << 11);
486 else if (block == 0)
487 return -1;
488
489 if (pb)
490 res += (((pb * pitchVbrMultiplier) & 0x0FF0) >> 8);
491
492 if (res < 0x4000) {
493 if (destFrequency)
494 *destFrequency = res;
495 if (destOctaveBlock)
496 *destOctaveBlock = block;
497 if (destVbrFrequencyModifier)
498 *destVbrFrequencyModifier = pitchVbrMultiplier;
499 return res;
500 }
501
502 return -1;
503 }
504
getVolume()505 uint8 SoundChannel_PC9801::getVolume() {
506 static const uint8 volumeTable1[] = {
507 0x00, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x12, 0x13, 0x14, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d,
508 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2d, 0x2d, 0x2e,
509 0x2f, 0x30, 0x31, 0x32, 0x32, 0x33, 0x34, 0x34, 0x35, 0x36, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3a,
510 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f
511 };
512
513 static const uint8 volumeTable2[] = {
514 0x00, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x61,
515 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x6f, 0x70,
516 0x71, 0x72, 0x72, 0x73, 0x74, 0x74, 0x75, 0x76, 0x76, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a,
517 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f
518 };
519
520 uint16 partVolume = ((_assign != 0xFF) ? _parts[_assign]->getCurrentVolume() : 0);
521 if (_version == SCI_VERSION_0_LATE)
522 return partVolume;
523
524 partVolume += 1;
525 uint16 velocity = volumeTable1[_velo] + 1;
526 uint16 volume = _soundOn ? (partVolume * velocity) >> 6 : 0;
527 volume = volumeTable2[volume] - _volume;
528
529 return (volume < 0x7F ? volume : 0);
530 }
531
processSounds()532 void SoundChannel_PC9801::processSounds() {
533 if (!(_flags & kChanVbrEnable))
534 return;
535
536 if (_flags & kChanVbrRestartEnv) {
537 if (--_vbrEnvelopeTimer)
538 return;
539
540 _vbrIncrStep = _vbrDepthIncr * _vbrSensitivity * _frequencyNoteModifier;
541 _vbrDecrStep = _vbrDepthDecr * _vbrSensitivity * _frequencyNoteModifier;
542 _vbrModulationTimer = ((_flags & kChanVbrMode) ? _vbrIncrTime : _vbrDecrTime) >> 1;
543 _vbrCur = 0x80;
544
545 _flags &= ~(kChanVbrDecrease | kChanVbrRestartEnv);
546 if (_flags & kChanVbrMode)
547 _flags |= kChanVbrDecrease;
548 }
549
550 uint16 t = _vbrEnvelopeTimer + _vbrEnvelopeSpeed;
551 _vbrEnvelopeTimer = t & 0xFF;
552 if (t & 0x100)
553 return;
554
555 if (!--_vbrModulationTimer) {
556 _vbrModulationTimer = (_flags & kChanVbrDecrease) ? _vbrDecrTime : _vbrIncrTime;
557 _flags ^= kChanVbrDecrease;
558 }
559
560 if (_flags & kChanVbrDecrease) {
561 uint8 sL = _vbrDecrStep & 0xFF;
562 uint8 sH = _vbrDecrStep >> 8;
563 bool ovrflow = (sL > _vbrCur);
564 _vbrCur -= sL;
565 if (!ovrflow)
566 return;
567 _vbrFrequencyModifier -= (sH + 1);
568 } else {
569 uint8 sL = _vbrDecrStep & 0xFF;
570 uint8 sH = _vbrDecrStep >> 8;
571 bool ovrflow = (sL + _vbrCur > 255);
572 _vbrCur += sL;
573 if (!ovrflow)
574 return;
575 _vbrFrequencyModifier += (sH + 1);
576 }
577
578 sendFrequency();
579 }
580
programChangeInit(SciSpan<const uint8> & data)581 void SoundChannel_PC9801::programChangeInit(SciSpan<const uint8> &data) {
582 _transpose = (int8)(data[0] & 0xC0 && data[0] < 0xC0 ? data[0] ^ 0x80 : data[0]);
583 _vbrInitialDelay = data[1];
584 _vbrDepthIncr = data[2];
585 _vbrDecrTime = data[3];
586 _vbrDepthDecr = data[4];
587 _vbrIncrTime = data[5];
588 _vbrSensitivity = (data[6] & 3) + 1;
589 _vbrEnvelopeSpeed = data[6] >> 3;
590 _flags = (_flags & ~(kChanVbrEnable | kChanVbrMode)) | ((data[6] << 4) & 0x40);
591 if (_vbrInitialDelay)
592 _flags |= (kChanVbrEnable | kChanVbrRestartEnv);
593 }
594
writeReg(uint8 part,uint8 reg,uint8 val)595 void SoundChannel_PC9801::writeReg(uint8 part, uint8 reg, uint8 val) {
596 _pc98a->writeReg(part, reg, val);
597 }
598
prepareFrequencyAndVolume(bool updateVolume)599 bool SoundChannel_PC9801::prepareFrequencyAndVolume(bool updateVolume) {
600 if (recalculateFrequency(_note, 0, &_frequencyBlock, &_frequencyCourse, &_frequencyNoteModifier) == -1)
601 return false;
602
603 sendFrequency();
604 if (updateVolume)
605 sendVolume();
606
607 return true;
608 }
609
SoundChannel_PC9801_FM4OP(uint8 id,PC98AudioCore * pc98a,MidiPart_PC9801 ** parts,SciVersion version,SciSpan<const uint8> instrumentData,uint8 patchSize,bool & soundOn)610 SoundChannel_PC9801_FM4OP::SoundChannel_PC9801_FM4OP(uint8 id, PC98AudioCore *pc98a, MidiPart_PC9801 **parts, SciVersion version, SciSpan<const uint8> instrumentData, uint8 patchSize, bool &soundOn)
611 : SoundChannel_PC9801(pc98a, parts, version, 0, instrumentData, soundOn), _carrier(0), _regPrt(id > 2 ? 1 : 0), _regOffs(id % 3),
612 _operatorFlags((id > 2 ? 4 : 0) | (id % 3) | 0xF0), _patchSize(patchSize) {
613 _operatorLevel[0] = _operatorLevel[1] = _operatorLevel[2] = _operatorLevel[3] = 0x7F;
614 }
615
programChange(uint8 program)616 void SoundChannel_PC9801_FM4OP::programChange(uint8 program) {
617 static const uint8 carrier[] = { 0x10, 0x10, 0x10, 0x10, 0x30, 0x70, 0x70, 0xF0 };
618 static const uint8 steps[] = { 0, 16, 8, 24 };
619 SciSpan<const uint8> data = _instrumentData.subspan(program * _patchSize);
620
621 if (_version == SCI_VERSION_1_LATE) {
622 programChangeInit(data);
623 uint8 pos = 8;
624
625 for (uint8 i = 0x40 + _regOffs; i < 0x50 + _regOffs; i += 4)
626 writeReg(_regPrt, i, 0xFF);
627 for (uint8 i = 0x30 + _regOffs; i < 0x40 + _regOffs; i += 4)
628 writeReg(_regPrt, i, data[pos++]);
629 for (int i = 0; i < 4; ++i)
630 _operatorLevel[i] = data[pos++];
631 for (uint8 i = 0x50 + _regOffs; i < 0xA0 + _regOffs; i += 4)
632 writeReg(_regPrt, i, data[pos++]);
633 writeReg(_regPrt, 0xB0 + _regOffs, data[pos]);
634 _carrier = carrier[data[pos] & 7];
635
636 } else {
637 uint8 pos = 11;
638 uint8 opFlags = data[pos];
639 uint8 fba = data[pos + 1] & 0x3F;
640 _carrier = carrier[fba & 7];
641
642 pos += 8;
643 uint8 reg = 0x30 + _regOffs;
644 for (int i = 0; i < 4; ++i)
645 writeReg(_regPrt, reg + (i << 2), data[pos + steps[i & 3]] & 0x7F);
646
647 pos -= 3;
648 _operatorLevel[0] = (opFlags & 0x08) ? data[pos + steps[0]] : 0x7F;
649 _operatorLevel[1] = (opFlags & 0x20) ? data[pos + steps[1]] : 0x7F;
650 _operatorLevel[2] = (opFlags & 0x10) ? data[pos + steps[2]] : 0x7F;
651 _operatorLevel[3] = (opFlags & 0x40) ? data[pos + steps[3]] : 0x7F;
652
653 pos += 4;
654 reg = 0x50 + _regOffs;
655 for (int i = 0; i < 16; ++i)
656 writeReg(_regPrt, reg + (i << 2), data[pos + steps[i & 3] + (i >> 2)]);
657
658 if (fba >= 24)
659 fba -= 24;
660 else
661 fba &= 7;
662
663 writeReg(_regPrt, 0xB0 + _regOffs, fba);
664 _operatorFlags = (_operatorFlags & 7) | (opFlags << 1);
665 }
666 }
667
sendSoundOnOff(bool soundOn)668 void SoundChannel_PC9801_FM4OP::sendSoundOnOff(bool soundOn) {
669 _flags = soundOn ? (_flags | kChanKeyOn) : (_flags & ~kChanKeyOn);
670 writeReg(0, 0x28, soundOn ? _operatorFlags : _operatorFlags & 7);
671 }
672
sendVolume()673 void SoundChannel_PC9801_FM4OP::sendVolume() {
674 uint8 vol = getVolume();
675 uint16 c = _carrier;
676
677 for (uint8 i = 0; i < 4; ++i) {
678 uint8 r = _operatorLevel[i];
679 c += c;
680 if (c & 0x100) {
681 c &= 0xFF;
682 if (_version == SCI_VERSION_1_LATE) {
683 r = (((r ^ 0x7F) * vol) / 0x7F) * 2;
684 r = ((r < 0x7F) ? 0x7F - r : 0) + 20;
685 if (r > 0x7F)
686 r = 0x7F;
687 } else {
688 r = 127 - ((127 - r) * vol / 128);
689 }
690 }
691 writeReg(_regPrt, 0x40 + (i << 2) + _regOffs, r);
692 }
693 }
694
sendFrequency()695 void SoundChannel_PC9801_FM4OP::sendFrequency() {
696 uint16 freq = _frequencyCourse + _vbrFrequencyModifier;
697 writeReg(_regPrt, 0xA4 + _regOffs, freq >> 8);
698 writeReg(_regPrt, 0xA0 + _regOffs, freq & 0xFF);
699 }
700
701 uint8 SoundChannel_PC9801_FM2OP::_activeOperators = 0;
702
SoundChannel_PC9801_FM2OP(uint8 id,PC98AudioCore * pc98a,MidiPart_PC9801 ** parts,SciVersion version,SciSpan<const uint8> instrumentData,uint8 patchSize,bool & soundOn)703 SoundChannel_PC9801_FM2OP::SoundChannel_PC9801_FM2OP(uint8 id, PC98AudioCore *pc98a, MidiPart_PC9801 **parts, SciVersion version, SciSpan<const uint8> instrumentData, uint8 patchSize, bool &soundOn)
704 : SoundChannel_PC9801(pc98a, parts, version, 1, instrumentData, soundOn), _patchOffset(37), _patchSize(patchSize), _frequencyCourse2(0), _frequencyNoteModifier2(0),
705 _vbrFrequencyModifier2(0), _vbrCur2(0x80), _vbrIncrStep2(0), _vbrDecrStep2(0), _regPrt(id > 3 ? 1 : 0), _regOffs(id & 1) {
706
707 static const uint16 opFreqOffset[] = { 0x0000, 0x0600, 0x07CF, 0x0980 };
708
709 _operatorLevel[0] = _operatorLevel[1] = 0x7F;
710 _operatorFrqIndex[0] = _operatorFrqIndex[1] = 0;
711 _opFreqOffset = opFreqOffset;
712 }
713
processNoteEvent(uint8 note,bool soundOn)714 void SoundChannel_PC9801_FM2OP::processNoteEvent(uint8 note, bool soundOn) {
715 if (_note != note) {
716 _vbrCur2 = 0x80;
717 _vbrFrequencyModifier2 = 0;
718 }
719 SoundChannel_PC9801::processNoteEvent(note, soundOn);
720 }
721
reset()722 void SoundChannel_PC9801_FM2OP::reset() {
723 SoundChannel_PC9801::reset();
724 _activeOperators = 0;
725 }
726
programChange(uint8 program)727 void SoundChannel_PC9801_FM2OP::programChange(uint8 program) {
728 SciSpan<const uint8> data = _instrumentData.subspan(program * _patchSize + _patchOffset);
729
730 programChangeInit(data);
731 uint8 pos = 7;
732
733 for (uint8 i = 0x42 + (_regOffs << 2); i < 0x52 + (_regOffs << 2); i += 8)
734 writeReg(_regPrt, i, 0xFF);
735 for (uint8 i = 0x32 + (_regOffs << 2); i < 0x42 + (_regOffs << 2); i += 8)
736 writeReg(_regPrt, i, data[pos++]);
737 for (int i = 0; i < 2; ++i)
738 _operatorLevel[i] = data[pos++];
739 for (uint8 i = 0x52 + (_regOffs << 2); i < 0x72 + (_regOffs << 2); i += 8)
740 writeReg(_regPrt, i, data[pos++]);
741 _operatorFrqIndex[0] = data[pos] >> 6;
742 _operatorFrqIndex[1] = data[pos + 1] >> 6;
743 for (uint8 i = 0x72 + (_regOffs << 2); i < 0xA2 + (_regOffs << 2); i += 8)
744 writeReg(_regPrt, i, data[pos++]);
745 }
746
prepareFrequencyAndVolume(bool updateVolume)747 bool SoundChannel_PC9801_FM2OP::prepareFrequencyAndVolume(bool updateVolume) {
748 if (recalculateFrequency(_note, _opFreqOffset[_operatorFrqIndex[0]], 0, &_frequencyCourse, &_frequencyNoteModifier) == -1)
749 return false;
750 if (recalculateFrequency(_note, _opFreqOffset[_operatorFrqIndex[1]], 0, &_frequencyCourse2, &_frequencyNoteModifier2) == -1)
751 return false;
752
753 sendFrequency();
754 if (updateVolume)
755 sendVolume();
756
757 return true;
758 }
759
sendSoundOnOff(bool soundOn)760 void SoundChannel_PC9801_FM2OP::sendSoundOnOff(bool soundOn) {
761 uint8 op = 0x30 << (_regOffs << 1);
762
763 if (soundOn) {
764 _flags |= kChanKeyOn;
765 _activeOperators |= op;
766 } else {
767 _flags &= ~kChanKeyOn;
768 _activeOperators &= ~op;
769 }
770
771 writeReg(0, 0x28, _activeOperators | (_regPrt << 2) | 2);
772 }
773
sendVolume()774 void SoundChannel_PC9801_FM2OP::sendVolume() {
775 writeReg(_regPrt, 0x42 + (_regOffs << 2), _operatorLevel[0]);
776 uint8 r = (((_operatorLevel[1] ^ 0x7F) * getVolume()) / 0x7F) * 2;
777 r = ((r < 0x7F) ? 0x7F - r : 0) + 16;
778 writeReg(_regPrt, 0x4A + (_regOffs << 2), r);
779 }
780
processSounds()781 void SoundChannel_PC9801_FM2OP::processSounds() {
782 if (!(_flags & kChanVbrEnable))
783 return;
784
785 if (_flags & kChanVbrRestartEnv) {
786 if (--_vbrEnvelopeTimer)
787 return;
788
789 _vbrIncrStep = _vbrDepthIncr * _vbrSensitivity * _frequencyNoteModifier;
790 _vbrIncrStep2 = _vbrDepthIncr * _vbrSensitivity * _frequencyNoteModifier2;
791 _vbrDecrStep = _vbrDepthDecr * _vbrSensitivity * _frequencyNoteModifier;
792 _vbrDecrStep2 = _vbrDepthDecr * _vbrSensitivity * _frequencyNoteModifier2;
793 _vbrModulationTimer = ((_flags & kChanVbrMode) ? _vbrIncrTime : _vbrDecrTime) >> 1;
794 _vbrCur = 0x80;
795
796 _flags &= ~(kChanVbrDecrease | kChanVbrRestartEnv);
797 if (_flags & kChanVbrMode)
798 _flags |= kChanVbrDecrease;
799 }
800
801 uint16 t = _vbrEnvelopeTimer + _vbrEnvelopeSpeed;
802 _vbrEnvelopeTimer = t & 0xFF;
803 if (t & 0x100)
804 return;
805
806 if (!--_vbrModulationTimer) {
807 _vbrModulationTimer = (_flags & kChanVbrDecrease) ? _vbrDecrTime : _vbrIncrTime;
808 _flags ^= kChanVbrDecrease;
809 }
810
811 if (_flags & kChanVbrDecrease) {
812 uint8 sL = _vbrDecrStep & 0xFF;
813 uint8 sH = _vbrDecrStep >> 8;
814 bool ovrflow = (sL > _vbrCur);
815 _vbrCur -= sL;
816 if (ovrflow)
817 _vbrFrequencyModifier -= (sH + 1);
818 sL = _vbrDecrStep2 & 0xFF;
819 sH = _vbrDecrStep2 >> 8;
820 ovrflow = (sL > _vbrCur2);
821 _vbrCur2 -= sL;
822 if (ovrflow)
823 _vbrFrequencyModifier2 -= (sH + 1);
824 } else {
825 uint8 sL = _vbrDecrStep & 0xFF;
826 uint8 sH = _vbrDecrStep >> 8;
827 bool ovrflow = (sL + _vbrCur > 255);
828 _vbrCur += sL;
829 if (ovrflow)
830 _vbrFrequencyModifier += (sH + 1);
831 sL = _vbrDecrStep2 & 0xFF;
832 sH = _vbrDecrStep2 >> 8;
833 ovrflow = (sL + _vbrCur2 > 255);
834 _vbrCur2 += sL;
835 if (ovrflow)
836 _vbrFrequencyModifier2 += (sH + 1);
837 }
838
839 sendFrequency();
840 }
841
sendFrequency()842 void SoundChannel_PC9801_FM2OP::sendFrequency() {
843 uint16 freq = _frequencyCourse + _vbrFrequencyModifier;
844 writeReg(_regPrt, 0xAD - _regOffs, freq >> 8);
845 writeReg(_regPrt, 0xA9 - _regOffs, freq & 0xFF);
846 freq = _frequencyCourse2 + _vbrFrequencyModifier2;
847 writeReg(_regPrt, 0xAE - (_regOffs << 3), freq >> 8);
848 writeReg(_regPrt, 0xAA - (_regOffs << 3), freq & 0xFF);
849 }
850
851 uint8 SoundChannel_PC9801_SSG::_activeChannnelsStatus = 0x3F;
852
SoundChannel_PC9801_SSG(uint8 id,PC98AudioCore * pc98a,MidiPart_PC9801 ** parts,SciVersion version,SciSpan<const uint8> instrumentData,uint8 patchOffset,uint8 patchSize,bool & soundOn)853 SoundChannel_PC9801_SSG::SoundChannel_PC9801_SSG(uint8 id, PC98AudioCore *pc98a, MidiPart_PC9801 **parts, SciVersion version, SciSpan<const uint8> instrumentData, uint8 patchOffset, uint8 patchSize, bool &soundOn)
854 : SoundChannel_PC9801(pc98a, parts, version, 2, instrumentData, soundOn), _patchOffset(patchOffset), _patchSize(patchSize), _regOffs(id & 3),
855 _instrumentChanMask(0x3F), _ngPhaseStep(0), _currentLevel(0), _ssgEnvelopeState(kEnvSSG_silent), _ngEnvelopeTimer(0),
856 _ngSpeed(0), _ngPhase(0), _ssgEnvelopeTimer(0), _ssgLevel(0), _ssgSpeed(0), _ccngEnabled(false) {
857
858 static const uint16 courseV0[] = {
859 0xfcf, 0xef1, 0xe16, 0xd59, 0xc87, 0xbcd, 0xb27, 0xa93, 0x9ee, 0x96a, 0x8da, 0x865, 0x778, 0x70d, 0x6a6, 0x643,
860 0x5ec, 0x599, 0x545, 0x4f7, 0x4b5, 0x46d, 0x432, 0x3f4, 0x3c5, 0x386, 0x353, 0x325, 0x2f6, 0x2cc, 0x2a3, 0x27d,
861 0x25a, 0x238, 0x218, 0x1fa, 0x1dd, 0x1c3, 0x1a9, 0x192, 0x17b, 0x166, 0x152, 0x13f, 0x12d, 0x11c, 0x10c, 0x0fd,
862 0x0ef, 0x0e1, 0x0d5, 0x0c9, 0x0bd, 0x0b3, 0x0a9, 0x09f, 0x096, 0x08e, 0x086, 0x07e, 0x077, 0x071, 0x06a, 0x064,
863 0x05f, 0x059, 0x054, 0x050, 0x04b, 0x047, 0x043, 0x03f, 0x03c, 0x038, 0x035, 0x032, 0x02f, 0x02d, 0x02a, 0x028,
864 0x026, 0x023, 0x021, 0x020, 0x01e, 0x01c, 0x01b, 0x019, 0x018, 0x016, 0x015, 0x014, 0x013, 0x012, 0x011, 0x010
865 };
866
867 static const uint16 courseV1[] = { 0x82D, 0x8A9, 0x92D, 0x9B6, 0xA4D, 0xAEA, 0xB90, 0xC40, 0xCFA, 0xDC0, 0xE90, 0xF6F };
868 static const uint16 fine[] = { 0x7C, 0x84, 0x8B, 0x94, 0x9D, 0xA6, 0xB0, 0xBA, 0xC5, 0xD0, 0xDE, 0xEB };
869 static const uint8 noiseFrq[] = { 0x00, 0x01, 0x04, 0x07, 0x0A, 0x0D, 0x10, 0x13, 0x16, 0x19, 0x1C, 0x1F };
870 static const uint8 disableMask[] = { 0xF6, 0xED, 0xDB };
871 static const uint8 enableMask1[] = { 0xBE, 0xBD, 0xBB };
872 static const uint8 enableMask2[] = { 0xB7, 0xAF, 0x9F };
873
874 _noteFrequency = (version > SCI_VERSION_0_LATE) ? courseV1 : courseV0;
875 _noteFrequencyModifier = fine;
876 _ngFreq = noiseFrq;
877 _chanDisableMask = disableMask[id & 3];
878 _chanEnableMask1 = enableMask1[id & 3];
879 _chanEnableMask2 = enableMask2[id & 3];
880 }
881
reset()882 void SoundChannel_PC9801_SSG::reset() {
883 SoundChannel_PC9801::reset();
884 _activeChannnelsStatus = (_version == SCI_VERSION_1_LATE) ? 0x3F : 0xFF;
885 sendActiveChannelsStatus();
886 }
887
toggleNoiseGenerator(bool enable)888 void SoundChannel_PC9801_SSG::toggleNoiseGenerator(bool enable) {
889 _ccngEnabled = enable;
890 }
891
programChange(uint8 program)892 void SoundChannel_PC9801_SSG::programChange(uint8 program) {
893 _selectedInstrument = _instrumentData.subspan(program * _patchSize + _patchOffset);
894
895 if (_version == SCI_VERSION_1_LATE) {
896 programChangeInit(_selectedInstrument);
897
898 _flags &= ~kChanNgEnable;
899 if (_selectedInstrument[7])
900 _flags |= (kChanNgEnable | kChanNgRestartEnv);
901 _instrumentChanMask = _selectedInstrument[22];
902 _activeChannnelsStatus = (_activeChannnelsStatus & _chanDisableMask) | (~_chanDisableMask & (_instrumentChanMask & 0x3F));
903 if (!(_instrumentChanMask & 8)) {
904 _ngPhaseStep = _selectedInstrument[21] & 0x1F;
905 updateNg();
906 }
907
908 sendActiveChannelsStatus();
909
910 } else {
911 writeReg(0, 13, _selectedInstrument[0]);
912 writeReg(0, 6, _selectedInstrument[1]);
913 writeReg(0, 11, _selectedInstrument[2]);
914 writeReg(0, 12, _selectedInstrument[3]);
915 }
916
917 _currentLevel = 0;
918 _ssgEnvelopeState = kEnvSSG_silent;
919 }
920
processSounds()921 void SoundChannel_PC9801_SSG::processSounds() {
922 if (_ssgEnvelopeState == kEnvSSG_silent)
923 return;
924
925 SoundChannel_PC9801::processSounds();
926
927 if (!(_instrumentChanMask & 0x38) && (_flags & kChanNgEnable)) {
928 bool cont = false;
929 if (_flags & kChanNgRestartEnv) {
930 if (--_ngEnvelopeTimer) {
931 cont = true;
932 } else {
933 uint8 flg = _selectedInstrument[10] & 4;
934 _ngSpeed = ((flg ? _selectedInstrument[9] : _selectedInstrument[8]) & 0x1F) >> 1;
935 _flags = (_flags & ~(kChanNgDecrease | kChanNgRestartEnv)) | (flg << 3);
936 }
937 }
938 if (!cont) {
939 uint16 s = _ngEnvelopeTimer + (_selectedInstrument[10] >> 3);
940 _ngEnvelopeTimer = s & 0xFF;
941 if (s & 0x100)
942 cont = true;
943 if (!cont) {
944 if (--_ngSpeed) {
945 if (_flags & kChanNgDecrease) {
946 _ngSpeed = _selectedInstrument[8] & 0x1F;
947 _flags &= ~kChanNgDecrease;
948 } else {
949 _ngSpeed = _selectedInstrument[9] & 0x1F;
950 _flags |= kChanNgDecrease;
951 }
952 }
953
954 if (_flags & kChanNgDecrease) {
955 _ngPhase -= (_selectedInstrument[9] >> 5) * ((_selectedInstrument[10] & 3) + 1);
956 } else {
957 _ngPhase += (_selectedInstrument[8] >> 5) * ((_selectedInstrument[10] & 3) + 1);
958 }
959 updateNg();
960 }
961 }
962 }
963
964 uint16 s = _ssgEnvelopeTimer + (_selectedInstrument[21] & 0x60);
965 _ssgEnvelopeTimer = s & 0xFF;
966 if ((s & 0x100) || !(_ssgEnvelopeState & 0x0F))
967 return;
968
969 uint8 vol = _currentLevel;
970 if (_ssgLevel & 1)
971 vol = (vol > (_ssgLevel & ~1)) ? vol - (_ssgLevel & ~1) : 0;
972 else
973 vol = (vol + _ssgLevel > 255) ? 255 : vol + _ssgLevel;
974
975 if (!--_ssgSpeed) {
976 if (--_ssgEnvelopeState == (kEnvSSG_keyOn | kEnvSSG_sustain)) {
977 _ssgLevel = _selectedInstrument[13];
978 _ssgSpeed = _selectedInstrument[14];
979 vol = (uint8)CLIP<int16>(vol + (int8)(_selectedInstrument[19] & 0xF0), 0, 255);
980 }
981 if (_ssgEnvelopeState == (kEnvSSG_keyOn | kEnvSSG_decay)) {
982 _ssgLevel = _selectedInstrument[15];
983 _ssgSpeed = _selectedInstrument[16];
984 vol = (uint8)CLIP<int16>(vol + (int8)((_selectedInstrument[20] & 0x0F) << 4), 0, 255);
985 }
986 }
987
988 if (_ssgEnvelopeState == kEnvSSG_silent)
989 vol = 0;
990
991 if (_currentLevel != vol) {
992 _currentLevel = vol;
993 sendVolume();
994 }
995 }
996
sendSoundOnOff(bool soundOn)997 void SoundChannel_PC9801_SSG::sendSoundOnOff(bool soundOn) {
998 if (_version == SCI_VERSION_1_LATE && soundOn && !(_ssgEnvelopeState & kEnvSSG_keyOn)) {
999 _currentLevel = _selectedInstrument[19] << 4;
1000 _ssgEnvelopeState = (kEnvSSG_keyOn | kEnvSSG_attack);
1001 _ssgLevel = _selectedInstrument[11];
1002 _ssgSpeed = _selectedInstrument[12];
1003 _ssgEnvelopeTimer = 1;
1004 if (!(_selectedInstrument[22] & 0x38)) {
1005 if (_selectedInstrument[21] & 0x80)
1006 _ngPhaseStep = _ngFreq[_note % 12];
1007 _ngEnvelopeTimer = _selectedInstrument[7];
1008 _ngPhase = 0;
1009 updateNg();
1010 _flags |= kChanNgRestartEnv;
1011 }
1012 } else if (_version == SCI_VERSION_1_LATE && !soundOn) {
1013 int16 l = _currentLevel + (int8)(_selectedInstrument[20] & 0xF0);
1014 _currentLevel = (uint8)CLIP<int16>(l, 0, 255);
1015 _ssgEnvelopeState = kEnvSSG_decay;
1016 _ssgLevel = _selectedInstrument[17];
1017 _ssgSpeed = _selectedInstrument[18];
1018 _note = 0xFF;
1019 } else if (_version == SCI_VERSION_0_LATE && soundOn) {
1020 _activeChannnelsStatus &= _chanEnableMask1;
1021 if (_ccngEnabled)
1022 _activeChannnelsStatus &= _chanEnableMask2;
1023 _currentLevel = 1;
1024 sendActiveChannelsStatus();
1025 writeReg(0, 13, _selectedInstrument[0]);
1026 } else if (_version == SCI_VERSION_0_LATE) {
1027 _activeChannnelsStatus |= ~_chanEnableMask1;
1028 if (_ccngEnabled)
1029 _activeChannnelsStatus |= ~_chanEnableMask2;
1030 _currentLevel = 0;
1031 _note = 0xFF;
1032 sendActiveChannelsStatus();
1033 }
1034 sendVolume();
1035 }
1036
sendVolume()1037 void SoundChannel_PC9801_SSG::sendVolume() {
1038 uint8 v1 = getVolume();
1039 uint16 r = 0;
1040
1041 if (_version == SCI_VERSION_1_LATE) {
1042 uint8 vol = v1 + (((v1 >> 1) + v1) >> 2);
1043
1044 if (vol > 0x7F)
1045 vol = 0x7F;
1046 vol = (vol >> 3) & 0x0F;
1047
1048 r = _currentLevel & 0xF0;
1049 for (uint8 i = 0; i < 4; ++i) {
1050 r += r;
1051 if (r & 0x100)
1052 r = (r + vol) & 0xFF;
1053 }
1054
1055 r = (r + 15) >> 4;
1056
1057 } else {
1058 r = _currentLevel * (0x10 | v1 >> 3);
1059 }
1060
1061 writeReg(0, 8 + _regOffs, r);
1062 }
1063
sendFrequency()1064 void SoundChannel_PC9801_SSG::sendFrequency() {
1065 uint16 freq = _frequencyCourse;
1066
1067 if (_version > SCI_VERSION_0_LATE) {
1068 freq = (uint16)(freq + _vbrFrequencyModifier) >> (8 - _frequencyBlock);
1069 if (!freq)
1070 return;
1071 freq = 62400 / freq;
1072 }
1073
1074 writeReg(0, _regOffs << 1, freq & 0xFF);
1075 writeReg(0, (_regOffs << 1) + 1, freq >> 8);
1076 }
1077
updateNg()1078 void SoundChannel_PC9801_SSG::updateNg() {
1079 int p = _ngPhase + _ngPhaseStep;
1080 if (p > 255)
1081 p = 0;
1082 if (p > 31)
1083 p = 31;
1084 _ngPhase = p & 0xFF;
1085 writeReg(0, 6, _ngPhase);
1086 }
1087
sendActiveChannelsStatus()1088 void SoundChannel_PC9801_SSG::sendActiveChannelsStatus() {
1089 writeReg(0, 7, (_activeChannnelsStatus & 0x3F) | 0x80);
1090 }
1091
MidiPart_PC9801(uint8 id,SoundChannel_PC9801 ** channels,uint8 numChan,SciVersion version)1092 MidiPart_PC9801::MidiPart_PC9801(uint8 id, SoundChannel_PC9801 **channels, uint8 numChan, SciVersion version) : _chan(channels), _id(id), _version(version), _numChan(numChan),
1093 _program(0), _volume(0x3f), _sustain(0), _chanMissing(0), _pitchBend(0x2000), _outChan(0), _noteRangeLow(version > SCI_VERSION_0_LATE ? 12 : 24), _noteRangeHigh(version > SCI_VERSION_0_LATE ? 107 : 119) {
1094 }
1095
noteOff(uint8 note)1096 void MidiPart_PC9801::noteOff(uint8 note) {
1097 for (int i = 0; i < _numChan; ++i) {
1098 if (_chan[i]->_assign != _id || _chan[i]->_note != note)
1099 continue;
1100 if (_sustain && _version > SCI_VERSION_0_LATE)
1101 _chan[i]->_sustain = 1;
1102 else
1103 _chan[i]->noteOff();
1104 return;
1105 }
1106 }
1107
noteOn(uint8 note,uint8 velo)1108 void MidiPart_PC9801::noteOn(uint8 note, uint8 velo) {
1109 if (note < _noteRangeLow || note > _noteRangeHigh)
1110 return;
1111
1112 if (velo == 0) {
1113 noteOff(note);
1114 return;
1115 }
1116
1117 velo >>= 1;
1118
1119 for (int i = 0; i < _numChan; ++i) {
1120 if (_chan[i]->_assign != _id || _chan[i]->_note != note)
1121 continue;
1122 _chan[i]->_sustain = 0;
1123 _chan[i]->noteOff();
1124 _chan[i]->noteOn(note, velo);
1125 return;
1126 }
1127
1128 int chan = allocateChannel();
1129 if (chan != -1)
1130 _chan[chan]->noteOn(note, velo);
1131 }
1132
controlChangeVolume(uint8 vol)1133 void MidiPart_PC9801::controlChangeVolume(uint8 vol) {
1134 _volume = (_version < SCI_VERSION_1_LATE) ? vol : CLIP(vol >> 1, 0, 0x3f);
1135 for (int i = 0; i < _numChan; ++i) {
1136 if (_chan[i]->_assign == _id && _chan[i]->_note != 0xff)
1137 _chan[i]->processNoteEvent(_chan[i]->_note, true);
1138 }
1139 }
1140
controlChangeSustain(uint8 sus)1141 void MidiPart_PC9801::controlChangeSustain(uint8 sus) {
1142 if (_version < SCI_VERSION_1_LATE)
1143 return;
1144
1145 _sustain = sus;
1146 if (_sustain)
1147 return;
1148
1149 for (int i = 0; i < _numChan; ++i) {
1150 if (_chan[i]->_assign == _id && _chan[i]->_sustain) {
1151 _chan[i]->_sustain = 0;
1152 _chan[i]->noteOff();
1153 }
1154 }
1155 }
1156
controlChangePolyphony(uint8 numChan)1157 void MidiPart_PC9801::controlChangePolyphony(uint8 numChan) {
1158 if (_version < SCI_VERSION_1_LATE)
1159 return;
1160
1161 uint8 numAssigned = 0;
1162 for (int i = 0; i < _numChan; ++i) {
1163 if (_chan[i]->_assign == _id)
1164 numAssigned++;
1165 }
1166
1167 numAssigned += _chanMissing;
1168 if (numAssigned < numChan) {
1169 addChannels(numChan - numAssigned);
1170 } else if (numAssigned > numChan) {
1171 dropChannels(numAssigned - numChan);
1172 assignFreeChannels();
1173 }
1174 }
1175
controlChangeNoiseGenerator(uint8 enable)1176 void MidiPart_PC9801::controlChangeNoiseGenerator(uint8 enable) {
1177 if (_version > SCI_VERSION_0_LATE)
1178 return;
1179
1180 for (int i = 0; i < _numChan; ++i) {
1181 if (_chan[i]->_assign == _id)
1182 _chan[i]->toggleNoiseGenerator(enable);
1183 }
1184 }
1185
controlChangeAllNotesOff()1186 void MidiPart_PC9801::controlChangeAllNotesOff() {
1187 for (int i = 0; i < _numChan; ++i) {
1188 if (_chan[i]->_assign == _id && _chan[i]->_note != 0xff)
1189 _chan[i]->noteOff();
1190 }
1191 }
1192
programChange(uint8 prg)1193 void MidiPart_PC9801::programChange(uint8 prg) {
1194 _program = prg;
1195 }
1196
pitchBend(int16 val)1197 void MidiPart_PC9801::pitchBend(int16 val) {
1198 if (_version < SCI_VERSION_1_LATE)
1199 return;
1200
1201 _pitchBend = val;
1202 for (int i = 0; i < _numChan; ++i) {
1203 if (_chan[i]->_assign == _id && _chan[i]->_note != 0xff)
1204 _chan[i]->processNoteEvent(_chan[i]->_note, true);
1205 }
1206 }
1207
1208
addChannels(int num,int resetMissingChannels,int channelType)1209 void MidiPart_PC9801::addChannels(int num, int resetMissingChannels, int channelType) {
1210 if (resetMissingChannels != -1)
1211 _chanMissing = resetMissingChannels;
1212
1213 for (int i = 0; i < _numChan; ++i) {
1214 if (_chan[i]->_assign != 0xFF || (channelType != -1 && _chan[i]->getType() != channelType))
1215 continue;
1216
1217 _chan[i]->_assign = _id;
1218
1219 #ifdef DEBUG_REMAP
1220 debug("===== MidiDriver_PC9801: hardware channel %d is assigned to device channel %d =====", i, _id);
1221 #endif
1222 if (_chan[i]->_note != 0xff)
1223 _chan[i]->noteOff();
1224
1225 if (!--num)
1226 break;
1227 }
1228 _chanMissing += num;
1229 }
1230
dropChannels(int num)1231 void MidiPart_PC9801::dropChannels(int num) {
1232 if (_chanMissing == num) {
1233 _chanMissing = 0;
1234 return;
1235 } else if (_chanMissing > num) {
1236 _chanMissing -= num;
1237 return;
1238 }
1239
1240 num -= _chanMissing;
1241 _chanMissing = 0;
1242
1243 for (int i = 0; i < _numChan; i++) {
1244 if (_chan[i]->_assign != _id || _chan[i]->_note != 0xff)
1245 continue;
1246 _chan[i]->_assign = 0xff;
1247
1248 #ifdef DEBUG_REMAP
1249 debug("===== MidiDriver_PC9801: hardware channel %d is dropped from device channel %d =====", i, _id);
1250 #endif
1251
1252 if (!--num)
1253 return;
1254 }
1255
1256 for (int i = 0; i < _numChan; i++) {
1257 if (_chan[i]->_assign != _id)
1258 continue;
1259 _chan[i]->_sustain = 0;
1260 _chan[i]->noteOff();
1261 _chan[i]->_assign = 0xff;
1262 if (!--num)
1263 return;
1264 }
1265 }
1266
allocateChannel()1267 int MidiPart_PC9801::allocateChannel() {
1268 int chan = _outChan;
1269 int ovrChan = 0;
1270 int ld = 0;
1271 bool found = false;
1272
1273 for (bool loop = true; loop; ) {
1274 if (++chan == _numChan)
1275 chan = 0;
1276
1277 if (chan == _outChan)
1278 loop = false;
1279
1280 if (_id == _chan[chan]->_assign) {
1281 if (_chan[chan]->_note == 0xff || _version < SCI_VERSION_1_LATE) {
1282 found = true;
1283 break;
1284 }
1285
1286 if (_chan[chan]->_duration >= ld) {
1287 ld = _chan[chan]->_duration;
1288 ovrChan = chan;
1289 }
1290 }
1291 }
1292
1293 if (!found) {
1294 if (!ld)
1295 return -1;
1296 chan = ovrChan;
1297 _chan[chan]->_sustain = 0;
1298 _chan[chan]->noteOff();
1299 }
1300
1301 _outChan = chan;
1302 return chan;
1303 }
1304
assignFreeChannels()1305 void MidiPart_PC9801::assignFreeChannels() {
1306 uint8 freeChan = 0;
1307 for (int i = 0; i < _numChan; i++) {
1308 if (_chan[i]->_assign == 0xff)
1309 freeChan++;
1310 }
1311
1312 if (!freeChan)
1313 return;
1314
1315 MidiDriver_PC9801::assignFreeChannels(freeChan);
1316 }
1317
1318 MidiPart_PC9801 **MidiDriver_PC9801::_parts = 0;
1319
MidiDriver_PC9801(Audio::Mixer * mixer,SciVersion version)1320 MidiDriver_PC9801::MidiDriver_PC9801(Audio::Mixer *mixer, SciVersion version)
1321 : _mixer(mixer), _version(version), _pc98a(0), _chan(0), _numChan(6), _internalVersion(0xFF), _ssgPatchOffset(0xFF), _patchSize(0),
1322 _timerProc(0), _timerProcPara(0), _baseTempo(10080), _ready(false), _isOpen(false), _masterVolume(0x0f) ,_soundOn(true), _playID(0),
1323 _polyphony(9), _channelMask1(0x10), _channelMask2(0x02) {
1324 }
1325
~MidiDriver_PC9801()1326 MidiDriver_PC9801::~MidiDriver_PC9801() {
1327 close();
1328 }
1329
open()1330 int MidiDriver_PC9801::open() {
1331 if (_isOpen)
1332 return MERR_ALREADY_OPEN;
1333
1334 if (!_pc98a) {
1335 _pc98a =
1336 #ifdef SCI_PC98_AUDIO_EXTENDED
1337 new PC98AudioCore(_mixer, this, kType86);
1338 #else
1339 new PC98AudioCore(_mixer, this, kType26);
1340 #endif
1341 }
1342
1343 if (!_ready) {
1344 if (!_pc98a->init())
1345 return MERR_CANNOT_CONNECT;
1346 _pc98a->setSoundEffectChanMask(0);
1347 _pc98a->ssgSetVolume(205);
1348 _ready = true;
1349 }
1350
1351 ResourceManager *resMan = g_sci->getResMan();
1352 if (!loadInstruments(*resMan->findResource(ResourceId(kResourceTypePatch, _version < SCI_VERSION_1_LATE ? 2 : 8), false)))
1353 return MERR_CANNOT_CONNECT;
1354
1355 if (_version == SCI_VERSION_0_LATE && _channelMask2 == 0x00) {
1356 _internalVersion = 0;
1357 _polyphony = 3;
1358 } else if (_version == SCI_VERSION_0_LATE && _channelMask2 == 0x02) {
1359 _internalVersion = 1;
1360 _polyphony = 6;
1361 } else if (_patchSize == 60 && _ssgPatchOffset == 37)
1362 _internalVersion = 2;
1363 else if (_patchSize == 81 && _ssgPatchOffset == 58)
1364 _internalVersion = 3;
1365 else
1366 return MERR_CANNOT_CONNECT;
1367
1368 if (_internalVersion == 3)
1369 _numChan++;
1370
1371 int config = _internalVersion;
1372
1373 #ifdef SCI_PC98_AUDIO_EXTENDED
1374 _numChan = 9;
1375 config = 4;
1376 #endif
1377
1378 static const int channelConfig[6][11] = {
1379 { 0, 0, 0, 2, 2, 2, -1, -1, -1, -1, -1 },
1380 { 0, 0, 0, 2, 2, 2, -1, -1, -1, -1, -1 },
1381 { 0, 0, 0, 2, 2, 2, -1, -1, -1, -1, -1 },
1382 { 0, 0, 1, 1, 2, 2, 2, -1, -1, -1, -1 },
1383 { 0, 0, 0, 0, 0, 0, 2, 2, 2, -1, -1 }
1384 };
1385
1386 _parts = new MidiPart_PC9801*[16];
1387 _chan = new SoundChannel_PC9801*[_numChan];
1388
1389 int numSSG = 0;
1390 for (int i = 0; i < _numChan; ++i) {
1391 if (channelConfig[config][i] == 0)
1392 _chan[i] = new SoundChannel_PC9801_FM4OP(i, _pc98a, _parts, _version, *_instrumentData, _patchSize, _soundOn);
1393 else if (channelConfig[config][i] == 1)
1394 _chan[i] = new SoundChannel_PC9801_FM2OP(i, _pc98a, _parts, _version, *_instrumentData, _patchSize, _soundOn);
1395 else if (channelConfig[config][i] == 2)
1396 _chan[i] = new SoundChannel_PC9801_SSG(numSSG++, _pc98a, _parts, _version, *_instrumentData, _ssgPatchOffset, _patchSize, _soundOn);
1397 else
1398 _chan[i] = 0;
1399 }
1400
1401 for (int i = 0; i < 16; ++i)
1402 _parts[i] = new MidiPart_PC9801(i, _chan, _numChan, _version);
1403
1404 _isOpen = true;
1405
1406 reset();
1407
1408 return 0;
1409 }
1410
close()1411 void MidiDriver_PC9801::close() {
1412 if (!_isOpen)
1413 return;
1414
1415 bool ready = _ready;
1416 _isOpen = _ready = false;
1417
1418 delete _pc98a;
1419 _pc98a = 0;
1420
1421 if (_parts) {
1422 for (int i = 0; i < 16; ++i) {
1423 delete _parts[i];
1424 _parts[i] = 0;
1425 }
1426 delete[] _parts;
1427 _parts = 0;
1428 }
1429
1430 if (_chan) {
1431 for (int i = 0; i < _numChan; ++i) {
1432 delete _chan[i];
1433 _chan[i] = 0;
1434 }
1435 delete[] _chan;
1436 _chan = 0;
1437 }
1438
1439 _instrumentData.clear();
1440
1441 _ready = ready;
1442 }
1443
send(uint32 b)1444 void MidiDriver_PC9801::send(uint32 b) {
1445 if (!_isOpen)
1446 return;
1447
1448 byte para2 = (b >> 16) & 0xFF;
1449 byte para1 = (b >> 8) & 0xFF;
1450 byte cmd = b & 0xF0;
1451
1452 MidiPart_PC9801 *part = _parts[b & 0x0F];
1453
1454 switch (cmd) {
1455 case 0x80:
1456 part->noteOff(para1);
1457 break;
1458 case 0x90:
1459 part->noteOn(para1, para2);
1460 break;
1461 case 0xb0:
1462 switch (para1) {
1463 case 7:
1464 part->controlChangeVolume(para2);
1465 break;
1466 case 64:
1467 part->controlChangeSustain(para2);
1468 break;
1469 case SCI_MIDI_SET_POLYPHONY:
1470 part->controlChangePolyphony(para2);
1471 break;
1472 case 76:
1473 // This event (from the SCI0 driver) is parsing related and can't be handled here. Lets's see if this ever comes up.
1474 warning("MidiDriver_PC9801: Midi Control Change '0x%2x' not implemented", para1);
1475 break;
1476 case 81:
1477 part->controlChangeNoiseGenerator(para2);
1478 break;
1479 case 96:
1480 // This event (from the SCI0 driver) is parsing related. It is handled in MidiParser_SCI::processEvent().
1481 break;
1482 case SCI_MIDI_CHANNEL_NOTES_OFF:
1483 part->controlChangeAllNotesOff();
1484 break;
1485 default:
1486 break;
1487 }
1488 break;
1489 case 0xc0:
1490 part->programChange(para1);
1491 break;
1492 case 0xe0:
1493 part->pitchBend(para1 | (para2 << 7));
1494 break;
1495 default:
1496 break;
1497 }
1498 }
1499
assignFreeChannels(int num)1500 void MidiDriver_PC9801::assignFreeChannels(int num) {
1501 assert(_parts);
1502 for (int i = 0; i < 16; ++i) {
1503 uint8 missing = _parts[i]->getMissingChannels();
1504 if (!missing)
1505 continue;
1506 if (missing < num) {
1507 num -= missing;
1508 _parts[i]->addChannels(missing, 0);
1509 } else {
1510 _parts[i]->addChannels(num, missing - num);
1511 return;
1512 }
1513 }
1514 }
1515
property(int prop,uint32 param)1516 uint32 MidiDriver_PC9801::property(int prop, uint32 param) {
1517 if (!_isOpen)
1518 return 0;
1519
1520 switch(prop) {
1521 case MIDI_PROP_MASTER_VOLUME:
1522 if (param != 0xffff && param != _masterVolume && param < 16) {
1523 _masterVolume = param;
1524 for (int i = 0; i < _numChan; ++i) {
1525 _chan[i]->setVolume(_masterVolume);
1526 if (_chan[i]->_note != 0xFF)
1527 _chan[i]->processNoteEvent(_chan[i]->_note, true);
1528 }
1529 }
1530 return _masterVolume;
1531 case MIDI_PROP_PLAYSWITCH:
1532 _soundOn = param;
1533 break;
1534 case MIDI_PROP_POLYPHONY:
1535 return _polyphony;
1536 case MIDI_PROP_CHANNEL_ID:
1537 return _version < SCI_VERSION_1_LATE ? (_channelMask1 | _channelMask2) : _playID;
1538 default:
1539 break;
1540 }
1541 return 0;
1542 }
1543
initTrack(SciSpan<const byte> & header)1544 void MidiDriver_PC9801::initTrack(SciSpan<const byte> &header) {
1545 if (!_isOpen || _version > SCI_VERSION_0_LATE)
1546 return;
1547
1548 for (int i = 0; i < _numChan; ++i)
1549 _chan[i]->reset();
1550
1551 uint8 readPos = 0;
1552 uint8 caps = header.getInt8At(readPos++);
1553 int numChan = (caps == 2) ? 15 : 16;
1554 if (caps != 0 && caps != 2)
1555 return;
1556
1557 for (int i = 0; i < numChan; ++i) {
1558 _parts[i]->controlChangeVolume(103);
1559
1560 uint8 num = (_internalVersion == 1) ? (header.getInt8At(readPos) & 0x7F) : 1;
1561 readPos++;
1562 uint8 flags = header.getInt8At(readPos);
1563 readPos++;
1564
1565 if (flags & _channelMask1 && num)
1566 _parts[i]->addChannels(num, -1, 0);
1567
1568 if (flags & _channelMask2 && num)
1569 _parts[i]->addChannels(num, -1, 2);
1570
1571 if (_internalVersion == 0)
1572 _parts[i]->programChange(10);
1573 }
1574 }
1575
setTimerCallback(void * timer_param,Common::TimerManager::TimerProc timer_proc)1576 void MidiDriver_PC9801::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
1577 _timerProc = timer_proc;
1578 _timerProcPara = timer_param;
1579 }
1580
getBaseTempo()1581 uint32 MidiDriver_PC9801::getBaseTempo() {
1582 return _baseTempo;
1583 }
1584
timerCallbackB()1585 void MidiDriver_PC9801::timerCallbackB() {
1586 if (!_isOpen)
1587 return;
1588 updateParser();
1589 updateChannels();
1590 }
1591
loadInstruments(const SciSpan<const uint8> & data)1592 bool MidiDriver_PC9801::loadInstruments(const SciSpan<const uint8> &data) {
1593 if (!data)
1594 return false;
1595
1596 SciSpan<const uint8> src = data;
1597 _instrumentData.clear();
1598
1599 if (_version == SCI_VERSION_0_LATE) {
1600 _ssgPatchOffset = 48;
1601 _patchSize = 52;
1602
1603 _instrumentData->allocate(96 * _patchSize);
1604 SciSpan<uint8> dst = *_instrumentData;
1605
1606 for (bool load = true; load; ) {
1607 for (int i = 0; i < 48; ++i) {
1608 src.subspan(0, _patchSize).copyDataTo(dst);
1609 src += 64;
1610 dst += _patchSize;
1611 }
1612 uint16 id = (src.byteSize() >= 2) ? src.getInt16BEAt(0) : 0;
1613 if (id == 0xABCD || id == 0xCDAB) {
1614 src += 2;
1615 _channelMask2 = 0x00;
1616 } else {
1617 load = false;
1618 }
1619 }
1620 } else if (_version == SCI_VERSION_1_LATE) {
1621 _instrumentData->allocateFromSpan(++src);
1622 _patchSize = (data.byteSize() - 1) / 96;
1623 _ssgPatchOffset = (_patchSize == 81) ? 58 : 37;
1624 }
1625
1626 return (_instrumentData->byteSize() && _patchSize && _ssgPatchOffset != 0xFF);
1627 }
1628
updateParser()1629 void MidiDriver_PC9801::updateParser() {
1630 if (_timerProc) {
1631 // The mutex lock has to be lifted, before entering the SCI engine space. The engine has its owns mutex and the different threads
1632 // will often cause an immediate lockup (each thread caught in the mutex lock of the other). I consider this safe for all realistic
1633 // scenarios, since a reentry of the space guarded by the PC98 audio mutex is not possible without triggering another mutex lock.
1634 // I have also rearranged the driver deconstruction appropriately.
1635 PC98AudioCore::MutexLock tempUnlock = _pc98a->stackUnlockMutex();
1636 _timerProc(_timerProcPara);
1637 }
1638 }
1639
updateChannels()1640 void MidiDriver_PC9801::updateChannels() {
1641 for (int i = 0; i < _numChan; ++i)
1642 _chan[i]->update();
1643 }
1644
reset()1645 void MidiDriver_PC9801::reset() {
1646 if (!_ready)
1647 return;
1648
1649 for (int i = 0; i < 3; ++i) {
1650 _pc98a->writeReg(0, 0x28, i);
1651 _pc98a->writeReg(0, i, 0);
1652 _pc98a->writeReg(0, 8 + i, 0);
1653 }
1654
1655 uint8 flag = 0;
1656 #ifndef SCI_PC98_AUDIO_EXTENDED
1657 if (_internalVersion == 3) {
1658 _pc98a->writeReg(0, 0xB2, 0x04);
1659 flag = 0x40;
1660 }
1661 #endif
1662
1663 _pc98a->writeReg(0, 0x27, 0x38);
1664 _pc98a->writeReg(0, 0x27, 0x3a | flag);
1665
1666 if (!_isOpen)
1667 return;
1668
1669 for (int i = 0; i < _numChan; ++i)
1670 _chan[i]->reset();
1671 }
1672
MidiPlayer_PC9801(SciVersion version)1673 MidiPlayer_PC9801::MidiPlayer_PC9801(SciVersion version) : MidiPlayer(version) {
1674 _driver = new MidiDriver_PC9801(g_system->getMixer(), version);
1675 }
1676
~MidiPlayer_PC9801()1677 MidiPlayer_PC9801::~MidiPlayer_PC9801() {
1678 delete _driver;
1679 }
1680
hasRhythmChannel() const1681 bool MidiPlayer_PC9801::hasRhythmChannel() const {
1682 return false;
1683 }
1684
getPlayId() const1685 byte MidiPlayer_PC9801::getPlayId() const {
1686 return _driver ? _driver->property(MIDI_PROP_CHANNEL_ID, 0) : 0;
1687 }
1688
getPolyphony() const1689 int MidiPlayer_PC9801::getPolyphony() const {
1690 return _driver ? _driver->property(MIDI_PROP_POLYPHONY, 0) : 0;
1691 }
1692
playSwitch(bool play)1693 void MidiPlayer_PC9801::playSwitch(bool play) {
1694 if (_driver)
1695 _driver->property(MIDI_PROP_PLAYSWITCH, play ? 1 : 0);
1696 }
1697
initTrack(SciSpan<const byte> & trackData)1698 void MidiPlayer_PC9801::initTrack(SciSpan<const byte> &trackData) {
1699 if (_driver)
1700 static_cast<MidiDriver_PC9801*>(_driver)->initTrack(trackData);
1701 }
1702
MidiPlayer_PC9801_create(SciVersion _soundVersion)1703 MidiPlayer *MidiPlayer_PC9801_create(SciVersion _soundVersion) {
1704 return new MidiPlayer_PC9801(_soundVersion);
1705 }
1706
1707 } // End of namespace Sci
1708
1709