Mercurial > hg > xmms-sid
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 */ |