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