comparison src/xs_sidplay2.cpp @ 834:a7ee5dc23e78

Rename .cc -> .cpp.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 08 Nov 2012 20:47:05 +0200
parents src/xs_sidplay2.cc@c0e892fa914a
children ae1f6418d093
comparison
equal deleted inserted replaced
833:c0e892fa914a 834:a7ee5dc23e78
1 /*
2 XMMS-SID - SIDPlay input plugin for X MultiMedia System (XMMS)
3
4 libSIDPlay v2 support
5
6 Programmed and designed by Matti 'ccr' Hamalainen <ccr@tnsp.org>
7 (C) Copyright 1999-2012 Tecnic Software productions (TNSP)
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License along
20 with this program; if not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23 #include "xmms-sid.h"
24
25 #ifdef HAVE_SIDPLAY2
26
27 #include "xs_sidplay2.h"
28 #include "xs_slsup.h"
29 #include "xs_config.h"
30
31 #include <sidplay/sidplay2.h>
32 #if G_BYTE_ORDER == G_BIG_ENDIAN
33 # define SID2_NATIVE_UNSIGNED SID2_BIG_UNSIGNED
34 # define SID2_NATIVE_SIGNED SID2_BIG_SIGNED
35 #elif G_BYTE_ORDER == G_LITTLE_ENDIAN
36 # define SID2_NATIVE_UNSIGNED SID2_LITTLE_UNSIGNED
37 # define SID2_NATIVE_SIGNED SID2_LITTLE_SIGNED
38 #else
39 # error Unsupported endianess!
40 #endif
41
42
43 class XSSIDPlay2 {
44 public:
45 sidplay2 emu;
46 sid2_config_t config;
47 SidTune tune;
48
49 XSSIDPlay2(void);
50 virtual ~XSSIDPlay2(void);
51 };
52
53
54 #ifdef HAVE_RESID_BUILDER
55 # include <sidplay/builders/resid.h>
56 #endif
57
58 #ifdef HAVE_HARDSID_BUILDER
59 # include <sidplay/builders/hardsid.h>
60 #endif
61
62
63 XSSIDPlay2::XSSIDPlay2(void) : tune(0)
64 {
65 }
66
67
68 XSSIDPlay2::~XSSIDPlay2(void)
69 {
70 emu.load(NULL);
71 }
72
73
74 /* We need to 'export' all this pseudo-C++ crap */
75 extern "C" {
76
77
78 /* Return song information
79 */
80 #define TFUNCTION xs_sidplay2_getinfo
81 #define TFUNCTION2 xs_sidplay2_updateinfo
82 #define TTUNEINFO SidTuneInfo
83 #define TTUNE SidTune
84 #define TENGINE XSSIDPlay2
85 #include "xs_sidplay.h"
86
87
88 /* Check if we can play the given file
89 */
90 gboolean xs_sidplay2_probe(XSFile *f)
91 {
92 gchar tmpBuf[5];
93
94 if (!f) return FALSE;
95
96 if (xs_fread(tmpBuf, sizeof(gchar), 4, f) != 4)
97 return FALSE;
98
99 if (!strncmp(tmpBuf, "PSID", 4) || !strncmp(tmpBuf, "RSID", 4))
100 return TRUE;
101 else
102 return FALSE;
103 }
104
105
106 /* Initialize SIDPlay2
107 */
108 gboolean xs_sidplay2_init(XSEngineState * state)
109 {
110 XSSIDPlay2 *engine;
111 sid_filter_t tmpFilter;
112 xs_sid_filter_t *f;
113 gint i;
114 assert(state);
115
116 /* Allocate internal structures */
117 engine = new XSSIDPlay2();
118 state->internal = engine;
119 if (!engine)
120 return FALSE;
121
122 /* Get current configuration */
123 engine->config = engine->emu.config();
124
125 /* Configure channels and stuff */
126 switch (state->audioChannels)
127 {
128 case XS_CHN_AUTOPAN:
129 engine->config.playback = sid2_stereo;
130 break;
131
132 case XS_CHN_STEREO:
133 engine->config.playback = sid2_stereo;
134 break;
135
136 case XS_CHN_MONO:
137 default:
138 engine->config.playback = sid2_mono;
139 state->audioChannels = XS_CHN_MONO;
140 break;
141 }
142
143
144 /* Memory mode settings */
145 switch (xs_cfg.memoryMode)
146 {
147 case XS_MPU_BANK_SWITCHING:
148 engine->config.environment = sid2_envBS;
149 break;
150
151 case XS_MPU_TRANSPARENT_ROM:
152 engine->config.environment = sid2_envTP;
153 break;
154
155 case XS_MPU_PLAYSID_ENVIRONMENT:
156 engine->config.environment = sid2_envPS;
157 break;
158
159 case XS_MPU_REAL:
160 default:
161 engine->config.environment = sid2_envR;
162 xs_cfg.memoryMode = XS_MPU_REAL;
163 break;
164 }
165
166
167 /* Audio parameters sanity checking and setup */
168 engine->config.precision = state->audioBitsPerSample;
169 engine->config.frequency = state->audioFrequency;
170
171
172 switch (state->audioBitsPerSample)
173 {
174 case XS_RES_8BIT:
175 state->audioFormat = FMT_U8;
176 engine->config.sampleFormat = SID2_LITTLE_UNSIGNED;
177 break;
178
179 case XS_RES_16BIT:
180 default:
181 switch (state->audioFormat)
182 {
183 case FMT_U16_LE:
184 engine->config.sampleFormat = SID2_LITTLE_UNSIGNED;
185 break;
186
187 case FMT_U16_BE:
188 engine->config.sampleFormat = SID2_BIG_UNSIGNED;
189 break;
190
191 case FMT_U16_NE:
192 engine->config.sampleFormat = SID2_NATIVE_UNSIGNED;
193 break;
194
195 case FMT_S16_LE:
196 engine->config.sampleFormat = SID2_LITTLE_SIGNED;
197 break;
198
199 case FMT_S16_BE:
200 engine->config.sampleFormat = SID2_BIG_SIGNED;
201 break;
202
203 default:
204 state->audioFormat = FMT_S16_NE;
205 engine->config.sampleFormat = SID2_NATIVE_SIGNED;
206 break;
207 }
208 break;
209 }
210
211 /* Convert filter */
212 f = &(xs_cfg.sid2Filter);
213 XSDEBUG("using filter '%s', %d points\n", f->name, f->npoints);
214 if (f->npoints > XS_SIDPLAY2_NFPOINTS)
215 {
216 xs_error("[SIDPlay2] Invalid number of filter curve points (%d > %d)\n",
217 f->npoints, XS_SIDPLAY2_NFPOINTS);
218 f->npoints = XS_SIDPLAY2_NFPOINTS;
219 }
220
221 tmpFilter.points = f->npoints;
222 for (i = 0; i < f->npoints; i++)
223 {
224 tmpFilter.cutoff[i][0] = f->points[i].x;
225 tmpFilter.cutoff[i][1] = f->points[i].y;
226 }
227
228 /* Initialize builder object */
229 XSDEBUG("init builder #%i, maxsids=%i\n", xs_cfg.sid2Builder, (engine->emu.info()).maxsids);
230
231 switch (xs_cfg.sid2Builder)
232 {
233 #ifdef HAVE_RESID_BUILDER
234 case XS_BLD_RESID:
235 {
236 ReSIDBuilder *rs = new ReSIDBuilder("ReSID builder");
237 if (rs)
238 {
239 engine->config.sidEmulation = rs;
240 if (!*rs) return FALSE;
241 rs->create((engine->emu.info()).maxsids);
242 if (!*rs) return FALSE;
243 }
244 }
245 break;
246 #endif
247
248 #ifdef HAVE_HARDSID_BUILDER
249 case XS_BLD_HARDSID:
250 {
251 HardSIDBuilder *hs = new HardSIDBuilder("HardSID builder (FP)");
252 engine->config.sidEmulation = (sidbuilder *) hs;
253 if (hs)
254 {
255 hs->create((engine->emu.info()).maxsids);
256 if (!*hs)
257 {
258 xs_error("hardSID->create() failed.\n");
259 return FALSE;
260 }
261 }
262 }
263 break;
264 #endif
265
266 default:
267 xs_error("[SIDPlay2] Invalid or unsupported builder selected.\n");
268 break;
269 }
270
271 if (!engine->config.sidEmulation)
272 {
273 xs_error("[SIDPlay2] Could not initialize SIDBuilder object.\n");
274 return FALSE;
275 }
276
277 #if 0
278 // Setup filter
279 engine->config.sidEmulation->filter(xs_cfg.emulateFilters);
280 if (!*(engine->config.sidEmulation))
281 {
282 xs_error("builder->filter(%d) failed.\n", xs_cfg.emulateFilters);
283 return FALSE;
284 }
285 #endif
286
287 XSDEBUG("%s\n", engine->config.sidEmulation->credits());
288
289 /* Clockspeed settings */
290 switch (xs_cfg.clockSpeed)
291 {
292 case XS_CLOCK_NTSC:
293 engine->config.clockDefault = SID2_CLOCK_NTSC;
294 break;
295
296 default:
297 case XS_CLOCK_PAL:
298 engine->config.clockDefault = SID2_CLOCK_PAL;
299 xs_cfg.clockSpeed = XS_CLOCK_PAL;
300 break;
301 }
302
303
304 /* Configure rest of the emulation */
305 if (xs_cfg.forceSpeed)
306 {
307 engine->config.clockForced = true;
308 engine->config.clockSpeed = engine->config.clockDefault;
309 }
310 else
311 {
312 engine->config.clockForced = false;
313 engine->config.clockSpeed = SID2_CLOCK_CORRECT;
314 }
315
316
317 if (xs_cfg.sid2OptLevel < 0 || xs_cfg.sid2OptLevel > SID2_MAX_OPTIMISATION)
318 {
319 xs_error("Invalid sid2OptLevel=%d, falling back to %d.\n",
320 xs_cfg.sid2OptLevel, SID2_DEFAULT_OPTIMISATION);
321
322 xs_cfg.sid2OptLevel = SID2_DEFAULT_OPTIMISATION;
323 }
324 engine->config.optimisation = xs_cfg.sid2OptLevel;
325
326 engine->config.sidDefault = xs_cfg.mos8580 ? SID2_MOS8580 : SID2_MOS6581;
327 engine->config.sidModel = xs_cfg.forceModel ? engine->config.sidDefault : SID2_MODEL_CORRECT;
328 engine->config.sidSamples = TRUE;
329
330 return TRUE;
331 }
332
333
334 /* Close SIDPlay2 engine
335 */
336 void xs_sidplay2_close(XSEngineState * state)
337 {
338 XSSIDPlay2 *engine = (XSSIDPlay2 *) state->internal;
339
340 xs_sidplay2_delete(state);
341
342 if (engine)
343 {
344 delete engine;
345 engine = NULL;
346 }
347
348 state->internal = NULL;
349 }
350
351
352 /* Initialize current song and sub-tune
353 */
354 gboolean xs_sidplay2_initsong(XSEngineState * state)
355 {
356 XSSIDPlay2 *engine = (XSSIDPlay2 *) state->internal;
357
358 if (!engine)
359 return FALSE;
360
361 if (!engine->tune.selectSong(state->currSong))
362 {
363 xs_error("[SIDPlay2] tune.selectSong() failed\n");
364 return FALSE;
365 }
366
367 if (engine->emu.load(&(engine->tune)) < 0)
368 {
369 xs_error("[SIDPlay2] emu.load() failed\n");
370 return FALSE;
371 }
372
373 if (engine->emu.config(engine->config) < 0)
374 {
375 xs_error("[SIDPlay2] Emulator engine configuration failed!\n");
376 return FALSE;
377 }
378
379 return TRUE;
380 }
381
382
383 /* Emulate and render audio data to given buffer
384 */
385 guint xs_sidplay2_fillbuffer(XSEngineState * state, gchar * audioBuffer, guint audioBufSize)
386 {
387 XSSIDPlay2 *engine = (XSSIDPlay2 *) state->internal;
388
389 if (!engine)
390 return 0;
391
392 return engine->emu.play(audioBuffer, audioBufSize);
393 }
394
395
396 /* Load a given SID-tune file
397 */
398 gboolean xs_sidplay2_load(XSEngineState * state, gchar * filename)
399 {
400 XSSIDPlay2 *engine = (XSSIDPlay2 *) state->internal;
401
402 if (!engine || !filename)
403 return FALSE;
404
405 engine->tune.load(filename);
406 if (!engine->tune)
407 {
408 xs_error("Could not load file '%s': %s\n",
409 filename, (engine->tune.getInfo()).statusString);
410 return FALSE;
411 }
412
413 return TRUE;
414 }
415
416
417 /* Delete INTERNAL information
418 */
419 void xs_sidplay2_delete(XSEngineState * state)
420 {
421 XSSIDPlay2 *engine = (XSSIDPlay2 *) state->internal;
422 }
423
424
425 /* Hardware backend flushing
426 */
427 void xs_sidplay2_flush(XSEngineState * state)
428 {
429 XSSIDPlay2 *engine = (XSSIDPlay2 *) state->internal;
430
431 #ifdef HAVE_HARDSID_BUILDER
432 if (xs_cfg.sid2Builder == XS_BLD_HARDSID)
433 {
434 ((HardSIDBuilder *) engine->config.sidEmulation)->flush();
435 }
436 #endif
437 }
438
439
440 } /* extern "C" */
441 #endif /* HAVE_SIDPLAY2 */