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