Mercurial > hg > xmms-sid
comparison src/xs_sidplayfp.cpp @ 835:d508c7c4bc69
Add libSIDPlay2-FP backend interface module.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 08 Nov 2012 20:47:49 +0200 |
parents | |
children | ae1f6418d093 |
comparison
equal
deleted
inserted
replaced
834:a7ee5dc23e78 | 835:d508c7c4bc69 |
---|---|
1 /* | |
2 XMMS-SID - SIDPlay input plugin for X MultiMedia System (XMMS) | |
3 | |
4 libSIDPlay v2-FP 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_FP | |
26 | |
27 #include <stdio.h> | |
28 #include "xs_sidplay2.h" | |
29 #include "xs_config.h" | |
30 | |
31 | |
32 #ifdef HAVE_SIDPLAY2_FP_V1 | |
33 # include <sidplayfp/SidTune.h> | |
34 # include <sidplayfp/sidplayfp.h> | |
35 # include <sidplayfp/event.h> | |
36 # include <sidplayfp/SidConfig.h> | |
37 # include <sidplayfp/SidTuneInfo.h> | |
38 #else | |
39 # include <sidplayfp/sidplay2.h> | |
40 # include <sidplayfp/SidTuneMod.h> | |
41 # include <sidplayfp/event.h> | |
42 #endif | |
43 | |
44 | |
45 class XSSIDPlayFP { | |
46 public: | |
47 #ifdef HAVE_SIDPLAY2_FP_V1 | |
48 sidplayfp emu; | |
49 SidConfig config; | |
50 #else | |
51 sidplay2 emu; | |
52 sid2_config_t config; | |
53 #endif | |
54 SidTune tune; | |
55 | |
56 XSSIDPlayFP(void); | |
57 virtual ~XSSIDPlayFP(void); | |
58 }; | |
59 | |
60 | |
61 #ifdef HAVE_RESID_BUILDER | |
62 # include <sidplayfp/builders/residfp.h> | |
63 # include <sidplayfp/builders/resid.h> | |
64 #endif | |
65 | |
66 #ifdef HAVE_HARDSID_BUILDER | |
67 # include <sidplayfp/builders/hardsid.h> | |
68 #endif | |
69 | |
70 | |
71 XSSIDPlayFP::XSSIDPlayFP(void) : tune(0) | |
72 { | |
73 } | |
74 | |
75 | |
76 XSSIDPlayFP::~XSSIDPlayFP(void) | |
77 { | |
78 emu.load(NULL); | |
79 } | |
80 | |
81 | |
82 /* We need to 'export' all this pseudo-C++ crap */ | |
83 extern "C" { | |
84 | |
85 | |
86 /* Return song information | |
87 */ | |
88 #define TFUNCTION xs_sidplayfp_getinfo | |
89 #define TFUNCTION2 xs_sidplayfp_updateinfo | |
90 #define TENGINE XSSIDPlayFP | |
91 #define TTUNEINFO SidTuneInfo | |
92 #define TTUNE SidTune | |
93 | |
94 #ifdef HAVE_SIDPLAY2_FP_V1 | |
95 #define sid2_mono SidConfig::MONO | |
96 #define sid2_stereo SidConfig::STEREO | |
97 #define SID2_MOS8580 SidConfig::MOS8580 | |
98 #define SID2_MOS6581 SidConfig::MOS6581 | |
99 #define SID2_CLOCK_PAL SidConfig::CLOCK_PAL | |
100 #define SID2_CLOCK_NTSC SidConfig::CLOCK_NTSC | |
101 #define SIDTUNE_CLOCK_UNKNOWN SidTuneInfo::CLOCK_UNKNOWN | |
102 #define SIDTUNE_CLOCK_PAL SidTuneInfo::CLOCK_PAL | |
103 #define SIDTUNE_CLOCK_NTSC SidTuneInfo::CLOCK_NTSC | |
104 #define SIDTUNE_CLOCK_ANY SidTuneInfo::CLOCK_ANY | |
105 #define SIDTUNE_SPEED_VBI SidTuneInfo::SPEED_VBI | |
106 #define SIDTUNE_SPEED_CIA_1A SidTuneInfo::SPEED_CIA_1A | |
107 #endif | |
108 | |
109 #include "xs_sidplay.h" | |
110 | |
111 | |
112 /* Check if we can play the given file | |
113 */ | |
114 gboolean xs_sidplayfp_probe(XSFile *f) | |
115 { | |
116 gchar tmpBuf[5]; | |
117 | |
118 if (!f) return FALSE; | |
119 | |
120 if (xs_fread(tmpBuf, sizeof(gchar), 4, f) != 4) | |
121 return FALSE; | |
122 | |
123 if (!strncmp(tmpBuf, "PSID", 4) || !strncmp(tmpBuf, "RSID", 4)) | |
124 return TRUE; | |
125 else | |
126 return FALSE; | |
127 } | |
128 | |
129 | |
130 /* Initialize SIDPlay2 | |
131 */ | |
132 gboolean xs_sidplayfp_init(XSEngineState * state) | |
133 { | |
134 XSSIDPlayFP *engine; | |
135 assert(state); | |
136 | |
137 /* Allocate internal structures */ | |
138 engine = new XSSIDPlayFP(); | |
139 state->internal = engine; | |
140 if (!engine) | |
141 return FALSE; | |
142 | |
143 /* Get current configuration */ | |
144 engine->config = engine->emu.config(); | |
145 | |
146 /* Configure channels and stuff */ | |
147 engine->config.playback = (state->audioChannels == XS_CHN_MONO) ? sid2_mono : sid2_stereo; | |
148 | |
149 /* Audio parameters sanity checking and setup */ | |
150 state->audioBitsPerSample = XS_RES_16BIT; | |
151 engine->config.samplingMethod = SID2_RESAMPLE_INTERPOLATE; | |
152 engine->config.frequency = state->audioFrequency; | |
153 | |
154 /* Initialize builder object */ | |
155 XSDEBUG("init builder #%i, maxsids=%i\n", xs_cfg.sid2Builder, (engine->emu.info()).maxsids); | |
156 | |
157 switch (xs_cfg.sid2Builder) | |
158 { | |
159 #ifdef HAVE_RESID_BUILDER | |
160 case XS_BLD_RESID: | |
161 { | |
162 ReSIDBuilder *rs = new ReSIDBuilder("ReSID builder"); | |
163 #ifdef HAVE_SIDPLAY2_FP_V1 | |
164 if (rs && rs->getStatus()) | |
165 { | |
166 } | |
167 #else | |
168 if (rs) | |
169 { | |
170 engine->config.sidEmulation = rs; | |
171 if (!*rs) return FALSE; | |
172 rs->create((engine->emu.info()).maxsids); | |
173 if (!*rs) return FALSE; | |
174 rs->bias(0.0f); | |
175 } | |
176 #endif // HAVE_SIDPLAY2_FP_V1 | |
177 } | |
178 break; | |
179 #endif // HAVE_RESID_BUILDER | |
180 | |
181 | |
182 #ifdef HAVE_RESID_FP_BUILDER | |
183 case XS_BLD_RESID_FP: | |
184 { | |
185 ReSIDfpBuilder *rs = new ReSIDfpBuilder("ReSID builder FP!"); | |
186 if (rs) | |
187 { | |
188 engine->config.sidEmulation = rs; | |
189 if (!*rs) return FALSE; | |
190 rs->create((engine->emu.info()).maxsids); | |
191 if (!*rs) return FALSE; | |
192 | |
193 rs->filter6581Curve(0.0); | |
194 rs->filter8580Curve(0.0); | |
195 } | |
196 } | |
197 break; | |
198 #endif | |
199 | |
200 #ifdef HAVE_HARDSID_BUILDER | |
201 case XS_BLD_HARDSID: | |
202 { | |
203 HardSIDBuilder *hs = new HardSIDBuilder("HardSID builder (FP)"); | |
204 engine->config.sidEmulation = (sidbuilder *) hs; | |
205 if (hs) | |
206 { | |
207 hs->create((engine->emu.info()).maxsids); | |
208 if (!*hs) | |
209 { | |
210 xs_error("hardSID->create() failed.\n"); | |
211 return FALSE; | |
212 } | |
213 } | |
214 } | |
215 break; | |
216 #endif | |
217 | |
218 default: | |
219 xs_error("[SIDPlay2] Invalid or unsupported builder selected.\n"); | |
220 break; | |
221 } | |
222 | |
223 if (!engine->config.sidEmulation) | |
224 { | |
225 xs_error("[SIDPlay2] Could not initialize SIDBuilder object.\n"); | |
226 return FALSE; | |
227 } | |
228 | |
229 // Setup filter | |
230 engine->config.sidEmulation->filter(xs_cfg.emulateFilters); | |
231 if (!*(engine->config.sidEmulation)) | |
232 { | |
233 xs_error("builder->filter(%d) failed.\n", xs_cfg.emulateFilters); | |
234 return FALSE; | |
235 } | |
236 | |
237 XSDEBUG("%s\n", engine->config.sidEmulation->credits()); | |
238 | |
239 /* Clockspeed settings */ | |
240 switch (xs_cfg.clockSpeed) | |
241 { | |
242 case XS_CLOCK_NTSC: | |
243 engine->config.clockDefault = SID2_CLOCK_NTSC; | |
244 break; | |
245 | |
246 default: | |
247 case XS_CLOCK_PAL: | |
248 engine->config.clockDefault = SID2_CLOCK_PAL; | |
249 xs_cfg.clockSpeed = XS_CLOCK_PAL; | |
250 break; | |
251 } | |
252 | |
253 | |
254 /* Configure rest of the emulation */ | |
255 engine->config.sidDefault = xs_cfg.mos8580 ? SID2_MOS8580 : SID2_MOS6581; | |
256 engine->config.clockForced = xs_cfg.forceSpeed; | |
257 | |
258 #ifndef HAVE_SIDPLAY2_FP_V1 | |
259 engine->config.sidSamples = TRUE; | |
260 engine->config.sidModel = xs_cfg.forceModel ? engine->config.sidDefault : SID2_MODEL_CORRECT; | |
261 engine->config.clockSpeed = xs_cfg.forceSpeed ? engine->config.clockDefault : SID2_CLOCK_CORRECT; | |
262 #endif | |
263 | |
264 return TRUE; | |
265 } | |
266 | |
267 | |
268 /* Close SIDPlay2 engine | |
269 */ | |
270 void xs_sidplayfp_close(XSEngineState * state) | |
271 { | |
272 XSSIDPlayFP *engine = (XSSIDPlayFP *) state->internal; | |
273 | |
274 xs_sidplayfp_delete(state); | |
275 | |
276 if (engine) | |
277 { | |
278 delete engine; | |
279 engine = NULL; | |
280 } | |
281 | |
282 state->internal = NULL; | |
283 } | |
284 | |
285 | |
286 /* Initialize current song and sub-tune | |
287 */ | |
288 gboolean xs_sidplayfp_initsong(XSEngineState * state) | |
289 { | |
290 XSSIDPlayFP *engine = (XSSIDPlayFP *) state->internal; | |
291 | |
292 if (!engine) | |
293 return FALSE; | |
294 | |
295 if (!engine->tune.selectSong(state->currSong)) | |
296 { | |
297 xs_error("[SIDPlay2] tune.selectSong() failed\n"); | |
298 return FALSE; | |
299 } | |
300 | |
301 if (engine->emu.load(&(engine->tune)) < 0) | |
302 { | |
303 xs_error("[SIDPlay2] emu.load() failed\n"); | |
304 return FALSE; | |
305 } | |
306 | |
307 if (engine->emu.config(engine->config) < 0) | |
308 { | |
309 xs_error("[SIDPlay2] Emulator engine configuration failed!\n"); | |
310 return FALSE; | |
311 } | |
312 | |
313 return TRUE; | |
314 } | |
315 | |
316 | |
317 /* Emulate and render audio data to given buffer | |
318 */ | |
319 guint xs_sidplayfp_fillbuffer(XSEngineState * state, gchar * audioBuffer, guint audioBufSize) | |
320 { | |
321 XSSIDPlayFP *engine = (XSSIDPlayFP *) state->internal; | |
322 | |
323 if (!engine) | |
324 return 0; | |
325 | |
326 #if 1 | |
327 int nsamples = audioBufSize / sizeof(short); | |
328 return engine->emu.play((short *) audioBuffer, nsamples) * sizeof(short); | |
329 #else | |
330 int nsamples = audioBufSize / sizeof(short); | |
331 fprintf(stderr, "%p, %d -> %d\n", audioBuffer, audioBufSize, nsamples); | |
332 return 0; | |
333 #endif | |
334 } | |
335 | |
336 | |
337 /* Load a given SID-tune file | |
338 */ | |
339 gboolean xs_sidplayfp_load(XSEngineState * state, gchar * filename) | |
340 { | |
341 XSSIDPlayFP *engine = (XSSIDPlayFP *) state->internal; | |
342 | |
343 if (!engine || !filename) | |
344 return FALSE; | |
345 | |
346 engine->tune.load(filename); | |
347 if (!engine->tune) | |
348 { | |
349 xs_error("Could not load file '%s': %s\n", | |
350 filename, (engine->tune.getInfo()).statusString); | |
351 return FALSE; | |
352 } | |
353 | |
354 return TRUE; | |
355 } | |
356 | |
357 | |
358 /* Delete INTERNAL information | |
359 */ | |
360 void xs_sidplayfp_delete(XSEngineState * state) | |
361 { | |
362 XSSIDPlayFP *engine = (XSSIDPlayFP *) state->internal; | |
363 } | |
364 | |
365 | |
366 /* Hardware backend flushing | |
367 */ | |
368 void xs_sidplayfp_flush(XSEngineState * state) | |
369 { | |
370 XSSIDPlayFP *engine = (XSSIDPlayFP *) state->internal; | |
371 | |
372 #ifdef HAVE_HARDSID_BUILDER | |
373 if (xs_cfg.sid2Builder == XS_BLD_HARDSID) | |
374 { | |
375 ((HardSIDBuilder *) engine->config.sidEmulation)->flush(); | |
376 } | |
377 #endif | |
378 } | |
379 | |
380 | |
381 } /* extern "C" */ | |
382 #endif /* HAVE_SIDPLAY2_FP */ |