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/sega_audio.h"
24 #include "audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h"
25 #include "audio/softsynth/fmtowns_pc98/pcm_common.h"
26 #include "common/mutex.h"
27
28 class SegaPCMChannel final : public PCMChannel_Base {
29 public:
SegaPCMChannel()30 SegaPCMChannel() : PCMChannel_Base(), _playing(false) {}
~SegaPCMChannel()31 ~SegaPCMChannel() override {}
32
33 void play(const int8 *data, uint16 dataSize, uint16 startAddress, uint16 loopStart, uint16 loopLen, uint16 pitch, uint8 pan, uint8 vol);
34 void stop();
35 bool isPlaying() const override;
36
37 private:
38 void stopInternal() override;
39 bool _playing;
40 };
41
42 class SegaPSG {
43 public:
44 SegaPSG(int samplingRate, int deviceVolume);
~SegaPSG()45 ~SegaPSG() {}
46
47 void write(uint8 val);
48
49 void setMusicVolume(uint16 vol);
50 void setSfxVolume(uint16 vol);
51 void setSfxChanMask(int mask);
52
53 void readBuffer(int32 *buffer, uint32 bufferSize);
54
55 private:
56 struct Channel {
ChannelSegaPSG::Channel57 Channel() : freq(0), curSample(0), counter(0), out(0) {}
58 uint16 freq;
59 int16 curSample;
60 int16 out;
61 uint16 counter;
62 };
63
64 Channel _channels[3];
65 uint8 _nfb;
66 uint8 _nfs;
67 uint8 _nat;
68 int _cr;
69
70 int16 _attnTable[16];
71
72 uint16 _musicVolume;
73 uint16 _sfxVolume;
74 int _sfxChanMask;
75
76 const uint32 _extRate;
77 const uint32 _intRate;
78 uint32 _timer;
79 const uint16 _deviceVolume;
80 const uint8 _numChannels;
81 };
82
83 class SegaAudioInterfaceInternal final : public TownsPC98_FmSynth {
84 private:
85 SegaAudioInterfaceInternal(Audio::Mixer *mixer, SegaAudioInterface *owner, SegaAudioPluginDriver *driver);
86 public:
87 ~SegaAudioInterfaceInternal();
88
89 static SegaAudioInterfaceInternal *addNewRef(Audio::Mixer *mixer, SegaAudioInterface *owner, SegaAudioPluginDriver *driver);
90 static void releaseRef(SegaAudioInterface *owner);
91
92 bool init() override;
93
94 void loadPCMData(uint16 address, const uint8 *data, uint16 dataLen);
95 void playPCMChannel(uint8 channel, uint8 dataStart, uint16 loopStart, uint16 pitch, uint8 pan, uint8 vol);
96 void stopPCMChannel(uint8 channel);
97
98 void psgWrite(uint8 data);
99
100 void setMusicVolume(int volume);
101 void setSoundEffectVolume(int volume);
102 // Defines the channels used as sound effect channels for the purpose of ScummVM GUI volume control.
103 // The first 6 bits are 6 fm channels. The next 3 bits are psg channels. The bits that follow represent pcm channels.
104 void setSoundEffectChanMask(int mask);
105
106 Common::Mutex &mutex();
107 int mixerThreadLockCounter() const;
108
109 private:
110 bool assignPluginDriver(SegaAudioInterface *owner, SegaAudioPluginDriver *driver, bool externalMutexHandling = false);
111 void removePluginDriver(SegaAudioInterface *owner);
112
113 void nextTickEx(int32 *buffer, uint32 bufferSize) override;
114
115 void timerCallbackA() override;
116 void timerCallbackB() override;
117
118 uint16 pcmCountSamples(uint16 address) const;
119
120 int8 *_pcmBanks;
121
122 uint16 _musicVolume;
123 uint16 _sfxVolume;
124
125 SegaPCMChannel **_pcmChan;
126 SegaPSG *_psgDev;
127 PCMDevice_Base *_pcmDev;
128
129 SegaAudioPluginDriver *_drv;
130 void *_drvOwner;
131 bool _ready;
132
133 static SegaAudioInterfaceInternal *_refInstance;
134 static int _refCount;
135 };
136
137 SegaAudioInterfaceInternal *SegaAudioInterfaceInternal::_refInstance = 0;
138 int SegaAudioInterfaceInternal::_refCount = 0;
139
SegaAudioInterfaceInternal(Audio::Mixer * mixer,SegaAudioInterface * owner,SegaAudioPluginDriver * driver)140 SegaAudioInterfaceInternal::SegaAudioInterfaceInternal(Audio::Mixer *mixer, SegaAudioInterface *owner, SegaAudioPluginDriver *driver) :TownsPC98_FmSynth(mixer, TownsPC98_FmSynth::kTypeTowns),
141 _drv(driver), _drvOwner(owner), _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), _pcmBanks(0), _pcmDev(0), _psgDev(0), _pcmChan(0), _ready(false) {
142 }
143
~SegaAudioInterfaceInternal()144 SegaAudioInterfaceInternal::~SegaAudioInterfaceInternal() {
145 deinit();
146 Common::StackLock lock(_mutex);
147 _ready = false;
148
149 if (_pcmChan) {
150 for (int i = 0; i < 8; ++i)
151 delete _pcmChan[i];
152 delete[] _pcmChan;
153 }
154 delete _pcmDev;
155 delete _psgDev;
156 delete[] _pcmBanks;
157 }
158
addNewRef(Audio::Mixer * mixer,SegaAudioInterface * owner,SegaAudioPluginDriver * driver)159 SegaAudioInterfaceInternal *SegaAudioInterfaceInternal::addNewRef(Audio::Mixer *mixer, SegaAudioInterface *owner, SegaAudioPluginDriver *driver) {
160 _refCount++;
161 if (_refCount == 1 && _refInstance == 0)
162 _refInstance = new SegaAudioInterfaceInternal(mixer, owner, driver);
163 else if (_refCount < 2 || _refInstance == 0)
164 error("SegaAudioInterfaceInternal::addNewRef(): Internal reference management failure");
165 else if (!_refInstance->assignPluginDriver(owner, driver))
166 error("SegaAudioInterfaceInternal::addNewRef(): Plugin driver conflict");
167
168 return _refInstance;
169 }
170
releaseRef(SegaAudioInterface * owner)171 void SegaAudioInterfaceInternal::releaseRef(SegaAudioInterface *owner) {
172 if (!_refCount)
173 return;
174
175 _refCount--;
176
177 if (_refCount) {
178 if (_refInstance)
179 _refInstance->removePluginDriver(owner);
180 } else {
181 delete _refInstance;
182 _refInstance = 0;
183 }
184 }
185
init()186 bool SegaAudioInterfaceInternal::init() {
187 if (_ready)
188 return true;
189
190 if (!TownsPC98_FmSynth::init())
191 return false;
192
193 _pcmBanks = new int8[0x10000];
194 memset(_pcmBanks, 0, 0x10000);
195 _pcmChan = new SegaPCMChannel*[8];
196 _psgDev = new SegaPSG(7670454 / 72, 16);
197 _pcmDev = new PCMDevice_Base(33300, 16, 8);
198 for (int i = 0; i < 8; ++i) {
199 _pcmChan[i] = new SegaPCMChannel();
200 _pcmDev->assignChannel(i, _pcmChan[i]);
201 }
202
203 reset();
204
205 writeReg(0, 0x26, 0xC6);
206 writeReg(0, 0x25, 0x62);
207 writeReg(0, 0x24, 0x00);
208 writeReg(0, 0x27, 0x30);
209
210 // Declare FM channels as music channels and PCM channels as sound effect channels.
211 setSoundEffectChanMask(~0x1FF);
212
213 _ready = true;
214
215 return true;
216 }
217
loadPCMData(uint16 address,const uint8 * data,uint16 dataSize)218 void SegaAudioInterfaceInternal::loadPCMData(uint16 address, const uint8 *data, uint16 dataSize) {
219 if (!_ready)
220 return;
221 Common::StackLock lock(_mutex);
222 while (dataSize--)
223 _pcmBanks[address++] = (*data & 0x80) ? (*data++ & 0x7F) : -*data++;
224 }
225
playPCMChannel(uint8 channel,uint8 dataStart,uint16 loopStart,uint16 rate,uint8 pan,uint8 vol)226 void SegaAudioInterfaceInternal::playPCMChannel(uint8 channel, uint8 dataStart, uint16 loopStart, uint16 rate, uint8 pan, uint8 vol) {
227 if (!_ready)
228 return;
229 Common::StackLock lock(_mutex);
230 assert(channel < 8);
231 _pcmChan[channel]->play(_pcmBanks, pcmCountSamples(dataStart << 8), dataStart << 8, loopStart, pcmCountSamples(loopStart), rate, pan, vol);
232 }
233
stopPCMChannel(uint8 channel)234 void SegaAudioInterfaceInternal::stopPCMChannel(uint8 channel) {
235 if (!_ready)
236 return;
237 Common::StackLock lock(_mutex);
238 assert(channel < 8);
239 _pcmChan[channel]->stop();
240 }
241
psgWrite(uint8 data)242 void SegaAudioInterfaceInternal::psgWrite(uint8 data) {
243 if (!_ready)
244 return;
245 Common::StackLock lock(_mutex);
246 _psgDev->write(data);
247 }
248
setMusicVolume(int volume)249 void SegaAudioInterfaceInternal::setMusicVolume(int volume) {
250 if (!_ready)
251 return;
252 Common::StackLock lock(_mutex);
253 _musicVolume = CLIP<uint16>(volume, 0, Audio::Mixer::kMaxMixerVolume);
254 _pcmDev->setMusicVolume(_musicVolume);
255 setVolumeIntern(_musicVolume, _sfxVolume);
256 }
257
setSoundEffectVolume(int volume)258 void SegaAudioInterfaceInternal::setSoundEffectVolume(int volume) {
259 if (!_ready)
260 return;
261 Common::StackLock lock(_mutex);
262 _sfxVolume = CLIP<uint16>(volume, 0, Audio::Mixer::kMaxMixerVolume);
263 _pcmDev->setSfxVolume(_sfxVolume);
264 setVolumeIntern(_musicVolume, _sfxVolume);
265 }
266
setSoundEffectChanMask(int mask)267 void SegaAudioInterfaceInternal::setSoundEffectChanMask(int mask) {
268 if (!_ready)
269 return;
270 Common::StackLock lock(_mutex);
271 _psgDev->setSfxChanMask((mask >> 6) & 7);
272 _pcmDev->setSfxChanMask(mask >> 9);
273 mask &= 0x3f;
274 setVolumeChannelMasks(~mask, mask);
275 }
276
mutex()277 Common::Mutex &SegaAudioInterfaceInternal::mutex() {
278 return _mutex;
279 }
280
mixerThreadLockCounter() const281 int SegaAudioInterfaceInternal::mixerThreadLockCounter() const {
282 return _mixerThreadLockCounter;
283 }
284
assignPluginDriver(SegaAudioInterface * owner,SegaAudioPluginDriver * driver,bool externalMutexHandling)285 bool SegaAudioInterfaceInternal::assignPluginDriver(SegaAudioInterface *owner, SegaAudioPluginDriver *driver, bool externalMutexHandling) {
286 Common::StackLock lock(_mutex);
287 if (_refCount <= 1)
288 return true;
289
290 if (_drv) {
291 if (driver && driver != _drv)
292 return false;
293 } else {
294 _drv = driver;
295 _drvOwner = owner;
296 }
297
298 return true;
299 }
300
removePluginDriver(SegaAudioInterface * owner)301 void SegaAudioInterfaceInternal::removePluginDriver(SegaAudioInterface *owner) {
302 Common::StackLock lock(_mutex);
303 if (_drvOwner == owner)
304 _drv = 0;
305 }
306
nextTickEx(int32 * buffer,uint32 bufferSize)307 void SegaAudioInterfaceInternal::nextTickEx(int32 *buffer, uint32 bufferSize) {
308 Common::StackLock lock(_mutex);
309 if (!_ready)
310 return;
311
312 _pcmDev->readBuffer(buffer, bufferSize);
313 _psgDev->readBuffer(buffer, bufferSize);
314 }
315
timerCallbackA()316 void SegaAudioInterfaceInternal::timerCallbackA() {
317 if (_drv && _ready)
318 _drv->timerCallbackA();
319 }
320
timerCallbackB()321 void SegaAudioInterfaceInternal::timerCallbackB() {
322 if (_drv && _ready)
323 _drv->timerCallbackB();
324 }
325
pcmCountSamples(uint16 address) const326 uint16 SegaAudioInterfaceInternal::pcmCountSamples(uint16 address) const {
327 const int8 *start = &_pcmBanks[address];
328 const int8 *end = &_pcmBanks[0xFFFF];
329 const int8 *pos = start;
330 for (; pos <= end; ++pos) {
331 if (*pos == 0x7F)
332 break;
333 }
334 return pos - start;
335 }
336
play(const int8 * data,uint16 dataSize,uint16 startAddress,uint16 loopStart,uint16 loopLen,uint16 rate,uint8 pan,uint8 vol)337 void SegaPCMChannel::play(const int8 *data, uint16 dataSize, uint16 startAddress, uint16 loopStart, uint16 loopLen, uint16 rate, uint8 pan, uint8 vol) {
338 setData(data, (startAddress + dataSize) << 11, startAddress << 11);
339 setupLoop(loopLen ? loopStart : (startAddress + dataSize), loopLen);
340 setRate(rate);
341 setPanPos(pan);
342 setVolume(vol);
343 activate();
344 _playing = true;
345 }
346
stop()347 void SegaPCMChannel::stop() {
348 stopInternal();
349 }
350
isPlaying() const351 bool SegaPCMChannel::isPlaying() const {
352 return _playing;
353 }
354
stopInternal()355 void SegaPCMChannel::stopInternal() {
356 _playing = false;
357 }
358
SegaPSG(int samplingRate,int deviceVolume)359 SegaPSG::SegaPSG(int samplingRate, int deviceVolume) : _intRate(3579545), _extRate(samplingRate), _deviceVolume(deviceVolume), _numChannels(3), _cr(-1),
360 _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), _sfxChanMask(0), _nfb(0), _nfs(0), _timer(0) {
361 memset(_attnTable, 0, sizeof(_attnTable));
362 for (int i = 0; i < 15; ++i)
363 _attnTable[i] = (32767.0 / (double)(_numChannels + 1)) / pow(2.0, (double)(i << 1) / 6.0);
364 }
365
write(uint8 val)366 void SegaPSG::write(uint8 val) {
367 if (val & 0x80) {
368 uint8 reg = (val >> 4) & 7;
369 val &= 0x0F;
370 _cr = -1;
371 // The noise generator is not implemented, since we don't have a single test case for it.
372 if (reg == 7) {
373 _nat = val;
374 } else if (reg & 1) {
375 _channels[reg >> 1].curSample = _attnTable[val];
376 } else if (reg == 6) {
377 _nfb = val >> 2;
378 _nfs = val & 3;
379 } else {
380 _channels[reg >> 1].freq = (_channels[reg >> 1].freq & 0x3F0) | val;
381 _cr = reg >> 1;
382 }
383 } else if (_cr != -1) {
384 _channels[_cr].freq = (_channels[_cr].freq & 0x0F) | (val << 4);
385 }
386 }
387
setMusicVolume(uint16 vol)388 void SegaPSG::setMusicVolume(uint16 vol) {
389 _musicVolume = vol;
390 }
391
setSfxVolume(uint16 vol)392 void SegaPSG::setSfxVolume(uint16 vol) {
393 _sfxVolume = vol;
394 }
395
setSfxChanMask(int mask)396 void SegaPSG::setSfxChanMask(int mask) {
397 _sfxChanMask = mask;
398 }
399
readBuffer(int32 * buffer,uint32 bufferSize)400 void SegaPSG::readBuffer(int32 *buffer, uint32 bufferSize) {
401 while (bufferSize--) {
402 _timer += _intRate;
403 while (_timer >= _extRate) {
404 _timer -= _extRate;
405 // The noise generator is not implemented, since we don't have a single test case for it.
406 for (int i = 0; i < _numChannels; ++i) {
407 Channel *c = &_channels[i];
408 if (c->counter)
409 c->counter--;
410 if (!c->counter) {
411 c->counter = c->freq << 4;
412 c->out = c->curSample;
413 c->curSample = ~c->curSample;
414 if (c->curSample < 0)
415 c->curSample++;
416 }
417 }
418 }
419
420 int32 smp = 0;
421 for (int i = 0; i < _numChannels; ++i)
422 smp += ((_channels[i].out * (((1 << i) & _sfxChanMask) ? _sfxVolume : _musicVolume)) / Audio::Mixer::kMaxMixerVolume);
423
424 smp = (smp * _deviceVolume) >> 7;
425 *buffer++ += smp;
426 *buffer++ += smp;
427 }
428 }
429
SegaAudioInterface(Audio::Mixer * mixer,SegaAudioPluginDriver * driver)430 SegaAudioInterface::SegaAudioInterface(Audio::Mixer *mixer, SegaAudioPluginDriver *driver) {
431 _internal = SegaAudioInterfaceInternal::addNewRef(mixer, this, driver);
432 }
433
~SegaAudioInterface()434 SegaAudioInterface::~SegaAudioInterface() {
435 SegaAudioInterfaceInternal::releaseRef(this);
436 _internal = 0;
437 }
438
init()439 bool SegaAudioInterface::init() {
440 return _internal->init();
441 }
442
reset()443 void SegaAudioInterface::reset() {
444 _internal->reset();
445 }
446
loadPCMData(uint16 address,const uint8 * data,uint16 dataSize)447 void SegaAudioInterface::loadPCMData(uint16 address, const uint8 *data, uint16 dataSize) {
448 _internal->loadPCMData(address, data, dataSize);
449 }
450
playPCMChannel(uint8 channel,uint8 dataStart,uint16 loopStart,uint16 rate,uint8 pan,uint8 vol)451 void SegaAudioInterface::playPCMChannel(uint8 channel, uint8 dataStart, uint16 loopStart, uint16 rate, uint8 pan, uint8 vol) {
452 _internal->playPCMChannel(channel, dataStart, loopStart, rate, pan, vol);
453 }
454
stopPCMChannel(uint8 channel)455 void SegaAudioInterface::stopPCMChannel(uint8 channel) {
456 _internal->stopPCMChannel(channel);
457 }
458
writeReg(uint8 part,uint8 regAddress,uint8 value)459 void SegaAudioInterface::writeReg(uint8 part, uint8 regAddress, uint8 value) {
460 _internal->writeReg(part, regAddress, value);
461 }
462
readReg(uint8 part,uint8 regAddress)463 uint8 SegaAudioInterface::readReg(uint8 part, uint8 regAddress) {
464 return _internal->readReg(part, regAddress);
465 }
466
psgWrite(uint8 data)467 void SegaAudioInterface::psgWrite(uint8 data) {
468 _internal->psgWrite(data);
469 }
470
setMusicVolume(int volume)471 void SegaAudioInterface::setMusicVolume(int volume) {
472 _internal->setMusicVolume(volume);
473 }
474
setSoundEffectVolume(int volume)475 void SegaAudioInterface::setSoundEffectVolume(int volume) {
476 _internal->setSoundEffectVolume(volume);
477 }
478
setSoundEffectChanMask(int mask)479 void SegaAudioInterface::setSoundEffectChanMask(int mask) {
480 _internal->setSoundEffectChanMask(mask);
481 }
482
stackLockMutex()483 SegaAudioInterface::MutexLock SegaAudioInterface::stackLockMutex() {
484 return MutexLock(_internal);
485 }
486
stackUnlockMutex()487 SegaAudioInterface::MutexLock SegaAudioInterface::stackUnlockMutex() {
488 return MutexLock(_internal, _internal->mixerThreadLockCounter());
489 }
490
MutexLock(SegaAudioInterfaceInternal * saii,int reverse)491 SegaAudioInterface::MutexLock::MutexLock(SegaAudioInterfaceInternal *saii, int reverse) : _saii(saii), _count(reverse) {
492 if (!_saii)
493 return;
494
495 if (!reverse) {
496 _saii->mutex().lock();
497 return;
498 }
499
500 while (reverse--)
501 _saii->mutex().unlock();
502 }
503
~MutexLock()504 SegaAudioInterface::MutexLock::~MutexLock() {
505 if (!_saii)
506 return;
507
508 if (!_count)
509 _saii->mutex().unlock();
510
511 while (_count--)
512 _saii->mutex().lock();
513 }
514