comparison src/xmms-sid.cc @ 1:183e7cbc1036

Initial revision
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 03 Jun 2003 10:23:04 +0000
parents
children 5b7009eef767
comparison
equal deleted inserted replaced
0:5ce0a94edc2e 1:183e7cbc1036
1 /*
2 xmms-sid - SIDPlay input plugin for X MultiMedia System (XMMS)
3
4 Main source file
5
6 Originally by Willem Monsuwe <willem@stack.nl>
7 Additions, fixes, etc by Matti "ccr" Hamalainen <mhamalai@ratol.fi>
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
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24 #include "xmms-sid.h"
25 #include <sidplay/player.h>
26 #include <sidplay/myendian.h>
27 #include <sidplay/fformat.h>
28
29
30 extern "C" {
31 #include <pthread.h>
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdio.h>
36
37 #include <xmms/plugin.h>
38 #include <xmms/util.h>
39 }
40
41
42 /*
43 * General variables
44 */
45 static struct emuConfig xs_emuConf;
46 static emuEngine xs_emuEngine;
47 static pthread_t xs_decode_thread;
48 static int xs_error = 0, xs_going = 0, xs_songs = 0;
49 struct T_sid_cfg xs_cfg;
50
51
52 /*
53 * Initialize xmms-sid plugin
54 */
55 void xs_init(void)
56 {
57
58 if (!xs_emuEngine) {
59 xs_error = 1;
60 XSERR("Couldn't start SIDPlay emulator engine!\n");
61 return;
62 }
63
64 if (!xs_emuEngine.verifyEndianess()) {
65 xs_error = 1;
66 XSERR("Wrong hardware endianess (SIDPlay error)!\n");
67 return;
68 }
69
70 // Initialize STIL structures
71 memset(&xs_stil_info, 0, sizeof(xs_stil_info));
72 xs_stil_clear();
73
74 // Get configuration
75 xs_get_configure();
76 }
77
78
79 /*
80 * Special, custom hand-made strcpy with smooth leather coating.
81 */
82 int xs_strcpy(char *dest, const char *src, unsigned int *j)
83 {
84 unsigned int i;
85
86 if ((dest == NULL) || (src == NULL)) return -1;
87
88 for (i = 0; i < strlen(src); i++) {
89 dest[(*j)++] = src[i];
90 }
91
92 return 0;
93 }
94
95
96 /*
97 Create the SID-tune description string from the
98 tune's information formatted by the user-specified
99 format-string.
100 */
101 static char * xs_make_filedesc(struct sidTuneInfo *s)
102 {
103 unsigned int i, len, j;
104 char *result;
105
106 /* Check the info strings */
107 if (s->numberOfInfoStrings != 3) {
108 if (s->numberOfInfoStrings < 1) {
109 return 0;
110 }
111 return g_strdup(s->infoString[0]);
112 }
113
114 /* Check the format-string for NULL */
115 if (xs_cfg.fileInfo == NULL) {
116 return g_strdup_printf("%s - %s", s->nameString, s->authorString);
117 }
118
119 /* Pre-calculate the length of the result-string */
120 len = 2;
121 for (i = 0; i < strlen(xs_cfg.fileInfo); i++) {
122 if (xs_cfg.fileInfo[i] == '%') {
123 switch (xs_cfg.fileInfo[++i]) {
124 case '1': len += strlen(s->authorString); break;
125 case '2': len += strlen(s->nameString); break;
126 case '3': len += strlen(s->copyrightString); break;
127 case '4': len += strlen(s->formatString); break;
128 }
129 } else len++;
130 }
131
132 /* Allocate the result-string */
133 result = (char *) g_malloc(len);
134
135 /* Construct the final result info */
136 j = 0;
137 for (i = 0; i < strlen(xs_cfg.fileInfo); i++) {
138
139 if (xs_cfg.fileInfo[i] == '%') {
140 switch (xs_cfg.fileInfo[++i]) {
141 case '1': xs_strcpy(result, s->authorString, &j); break;
142 case '2': xs_strcpy(result, s->nameString, &j); break;
143 case '3': xs_strcpy(result, s->copyrightString, &j); break;
144 case '4': xs_strcpy(result, s->formatString, &j); break;
145 }
146
147 } else {
148 result[j++] = xs_cfg.fileInfo[i];
149 } /* if */
150
151 } /* for */
152
153 result[j] = '\0';
154
155 return result;
156 }
157
158
159 /*
160 * Check whether the given file is handled by this plugin
161 */
162 int xs_is_our_file(char *filename)
163 {
164 if (xs_cfg.detectMagic) {
165 sidTune *t = new sidTune(filename);
166
167 if (!t->getStatus()) {
168 delete t;
169 return FALSE;
170 }
171
172 delete t;
173 return TRUE;
174 }
175
176 char *ext = strrchr(filename, '.');
177 if (ext) {
178 ext++;
179 if (!strcasecmp(ext, "psid")) return TRUE;
180 if (!strcasecmp(ext, "sid")) return TRUE;
181 if (!strcasecmp(ext, "dat")) return TRUE;
182 if (!strcasecmp(ext, "inf")) return TRUE;
183 if (!strcasecmp(ext, "info")) return TRUE;
184 }
185 return FALSE;
186 }
187
188
189 /*
190 * Playing thread loop function
191 */
192 static void * xs_play_loop(void *arg)
193 {
194 sidTune *tune = (sidTune *)arg;
195 char data[XMMS_SID_BUFSIZE];
196 int fxlen, tn;
197 struct sidTuneInfo sidInf;
198 char *name;
199 enum AFormat fmt = (xs_emuConf.bitsPerSample == 16) ? FMT_S16_NE : FMT_U8;
200 gint chn = xs_emuConf.channels;
201
202 tune->getInfo(sidInf);
203 name = xs_make_filedesc(&sidInf);
204
205 play_loop_new_tune:
206 tn = xs_going;
207 if (tn <= 0) tn = 1;
208 if (!xmms_sid_ip.output->open_audio(fmt, xs_emuConf.frequency, chn))
209 {
210 xs_error = 1;
211 XSERR("Couldn't open XMMS audio output!\n");
212 delete tune;
213 pthread_exit(NULL);
214 xs_stop();
215 }
216
217 if (!sidEmuInitializeSong(xs_emuEngine, *tune, tn)) {
218 xs_error = 1;
219 XSERR("Couldn't initialize SIDPlay emulator engine!\n");
220 delete tune;
221 pthread_exit(NULL);
222 xs_stop();
223 }
224
225 tune->getInfo(sidInf);
226
227 xmms_sid_ip.set_info(name, -1,
228 1000 * (sidInf.songSpeed ? sidInf.songSpeed : (sidInf.clockSpeed == SIDTUNE_CLOCK_NTSC) ? 60 : 50),
229 xs_emuConf.frequency, chn);
230
231 while (xs_going == tn)
232 {
233 fxlen = XMMS_SID_BUFSIZE;
234 sidEmuFillBuffer(xs_emuEngine, *tune, data, fxlen);
235
236 xmms_sid_ip.add_vis_pcm(xmms_sid_ip.output->written_time(),
237 fmt, chn, fxlen, data);
238
239 while ((xs_going == tn) && (xmms_sid_ip.output->buffer_free() < fxlen))
240 xmms_usleep(10000);
241
242 if (xs_going == tn)
243 xmms_sid_ip.output->write_audio(data, fxlen);
244 }
245
246 /* Exit the playing thread */
247 xmms_sid_ip.output->close_audio();
248
249 if (xs_going) goto play_loop_new_tune;
250
251 g_free(name);
252
253 delete tune;
254
255 pthread_exit(NULL);
256 }
257
258
259 /*
260 * Start playing the given file
261 */
262 void xs_play_file(char *filename)
263 {
264 sidTune *tune = new sidTune(filename);
265 struct sidTuneInfo sidInf;
266
267 /* Get current configuration */
268 xs_emuEngine.getConfig(xs_emuConf);
269
270 /* Configure channels and stuff */
271 switch (xs_cfg.channels) {
272
273 case XMMS_SID_CHN_AUTOPAN:
274 xs_emuConf.channels = SIDEMU_STEREO;
275 xs_emuConf.autoPanning = SIDEMU_CENTEREDAUTOPANNING;
276 xs_emuConf.volumeControl = SIDEMU_FULLPANNING;
277 break;
278
279 case XMMS_SID_CHN_STEREO:
280 xs_emuConf.channels = SIDEMU_STEREO;
281 xs_emuConf.autoPanning = SIDEMU_NONE;
282 xs_emuConf.volumeControl = SIDEMU_NONE;
283 break;
284
285 case XMMS_SID_CHN_MONO:
286 xs_emuConf.channels = SIDEMU_MONO;
287 xs_emuConf.autoPanning = SIDEMU_NONE;
288 xs_emuConf.volumeControl = SIDEMU_NONE;
289 break;
290
291 default:xs_error = 1;
292 XSERR("Internal: Invalid channels setting. Please report to author!\n");
293 delete tune;
294 break;
295 }
296
297 /* Memory mode settings */
298 switch (xs_cfg.memoryMode) {
299 case XMMS_SID_MPU_BANK_SWITCHING:
300 xs_emuConf.memoryMode = MPU_BANK_SWITCHING;
301 break;
302
303 case XMMS_SID_MPU_TRANSPARENT_ROM:
304 xs_emuConf.memoryMode = MPU_TRANSPARENT_ROM;
305 break;
306
307 case XMMS_SID_MPU_PLAYSID_ENVIRONMENT:
308 xs_emuConf.memoryMode = MPU_PLAYSID_ENVIRONMENT;
309 break;
310
311 default:xs_error = 1;
312 XSERR("Internal: Invalid memoryMode setting. Please report to author!\n");
313 delete tune;
314 break;
315 }
316
317
318 /* Clockspeed settings */
319 switch (xs_cfg.clockSpeed) {
320 case XMMS_SID_CLOCK_PAL:
321 xs_emuConf.clockSpeed = SIDTUNE_CLOCK_PAL;
322 break;
323
324 case XMMS_SID_CLOCK_NTSC:
325 xs_emuConf.clockSpeed = SIDTUNE_CLOCK_NTSC;
326 break;
327
328 default:xs_error = 1;
329 XSERR("Internal: Invalid clockSpeed setting. Please report to author!\n");
330 delete tune;
331 break;
332 }
333
334 /* Configure rest of the paske */
335 xs_emuConf.bitsPerSample = xs_cfg.bitsPerSample;
336 xs_emuConf.frequency = xs_cfg.frequency;
337 xs_emuConf.sampleFormat = SIDEMU_SIGNED_PCM;
338 xs_emuConf.mos8580 = xs_cfg.mos8580;
339 xs_emuConf.emulateFilter = xs_cfg.emulateFilter;
340 xs_emuConf.filterFs = xs_cfg.filterFs;
341 xs_emuConf.filterFm = xs_cfg.filterFm;
342 xs_emuConf.filterFt = xs_cfg.filterFt;
343
344 /* Now set the emulator configuration */
345 xs_emuEngine.setConfig(xs_emuConf);
346 tune->getInfo(sidInf);
347 xs_error = 0;
348 xs_going = sidInf.startSong;
349 xs_songs = sidInf.songs;
350
351 /* Start the playing thread! */
352 if (pthread_create(&xs_decode_thread, NULL, xs_play_loop, tune) < 0) {
353 xs_error = 1;
354 XSERR("Couldn't start playing thread!\n");
355 delete tune;
356 }
357 }
358
359
360 /*
361 * Stop playing
362 */
363 void xs_stop(void)
364 {
365 if (xs_going)
366 {
367 xs_going = 0;
368 pthread_join(xs_decode_thread, NULL);
369 }
370 }
371
372
373 /*
374 * Pause the playing
375 */
376 void xs_pause(short p)
377 {
378 xmms_sid_ip.output->pause(p);
379 }
380
381
382 /*
383 * Set the time-seek position
384 * (the playing thread will do the "seeking" aka song-change)
385 */
386 void xs_seek(int time)
387 {
388 if ((time > 0) && (time <= xs_songs)) {
389 xs_going = time;
390 }
391 }
392
393
394 /*
395 * Return the playing "position/time" aka song number
396 */
397 int xs_get_time(void)
398 {
399 if (xs_error) return -2;
400 if (!xs_going) return -1;
401 #ifdef HAVE_SONG_POSITION
402 set_song_position(xs_going, 1, xs_songs);
403 #endif
404 return xmms_sid_ip.output->output_time();
405 }
406
407
408 /*
409 * Return song information
410 */
411 void xs_get_song_info(char *filename, char **title, int *length)
412 {
413 struct sidTuneInfo sidInf;
414 sidTune t(filename);
415
416 if (!t) return;
417
418 t.getInfo(sidInf);
419
420 *title = xs_make_filedesc(&sidInf);
421
422 *length = -1;
423 }
424
425