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/fmopl.h"
24 
25 #include "audio/mixer.h"
26 #include "audio/softsynth/opl/dosbox.h"
27 #include "audio/softsynth/opl/mame.h"
28 #include "audio/softsynth/opl/nuked.h"
29 
30 #include "common/config-manager.h"
31 #include "common/system.h"
32 #include "common/textconsole.h"
33 #include "common/timer.h"
34 #include "common/translation.h"
35 
36 namespace OPL {
37 
38 // Factory functions
39 
40 #ifdef USE_ALSA
41 namespace ALSA {
42 	OPL *create(Config::OplType type);
43 } // End of namespace ALSA
44 #endif // USE_ALSA
45 
46 #ifdef ENABLE_OPL2LPT
47 namespace OPL2LPT {
48 	OPL *create(Config::OplType type);
49 } // End of namespace OPL2LPT
50 #endif // ENABLE_OPL2LPT
51 
52 // Config implementation
53 
54 enum OplEmulator {
55 	kAuto = 0,
56 	kMame = 1,
57 	kDOSBox = 2,
58 	kALSA = 3,
59 	kNuked = 4,
60 	kOPL2LPT = 5,
61 	kOPL3LPT = 6
62 };
63 
OPL()64 OPL::OPL() {
65 	if (_hasInstance)
66 		error("There are multiple OPL output instances running");
67 	_hasInstance = true;
68 }
69 
70 const Config::EmulatorDescription Config::_drivers[] = {
71 	{ "auto", "<default>", kAuto, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
72 	{ "mame", _s("MAME OPL emulator"), kMame, kFlagOpl2 },
73 #ifndef DISABLE_DOSBOX_OPL
74 	{ "db", _s("DOSBox OPL emulator"), kDOSBox, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
75 #endif
76 #ifndef DISABLE_NUKED_OPL
77 	{ "nuked", _s("Nuked OPL emulator"), kNuked, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
78 #endif
79 #ifdef USE_ALSA
80 	{ "alsa", _s("ALSA Direct FM"), kALSA, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
81 #endif
82 #ifdef ENABLE_OPL2LPT
83 	{ "opl2lpt", _s("OPL2LPT"), kOPL2LPT, kFlagOpl2},
84 	{ "opl3lpt", _s("OPL3LPT"), kOPL3LPT, kFlagOpl2 | kFlagOpl3 },
85 #endif
86 	{ 0, 0, 0, 0 }
87 };
88 
parse(const Common::String & name)89 Config::DriverId Config::parse(const Common::String &name) {
90 	for (int i = 0; _drivers[i].name; ++i) {
91 		if (name.equalsIgnoreCase(_drivers[i].name))
92 			return _drivers[i].id;
93 	}
94 
95 	return -1;
96 }
97 
findDriver(DriverId id)98 const Config::EmulatorDescription *Config::findDriver(DriverId id) {
99 	for (int i = 0; _drivers[i].name; ++i) {
100 		if (_drivers[i].id == id)
101 			return &_drivers[i];
102 	}
103 
104 	return 0;
105 }
106 
detect(OplType type)107 Config::DriverId Config::detect(OplType type) {
108 	uint32 flags = 0;
109 	switch (type) {
110 	case kOpl2:
111 		flags = kFlagOpl2;
112 		break;
113 
114 	case kDualOpl2:
115 		flags = kFlagDualOpl2;
116 		break;
117 
118 	case kOpl3:
119 		flags = kFlagOpl3;
120 		break;
121 
122 	default:
123 		break;
124 	}
125 
126 	DriverId drv = parse(ConfMan.get("opl_driver"));
127 	if (drv == kAuto) {
128 		// Since the "auto" can be explicitly set for a game, and this
129 		// driver shows up in the GUI as "<default>", check if there is
130 		// a global setting for it before resorting to auto-detection.
131 		drv = parse(ConfMan.get("opl_driver", Common::ConfigManager::kApplicationDomain));
132 	}
133 
134 	// When a valid driver is selected, check whether it supports
135 	// the requested OPL chip.
136 	if (drv != -1 && drv != kAuto) {
137 		const EmulatorDescription *driverDesc = findDriver(drv);
138 		// If the chip is supported, just use the driver.
139 		if (!driverDesc) {
140 			warning("The selected OPL driver %d could not be found", drv);
141 		} else if ((flags & driverDesc->flags)) {
142 			return drv;
143 		} else {
144 			// Else we will output a warning and just
145 			// return that no valid driver is found.
146 			warning("Your selected OPL driver \"%s\" does not support type %d emulation, which is requested by your game", _drivers[drv].description, type);
147 			return -1;
148 		}
149 	}
150 
151 	// Detect the first matching emulator
152 	drv = -1;
153 
154 	for (int i = 1; _drivers[i].name; ++i) {
155 		if (_drivers[i].flags & flags) {
156 			drv = _drivers[i].id;
157 			break;
158 		}
159 	}
160 
161 	return drv;
162 }
163 
create(OplType type)164 OPL *Config::create(OplType type) {
165 	return create(kAuto, type);
166 }
167 
create(DriverId driver,OplType type)168 OPL *Config::create(DriverId driver, OplType type) {
169 	// On invalid driver selection, we try to do some fallback detection
170 	if (driver == -1) {
171 		warning("Invalid OPL driver selected, trying to detect a fallback emulator");
172 		driver = kAuto;
173 	}
174 
175 	// If autodetection is selected, we search for a matching
176 	// driver.
177 	if (driver == kAuto) {
178 		driver = detect(type);
179 
180 		// No emulator for the specified OPL chip could
181 		// be found, thus stop here.
182 		if (driver == -1) {
183 			warning("No OPL emulator available for type %d", type);
184 			return 0;
185 		}
186 	}
187 
188 	switch (driver) {
189 	case kMame:
190 		if (type == kOpl2)
191 			return new MAME::OPL();
192 		else
193 			warning("MAME OPL emulator only supports OPL2 emulation");
194 		return 0;
195 
196 #ifndef DISABLE_DOSBOX_OPL
197 	case kDOSBox:
198 		return new DOSBox::OPL(type);
199 #endif
200 
201 #ifndef DISABLE_NUKED_OPL
202 	case kNuked:
203 		return new NUKED::OPL(type);
204 #endif
205 
206 #ifdef USE_ALSA
207 	case kALSA:
208 		return ALSA::create(type);
209 #endif
210 
211 #ifdef ENABLE_OPL2LPT
212 	case kOPL2LPT:
213 		if (type == kOpl2) {
214 			return OPL2LPT::create(type);
215 		}
216 
217 		warning("OPL2LPT only supprts OPL2");
218 		return 0;
219 	case kOPL3LPT:
220 		if (type == kOpl2 || type == kOpl3) {
221 			return OPL2LPT::create(type);
222 		}
223 
224 		warning("OPL3LPT does not support dual OPL2");
225 		return 0;
226 #endif
227 
228 	default:
229 		warning("Unsupported OPL emulator %d", driver);
230 		// TODO: Maybe we should add some dummy emulator too, which just outputs
231 		// silence as sound?
232 		return 0;
233 	}
234 }
235 
start(TimerCallback * callback,int timerFrequency)236 void OPL::start(TimerCallback *callback, int timerFrequency) {
237 	_callback.reset(callback);
238 	startCallbacks(timerFrequency);
239 }
240 
stop()241 void OPL::stop() {
242 	stopCallbacks();
243 	_callback.reset();
244 }
245 
246 bool OPL::_hasInstance = false;
247 
RealOPL()248 RealOPL::RealOPL() : _baseFreq(0), _remainingTicks(0) {
249 }
250 
~RealOPL()251 RealOPL::~RealOPL() {
252 	// Stop callbacks, just in case. If it's still playing at this
253 	// point, there's probably a bigger issue, though. The subclass
254 	// needs to call stop() or the pointer can still use be used in
255 	// the mixer thread at the same time.
256 	stop();
257 }
258 
setCallbackFrequency(int timerFrequency)259 void RealOPL::setCallbackFrequency(int timerFrequency) {
260 	stopCallbacks();
261 	startCallbacks(timerFrequency);
262 }
263 
startCallbacks(int timerFrequency)264 void RealOPL::startCallbacks(int timerFrequency) {
265 	_baseFreq = timerFrequency;
266 	assert(_baseFreq > 0);
267 
268 	// We can't request more a timer faster than 100Hz. We'll handle this by calling
269 	// the proc multiple times in onTimer() later on.
270 	if (timerFrequency > kMaxFreq)
271 		timerFrequency = kMaxFreq;
272 
273 	_remainingTicks = 0;
274 	g_system->getTimerManager()->installTimerProc(timerProc, 1000000 / timerFrequency, this, "RealOPL");
275 }
276 
stopCallbacks()277 void RealOPL::stopCallbacks() {
278 	g_system->getTimerManager()->removeTimerProc(timerProc);
279 	_baseFreq = 0;
280 	_remainingTicks = 0;
281 }
282 
timerProc(void * refCon)283 void RealOPL::timerProc(void *refCon) {
284 	static_cast<RealOPL *>(refCon)->onTimer();
285 }
286 
onTimer()287 void RealOPL::onTimer() {
288 	uint callbacks = 1;
289 
290 	if (_baseFreq > kMaxFreq) {
291 		// We run faster than our max, so run the callback multiple
292 		// times to approximate the actual timer callback frequency.
293 		uint totalTicks = _baseFreq + _remainingTicks;
294 		callbacks = totalTicks / kMaxFreq;
295 		_remainingTicks = totalTicks % kMaxFreq;
296 	}
297 
298 	// Call the callback multiple times. The if is on the inside of the
299 	// loop in case the callback removes itself.
300 	for (uint i = 0; i < callbacks; i++)
301 		if (_callback && _callback->isValid())
302 			(*_callback)();
303 }
304 
EmulatedOPL()305 EmulatedOPL::EmulatedOPL() :
306 	_nextTick(0),
307 	_samplesPerTick(0),
308 	_baseFreq(0),
309 	_handle(new Audio::SoundHandle()) {
310 }
311 
~EmulatedOPL()312 EmulatedOPL::~EmulatedOPL() {
313 	// Stop callbacks, just in case. If it's still playing at this
314 	// point, there's probably a bigger issue, though. The subclass
315 	// needs to call stop() or the pointer can still use be used in
316 	// the mixer thread at the same time.
317 	stop();
318 
319 	delete _handle;
320 }
321 
readBuffer(int16 * buffer,const int numSamples)322 int EmulatedOPL::readBuffer(int16 *buffer, const int numSamples) {
323 	const int stereoFactor = isStereo() ? 2 : 1;
324 	int len = numSamples / stereoFactor;
325 	int step;
326 
327 	do {
328 		step = len;
329 		if (step > (_nextTick >> FIXP_SHIFT))
330 			step = (_nextTick >> FIXP_SHIFT);
331 
332 		generateSamples(buffer, step * stereoFactor);
333 
334 		_nextTick -= step << FIXP_SHIFT;
335 		if (!(_nextTick >> FIXP_SHIFT)) {
336 			if (_callback && _callback->isValid())
337 				(*_callback)();
338 
339 			_nextTick += _samplesPerTick;
340 		}
341 
342 		buffer += step * stereoFactor;
343 		len -= step;
344 	} while (len);
345 
346 	return numSamples;
347 }
348 
getRate() const349 int EmulatedOPL::getRate() const {
350 	return g_system->getMixer()->getOutputRate();
351 }
352 
startCallbacks(int timerFrequency)353 void EmulatedOPL::startCallbacks(int timerFrequency) {
354 	setCallbackFrequency(timerFrequency);
355 	g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
356 }
357 
stopCallbacks()358 void EmulatedOPL::stopCallbacks() {
359 	g_system->getMixer()->stopHandle(*_handle);
360 }
361 
setCallbackFrequency(int timerFrequency)362 void EmulatedOPL::setCallbackFrequency(int timerFrequency) {
363 	_baseFreq = timerFrequency;
364 	assert(_baseFreq != 0);
365 
366 	int d = getRate() / _baseFreq;
367 	int r = getRate() % _baseFreq;
368 
369 	// This is equivalent to (getRate() << FIXP_SHIFT) / BASE_FREQ
370 	// but less prone to arithmetic overflow.
371 
372 	_samplesPerTick = (d << FIXP_SHIFT) + (r << FIXP_SHIFT) / _baseFreq;
373 }
374 
375 } // End of namespace OPL
376