comparison src/xmms-sid.c @ 660:b0743dc9165d

Change tabs to 4 spaces, everywhere.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 02 Apr 2008 22:10:05 +0300
parents 04ea91a61225
children f22a708d29fd
comparison
equal deleted inserted replaced
659:04ea91a61225 660:b0743dc9165d
56 /* 56 /*
57 * List of players and links to their functions 57 * List of players and links to their functions
58 */ 58 */
59 static const xs_player_t xs_playerlist[] = { 59 static const xs_player_t xs_playerlist[] = {
60 #ifdef HAVE_SIDPLAY1 60 #ifdef HAVE_SIDPLAY1
61 {XS_ENG_SIDPLAY1, 61 {XS_ENG_SIDPLAY1,
62 xs_sidplay1_probe, 62 xs_sidplay1_probe,
63 xs_sidplay1_init, xs_sidplay1_close, 63 xs_sidplay1_init, xs_sidplay1_close,
64 xs_sidplay1_initsong, xs_sidplay1_fillbuffer, 64 xs_sidplay1_initsong, xs_sidplay1_fillbuffer,
65 xs_sidplay1_load, xs_sidplay1_delete, 65 xs_sidplay1_load, xs_sidplay1_delete,
66 xs_sidplay1_getinfo, xs_sidplay1_updateinfo, 66 xs_sidplay1_getinfo, xs_sidplay1_updateinfo,
67 NULL 67 NULL
68 }, 68 },
69 #endif 69 #endif
70 #ifdef HAVE_SIDPLAY2 70 #ifdef HAVE_SIDPLAY2
71 {XS_ENG_SIDPLAY2, 71 {XS_ENG_SIDPLAY2,
72 xs_sidplay2_probe, 72 xs_sidplay2_probe,
73 xs_sidplay2_init, xs_sidplay2_close, 73 xs_sidplay2_init, xs_sidplay2_close,
74 xs_sidplay2_initsong, xs_sidplay2_fillbuffer, 74 xs_sidplay2_initsong, xs_sidplay2_fillbuffer,
75 xs_sidplay2_load, xs_sidplay2_delete, 75 xs_sidplay2_load, xs_sidplay2_delete,
76 xs_sidplay2_getinfo, xs_sidplay2_updateinfo, 76 xs_sidplay2_getinfo, xs_sidplay2_updateinfo,
77 xs_sidplay2_flush 77 xs_sidplay2_flush
78 }, 78 },
79 #endif 79 #endif
80 }; 80 };
81 81
82 const gint xs_nplayerlist = (sizeof(xs_playerlist) / sizeof(xs_playerlist[0])); 82 const gint xs_nplayerlist = (sizeof(xs_playerlist) / sizeof(xs_playerlist[0]));
83 83
91 91
92 static GtkWidget *xs_subctrl = NULL; 92 static GtkWidget *xs_subctrl = NULL;
93 static GtkObject *xs_subctrl_adj = NULL; 93 static GtkObject *xs_subctrl_adj = NULL;
94 XS_MUTEX(xs_subctrl); 94 XS_MUTEX(xs_subctrl);
95 95
96 void xs_subctrl_close(void); 96 void xs_subctrl_close(void);
97 void xs_subctrl_update(void); 97 void xs_subctrl_update(void);
98 98
99 99
100 /* 100 /*
101 * Error messages 101 * Error messages
102 */ 102 */
103 void xs_error(const char *fmt, ...) 103 void xs_error(const char *fmt, ...)
104 { 104 {
105 va_list ap; 105 va_list ap;
106 fprintf(stderr, "XMMS-SID: "); 106 fprintf(stderr, "XMMS-SID: ");
107 va_start(ap, fmt); 107 va_start(ap, fmt);
108 vfprintf(stderr, fmt, ap); 108 vfprintf(stderr, fmt, ap);
109 va_end(ap); 109 va_end(ap);
110 } 110 }
111 111
112 #ifndef DEBUG_NP 112 #ifndef DEBUG_NP
113 void XSDEBUG(const char *fmt, ...) 113 void XSDEBUG(const char *fmt, ...)
114 { 114 {
115 #ifdef DEBUG 115 #ifdef DEBUG
116 va_list ap; 116 va_list ap;
117 fprintf(stderr, "XSDEBUG: "); 117 fprintf(stderr, "XSDEBUG: ");
118 va_start(ap, fmt); 118 va_start(ap, fmt);
119 vfprintf(stderr, fmt, ap); 119 vfprintf(stderr, fmt, ap);
120 va_end(ap); 120 va_end(ap);
121 #endif 121 #endif
122 } 122 }
123 #endif 123 #endif
124 124
125 125
126 /* 126 /*
127 * Initialization functions 127 * Initialization functions
128 */ 128 */
129 void xs_reinit(void) 129 void xs_reinit(void)
130 { 130 {
131 gint iPlayer; 131 gint iPlayer;
132 gboolean isInitialized; 132 gboolean isInitialized;
133 133
134 /* Stop playing, if we are */ 134 /* Stop playing, if we are */
135 XS_MUTEX_LOCK(xs_status); 135 XS_MUTEX_LOCK(xs_status);
136 if (xs_status.isPlaying) { 136 if (xs_status.isPlaying) {
137 XS_MUTEX_UNLOCK(xs_status); 137 XS_MUTEX_UNLOCK(xs_status);
138 xs_stop(); 138 xs_stop();
139 } else { 139 } else {
140 XS_MUTEX_UNLOCK(xs_status); 140 XS_MUTEX_UNLOCK(xs_status);
141 } 141 }
142 142
143 XS_MUTEX_LOCK(xs_status); 143 XS_MUTEX_LOCK(xs_status);
144 XS_MUTEX_LOCK(xs_cfg); 144 XS_MUTEX_LOCK(xs_cfg);
145 145
146 /* Initialize status and sanitize configuration */ 146 /* Initialize status and sanitize configuration */
147 memset(&xs_status, 0, sizeof(xs_status)); 147 memset(&xs_status, 0, sizeof(xs_status));
148 148
149 if (xs_cfg.audioFrequency < 8000) 149 if (xs_cfg.audioFrequency < 8000)
150 xs_cfg.audioFrequency = 8000; 150 xs_cfg.audioFrequency = 8000;
151 151
152 if (xs_cfg.oversampleFactor < XS_MIN_OVERSAMPLE) 152 if (xs_cfg.oversampleFactor < XS_MIN_OVERSAMPLE)
153 xs_cfg.oversampleFactor = XS_MIN_OVERSAMPLE; 153 xs_cfg.oversampleFactor = XS_MIN_OVERSAMPLE;
154 else if (xs_cfg.oversampleFactor > XS_MAX_OVERSAMPLE) 154 else if (xs_cfg.oversampleFactor > XS_MAX_OVERSAMPLE)
155 xs_cfg.oversampleFactor = XS_MAX_OVERSAMPLE; 155 xs_cfg.oversampleFactor = XS_MAX_OVERSAMPLE;
156 156
157 if (xs_cfg.audioChannels != XS_CHN_MONO) 157 if (xs_cfg.audioChannels != XS_CHN_MONO)
158 xs_cfg.oversampleEnable = FALSE; 158 xs_cfg.oversampleEnable = FALSE;
159 159
160 xs_status.audioFrequency = xs_cfg.audioFrequency; 160 xs_status.audioFrequency = xs_cfg.audioFrequency;
161 xs_status.audioBitsPerSample = xs_cfg.audioBitsPerSample; 161 xs_status.audioBitsPerSample = xs_cfg.audioBitsPerSample;
162 xs_status.audioChannels = xs_cfg.audioChannels; 162 xs_status.audioChannels = xs_cfg.audioChannels;
163 xs_status.audioFormat = -1; 163 xs_status.audioFormat = -1;
164 xs_status.oversampleEnable = xs_cfg.oversampleEnable; 164 xs_status.oversampleEnable = xs_cfg.oversampleEnable;
165 xs_status.oversampleFactor = xs_cfg.oversampleFactor; 165 xs_status.oversampleFactor = xs_cfg.oversampleFactor;
166 166
167 /* Try to initialize emulator engine */ 167 /* Try to initialize emulator engine */
168 XSDEBUG("initializing emulator engine #%i...\n", xs_cfg.playerEngine); 168 XSDEBUG("initializing emulator engine #%i...\n", xs_cfg.playerEngine);
169 169
170 iPlayer = 0; 170 iPlayer = 0;
171 isInitialized = FALSE; 171 isInitialized = FALSE;
172 while ((iPlayer < xs_nplayerlist) && !isInitialized) { 172 while ((iPlayer < xs_nplayerlist) && !isInitialized) {
173 if (xs_playerlist[iPlayer].plrIdent == xs_cfg.playerEngine) { 173 if (xs_playerlist[iPlayer].plrIdent == xs_cfg.playerEngine) {
174 if (xs_playerlist[iPlayer].plrInit(&xs_status)) { 174 if (xs_playerlist[iPlayer].plrInit(&xs_status)) {
175 isInitialized = TRUE; 175 isInitialized = TRUE;
176 xs_status.sidPlayer = (xs_player_t *) & xs_playerlist[iPlayer]; 176 xs_status.sidPlayer = (xs_player_t *) & xs_playerlist[iPlayer];
177 } 177 }
178 } 178 }
179 iPlayer++; 179 iPlayer++;
180 } 180 }
181 181
182 XSDEBUG("init#1: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer); 182 XSDEBUG("init#1: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer);
183 183
184 iPlayer = 0; 184 iPlayer = 0;
185 while ((iPlayer < xs_nplayerlist) && !isInitialized) { 185 while ((iPlayer < xs_nplayerlist) && !isInitialized) {
186 if (xs_playerlist[iPlayer].plrInit(&xs_status)) { 186 if (xs_playerlist[iPlayer].plrInit(&xs_status)) {
187 isInitialized = TRUE; 187 isInitialized = TRUE;
188 xs_status.sidPlayer = (xs_player_t *) & xs_playerlist[iPlayer]; 188 xs_status.sidPlayer = (xs_player_t *) & xs_playerlist[iPlayer];
189 xs_cfg.playerEngine = xs_playerlist[iPlayer].plrIdent; 189 xs_cfg.playerEngine = xs_playerlist[iPlayer].plrIdent;
190 } else 190 } else
191 iPlayer++; 191 iPlayer++;
192 } 192 }
193 193
194 XSDEBUG("init#2: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer); 194 XSDEBUG("init#2: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer);
195 195
196 196
197 /* Get settings back, in case the chosen emulator backend changed them */ 197 /* Get settings back, in case the chosen emulator backend changed them */
198 xs_cfg.audioFrequency = xs_status.audioFrequency; 198 xs_cfg.audioFrequency = xs_status.audioFrequency;
199 xs_cfg.audioBitsPerSample = xs_status.audioBitsPerSample; 199 xs_cfg.audioBitsPerSample = xs_status.audioBitsPerSample;
200 xs_cfg.audioChannels = xs_status.audioChannels; 200 xs_cfg.audioChannels = xs_status.audioChannels;
201 xs_cfg.oversampleEnable = xs_status.oversampleEnable; 201 xs_cfg.oversampleEnable = xs_status.oversampleEnable;
202 202
203 XS_MUTEX_UNLOCK(xs_status); 203 XS_MUTEX_UNLOCK(xs_status);
204 XS_MUTEX_UNLOCK(xs_cfg); 204 XS_MUTEX_UNLOCK(xs_cfg);
205 205
206 /* Initialize song-length database */ 206 /* Initialize song-length database */
207 xs_songlen_close(); 207 xs_songlen_close();
208 if (xs_cfg.songlenDBEnable && (xs_songlen_init() != 0)) { 208 if (xs_cfg.songlenDBEnable && (xs_songlen_init() != 0)) {
209 xs_error("Error initializing song-length database!\n"); 209 xs_error("Error initializing song-length database!\n");
210 } 210 }
211 211
212 /* Initialize STIL database */ 212 /* Initialize STIL database */
213 xs_stil_close(); 213 xs_stil_close();
214 if (xs_cfg.stilDBEnable && (xs_stil_init() != 0)) { 214 if (xs_cfg.stilDBEnable && (xs_stil_init() != 0)) {
215 xs_error("Error initializing STIL database!\n"); 215 xs_error("Error initializing STIL database!\n");
216 } 216 }
217 217
218 } 218 }
219 219
220 220
221 /* 221 /*
222 * Initialize XMMS-SID 222 * Initialize XMMS-SID
223 */ 223 */
224 void xs_init(void) 224 void xs_init(void)
225 { 225 {
226 XSDEBUG("xs_init()\n"); 226 XSDEBUG("xs_init()\n");
227 227
228 /* Initialize and get configuration */ 228 /* Initialize and get configuration */
229 xs_init_configuration(); 229 xs_init_configuration();
230 xs_read_configuration(); 230 xs_read_configuration();
231 231
232 /* Initialize subsystems */ 232 /* Initialize subsystems */
233 xs_reinit(); 233 xs_reinit();
234 234
235 XSDEBUG("OK\n"); 235 XSDEBUG("OK\n");
236 } 236 }
237 237
238 238
239 /* 239 /*
240 * Shut down XMMS-SID 240 * Shut down XMMS-SID
241 */ 241 */
242 void xs_close(void) 242 void xs_close(void)
243 { 243 {
244 XSDEBUG("xs_close(): shutting down...\n"); 244 XSDEBUG("xs_close(): shutting down...\n");
245 245
246 /* Stop playing, free structures */ 246 /* Stop playing, free structures */
247 xs_stop(); 247 xs_stop();
248 248
249 xs_tuneinfo_free(xs_status.tuneInfo); 249 xs_tuneinfo_free(xs_status.tuneInfo);
250 xs_status.tuneInfo = NULL; 250 xs_status.tuneInfo = NULL;
251 xs_status.sidPlayer->plrDeleteSID(&xs_status); 251 xs_status.sidPlayer->plrDeleteSID(&xs_status);
252 xs_status.sidPlayer->plrClose(&xs_status); 252 xs_status.sidPlayer->plrClose(&xs_status);
253 253
254 xs_songlen_close(); 254 xs_songlen_close();
255 xs_stil_close(); 255 xs_stil_close();
256 256
257 XSDEBUG("shutdown finished.\n"); 257 XSDEBUG("shutdown finished.\n");
258 } 258 }
259 259
260 260
261 /* 261 /*
262 * Check whether the given file is handled by this plugin 262 * Check whether the given file is handled by this plugin
263 */ 263 */
264 gint xs_is_our_file(gchar *pcFilename) 264 gint xs_is_our_file(gchar *pcFilename)
265 { 265 {
266 gchar *pcExt; 266 gchar *pcExt;
267 assert(xs_status.sidPlayer); 267 assert(xs_status.sidPlayer);
268 268
269 /* Check the filename */ 269 /* Check the filename */
270 if (pcFilename == NULL) 270 if (pcFilename == NULL)
271 return FALSE; 271 return FALSE;
272 272
273 /* Try to detect via detection routine, if required */ 273 /* Try to detect via detection routine, if required */
274 if (xs_cfg.detectMagic) { 274 if (xs_cfg.detectMagic) {
275 xs_file_t *f; 275 xs_file_t *f;
276 if ((f = xs_fopen(pcFilename, "rb")) != NULL) { 276 if ((f = xs_fopen(pcFilename, "rb")) != NULL) {
277 if (xs_status.sidPlayer->plrProbe(f)) 277 if (xs_status.sidPlayer->plrProbe(f))
278 return TRUE; 278 return TRUE;
279 xs_fclose(f); 279 xs_fclose(f);
280 } 280 }
281 } 281 }
282 282
283 /* Detect just by checking filename extension */ 283 /* Detect just by checking filename extension */
284 pcExt = xs_strrchr(pcFilename, '.'); 284 pcExt = xs_strrchr(pcFilename, '.');
285 if (pcExt) { 285 if (pcExt) {
286 pcExt++; 286 pcExt++;
287 switch (xs_cfg.playerEngine) { 287 switch (xs_cfg.playerEngine) {
288 case XS_ENG_SIDPLAY1: 288 case XS_ENG_SIDPLAY1:
289 case XS_ENG_SIDPLAY2: 289 case XS_ENG_SIDPLAY2:
290 if (!g_strcasecmp(pcExt, "psid")) 290 if (!g_strcasecmp(pcExt, "psid"))
291 return TRUE; 291 return TRUE;
292 if (!g_strcasecmp(pcExt, "sid")) 292 if (!g_strcasecmp(pcExt, "sid"))
293 return TRUE; 293 return TRUE;
294 if (!g_strcasecmp(pcExt, "dat")) 294 if (!g_strcasecmp(pcExt, "dat"))
295 return TRUE; 295 return TRUE;
296 if (!g_strcasecmp(pcExt, "inf")) 296 if (!g_strcasecmp(pcExt, "inf"))
297 return TRUE; 297 return TRUE;
298 if (!g_strcasecmp(pcExt, "info")) 298 if (!g_strcasecmp(pcExt, "info"))
299 return TRUE; 299 return TRUE;
300 break; 300 break;
301 } 301 }
302 } 302 }
303 303
304 return FALSE; 304 return FALSE;
305 } 305 }
306 306
307 307
308 /* 308 /*
309 * Main playing thread loop 309 * Main playing thread loop
310 */ 310 */
311 void *xs_playthread(void *argPointer) 311 void *xs_playthread(void *argPointer)
312 { 312 {
313 xs_status_t myStatus; 313 xs_status_t myStatus;
314 xs_tuneinfo_t *myTune; 314 xs_tuneinfo_t *myTune;
315 gboolean audioOpen = FALSE, doPlay = FALSE, isFound = FALSE; 315 gboolean audioOpen = FALSE, doPlay = FALSE, isFound = FALSE;
316 gint audioGot, songLength, i; 316 gint audioGot, songLength, i;
317 gchar *audioBuffer = NULL, *oversampleBuffer = NULL, *tmpTitle; 317 gchar *audioBuffer = NULL, *oversampleBuffer = NULL, *tmpTitle;
318 318
319 (void) argPointer; 319 (void) argPointer;
320 320
321 /* Initialize */ 321 /* Initialize */
322 XSDEBUG("entering player thread\n"); 322 XSDEBUG("entering player thread\n");
323 XS_MUTEX_LOCK(xs_status); 323 XS_MUTEX_LOCK(xs_status);
324 memcpy(&myStatus, &xs_status, sizeof(xs_status_t)); 324 memcpy(&myStatus, &xs_status, sizeof(xs_status_t));
325 myTune = xs_status.tuneInfo; 325 myTune = xs_status.tuneInfo;
326 for (i = 0; i <= myTune->nsubTunes; i++) 326 for (i = 0; i <= myTune->nsubTunes; i++)
327 myTune->subTunes[i].tunePlayed = FALSE; 327 myTune->subTunes[i].tunePlayed = FALSE;
328 XS_MUTEX_UNLOCK(xs_status); 328 XS_MUTEX_UNLOCK(xs_status);
329 329
330 /* Allocate audio buffer */ 330 /* Allocate audio buffer */
331 audioBuffer = (gchar *) g_malloc(XS_AUDIOBUF_SIZE); 331 audioBuffer = (gchar *) g_malloc(XS_AUDIOBUF_SIZE);
332 if (audioBuffer == NULL) { 332 if (audioBuffer == NULL) {
333 xs_error("Couldn't allocate memory for audio data buffer!\n"); 333 xs_error("Couldn't allocate memory for audio data buffer!\n");
334 goto xs_err_exit; 334 goto xs_err_exit;
335 } 335 }
336 336
337 if (myStatus.oversampleEnable) { 337 if (myStatus.oversampleEnable) {
338 oversampleBuffer = (gchar *) g_malloc(XS_AUDIOBUF_SIZE * myStatus.oversampleFactor); 338 oversampleBuffer = (gchar *) g_malloc(XS_AUDIOBUF_SIZE * myStatus.oversampleFactor);
339 if (oversampleBuffer == NULL) { 339 if (oversampleBuffer == NULL) {
340 xs_error("Couldn't allocate memory for audio oversampling buffer!\n"); 340 xs_error("Couldn't allocate memory for audio oversampling buffer!\n");
341 goto xs_err_exit; 341 goto xs_err_exit;
342 } 342 }
343 } 343 }
344 344
345 /* 345 /*
346 * Main player loop: while not stopped, loop here - play subtunes 346 * Main player loop: while not stopped, loop here - play subtunes
347 */ 347 */
348 audioOpen = FALSE; 348 audioOpen = FALSE;
349 doPlay = TRUE; 349 doPlay = TRUE;
350 while (xs_status.isPlaying && doPlay) { 350 while (xs_status.isPlaying && doPlay) {
351 /* Automatic sub-tune change logic */ 351 /* Automatic sub-tune change logic */
352 XS_MUTEX_LOCK(xs_cfg); 352 XS_MUTEX_LOCK(xs_cfg);
353 XS_MUTEX_LOCK(xs_status); 353 XS_MUTEX_LOCK(xs_status);
354 myStatus.isPlaying = TRUE; 354 myStatus.isPlaying = TRUE;
355 355
356 if (xs_status.currSong < 1 || myStatus.currSong < 1) { 356 if (xs_status.currSong < 1 || myStatus.currSong < 1) {
357 XS_MUTEX_UNLOCK(xs_status); 357 XS_MUTEX_UNLOCK(xs_status);
358 XS_MUTEX_UNLOCK(xs_cfg); 358 XS_MUTEX_UNLOCK(xs_cfg);
359 goto xs_err_exit; 359 goto xs_err_exit;
360 } 360 }
361 361
362 if (xs_cfg.subAutoEnable && (myStatus.currSong == xs_status.currSong)) { 362 if (xs_cfg.subAutoEnable && (myStatus.currSong == xs_status.currSong)) {
363 /* Check if currently selected sub-tune has been played already */ 363 /* Check if currently selected sub-tune has been played already */
364 if (myTune->subTunes[myStatus.currSong-1].tunePlayed) { 364 if (myTune->subTunes[myStatus.currSong-1].tunePlayed) {
365 /* Find a tune that has not been played */ 365 /* Find a tune that has not been played */
366 XSDEBUG("tune #%i already played, finding next match ...\n", myStatus.currSong); 366 XSDEBUG("tune #%i already played, finding next match ...\n", myStatus.currSong);
367 isFound = FALSE; 367 isFound = FALSE;
368 i = 0; 368 i = 0;
369 while (!isFound && (++i <= myTune->nsubTunes)) { 369 while (!isFound && (++i <= myTune->nsubTunes)) {
370 if (xs_cfg.subAutoMinOnly) { 370 if (xs_cfg.subAutoMinOnly) {
371 /* A tune with minimum length must be found */ 371 /* A tune with minimum length must be found */
372 if (!myTune->subTunes[i-1].tunePlayed && 372 if (!myTune->subTunes[i-1].tunePlayed &&
373 myTune->subTunes[i-1].tuneLength >= xs_cfg.subAutoMinTime) 373 myTune->subTunes[i-1].tuneLength >= xs_cfg.subAutoMinTime)
374 isFound = TRUE; 374 isFound = TRUE;
375 } else { 375 } else {
376 /* Any unplayed tune is okay */ 376 /* Any unplayed tune is okay */
377 if (!myTune->subTunes[i-1].tunePlayed) 377 if (!myTune->subTunes[i-1].tunePlayed)
378 isFound = TRUE; 378 isFound = TRUE;
379 } 379 }
380 } 380 }
381 381
382 if (isFound) { 382 if (isFound) {
383 /* Set the new sub-tune */ 383 /* Set the new sub-tune */
384 XSDEBUG("found #%i\n", i); 384 XSDEBUG("found #%i\n", i);
385 xs_status.currSong = i; 385 xs_status.currSong = i;
386 } else 386 } else
387 /* This is the end */ 387 /* This is the end */
388 doPlay = FALSE; 388 doPlay = FALSE;
389 389
390 XS_MUTEX_UNLOCK(xs_status); 390 XS_MUTEX_UNLOCK(xs_status);
391 XS_MUTEX_UNLOCK(xs_cfg); 391 XS_MUTEX_UNLOCK(xs_cfg);
392 continue; /* This is ugly, but ... */ 392 continue; /* This is ugly, but ... */
393 } 393 }
394 } 394 }
395 395
396 /* Tell that we are initializing, update sub-tune controls */ 396 /* Tell that we are initializing, update sub-tune controls */
397 myStatus.currSong = xs_status.currSong; 397 myStatus.currSong = xs_status.currSong;
398 myTune->subTunes[myStatus.currSong-1].tunePlayed = TRUE; 398 myTune->subTunes[myStatus.currSong-1].tunePlayed = TRUE;
399 XS_MUTEX_UNLOCK(xs_status); 399 XS_MUTEX_UNLOCK(xs_status);
400 XS_MUTEX_UNLOCK(xs_cfg); 400 XS_MUTEX_UNLOCK(xs_cfg);
401 401
402 XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong); 402 XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong);
403 403
404 GDK_THREADS_ENTER(); 404 GDK_THREADS_ENTER();
405 xs_subctrl_update(); 405 xs_subctrl_update();
406 GDK_THREADS_LEAVE(); 406 GDK_THREADS_LEAVE();
407 407
408 /* Check minimum playtime */ 408 /* Check minimum playtime */
409 songLength = myTune->subTunes[myStatus.currSong-1].tuneLength; 409 songLength = myTune->subTunes[myStatus.currSong-1].tuneLength;
410 if (xs_cfg.playMinTimeEnable && (songLength >= 0)) { 410 if (xs_cfg.playMinTimeEnable && (songLength >= 0)) {
411 if (songLength < xs_cfg.playMinTime) 411 if (songLength < xs_cfg.playMinTime)
412 songLength = xs_cfg.playMinTime; 412 songLength = xs_cfg.playMinTime;
413 } 413 }
414 414
415 /* Initialize song */ 415 /* Initialize song */
416 if (!myStatus.sidPlayer->plrInitSong(&myStatus)) { 416 if (!myStatus.sidPlayer->plrInitSong(&myStatus)) {
417 xs_error("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n", 417 xs_error("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n",
418 myTune->sidFilename, myStatus.currSong); 418 myTune->sidFilename, myStatus.currSong);
419 goto xs_err_exit; 419 goto xs_err_exit;
420 } 420 }
421 421
422 /* Open the audio output */ 422 /* Open the audio output */
423 XSDEBUG("open audio output (%d, %d, %d)\n", 423 XSDEBUG("open audio output (%d, %d, %d)\n",
424 myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels); 424 myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels);
425 425
426 if (!xs_plugin_ip.output-> 426 if (!xs_plugin_ip.output->
427 open_audio(myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels)) { 427 open_audio(myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels)) {
428 xs_error("Couldn't open XMMS audio output (fmt=%x, freq=%i, nchan=%i)!\n", 428 xs_error("Couldn't open XMMS audio output (fmt=%x, freq=%i, nchan=%i)!\n",
429 myStatus.audioFormat, 429 myStatus.audioFormat,
430 myStatus.audioFrequency, 430 myStatus.audioFrequency,
431 myStatus.audioChannels); 431 myStatus.audioChannels);
432 432
433 XS_MUTEX_LOCK(xs_status); 433 XS_MUTEX_LOCK(xs_status);
434 xs_status.isError = TRUE; 434 xs_status.isError = TRUE;
435 XS_MUTEX_UNLOCK(xs_status); 435 XS_MUTEX_UNLOCK(xs_status);
436 goto xs_err_exit; 436 goto xs_err_exit;
437 } 437 }
438 438
439 audioOpen = TRUE; 439 audioOpen = TRUE;
440 440
441 /* Set song information for current subtune */ 441 /* Set song information for current subtune */
442 XSDEBUG("set tune info\n"); 442 XSDEBUG("set tune info\n");
443 myStatus.sidPlayer->plrUpdateSIDInfo(&myStatus); 443 myStatus.sidPlayer->plrUpdateSIDInfo(&myStatus);
444 tmpTitle = xs_make_titlestring(myTune, myStatus.currSong); 444 tmpTitle = xs_make_titlestring(myTune, myStatus.currSong);
445 445
446 xs_plugin_ip.set_info( 446 xs_plugin_ip.set_info(
447 tmpTitle, 447 tmpTitle,
448 (songLength > 0) ? (songLength * 1000) : 0, 448 (songLength > 0) ? (songLength * 1000) : 0,
449 -1, 449 -1,
450 myStatus.audioFrequency, 450 myStatus.audioFrequency,
451 myStatus.audioChannels); 451 myStatus.audioChannels);
452 452
453 g_free(tmpTitle); 453 g_free(tmpTitle);
454 454
455 XSDEBUG("playing\n"); 455 XSDEBUG("playing\n");
456 456
457 /* 457 /*
458 * Play the subtune 458 * Play the subtune
459 */ 459 */
460 while (xs_status.isPlaying && myStatus.isPlaying && (xs_status.currSong == myStatus.currSong)) { 460 while (xs_status.isPlaying && myStatus.isPlaying && (xs_status.currSong == myStatus.currSong)) {
461 /* Render audio data */ 461 /* Render audio data */
462 if (myStatus.oversampleEnable) { 462 if (myStatus.oversampleEnable) {
463 /* Perform oversampled rendering */ 463 /* Perform oversampled rendering */
464 audioGot = myStatus.sidPlayer->plrFillBuffer( 464 audioGot = myStatus.sidPlayer->plrFillBuffer(
465 &myStatus, 465 &myStatus,
466 oversampleBuffer, 466 oversampleBuffer,
467 (XS_AUDIOBUF_SIZE * myStatus.oversampleFactor)); 467 (XS_AUDIOBUF_SIZE * myStatus.oversampleFactor));
468 468
469 audioGot /= myStatus.oversampleFactor; 469 audioGot /= myStatus.oversampleFactor;
470 470
471 /* Execute rate-conversion with filtering */ 471 /* Execute rate-conversion with filtering */
472 if (xs_filter_rateconv(audioBuffer, oversampleBuffer, 472 if (xs_filter_rateconv(audioBuffer, oversampleBuffer,
473 myStatus.audioFormat, myStatus.oversampleFactor, audioGot) < 0) { 473 myStatus.audioFormat, myStatus.oversampleFactor, audioGot) < 0) {
474 xs_error("Oversampling rate-conversion pass failed.\n"); 474 xs_error("Oversampling rate-conversion pass failed.\n");
475 XS_MUTEX_LOCK(xs_status); 475 XS_MUTEX_LOCK(xs_status);
476 xs_status.isError = TRUE; 476 xs_status.isError = TRUE;
477 XS_MUTEX_UNLOCK(xs_status); 477 XS_MUTEX_UNLOCK(xs_status);
478 goto xs_err_exit; 478 goto xs_err_exit;
479 } 479 }
480 } else { 480 } else {
481 audioGot = myStatus.sidPlayer->plrFillBuffer( 481 audioGot = myStatus.sidPlayer->plrFillBuffer(
482 &myStatus, audioBuffer, XS_AUDIOBUF_SIZE); 482 &myStatus, audioBuffer, XS_AUDIOBUF_SIZE);
483 } 483 }
484 484
485 /* I <3 visualice/haujobb */ 485 /* I <3 visualice/haujobb */
486 xs_plugin_ip.add_vis_pcm( 486 xs_plugin_ip.add_vis_pcm(
487 xs_plugin_ip.output->written_time(), 487 xs_plugin_ip.output->written_time(),
488 myStatus.audioFormat, myStatus.audioChannels, 488 myStatus.audioFormat, myStatus.audioChannels,
489 audioGot, audioBuffer); 489 audioGot, audioBuffer);
490 490
491 /* Wait a little */ 491 /* Wait a little */
492 while (xs_status.isPlaying && 492 while (xs_status.isPlaying &&
493 (xs_status.currSong == myStatus.currSong) && 493 (xs_status.currSong == myStatus.currSong) &&
494 (xs_plugin_ip.output->buffer_free() < audioGot)) 494 (xs_plugin_ip.output->buffer_free() < audioGot))
495 xmms_usleep(500); 495 xmms_usleep(500);
496 496
497 /* Output audio */ 497 /* Output audio */
498 if (xs_status.isPlaying && (xs_status.currSong == myStatus.currSong)) 498 if (xs_status.isPlaying && (xs_status.currSong == myStatus.currSong))
499 xs_plugin_ip.output->write_audio(audioBuffer, audioGot); 499 xs_plugin_ip.output->write_audio(audioBuffer, audioGot);
500 500
501 /* Check if we have played enough */ 501 /* Check if we have played enough */
502 if (xs_cfg.playMaxTimeEnable) { 502 if (xs_cfg.playMaxTimeEnable) {
503 if (xs_cfg.playMaxTimeUnknown) { 503 if (xs_cfg.playMaxTimeUnknown) {
504 if ((songLength < 0) && 504 if ((songLength < 0) &&
505 (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000))) 505 (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000)))
506 myStatus.isPlaying = FALSE; 506 myStatus.isPlaying = FALSE;
507 } else { 507 } else {
508 if (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000)) 508 if (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000))
509 myStatus.isPlaying = FALSE; 509 myStatus.isPlaying = FALSE;
510 } 510 }
511 } 511 }
512 512
513 if (songLength >= 0) { 513 if (songLength >= 0) {
514 if (xs_plugin_ip.output->output_time() >= (songLength * 1000)) 514 if (xs_plugin_ip.output->output_time() >= (songLength * 1000))
515 myStatus.isPlaying = FALSE; 515 myStatus.isPlaying = FALSE;
516 } 516 }
517 } 517 }
518 518
519 XSDEBUG("subtune ended/stopped\n"); 519 XSDEBUG("subtune ended/stopped\n");
520 520
521 /* Close audio output plugin */ 521 /* Close audio output plugin */
522 if (audioOpen) { 522 if (audioOpen) {
523 XSDEBUG("close audio #1\n"); 523 XSDEBUG("close audio #1\n");
524 xs_plugin_ip.output->close_audio(); 524 xs_plugin_ip.output->close_audio();
525 audioOpen = FALSE; 525 audioOpen = FALSE;
526 XSDEBUG("closed\n"); 526 XSDEBUG("closed\n");
527 } 527 }
528 528
529 /* Now determine if we continue by selecting other subtune or something */ 529 /* Now determine if we continue by selecting other subtune or something */
530 if (!myStatus.isPlaying && !xs_cfg.subAutoEnable) 530 if (!myStatus.isPlaying && !xs_cfg.subAutoEnable)
531 doPlay = FALSE; 531 doPlay = FALSE;
532 } 532 }
533 533
534 xs_err_exit: 534 xs_err_exit:
535 XSDEBUG("out of playing loop\n"); 535 XSDEBUG("out of playing loop\n");
536 536
537 /* Close audio output plugin */ 537 /* Close audio output plugin */
538 if (audioOpen) { 538 if (audioOpen) {
539 XSDEBUG("close audio #2\n"); 539 XSDEBUG("close audio #2\n");
540 xs_plugin_ip.output->close_audio(); 540 xs_plugin_ip.output->close_audio();
541 XSDEBUG("closed\n"); 541 XSDEBUG("closed\n");
542 } 542 }
543 543
544 g_free(audioBuffer); 544 g_free(audioBuffer);
545 g_free(oversampleBuffer); 545 g_free(oversampleBuffer);
546 546
547 /* Set playing status to false (stopped), thus when 547 /* Set playing status to false (stopped), thus when
548 * XMMS next calls xs_get_time(), it can return appropriate 548 * XMMS next calls xs_get_time(), it can return appropriate
549 * value "not playing" status and XMMS knows to move to 549 * value "not playing" status and XMMS knows to move to
550 * next entry in the playlist .. or whatever it wishes. 550 * next entry in the playlist .. or whatever it wishes.
551 */ 551 */
552 XS_MUTEX_LOCK(xs_status); 552 XS_MUTEX_LOCK(xs_status);
553 xs_status.isPlaying = FALSE; 553 xs_status.isPlaying = FALSE;
554 XS_MUTEX_UNLOCK(xs_status); 554 XS_MUTEX_UNLOCK(xs_status);
555 555
556 /* Exit the playing thread */ 556 /* Exit the playing thread */
557 XSDEBUG("exiting thread, bye.\n"); 557 XSDEBUG("exiting thread, bye.\n");
558 XS_THREAD_EXIT(NULL); 558 XS_THREAD_EXIT(NULL);
559 } 559 }
560 560
561 561
562 /* 562 /*
563 * Start playing the given file 563 * Start playing the given file
565 * Usually you would also initialize the output-plugin, but 565 * Usually you would also initialize the output-plugin, but
566 * this is XMMS-SID and we do it on the player thread instead. 566 * this is XMMS-SID and we do it on the player thread instead.
567 */ 567 */
568 void xs_play_file(gchar * pcFilename) 568 void xs_play_file(gchar * pcFilename)
569 { 569 {
570 assert(xs_status.sidPlayer); 570 assert(xs_status.sidPlayer);
571 571
572 XSDEBUG("play '%s'\n", pcFilename); 572 XSDEBUG("play '%s'\n", pcFilename);
573 573
574 /* Get tune information */ 574 /* Get tune information */
575 if ((xs_status.tuneInfo = xs_status.sidPlayer->plrGetSIDInfo(pcFilename)) == NULL) 575 if ((xs_status.tuneInfo = xs_status.sidPlayer->plrGetSIDInfo(pcFilename)) == NULL)
576 return; 576 return;
577 577
578 /* Initialize the tune */ 578 /* Initialize the tune */
579 if (!xs_status.sidPlayer->plrLoadSID(&xs_status, pcFilename)) { 579 if (!xs_status.sidPlayer->plrLoadSID(&xs_status, pcFilename)) {
580 xs_tuneinfo_free(xs_status.tuneInfo); 580 xs_tuneinfo_free(xs_status.tuneInfo);
581 xs_status.tuneInfo = NULL; 581 xs_status.tuneInfo = NULL;
582 return; 582 return;
583 } 583 }
584 584
585 XSDEBUG("load ok\n"); 585 XSDEBUG("load ok\n");
586 586
587 /* Set general status information */ 587 /* Set general status information */
588 xs_status.isPlaying = TRUE; 588 xs_status.isPlaying = TRUE;
589 xs_status.isError = FALSE; 589 xs_status.isError = FALSE;
590 xs_status.currSong = xs_status.tuneInfo->startTune; 590 xs_status.currSong = xs_status.tuneInfo->startTune;
591 591
592 /* Start the playing thread! */ 592 /* Start the playing thread! */
593 if (pthread_create(&xs_decode_thread, NULL, xs_playthread, NULL) < 0) { 593 if (pthread_create(&xs_decode_thread, NULL, xs_playthread, NULL) < 0) {
594 xs_error("Couldn't create playing thread!\n"); 594 xs_error("Couldn't create playing thread!\n");
595 xs_tuneinfo_free(xs_status.tuneInfo); 595 xs_tuneinfo_free(xs_status.tuneInfo);
596 xs_status.tuneInfo = NULL; 596 xs_status.tuneInfo = NULL;
597 xs_status.sidPlayer->plrDeleteSID(&xs_status); 597 xs_status.sidPlayer->plrDeleteSID(&xs_status);
598 } 598 }
599 599
600 /* Okay, here the playing thread has started up and we 600 /* Okay, here the playing thread has started up and we
601 * return from here to XMMS. Rest is up to XMMS's GUI 601 * return from here to XMMS. Rest is up to XMMS's GUI
602 * and playing thread. 602 * and playing thread.
603 */ 603 */
604 XSDEBUG("systems should be up?\n"); 604 XSDEBUG("systems should be up?\n");
605 } 605 }
606 606
607 607
608 /* 608 /*
609 * Stop playing 609 * Stop playing
615 * 615 *
616 * Finally tune and other memory allocations are free'd. 616 * Finally tune and other memory allocations are free'd.
617 */ 617 */
618 void xs_stop(void) 618 void xs_stop(void)
619 { 619 {
620 XSDEBUG("stop requested\n"); 620 XSDEBUG("stop requested\n");
621 621
622 /* Close the sub-tune control window, if any */ 622 /* Close the sub-tune control window, if any */
623 xs_subctrl_close(); 623 xs_subctrl_close();
624 624
625 /* Lock xs_status and stop playing thread */ 625 /* Lock xs_status and stop playing thread */
626 XS_MUTEX_LOCK(xs_status); 626 XS_MUTEX_LOCK(xs_status);
627 if (xs_status.isPlaying) { 627 if (xs_status.isPlaying) {
628 XSDEBUG("stopping...\n"); 628 XSDEBUG("stopping...\n");
629 xs_status.isPlaying = FALSE; 629 xs_status.isPlaying = FALSE;
630 XS_MUTEX_UNLOCK(xs_status); 630 XS_MUTEX_UNLOCK(xs_status);
631 XS_THREAD_JOIN(xs_decode_thread); 631 XS_THREAD_JOIN(xs_decode_thread);
632 } else { 632 } else {
633 XS_MUTEX_UNLOCK(xs_status); 633 XS_MUTEX_UNLOCK(xs_status);
634 } 634 }
635 635
636 XSDEBUG("done, updating status\n"); 636 XSDEBUG("done, updating status\n");
637 637
638 /* Status is now stopped, update the sub-tune 638 /* Status is now stopped, update the sub-tune
639 * controller in fileinfo window (if open) 639 * controller in fileinfo window (if open)
640 */ 640 */
641 xs_fileinfo_update(); 641 xs_fileinfo_update();
642 642
643 /* Free tune information */ 643 /* Free tune information */
644 XS_MUTEX_LOCK(xs_status); 644 XS_MUTEX_LOCK(xs_status);
645 xs_status.sidPlayer->plrDeleteSID(&xs_status); 645 xs_status.sidPlayer->plrDeleteSID(&xs_status);
646 xs_tuneinfo_free(xs_status.tuneInfo); 646 xs_tuneinfo_free(xs_status.tuneInfo);
647 xs_status.tuneInfo = NULL; 647 xs_status.tuneInfo = NULL;
648 XS_MUTEX_UNLOCK(xs_status); 648 XS_MUTEX_UNLOCK(xs_status);
649 XSDEBUG("ok\n"); 649 XSDEBUG("ok\n");
650 } 650 }
651 651
652 652
653 /* 653 /*
654 * Pause/unpause the playing 654 * Pause/unpause the playing
655 */ 655 */
656 void xs_pause(short pauseState) 656 void xs_pause(short pauseState)
657 { 657 {
658 XS_MUTEX_LOCK(xs_status); 658 XS_MUTEX_LOCK(xs_status);
659 /* FIXME FIX ME todo: pause should disable sub-tune controls */ 659 /* FIXME FIX ME todo: pause should disable sub-tune controls */
660 XS_MUTEX_UNLOCK(xs_status); 660 XS_MUTEX_UNLOCK(xs_status);
661 661
662 xs_subctrl_close(); 662 xs_subctrl_close();
663 xs_fileinfo_update(); 663 xs_fileinfo_update();
664 xs_plugin_ip.output->pause(pauseState); 664 xs_plugin_ip.output->pause(pauseState);
665 } 665 }
666 666
667 667
668 /* 668 /*
669 * Pop-up subtune selector 669 * Pop-up subtune selector
670 */ 670 */
671 void xs_subctrl_setsong(void) 671 void xs_subctrl_setsong(void)
672 { 672 {
673 gint n; 673 gint n;
674 674
675 XS_MUTEX_LOCK(xs_status); 675 XS_MUTEX_LOCK(xs_status);
676 XS_MUTEX_LOCK(xs_subctrl); 676 XS_MUTEX_LOCK(xs_subctrl);
677 677
678 if (xs_status.tuneInfo && xs_status.isPlaying) { 678 if (xs_status.tuneInfo && xs_status.isPlaying) {
679 n = (gint) GTK_ADJUSTMENT(xs_subctrl_adj)->value; 679 n = (gint) GTK_ADJUSTMENT(xs_subctrl_adj)->value;
680 if ((n >= 1) && (n <= xs_status.tuneInfo->nsubTunes)) 680 if ((n >= 1) && (n <= xs_status.tuneInfo->nsubTunes))
681 xs_status.currSong = n; 681 xs_status.currSong = n;
682 } 682 }
683 683
684 XS_MUTEX_UNLOCK(xs_subctrl); 684 XS_MUTEX_UNLOCK(xs_subctrl);
685 XS_MUTEX_UNLOCK(xs_status); 685 XS_MUTEX_UNLOCK(xs_status);
686 } 686 }
687 687
688 688
689 void xs_subctrl_prevsong(void) 689 void xs_subctrl_prevsong(void)
690 { 690 {
691 XS_MUTEX_LOCK(xs_status); 691 XS_MUTEX_LOCK(xs_status);
692 692
693 if (xs_status.tuneInfo && xs_status.isPlaying) { 693 if (xs_status.tuneInfo && xs_status.isPlaying) {
694 if (xs_status.currSong > 1) 694 if (xs_status.currSong > 1)
695 xs_status.currSong--; 695 xs_status.currSong--;
696 } 696 }
697 697
698 XS_MUTEX_UNLOCK(xs_status); 698 XS_MUTEX_UNLOCK(xs_status);
699 699
700 xs_subctrl_update(); 700 xs_subctrl_update();
701 } 701 }
702 702
703 703
704 void xs_subctrl_nextsong(void) 704 void xs_subctrl_nextsong(void)
705 { 705 {
706 XS_MUTEX_LOCK(xs_status); 706 XS_MUTEX_LOCK(xs_status);
707 707
708 if (xs_status.tuneInfo && xs_status.isPlaying) { 708 if (xs_status.tuneInfo && xs_status.isPlaying) {
709 if (xs_status.currSong < xs_status.tuneInfo->nsubTunes) 709 if (xs_status.currSong < xs_status.tuneInfo->nsubTunes)
710 xs_status.currSong++; 710 xs_status.currSong++;
711 } 711 }
712 712
713 XS_MUTEX_UNLOCK(xs_status); 713 XS_MUTEX_UNLOCK(xs_status);
714 714
715 xs_subctrl_update(); 715 xs_subctrl_update();
716 } 716 }
717 717
718 718
719 void xs_subctrl_update(void) 719 void xs_subctrl_update(void)
720 { 720 {
721 GtkAdjustment *tmpAdj; 721 GtkAdjustment *tmpAdj;
722 722
723 XS_MUTEX_LOCK(xs_status); 723 XS_MUTEX_LOCK(xs_status);
724 XS_MUTEX_LOCK(xs_subctrl); 724 XS_MUTEX_LOCK(xs_subctrl);
725 725
726 /* Check if control window exists, we are currently playing and have a tune */ 726 /* Check if control window exists, we are currently playing and have a tune */
727 if (xs_subctrl) { 727 if (xs_subctrl) {
728 if (xs_status.tuneInfo && xs_status.isPlaying) { 728 if (xs_status.tuneInfo && xs_status.isPlaying) {
729 tmpAdj = GTK_ADJUSTMENT(xs_subctrl_adj); 729 tmpAdj = GTK_ADJUSTMENT(xs_subctrl_adj);
730 730
731 tmpAdj->value = xs_status.currSong; 731 tmpAdj->value = xs_status.currSong;
732 tmpAdj->lower = 1; 732 tmpAdj->lower = 1;
733 tmpAdj->upper = xs_status.tuneInfo->nsubTunes; 733 tmpAdj->upper = xs_status.tuneInfo->nsubTunes;
734 XS_MUTEX_UNLOCK(xs_status); 734 XS_MUTEX_UNLOCK(xs_status);
735 XS_MUTEX_UNLOCK(xs_subctrl); 735 XS_MUTEX_UNLOCK(xs_subctrl);
736 gtk_adjustment_value_changed(tmpAdj); 736 gtk_adjustment_value_changed(tmpAdj);
737 } else { 737 } else {
738 XS_MUTEX_UNLOCK(xs_status); 738 XS_MUTEX_UNLOCK(xs_status);
739 XS_MUTEX_UNLOCK(xs_subctrl); 739 XS_MUTEX_UNLOCK(xs_subctrl);
740 xs_subctrl_close(); 740 xs_subctrl_close();
741 } 741 }
742 } else { 742 } else {
743 XS_MUTEX_UNLOCK(xs_subctrl); 743 XS_MUTEX_UNLOCK(xs_subctrl);
744 XS_MUTEX_UNLOCK(xs_status); 744 XS_MUTEX_UNLOCK(xs_status);
745 } 745 }
746 746
747 xs_fileinfo_update(); 747 xs_fileinfo_update();
748 } 748 }
749 749
750 750
751 void xs_subctrl_close(void) 751 void xs_subctrl_close(void)
752 { 752 {
753 XS_MUTEX_LOCK(xs_subctrl); 753 XS_MUTEX_LOCK(xs_subctrl);
754 754
755 if (xs_subctrl) { 755 if (xs_subctrl) {
756 gtk_widget_destroy(xs_subctrl); 756 gtk_widget_destroy(xs_subctrl);
757 xs_subctrl = NULL; 757 xs_subctrl = NULL;
758 } 758 }
759 759
760 XS_MUTEX_UNLOCK(xs_subctrl); 760 XS_MUTEX_UNLOCK(xs_subctrl);
761 } 761 }
762 762
763 763
764 gboolean xs_subctrl_keypress(GtkWidget * win, GdkEventKey * ev) 764 gboolean xs_subctrl_keypress(GtkWidget * win, GdkEventKey * ev)
765 { 765 {
766 (void) win; 766 (void) win;
767 767
768 if (ev->keyval == GDK_Escape) 768 if (ev->keyval == GDK_Escape)
769 xs_subctrl_close(); 769 xs_subctrl_close();
770 770
771 return FALSE; 771 return FALSE;
772 } 772 }
773 773
774 774
775 void xs_subctrl_open(void) 775 void xs_subctrl_open(void)
776 { 776 {
777 GtkWidget *frame25, *hbox15, *subctrl_prev, *subctrl_current, *subctrl_next; 777 GtkWidget *frame25, *hbox15, *subctrl_prev, *subctrl_current, *subctrl_next;
778 778
779 XS_MUTEX_LOCK(xs_subctrl); 779 XS_MUTEX_LOCK(xs_subctrl);
780 if (!xs_status.tuneInfo || !xs_status.isPlaying || 780 if (!xs_status.tuneInfo || !xs_status.isPlaying ||
781 xs_subctrl || (xs_status.tuneInfo->nsubTunes <= 1)) { 781 xs_subctrl || (xs_status.tuneInfo->nsubTunes <= 1)) {
782 XS_MUTEX_UNLOCK(xs_subctrl); 782 XS_MUTEX_UNLOCK(xs_subctrl);
783 return; 783 return;
784 } 784 }
785 785
786 /* Create the pop-up window */ 786 /* Create the pop-up window */
787 xs_subctrl = gtk_window_new(GTK_WINDOW_DIALOG); 787 xs_subctrl = gtk_window_new(GTK_WINDOW_DIALOG);
788 gtk_widget_set_name(xs_subctrl, "xs_subctrl"); 788 gtk_widget_set_name(xs_subctrl, "xs_subctrl");
789 gtk_object_set_data(GTK_OBJECT(xs_subctrl), "xs_subctrl", xs_subctrl); 789 gtk_object_set_data(GTK_OBJECT(xs_subctrl), "xs_subctrl", xs_subctrl);
790 790
791 gtk_window_set_title(GTK_WINDOW(xs_subctrl), _("Subtune Control")); 791 gtk_window_set_title(GTK_WINDOW(xs_subctrl), _("Subtune Control"));
792 gtk_window_set_position(GTK_WINDOW(xs_subctrl), GTK_WIN_POS_MOUSE); 792 gtk_window_set_position(GTK_WINDOW(xs_subctrl), GTK_WIN_POS_MOUSE);
793 gtk_container_set_border_width(GTK_CONTAINER(xs_subctrl), 0); 793 gtk_container_set_border_width(GTK_CONTAINER(xs_subctrl), 0);
794 gtk_window_set_policy(GTK_WINDOW(xs_subctrl), FALSE, FALSE, FALSE); 794 gtk_window_set_policy(GTK_WINDOW(xs_subctrl), FALSE, FALSE, FALSE);
795 795
796 XS_SIGNAL_CONNECT(xs_subctrl, "destroy", gtk_widget_destroyed, &xs_subctrl); 796 XS_SIGNAL_CONNECT(xs_subctrl, "destroy", gtk_widget_destroyed, &xs_subctrl);
797 XS_SIGNAL_CONNECT(xs_subctrl, "focus_out_event", xs_subctrl_close, NULL); 797 XS_SIGNAL_CONNECT(xs_subctrl, "focus_out_event", xs_subctrl_close, NULL);
798 798
799 gtk_widget_realize(xs_subctrl); 799 gtk_widget_realize(xs_subctrl);
800 gdk_window_set_decorations(xs_subctrl->window, (GdkWMDecoration) 0); 800 gdk_window_set_decorations(xs_subctrl->window, (GdkWMDecoration) 0);
801 801
802 802
803 /* Create the control widgets */ 803 /* Create the control widgets */
804 frame25 = gtk_frame_new(NULL); 804 frame25 = gtk_frame_new(NULL);
805 gtk_container_add(GTK_CONTAINER(xs_subctrl), frame25); 805 gtk_container_add(GTK_CONTAINER(xs_subctrl), frame25);
806 gtk_container_set_border_width(GTK_CONTAINER(frame25), 2); 806 gtk_container_set_border_width(GTK_CONTAINER(frame25), 2);
807 gtk_frame_set_shadow_type(GTK_FRAME(frame25), GTK_SHADOW_OUT); 807 gtk_frame_set_shadow_type(GTK_FRAME(frame25), GTK_SHADOW_OUT);
808 808
809 hbox15 = gtk_hbox_new(FALSE, 4); 809 hbox15 = gtk_hbox_new(FALSE, 4);
810 gtk_container_add(GTK_CONTAINER(frame25), hbox15); 810 gtk_container_add(GTK_CONTAINER(frame25), hbox15);
811 811
812 subctrl_prev = gtk_button_new_with_label(" < "); 812 subctrl_prev = gtk_button_new_with_label(" < ");
813 gtk_widget_set_name(subctrl_prev, "subctrl_prev"); 813 gtk_widget_set_name(subctrl_prev, "subctrl_prev");
814 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_prev, FALSE, FALSE, 0); 814 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_prev, FALSE, FALSE, 0);
815 815
816 xs_subctrl_adj = gtk_adjustment_new(xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes, 1, 1, 0); 816 xs_subctrl_adj = gtk_adjustment_new(xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes, 1, 1, 0);
817 XS_SIGNAL_CONNECT(xs_subctrl_adj, "value_changed", xs_subctrl_setsong, NULL); 817 XS_SIGNAL_CONNECT(xs_subctrl_adj, "value_changed", xs_subctrl_setsong, NULL);
818 818
819 subctrl_current = gtk_hscale_new(GTK_ADJUSTMENT(xs_subctrl_adj)); 819 subctrl_current = gtk_hscale_new(GTK_ADJUSTMENT(xs_subctrl_adj));
820 gtk_widget_set_name(subctrl_current, "subctrl_current"); 820 gtk_widget_set_name(subctrl_current, "subctrl_current");
821 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_current, FALSE, TRUE, 0); 821 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_current, FALSE, TRUE, 0);
822 gtk_scale_set_digits(GTK_SCALE(subctrl_current), 0); 822 gtk_scale_set_digits(GTK_SCALE(subctrl_current), 0);
823 gtk_range_set_update_policy(GTK_RANGE(subctrl_current), GTK_UPDATE_DELAYED); 823 gtk_range_set_update_policy(GTK_RANGE(subctrl_current), GTK_UPDATE_DELAYED);
824 gtk_widget_grab_focus(subctrl_current); 824 gtk_widget_grab_focus(subctrl_current);
825 825
826 subctrl_next = gtk_button_new_with_label(" > "); 826 subctrl_next = gtk_button_new_with_label(" > ");
827 gtk_widget_set_name(subctrl_next, "subctrl_next"); 827 gtk_widget_set_name(subctrl_next, "subctrl_next");
828 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_next, FALSE, FALSE, 0); 828 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_next, FALSE, FALSE, 0);
829 829
830 XS_SIGNAL_CONNECT(subctrl_prev, "clicked", xs_subctrl_prevsong, NULL); 830 XS_SIGNAL_CONNECT(subctrl_prev, "clicked", xs_subctrl_prevsong, NULL);
831 XS_SIGNAL_CONNECT(subctrl_next, "clicked", xs_subctrl_nextsong, NULL); 831 XS_SIGNAL_CONNECT(subctrl_next, "clicked", xs_subctrl_nextsong, NULL);
832 XS_SIGNAL_CONNECT(xs_subctrl, "key_press_event", xs_subctrl_keypress, NULL); 832 XS_SIGNAL_CONNECT(xs_subctrl, "key_press_event", xs_subctrl_keypress, NULL);
833 833
834 gtk_widget_show_all(xs_subctrl); 834 gtk_widget_show_all(xs_subctrl);
835 835
836 XS_MUTEX_UNLOCK(xs_subctrl); 836 XS_MUTEX_UNLOCK(xs_subctrl);
837 } 837 }
838 838
839 839
840 /* 840 /*
841 * Set the time-seek position 841 * Set the time-seek position
846 * This function is called whenever position slider is clicked or 846 * This function is called whenever position slider is clicked or
847 * other method of seeking is used (keyboard, etc.) 847 * other method of seeking is used (keyboard, etc.)
848 */ 848 */
849 void xs_seek(gint iTime) 849 void xs_seek(gint iTime)
850 { 850 {
851 /* Check status */ 851 /* Check status */
852 XS_MUTEX_LOCK(xs_status); 852 XS_MUTEX_LOCK(xs_status);
853 if (!xs_status.tuneInfo || !xs_status.isPlaying) { 853 if (!xs_status.tuneInfo || !xs_status.isPlaying) {
854 XS_MUTEX_UNLOCK(xs_status); 854 XS_MUTEX_UNLOCK(xs_status);
855 return; 855 return;
856 } 856 }
857 857
858 /* Act according to settings */ 858 /* Act according to settings */
859 switch (xs_cfg.subsongControl) { 859 switch (xs_cfg.subsongControl) {
860 case XS_SSC_SEEK: 860 case XS_SSC_SEEK:
861 if (iTime < xs_status.lastTime) { 861 if (iTime < xs_status.lastTime) {
862 if (xs_status.currSong > 1) 862 if (xs_status.currSong > 1)
863 xs_status.currSong--; 863 xs_status.currSong--;
864 } else if (iTime > xs_status.lastTime) { 864 } else if (iTime > xs_status.lastTime) {
865 if (xs_status.currSong < xs_status.tuneInfo->nsubTunes) 865 if (xs_status.currSong < xs_status.tuneInfo->nsubTunes)
866 xs_status.currSong++; 866 xs_status.currSong++;
867 } 867 }
868 break; 868 break;
869 869
870 case XS_SSC_POPUP: 870 case XS_SSC_POPUP:
871 xs_subctrl_open(); 871 xs_subctrl_open();
872 break; 872 break;
873 873
874 /* If we have song-position patch, check settings */ 874 /* If we have song-position patch, check settings */
875 #ifdef HAVE_SONG_POSITION 875 #ifdef HAVE_SONG_POSITION
876 case XS_SSC_PATCH: 876 case XS_SSC_PATCH:
877 if ((iTime > 0) && (iTime <= xs_status.tuneInfo->nsubTunes)) 877 if ((iTime > 0) && (iTime <= xs_status.tuneInfo->nsubTunes))
878 xs_status.currSong = iTime; 878 xs_status.currSong = iTime;
879 break; 879 break;
880 #endif 880 #endif
881 } 881 }
882 882
883 XS_MUTEX_UNLOCK(xs_status); 883 XS_MUTEX_UNLOCK(xs_status);
884 } 884 }
885 885
886 886
887 /* 887 /*
888 * Return the playing "position/time" 888 * Return the playing "position/time"
891 * END OF SONG! Return value of -2 means error, XMMS opens an audio 891 * END OF SONG! Return value of -2 means error, XMMS opens an audio
892 * error dialog. -1 means end of song (if one was playing currently). 892 * error dialog. -1 means end of song (if one was playing currently).
893 */ 893 */
894 gint xs_get_time(void) 894 gint xs_get_time(void)
895 { 895 {
896 /* If errorflag is set, return -2 to signal it to XMMS's idle callback */ 896 /* If errorflag is set, return -2 to signal it to XMMS's idle callback */
897 XS_MUTEX_LOCK(xs_status); 897 XS_MUTEX_LOCK(xs_status);
898 if (xs_status.isError) { 898 if (xs_status.isError) {
899 XS_MUTEX_UNLOCK(xs_status); 899 XS_MUTEX_UNLOCK(xs_status);
900 return -2; 900 return -2;
901 } 901 }
902 902
903 /* If there is no tune, return -1 */ 903 /* If there is no tune, return -1 */
904 if (!xs_status.tuneInfo) { 904 if (!xs_status.tuneInfo) {
905 XS_MUTEX_UNLOCK(xs_status); 905 XS_MUTEX_UNLOCK(xs_status);
906 return -1; 906 return -1;
907 } 907 }
908 908
909 /* If tune has ended, return -1 */ 909 /* If tune has ended, return -1 */
910 if (!xs_status.isPlaying) { 910 if (!xs_status.isPlaying) {
911 XS_MUTEX_UNLOCK(xs_status); 911 XS_MUTEX_UNLOCK(xs_status);
912 return -1; 912 return -1;
913 } 913 }
914 914
915 /* Let's see what we do */ 915 /* Let's see what we do */
916 switch (xs_cfg.subsongControl) { 916 switch (xs_cfg.subsongControl) {
917 case XS_SSC_SEEK: 917 case XS_SSC_SEEK:
918 xs_status.lastTime = (xs_plugin_ip.output->output_time() / 1000); 918 xs_status.lastTime = (xs_plugin_ip.output->output_time() / 1000);
919 break; 919 break;
920 920
921 #ifdef HAVE_SONG_POSITION 921 #ifdef HAVE_SONG_POSITION
922 case XS_SSC_PATCH: 922 case XS_SSC_PATCH:
923 set_song_position(xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes); 923 set_song_position(xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes);
924 break; 924 break;
925 #endif 925 #endif
926 } 926 }
927 927
928 XS_MUTEX_UNLOCK(xs_status); 928 XS_MUTEX_UNLOCK(xs_status);
929 929
930 /* Return output time reported by audio output plugin */ 930 /* Return output time reported by audio output plugin */
931 return xs_plugin_ip.output->output_time(); 931 return xs_plugin_ip.output->output_time();
932 } 932 }
933 933
934 934
935 /* Return song information: called by XMMS when initially loading the playlist. 935 /* Return song information: called by XMMS when initially loading the playlist.
936 * Subsequent changes to information are made by the player thread, 936 * Subsequent changes to information are made by the player thread,
937 * which uses xs_plugin_ip.set_info(); 937 * which uses xs_plugin_ip.set_info();
938 */ 938 */
939 void xs_get_song_info(gchar * songFilename, gchar ** songTitle, gint * songLength) 939 void xs_get_song_info(gchar * songFilename, gchar ** songTitle, gint * songLength)
940 { 940 {
941 xs_tuneinfo_t *pInfo; 941 xs_tuneinfo_t *pInfo;
942 942
943 XS_MUTEX_LOCK(xs_status); 943 XS_MUTEX_LOCK(xs_status);
944 944
945 /* Get tune information from emulation engine */ 945 /* Get tune information from emulation engine */
946 pInfo = xs_status.sidPlayer->plrGetSIDInfo(songFilename); 946 pInfo = xs_status.sidPlayer->plrGetSIDInfo(songFilename);
947 if (!pInfo) { 947 if (!pInfo) {
948 XS_MUTEX_UNLOCK(xs_status); 948 XS_MUTEX_UNLOCK(xs_status);
949 return; 949 return;
950 } 950 }
951 951
952 /* Get sub-tune information, if available */ 952 /* Get sub-tune information, if available */
953 if ((pInfo->startTune > 0) && (pInfo->startTune <= pInfo->nsubTunes)) { 953 if ((pInfo->startTune > 0) && (pInfo->startTune <= pInfo->nsubTunes)) {
954 gint tmpInt; 954 gint tmpInt;
955 955
956 (*songTitle) = xs_make_titlestring(pInfo, pInfo->startTune); 956 (*songTitle) = xs_make_titlestring(pInfo, pInfo->startTune);
957 957
958 tmpInt = pInfo->subTunes[pInfo->startTune-1].tuneLength; 958 tmpInt = pInfo->subTunes[pInfo->startTune-1].tuneLength;
959 if (tmpInt < 0) 959 if (tmpInt < 0)
960 (*songLength) = -1; 960 (*songLength) = -1;
961 else 961 else
962 (*songLength) = (tmpInt * 1000); 962 (*songLength) = (tmpInt * 1000);
963 } 963 }
964 964
965 /* Free tune information */ 965 /* Free tune information */
966 xs_tuneinfo_free(pInfo); 966 xs_tuneinfo_free(pInfo);
967 XS_MUTEX_UNLOCK(xs_status); 967 XS_MUTEX_UNLOCK(xs_status);
968 } 968 }
969 969