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 /* OPL implementation for hardware OPL using ALSA Direct FM API.
24  *
25  * Caveats and limitations:
26  * - Pretends to be a softsynth (emitting silence).
27  * - Dual OPL2 mode requires OPL3 hardware.
28  * - Every register write leads to a series of register writes on the hardware,
29  *   due to the lack of direct register access in the ALSA Direct FM API.
30  * - No timers
31  */
32 
33 #define FORBIDDEN_SYMBOL_ALLOW_ALL
34 #include "common/scummsys.h"
35 
36 #include "common/debug.h"
37 #include "common/str.h"
38 #include "audio/fmopl.h"
39 
40 #include <sys/ioctl.h>
41 #include <alsa/asoundlib.h>
42 #include <sound/asound_fm.h>
43 
44 namespace OPL {
45 namespace ALSA {
46 
47 class OPL : public ::OPL::RealOPL {
48 private:
49 	enum {
50 		kOpl2Voices = 9,
51 		kVoices = 18,
52 		kOpl2Operators = 18,
53 		kOperators = 36
54 	};
55 
56 	Config::OplType _type;
57 	int _iface;
58 	snd_hwdep_t *_opl;
59 	snd_dm_fm_voice _oper[kOperators];
60 	snd_dm_fm_note _voice[kVoices];
61 	snd_dm_fm_params _params;
62 	int index[2];
63 	static const int voiceToOper0[kVoices];
64 	static const int regOffsetToOper[0x20];
65 
66 	void writeOplReg(int c, int r, int v);
67 	void clear();
68 
69 public:
70 	OPL(Config::OplType type);
71 	~OPL();
72 
73 	bool init();
74 	void reset();
75 
76 	void write(int a, int v);
77 	byte read(int a);
78 
79 	void writeReg(int r, int v);
80 };
81 
82 const int OPL::voiceToOper0[OPL::kVoices] =
83 	{ 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 };
84 
85 const int OPL::regOffsetToOper[0x20] =
86 	{ 0,  1,  2,  3,  4,  5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1,
87 	 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
88 
OPL(Config::OplType type)89 OPL::OPL(Config::OplType type) : _type(type), _opl(nullptr), _iface(0) {
90 }
91 
~OPL()92 OPL::~OPL() {
93 	stop();
94 
95 	if (_opl) {
96 		snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_RESET, nullptr);
97 		snd_hwdep_close(_opl);
98 	}
99 }
100 
clear()101 void OPL::clear() {
102 	index[0] = index[1] = 0;
103 
104 	memset(_oper, 0, sizeof(_oper));
105 	memset(_voice, 0, sizeof(_voice));
106 	memset(&_params, 0, sizeof(_params));
107 
108 	for (int i = 0; i < kOperators; ++i) {
109 		_oper[i].op = (i / 3) % 2;
110 		_oper[i].voice = (i / 6) * 3 + (i % 3);
111 	}
112 
113 	for (int i = 0; i < kVoices; ++i)
114 		_voice[i].voice = i;
115 
116 	// For OPL3 hardware we need to set up the panning in OPL2 modes
117 	if (_iface == SND_HWDEP_IFACE_OPL3) {
118 		if (_type == Config::kDualOpl2) {
119 			for (int i = 0; i < kOpl2Operators; ++i)
120 				_oper[i].left = 1; // FIXME below
121 			for (int i = kOpl2Operators; i < kOperators; ++i)
122 				_oper[i].right = 1;
123 		} else if (_type == Config::kOpl2) {
124 			for (int i = 0; i < kOpl2Operators; ++i) {
125 				_oper[i].left = 1;
126 				_oper[i].right = 1;
127 			}
128 		}
129 	}
130 }
131 
init()132 bool OPL::init() {
133 	clear();
134 
135 	int card = -1;
136 	snd_ctl_t *ctl;
137 	snd_hwdep_info_t *info;
138 	snd_hwdep_info_alloca(&info);
139 
140 	int iface = SND_HWDEP_IFACE_OPL3;
141 	if (_type == Config::kOpl2)
142 		iface = SND_HWDEP_IFACE_OPL2;
143 
144 	// Look for OPL hwdep interface
145 	while (!snd_card_next(&card) && card >= 0) {
146 		int dev = -1;
147 		Common::String name = Common::String::format("hw:%d", card);
148 
149 		if (snd_ctl_open(&ctl, name.c_str(), 0) < 0)
150 			continue;
151 
152 		while (!snd_ctl_hwdep_next_device(ctl, &dev) && dev >= 0) {
153 			name = Common::String::format("hw:%d,%d", card, dev);
154 
155 			if (snd_hwdep_open(&_opl, name.c_str(), SND_HWDEP_OPEN_WRITE) < 0)
156 				continue;
157 
158 			if (!snd_hwdep_info(_opl, info)) {
159 				int found = snd_hwdep_info_get_iface(info);
160 				// OPL3 can be used for (Dual) OPL2 mode
161 				if (found == iface || found == SND_HWDEP_IFACE_OPL3) {
162 					snd_ctl_close(ctl);
163 					_iface = found;
164 					reset();
165 					return true;
166 				}
167 			}
168 
169 			// Wrong interface, try next device
170 			snd_hwdep_close(_opl);
171 			_opl = nullptr;
172 		}
173 
174 		snd_ctl_close(ctl);
175 	}
176 
177 	return false;
178 }
179 
reset()180 void OPL::reset() {
181 	snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_RESET, nullptr);
182 	if (_iface == SND_HWDEP_IFACE_OPL3)
183 		snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_MODE, (void *)SNDRV_DM_FM_MODE_OPL3);
184 
185 	clear();
186 
187 	// Sync up with the hardware
188 	snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_PARAMS, (void *)&_params);
189 	for (uint i = 0; i < (_iface == SND_HWDEP_IFACE_OPL3 ? kVoices : kOpl2Voices); ++i)
190 		snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_PLAY_NOTE, (void *)&_voice[i]);
191 	for (uint i = 0; i < (_iface == SND_HWDEP_IFACE_OPL3 ? kOperators : kOpl2Operators); ++i)
192 		snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[i]);
193 }
194 
write(int port,int val)195 void OPL::write(int port, int val) {
196 	val &= 0xff;
197 	int chip = (port & 2) >> 1;
198 
199 	if (port & 1) {
200 		switch(_type) {
201 		case Config::kOpl2:
202 			writeOplReg(0, index[0], val);
203 			break;
204 		case Config::kDualOpl2:
205 			if (port & 8) {
206 				writeOplReg(0, index[0], val);
207 				writeOplReg(1, index[1], val);
208 			} else
209 				writeOplReg(chip, index[chip], val);
210 			break;
211 		case Config::kOpl3:
212 			writeOplReg(chip, index[chip], val);
213 			break;
214 		default:
215 			break;
216 		}
217 	} else {
218 		switch(_type) {
219 		case Config::kOpl2:
220 			index[0] = val;
221 			break;
222 		case Config::kDualOpl2:
223 			if (port & 8) {
224 				index[0] = val;
225 				index[1] = val;
226 			} else
227 				index[chip] = val;
228 			break;
229 		case Config::kOpl3:
230 			index[chip] = val;
231 			break;
232 		default:
233 			break;
234 		}
235 	}
236 }
237 
read(int port)238 byte OPL::read(int port) {
239 	return 0;
240 }
241 
writeReg(int r,int v)242 void OPL::writeReg(int r, int v) {
243 	switch (_type) {
244 	case Config::kOpl2:
245 		writeOplReg(0, r, v);
246 		break;
247 	case Config::kDualOpl2:
248 		writeOplReg(0, r, v);
249 		writeOplReg(1, r, v);
250 		break;
251 	case Config::kOpl3:
252 		writeOplReg(r >= 0x100, r & 0xff, v);
253 		break;
254 	default:
255 		break;
256 	}
257 }
258 
writeOplReg(int c,int r,int v)259 void OPL::writeOplReg(int c, int r, int v) {
260 	if (r == 0x04 && c == 1 && _type == Config::kOpl3) {
261 		snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_CONNECTION, reinterpret_cast<void *>(v & 0x3f));
262 	} else if (r == 0x08 && c == 0) {
263 		_params.kbd_split = (v >> 6) & 0x1;
264 		snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_PARAMS, (void *)&_params);
265 	} else if (r == 0xbd && c == 0) {
266 		_params.hihat = v & 0x1;
267 		_params.cymbal = (v >> 1) & 0x1;
268 		_params.tomtom = (v >> 2) & 0x1;
269 		_params.snare = (v >> 3) & 0x1;
270 		_params.bass = (v >> 4) & 0x1;
271 		_params.rhythm = (v >> 5) & 0x1;
272 		_params.vib_depth = (v >> 6) & 0x1;
273 		_params.am_depth = (v >> 7) & 0x1;
274 		snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_PARAMS, (void *)&_params);
275 	} else if (r < 0xa0 || r >= 0xe0) {
276 		// Operator
277 		int idx = regOffsetToOper[r & 0x1f];
278 
279 		if (idx == -1)
280 			return;
281 
282 		if (c == 1)
283 			idx += kOpl2Operators;
284 
285 		switch (r & 0xf0) {
286 		case 0x20:
287 		case 0x30:
288 			_oper[idx].harmonic = v & 0xf;
289 			_oper[idx].kbd_scale = (v >> 4) & 0x1;
290 			_oper[idx].do_sustain = (v >> 5) & 0x1;
291 			_oper[idx].vibrato = (v >> 6) & 0x1;
292 			_oper[idx].am = (v >> 7) & 0x1;
293 			snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
294 			break;
295 		case 0x40:
296 		case 0x50:
297 			_oper[idx].volume = ~v & 0x3f;
298 			_oper[idx].scale_level = (v >> 6) & 0x3;
299 			snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
300 			break;
301 		case 0x60:
302 		case 0x70:
303 			_oper[idx].decay = v & 0xf;
304 			_oper[idx].attack = (v >> 4) & 0xf;
305 			snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
306 			break;
307 		case 0x80:
308 		case 0x90:
309 			_oper[idx].release = v & 0xf;
310 			_oper[idx].sustain = (v >> 4) & 0xf;
311 			snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
312 			break;
313 		case 0xe0:
314 		case 0xf0:
315 			_oper[idx].waveform = v & (_type == Config::kOpl3 ? 0x7 : 0x3);
316 			snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
317 			break;
318 		default:
319 			break;
320 		}
321 	} else {
322 		// Voice
323 		int idx = r & 0xf;
324 
325 		if (idx >= kOpl2Voices)
326 			return;
327 
328 		if (c == 1)
329 			idx += kOpl2Voices;
330 
331 		int opIdx = voiceToOper0[idx];
332 
333 		switch (r & 0xf0) {
334 		case 0xa0:
335 			_voice[idx].fnum = (_voice[idx].fnum & 0x300) | (v & 0xff);
336 			snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_PLAY_NOTE, (void *)&_voice[idx]);
337 			break;
338 		case 0xb0:
339 			_voice[idx].fnum = ((v << 8) & 0x300) | (_voice[idx].fnum & 0xff);
340 			_voice[idx].octave = (v >> 2) & 0x7;
341 			_voice[idx].key_on = (v >> 5) & 0x1;
342 			snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_PLAY_NOTE, (void *)&_voice[idx]);
343 			break;
344 		case 0xc0:
345 			_oper[opIdx].connection = _oper[opIdx + 3].connection = v & 0x1;
346 			_oper[opIdx].feedback = _oper[opIdx + 3].feedback = (v >> 1) & 0x7;
347 			if (_type == Config::kOpl3) {
348 				_oper[opIdx].left = _oper[opIdx + 3].left = (v >> 4) & 0x1;
349 				_oper[opIdx].right = _oper[opIdx + 3].right = (v >> 5) & 0x1;
350 			}
351 			snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[opIdx]);
352 			break;
353 		default:
354 			break;
355 		}
356 	}
357 }
358 
create(Config::OplType type)359 OPL *create(Config::OplType type) {
360 	return new OPL(type);
361 }
362 
363 } // End of namespace ALSA
364 } // End of namespace OPL
365