comparison src/xmms-sid.cc @ 5:5b7009eef767

Updated to 0.8
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 03 Jun 2003 11:07:00 +0000
parents 183e7cbc1036
children ac2972a7ccd5
comparison
equal deleted inserted replaced
4:4bb09e405eab 5:5b7009eef767
1 /* 1 /*
2 xmms-sid - SIDPlay input plugin for X MultiMedia System (XMMS) 2 XMMS-SID - SIDPlay input plugin for X MultiMedia System (XMMS)
3 3
4 Main source file 4 Main source file
5 5
6 Originally by Willem Monsuwe <willem@stack.nl> 6 Written by Matti "ccr" Hamalainen <ccr@tnsp.org>
7 Additions, fixes, etc by Matti "ccr" Hamalainen <mhamalai@ratol.fi> 7 (few bits may still be by Willem Monsuwe)
8 8
9 This program is free software; you can redistribute it and/or modify 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 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 11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version. 12 (at your option) any later version.
24 #include "xmms-sid.h" 24 #include "xmms-sid.h"
25 #include <sidplay/player.h> 25 #include <sidplay/player.h>
26 #include <sidplay/myendian.h> 26 #include <sidplay/myendian.h>
27 #include <sidplay/fformat.h> 27 #include <sidplay/fformat.h>
28 28
29
30 extern "C" { 29 extern "C" {
31 #include <pthread.h> 30 #include <pthread.h>
32 31
33 #include <stdlib.h> 32 #include <stdlib.h>
34 #include <string.h> 33 #include <string.h>
35 #include <stdio.h> 34 #include <stdio.h>
35 #include <errno.h>
36 36
37 #include <xmms/plugin.h> 37 #include <xmms/plugin.h>
38 #include <xmms/util.h> 38 #include <xmms/util.h>
39 } 39 }
40 40
41 41
42 /* 42 /*
43 * General variables 43 * Global variables
44 */ 44 */
45 static struct emuConfig xs_emuConf; 45 static struct emuConfig xs_emuConf;
46 static emuEngine xs_emuEngine; 46 static emuEngine xs_emuEngine;
47 static pthread_t xs_decode_thread; 47 static pthread_t xs_decode_thread;
48 static int xs_error = 0, xs_going = 0, xs_songs = 0; 48 struct t_xs_cfg xs_cfg;
49 struct T_sid_cfg xs_cfg; 49
50 50 struct {
51 51 int s_error, s_playing, s_songs, s_allownext;
52 /* 52 sidTune *s_tune;
53 * Initialize xmms-sid plugin 53 gchar *s_fname;
54 } xs_status;
55
56 pthread_mutex_t xs_mutex = PTHREAD_MUTEX_INITIALIZER;
57
58
59 /*
60 * Initialize XMMS-SID
54 */ 61 */
55 void xs_init(void) 62 void xs_init(void)
56 { 63 {
57 64 XSDEBUG("xs_init()\n");
58 if (!xs_emuEngine) { 65
59 xs_error = 1; 66 /* Try to initialize libSIDPlay */
60 XSERR("Couldn't start SIDPlay emulator engine!\n"); 67 if (!xs_emuEngine)
61 return; 68 {
62 } 69 XSERR("Couldn't start SIDPlay emulator engine!\n");
63 70 return;
64 if (!xs_emuEngine.verifyEndianess()) { 71 }
65 xs_error = 1; 72
66 XSERR("Wrong hardware endianess (SIDPlay error)!\n"); 73 if (!xs_emuEngine.verifyEndianess())
67 return; 74 {
68 } 75 XSERR("Wrong hardware endianess (SIDPlay error)!\n");
69 76 return;
70 // Initialize STIL structures 77 }
71 memset(&xs_stil_info, 0, sizeof(xs_stil_info)); 78
72 xs_stil_clear(); 79 /* Initialize and get configuration */
73 80 memset(&xs_cfg, 0, sizeof(xs_cfg));
74 // Get configuration 81 xs_get_configure();
75 xs_get_configure(); 82
76 } 83 xs_status.s_error = 0;
77 84 xs_status.s_playing = 0;
78 85 xs_status.s_songs = 0;
79 /* 86 xs_status.s_allownext = 1; // Initialize to TRUE to allow first song
80 * Special, custom hand-made strcpy with smooth leather coating. 87 xs_status.s_tune = NULL;
81 */ 88 xs_status.s_fname = NULL;
82 int xs_strcpy(char *dest, const char *src, unsigned int *j) 89
83 { 90 /* Initialize STIL structures */
84 unsigned int i; 91 // FIXME FIXME FIx ME
85 92
86 if ((dest == NULL) || (src == NULL)) return -1; 93 /* Create sub-song control window */
87 94 // FIX ME FIXME
88 for (i = 0; i < strlen(src); i++) { 95 }
89 dest[(*j)++] = src[i]; 96
90 } 97
91 98 /*
92 return 0; 99 * Shut down XMMS-SID
93 } 100 */
94 101 void xs_close(void)
95 102 {
96 /* 103 XSDEBUG("shutting down...\n");
97 Create the SID-tune description string from the 104
98 tune's information formatted by the user-specified 105 /* Stop playing */
99 format-string. 106 xmms_sid_ip.stop();
100 */ 107
101 static char * xs_make_filedesc(struct sidTuneInfo *s) 108 /* Free allocated memory */
102 { 109
103 unsigned int i, len, j; 110 // FIXME FIXME: STIL-entries, songlendb
104 char *result; 111
105 112 }
106 /* Check the info strings */ 113
107 if (s->numberOfInfoStrings != 3) { 114
108 if (s->numberOfInfoStrings < 1) { 115 /*
109 return 0; 116 * Check whether the given file is handled by this plugin
117 */
118 gint xs_is_our_file(char *fileName)
119 {
120 char *pcExt;
121
122 /* Check the filename */
123 if (fileName == NULL)
124 return FALSE;
125
126 /* Try to detect via libSIDPlay's detection routine, if required */
127 if (xs_cfg.detectMagic) {
128
129 sidTune *testTune = new sidTune(fileName);
130
131 if (!testTune) return FALSE;
132 if (!testTune->getStatus())
133 {
134 delete testTune;
135 return FALSE;
110 } 136 }
111 return g_strdup(s->infoString[0]); 137
112 } 138 delete testTune;
113 139 return TRUE;
114 /* Check the format-string for NULL */ 140 }
115 if (xs_cfg.fileInfo == NULL) { 141
116 return g_strdup_printf("%s - %s", s->nameString, s->authorString); 142
143 /* Detect just by checking filename extension */
144 pcExt = strrchr(fileName, '.');
145 if (pcExt)
146 {
147 pcExt++;
148 if (!strcasecmp(pcExt, "psid")) return TRUE;
149 if (!strcasecmp(pcExt, "sid")) return TRUE;
150 if (!strcasecmp(pcExt, "dat")) return TRUE;
151 if (!strcasecmp(pcExt, "inf")) return TRUE;
152 if (!strcasecmp(pcExt, "info")) return TRUE;
153 }
154
155 return FALSE;
156 }
157
158
159 /*
160 * Playing thread loop function
161 */
162 static void *xs_play_loop(void *argPointer)
163 {
164 gchar plr_data[XMMS_SID_BUFSIZE];
165 struct sidTuneInfo plr_sidInf;
166 gchar *plr_tune_title = NULL;
167 gint plr_fxlen;
168 enum AFormat plr_fmt;
169 gint plr_tune_num;
170 gint32 plr_tune_len;
171
172
173 /* Don't allow next song to be set yet */
174 pthread_mutex_lock(&xs_mutex);
175 xs_status.s_allownext = 0;
176 pthread_mutex_unlock(&xs_mutex);
177
178
179 /* Check tune number */
180 plr_tune_num = xs_status.s_playing;
181
182 if (plr_tune_num <= 0)
183 plr_tune_num = 1;
184
185 XSDEBUG("xs_play_loop(%d, %d)\n", plr_tune_num, xs_status.s_playing);
186
187 /* Get song information */
188 xs_status.s_tune->getInfo(plr_sidInf);
189 plr_tune_len = xs_get_length(xs_status.s_fname, plr_tune_num);
190 plr_tune_title = xs_get_filetitle(&plr_sidInf, plr_tune_num);
191
192 XSDEBUG("title='%s', len=%d\n", plr_tune_title, plr_tune_len);
193
194
195 /* Initialize audio output */
196 // FIXME FIXME: FMT_S16_XXX -- different architechtures??
197 // the patch may break something ...
198 plr_fmt = (xs_emuConf.bitsPerSample == 16) ? FMT_S16_NE : FMT_U8;
199
200
201 if (!xmms_sid_ip.output->open_audio(plr_fmt, xs_emuConf.frequency, xs_emuConf.channels))
202 {
203 pthread_mutex_lock(&xs_mutex);
204 xs_status.s_error = 1;
205 if (plr_tune_title) g_free(plr_tune_title);
206 if (xs_status.s_tune) delete xs_status.s_tune;
207 xs_status.s_allownext = 1;
208 pthread_mutex_unlock(&xs_mutex);
209 return NULL;
210 }
211
212
213 /* Initialize the SIDPlay-emulator for song */
214 if (!sidEmuInitializeSong(xs_emuEngine, *xs_status.s_tune, plr_tune_num))
215 {
216 XSERR("Couldn't initialize SIDPlay emulator engine! This may be a problem with your sound settings, or possibly a bug in XMMS-SID.\n");
217 pthread_mutex_lock(&xs_mutex);
218 xs_status.s_error = 1;
219 pthread_mutex_unlock(&xs_mutex);
220 goto pl_cleanup;
221 }
222
223
224 /* Set song title information */
225 xmms_sid_ip.set_info(
226 plr_tune_title,
227 (plr_tune_len * 1000),
228 (1000 * (plr_sidInf.songSpeed ? plr_sidInf.songSpeed : (plr_sidInf.clockSpeed == SIDTUNE_CLOCK_NTSC) ? 60 : 50)),
229 xs_emuConf.frequency,
230 xs_emuConf.channels);
231
232
233 /* Run playing loop: loop as long as xs_playing is same as current tune number */
234 while (xs_status.s_playing == plr_tune_num)
235 {
236 plr_fxlen = XMMS_SID_BUFSIZE;
237
238 /* Run emulator to fill output buffer with audio data */
239 sidEmuFillBuffer(xs_emuEngine, *xs_status.s_tune, plr_data, plr_fxlen);
240
241 /* If Max Playtime option set, check playtime */
242 if (xs_cfg.playUseMaxTime)
243 {
244 if ((xmms_sid_ip.output->output_time() / 1000) >= xs_cfg.playMaxTime)
245 {
246 pthread_mutex_lock(&xs_mutex);
247 xs_status.s_playing = 0;
248 pthread_mutex_unlock(&xs_mutex);
249 }
117 } 250 }
118 251
119 /* Pre-calculate the length of the result-string */ 252 /* Check playtime against database */
120 len = 2; 253 if (xs_cfg.playMethod == XMMS_SID_PMETHOD_DATABASE)
121 for (i = 0; i < strlen(xs_cfg.fileInfo); i++) { 254 {
122 if (xs_cfg.fileInfo[i] == '%') { 255 if ((xmms_sid_ip.output->output_time() / 1000) >= plr_tune_len)
123 switch (xs_cfg.fileInfo[++i]) { 256 {
124 case '1': len += strlen(s->authorString); break; 257 pthread_mutex_lock(&xs_mutex);
125 case '2': len += strlen(s->nameString); break; 258 xs_status.s_playing = 0;
126 case '3': len += strlen(s->copyrightString); break; 259 pthread_mutex_unlock(&xs_mutex);
127 case '4': len += strlen(s->formatString); break; 260 }
261
128 } 262 }
129 } else len++; 263 #if 0
130 } 264 else
131 265
132 /* Allocate the result-string */ 266 /* Check for silence */
133 result = (char *) g_malloc(len); 267 if (xs_cfg.playMethod == XMMS_SID_PMETHOD_MAXSILENCE)
134 268 {
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 } 269 }
146 270
147 } else { 271 /* Add static noise */
148 result[j++] = xs_cfg.fileInfo[i]; 272
149 } /* if */ 273 /* Muffle waveform (low-pass filter) */
150 274
151 } /* for */ 275 #endif
152 276
153 result[j] = '\0'; 277
154 278 /* Send audio data to visualization plugin */
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(), 279 xmms_sid_ip.add_vis_pcm(xmms_sid_ip.output->written_time(),
237 fmt, chn, fxlen, data); 280 plr_fmt, xs_emuConf.channels, plr_fxlen, plr_data);
238 281
239 while ((xs_going == tn) && (xmms_sid_ip.output->buffer_free() < fxlen)) 282 /* Wait for a while */
283 while ((xs_status.s_playing == plr_tune_num) && (xmms_sid_ip.output->buffer_free() < plr_fxlen))
240 xmms_usleep(10000); 284 xmms_usleep(10000);
241 285
242 if (xs_going == tn) 286
243 xmms_sid_ip.output->write_audio(data, fxlen); 287 /* If playing, send final audio data to output plugin */
244 } 288 if (xs_status.s_playing == plr_tune_num)
245 289 xmms_sid_ip.output->write_audio(plr_data, plr_fxlen);
246 /* Exit the playing thread */ 290
291 } /* End of playerloop */
292
293
294 pl_cleanup:
295 XSDEBUG("cleaning up...\n");
296
297 /* Cleanup & shutdown */
247 xmms_sid_ip.output->close_audio(); 298 xmms_sid_ip.output->close_audio();
248 299
249 if (xs_going) goto play_loop_new_tune; 300 if (plr_tune_title) g_free(plr_tune_title);
250 301
251 g_free(name); 302 pthread_mutex_lock(&xs_mutex);
252 303 xs_status.s_playing = 0;
253 delete tune; 304 if (xs_status.s_tune) delete xs_status.s_tune;
254 305 xs_status.s_allownext = 1;
255 pthread_exit(NULL); 306 pthread_mutex_unlock(&xs_mutex);
307
308 XSDEBUG("exiting thread, bye.\n");
309 return NULL;
256 } 310 }
257 311
258 312
259 /* 313 /*
260 * Start playing the given file 314 * Start playing the given file
261 */ 315 */
262 void xs_play_file(char *filename) 316 void xs_play_file(char *fileName)
263 { 317 {
264 sidTune *tune = new sidTune(filename); 318 sidTune *newTune;
265 struct sidTuneInfo sidInf; 319 struct sidTuneInfo sidInf;
266 320
267 /* Get current configuration */ 321 XSDEBUG("request to start '%s'\n", fileName);
268 xs_emuEngine.getConfig(xs_emuConf); 322
269 323 /* Wait until the previous song has finished for sure */
270 /* Configure channels and stuff */ 324 if (!xs_status.s_allownext)
271 switch (xs_cfg.channels) { 325 pthread_join(xs_decode_thread, NULL);
326
327 /* Try to get the tune */
328 newTune = new sidTune(fileName);
329 if (newTune == NULL) return;
330
331 XSDEBUG("tune ok, status %i\n", xs_status.s_playing);
332
333 /* Get current configuration */
334 xs_emuEngine.getConfig(xs_emuConf);
335
336
337 /* Configure channels and stuff */
338 switch (xs_cfg.fmtChannels) {
272 339
273 case XMMS_SID_CHN_AUTOPAN: 340 case XMMS_SID_CHN_AUTOPAN:
274 xs_emuConf.channels = SIDEMU_STEREO; 341 xs_emuConf.channels = SIDEMU_STEREO;
275 xs_emuConf.autoPanning = SIDEMU_CENTEREDAUTOPANNING; 342 xs_emuConf.autoPanning = SIDEMU_CENTEREDAUTOPANNING;
276 xs_emuConf.volumeControl = SIDEMU_FULLPANNING; 343 xs_emuConf.volumeControl = SIDEMU_FULLPANNING;
286 xs_emuConf.channels = SIDEMU_MONO; 353 xs_emuConf.channels = SIDEMU_MONO;
287 xs_emuConf.autoPanning = SIDEMU_NONE; 354 xs_emuConf.autoPanning = SIDEMU_NONE;
288 xs_emuConf.volumeControl = SIDEMU_NONE; 355 xs_emuConf.volumeControl = SIDEMU_NONE;
289 break; 356 break;
290 357
291 default:xs_error = 1; 358 default:
292 XSERR("Internal: Invalid channels setting. Please report to author!\n"); 359 XSERR("Internal: Invalid channels setting. Possibly corrupted configuration file.\n");
293 delete tune; 360 delete newTune;
294 break; 361 return;
295 } 362 }
296 363
297 /* Memory mode settings */ 364 /* Memory mode settings */
298 switch (xs_cfg.memoryMode) { 365 switch (xs_cfg.memoryMode) {
299 case XMMS_SID_MPU_BANK_SWITCHING: 366 case XMMS_SID_MPU_BANK_SWITCHING:
300 xs_emuConf.memoryMode = MPU_BANK_SWITCHING; 367 xs_emuConf.memoryMode = MPU_BANK_SWITCHING;
301 break; 368 break;
302 369
303 case XMMS_SID_MPU_TRANSPARENT_ROM: 370 case XMMS_SID_MPU_TRANSPARENT_ROM:
306 373
307 case XMMS_SID_MPU_PLAYSID_ENVIRONMENT: 374 case XMMS_SID_MPU_PLAYSID_ENVIRONMENT:
308 xs_emuConf.memoryMode = MPU_PLAYSID_ENVIRONMENT; 375 xs_emuConf.memoryMode = MPU_PLAYSID_ENVIRONMENT;
309 break; 376 break;
310 377
311 default:xs_error = 1; 378 default:
312 XSERR("Internal: Invalid memoryMode setting. Please report to author!\n"); 379 XSERR("Internal: Invalid memoryMode setting. Possibly corrupted configuration file.\n");
313 delete tune; 380 delete newTune;
314 break; 381 return;
315 } 382 }
316 383
317 384
318 /* Clockspeed settings */ 385 /* Clockspeed settings */
319 switch (xs_cfg.clockSpeed) { 386 switch (xs_cfg.clockSpeed) {
320 case XMMS_SID_CLOCK_PAL: 387 case XMMS_SID_CLOCK_PAL:
321 xs_emuConf.clockSpeed = SIDTUNE_CLOCK_PAL; 388 xs_emuConf.clockSpeed = SIDTUNE_CLOCK_PAL;
322 break; 389 break;
323 390
324 case XMMS_SID_CLOCK_NTSC: 391 case XMMS_SID_CLOCK_NTSC:
325 xs_emuConf.clockSpeed = SIDTUNE_CLOCK_NTSC; 392 xs_emuConf.clockSpeed = SIDTUNE_CLOCK_NTSC;
326 break; 393 break;
327 394
328 default:xs_error = 1; 395 default:
329 XSERR("Internal: Invalid clockSpeed setting. Please report to author!\n"); 396 XSERR("Internal: Invalid clockSpeed setting. Possibly corrupted configuration file.\n");
330 delete tune; 397 delete newTune;
331 break; 398 return;
332 } 399 }
333 400
334 /* Configure rest of the paske */ 401
335 xs_emuConf.bitsPerSample = xs_cfg.bitsPerSample; 402 /* Configure rest of the emulation */
336 xs_emuConf.frequency = xs_cfg.frequency; 403 xs_emuConf.bitsPerSample = xs_cfg.fmtBitsPerSample;
337 xs_emuConf.sampleFormat = SIDEMU_SIGNED_PCM; 404 xs_emuConf.frequency = xs_cfg.fmtFrequency;
338 xs_emuConf.mos8580 = xs_cfg.mos8580; 405 xs_emuConf.sampleFormat = SIDEMU_SIGNED_PCM;
339 xs_emuConf.emulateFilter = xs_cfg.emulateFilter; 406 xs_emuConf.mos8580 = xs_cfg.mos8580;
340 xs_emuConf.filterFs = xs_cfg.filterFs; 407 xs_emuConf.emulateFilter = xs_cfg.emulateFilter;
341 xs_emuConf.filterFm = xs_cfg.filterFm; 408 xs_emuConf.filterFs = xs_cfg.filterFs;
342 xs_emuConf.filterFt = xs_cfg.filterFt; 409 xs_emuConf.filterFm = xs_cfg.filterFm;
343 410 xs_emuConf.filterFt = xs_cfg.filterFt;
344 /* Now set the emulator configuration */ 411
345 xs_emuEngine.setConfig(xs_emuConf); 412 XSDEBUG("configuring engine..\n");
346 tune->getInfo(sidInf); 413
347 xs_error = 0; 414 /* Now set the emulator configuration */
348 xs_going = sidInf.startSong; 415 xs_emuEngine.setConfig(xs_emuConf);
349 xs_songs = sidInf.songs; 416 newTune->getInfo(sidInf);
350 417
351 /* Start the playing thread! */ 418 pthread_mutex_lock(&xs_mutex);
352 if (pthread_create(&xs_decode_thread, NULL, xs_play_loop, tune) < 0) { 419 xs_status.s_error = 0;
353 xs_error = 1; 420 xs_status.s_playing = sidInf.startSong;
354 XSERR("Couldn't start playing thread!\n"); 421 xs_status.s_songs = sidInf.songs;
355 delete tune; 422 xs_status.s_tune = newTune;
356 } 423 pthread_mutex_unlock(&xs_mutex);
357 } 424
358 425 XSDEBUG("starting thread!\n");
359 426
360 /* 427 /* Start the playing thread! */
361 * Stop playing 428 if (pthread_create(&xs_decode_thread, NULL, xs_play_loop, NULL) < 0)
429 {
430 XSERR("Couldn't start playing thread! Possible reason reported by system: %s\n", strerror(errno));
431 delete newTune;
432 }
433
434 /* Exit */
435 }
436
437
438 /*
439 * Stop playing
362 */ 440 */
363 void xs_stop(void) 441 void xs_stop(void)
364 { 442 {
365 if (xs_going) 443 /* If playing, stop. */
366 { 444 if (xs_status.s_playing)
367 xs_going = 0; 445 {
368 pthread_join(xs_decode_thread, NULL); 446 pthread_mutex_lock(&xs_mutex);
369 } 447 xs_status.s_playing = 0;
370 } 448 pthread_mutex_unlock(&xs_mutex);
371 449
372 450 pthread_join(xs_decode_thread, NULL);
373 /* 451 }
374 * Pause the playing 452 }
375 */ 453
376 void xs_pause(short p) 454
377 { 455 /*
378 xmms_sid_ip.output->pause(p); 456 * Pause the playing
379 } 457 */
380 458 void xs_pause(short pauseState)
381 459 {
382 /* 460 xmms_sid_ip.output->pause(pauseState);
383 * Set the time-seek position 461 }
384 * (the playing thread will do the "seeking" aka song-change) 462
385 */ 463
386 void xs_seek(int time) 464 /*
387 { 465 * Set the time-seek position
388 if ((time > 0) && (time <= xs_songs)) { 466 * (the playing thread will do the "seeking" aka song-change)
389 xs_going = time; 467 */
390 } 468 void xs_seek(int iTime)
391 } 469 {
392 470 #ifdef HAVE_SONG_POSITION
393 471 if ((iTime > 0) && (iTime <= xs_songs))
394 /* 472 {
395 * Return the playing "position/time" aka song number 473 pthread_mutex_lock(&xs_mutex);
474 xs_status.s_playing = iTime;
475 pthread_mutex_unlock(&xs_mutex);
476 }
477 #endif
478 }
479
480
481 /*
482 * Return the playing "position/time"
396 */ 483 */
397 int xs_get_time(void) 484 int xs_get_time(void)
398 { 485 {
399 if (xs_error) return -2; 486 if (xs_status.s_error)
400 if (!xs_going) return -1; 487 return -2;
488
489 if (!xs_status.s_playing)
490 return -1;
491
401 #ifdef HAVE_SONG_POSITION 492 #ifdef HAVE_SONG_POSITION
402 set_song_position(xs_going, 1, xs_songs); 493 set_song_position(xs_status.s_playing, 1, xs_status.s_songs);
403 #endif 494 #endif
404 return xmms_sid_ip.output->output_time(); 495
405 } 496 return xmms_sid_ip.output->output_time();
406 497 }
407 498
408 /* 499
409 * Return song information 500 /*
410 */ 501 * Return song information
411 void xs_get_song_info(char *filename, char **title, int *length) 502 */
412 { 503 void xs_get_song_info(char *songFilename, char **songTitle, int *songLength)
413 struct sidTuneInfo sidInf; 504 {
414 sidTune t(filename); 505 struct sidTuneInfo sidInf;
415 506 sidTune *testTune = new sidTune(songFilename);
416 if (!t) return; 507
417 508 /* Check if the tune exists and is readable */
418 t.getInfo(sidInf); 509 if (!testTune) return;
419 510 if (!testTune->getStatus())
420 *title = xs_make_filedesc(&sidInf); 511 {
421 512 delete testTune;
422 *length = -1; 513 return;
423 } 514 }
424 515
425 516 /* Get general tune information */
517 testTune->getInfo(sidInf);
518 delete testTune;
519
520 /* Get titlestring */
521 *songTitle = xs_get_filetitle(&sidInf, sidInf.startSong);
522
523 /* Get song length (in seconds), negative if no known length */
524 *songLength = xs_get_length(songFilename, sidInf.startSong);
525 }
526