comparison src/xmms-sid.c @ 230:608f31f6c095

Raw cleanup.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 21 Dec 2004 09:25:03 +0000
parents 2986069309c6
children e613873c3379
comparison
equal deleted inserted replaced
229:7bb9e20e3092 230:608f31f6c095
57 #include "xs_sidplay1.h" 57 #include "xs_sidplay1.h"
58 #endif 58 #endif
59 #ifdef HAVE_SIDPLAY2 59 #ifdef HAVE_SIDPLAY2
60 #include "xs_sidplay2.h" 60 #include "xs_sidplay2.h"
61 #endif 61 #endif
62
63
64 /*
65 * Structure defining methods/functions of each player
66 */
67 typedef struct {
68 gint plrIdent;
69 gboolean (*plrIsOurFile)(gchar *);
70 gboolean (*plrInit)(t_xs_status *);
71 void (*plrClose)(t_xs_status *);
72 gboolean (*plrInitSong)(t_xs_status *);
73 guint (*plrFillBuffer)(t_xs_status *, gchar *, guint);
74 gboolean (*plrLoadSID)(t_xs_status *, gchar *);
75 void (*plrDeleteSID)(t_xs_status *);
76 t_xs_tune* (*plrGetSIDInfo)(gchar *);
77 } t_xs_player;
78 62
79 63
80 /* 64 /*
81 * List of players and links to their functions 65 * List of players and links to their functions
82 */ 66 */
105 89
106 90
107 /* 91 /*
108 * Global variables 92 * Global variables
109 */ 93 */
110 struct t_xs_cfg xs_cfg; 94 t_xs_status xs_status;
111 t_xs_status xs_status; 95 XS_MUTEX(xs_status);
112 t_xs_player *xs_player = NULL; 96 static pthread_t xs_decode_thread;
113 static pthread_t xs_decode_thread; 97
114 static pthread_mutex_t xs_mutex = PTHREAD_MUTEX_INITIALIZER; 98 static GtkWidget *xs_subctrl = NULL;
115 static GtkWidget *xs_subctrl = NULL; 99 static GtkObject *xs_subctrl_adj = NULL;
116 static GtkObject *xs_subctrl_adj = NULL; 100 XS_MUTEX(xs_subctrl);
117 static t_xs_tune *xs_fileinfotune = NULL;
118 static t_xs_stil_node *xs_fileinfostil = NULL;
119
120 101
121 void xs_subctrl_close(void); 102 void xs_subctrl_close(void);
122 void xs_subctrl_update(void); 103 void xs_subctrl_update(void);
123 104
124 105
125 /* 106 /*
126 * Re-initialize some settings 107 * Initialization functions
127 */ 108 */
128 void xs_reinit(void) 109 void xs_reinit(void)
129 { 110 {
130 gint iPlayer; 111 gint iPlayer;
131 gboolean isInitialized; 112 gboolean isInitialized;
151 if (xs_playerlist[iPlayer].plrIdent == xs_cfg.playerEngine) 132 if (xs_playerlist[iPlayer].plrIdent == xs_cfg.playerEngine)
152 { 133 {
153 if (xs_playerlist[iPlayer].plrInit(&xs_status)) 134 if (xs_playerlist[iPlayer].plrInit(&xs_status))
154 { 135 {
155 isInitialized = TRUE; 136 isInitialized = TRUE;
156 xs_player = (t_xs_player *) &xs_playerlist[iPlayer]; 137 xs_status.sidPlayer = (t_xs_player *) &xs_playerlist[iPlayer];
157 } 138 }
158 } 139 }
159 iPlayer++; 140 iPlayer++;
160 } 141 }
161 142
165 while ((iPlayer < xs_nplayerlist) && !isInitialized) 146 while ((iPlayer < xs_nplayerlist) && !isInitialized)
166 { 147 {
167 if (xs_playerlist[iPlayer].plrInit(&xs_status)) 148 if (xs_playerlist[iPlayer].plrInit(&xs_status))
168 { 149 {
169 isInitialized = TRUE; 150 isInitialized = TRUE;
170 xs_player = (t_xs_player *) &xs_playerlist[iPlayer]; 151 xs_status.sidPlayer = (t_xs_player *) &xs_playerlist[iPlayer];
171 } else 152 } else
172 iPlayer++; 153 iPlayer++;
173 } 154 }
174 155
175 XSDEBUG("init#2: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer); 156 XSDEBUG("init#2: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer);
176 157
177 /* Initialize song-length database */ 158 /* Initialize song-length database */
178 xs_songlen_close(); 159 xs_songlen_close();
179 if (xs_cfg.songlenDBEnable && (xs_songlen_init() < 0)) 160 if (xs_cfg.songlenDBEnable && (xs_songlen_init() != 0))
180 { 161 {
181 XSERR("Error initializing song-length database!\n"); 162 XSERR("Error initializing song-length database!\n");
182 } 163 }
183 164
184 /* Initialize STIL database */ 165 /* Initialize STIL database */
185 xs_stil_close(); 166 xs_stil_close();
186 if (xs_cfg.stilDBEnable && (xs_stil_init() < 0)) 167 if (xs_cfg.stilDBEnable && (xs_stil_init() != 0))
187 { 168 {
188 XSERR("Error initializing STIL database!\n"); 169 XSERR("Error initializing STIL database!\n");
189 } 170 }
190 } 171 }
191 172
216 XSDEBUG("xs_close(): shutting down...\n"); 197 XSDEBUG("xs_close(): shutting down...\n");
217 198
218 /* Stop playing, free structures */ 199 /* Stop playing, free structures */
219 xs_stop(); 200 xs_stop();
220 201
221 xs_tune_free(xs_status.pTune); 202 xs_tuneinfo_free(xs_status.tuneInfo);
222 xs_status.pTune = NULL; 203 xs_status.tuneInfo = NULL;
223 204
224 xs_player->plrDeleteSID(&xs_status); 205 xs_status.sidPlayer->plrDeleteSID(&xs_status);
225 xs_player->plrClose(&xs_status); 206 xs_status.sidPlayer->plrClose(&xs_status);
226 207
227 xs_songlen_close(); 208 xs_songlen_close();
228 xs_stil_close(); 209 xs_stil_close();
229 210
230 XSDEBUG("shutdown finished.\n"); 211 XSDEBUG("shutdown finished.\n");
235 * Check whether the given file is handled by this plugin 216 * Check whether the given file is handled by this plugin
236 */ 217 */
237 gint xs_is_our_file(gchar *pcFilename) 218 gint xs_is_our_file(gchar *pcFilename)
238 { 219 {
239 gchar *pcExt; 220 gchar *pcExt;
240 assert(xs_player); 221 assert(xs_status.sidPlayer);
241 222
242 /* Check the filename */ 223 /* Check the filename */
243 if (pcFilename == NULL) 224 if (pcFilename == NULL)
244 return FALSE; 225 return FALSE;
245 226
246 /* Try to detect via detection routine, if required */ 227 /* Try to detect via detection routine, if required */
247 if (xs_cfg.detectMagic && xs_player->plrIsOurFile(pcFilename)) 228 if (xs_cfg.detectMagic && xs_status.sidPlayer->plrIsOurFile(pcFilename))
248 return TRUE; 229 return TRUE;
249 230
250 /* Detect just by checking filename extension */ 231 /* Detect just by checking filename extension */
251 pcExt = xs_strrchr(pcFilename, '.'); 232 pcExt = xs_strrchr(pcFilename, '.');
252 if (pcExt) 233 if (pcExt)
272 * Main playing thread loop 253 * Main playing thread loop
273 */ 254 */
274 void *xs_play_loop(void *argPointer) 255 void *xs_play_loop(void *argPointer)
275 { 256 {
276 t_xs_status myStatus; 257 t_xs_status myStatus;
277 t_xs_tune *myTune; 258 t_xs_tuneinfo *myTune;
278 gboolean audioOpen = FALSE, doPlay = FALSE; 259 gboolean audioOpen = FALSE, doPlay = FALSE;
279 guint audioGot; 260 guint audioGot;
280 gint songLength; 261 gint songLength;
281 gchar audioBuffer[XS_BUFSIZE]; 262 gchar audioBuffer[XS_BUFSIZE];
282 263
283 /* Initialize */ 264 /* Initialize */
284 pthread_mutex_lock(&xs_mutex); 265 XSDEBUG("entering player thread\n");
285 XSDEBUG("entering play thread\n"); 266 XS_MUTEX_LOCK(xs_status);
286 memcpy(&myStatus, &xs_status, sizeof(t_xs_status)); 267 memcpy(&myStatus, &xs_status, sizeof(t_xs_status));
287 myTune = xs_status.pTune; 268 myTune = xs_status.tuneInfo;
288 pthread_mutex_unlock(&xs_mutex); 269 XS_MUTEX_UNLOCK(xs_status);
289 270
290 271
291 /* 272 /*
292 * Main player loop: while not stopped, loop here - play subtunes 273 * Main player loop: while not stopped, loop here - play subtunes
293 */ 274 */
294 doPlay = TRUE; 275 doPlay = TRUE;
295 while (xs_status.isPlaying && doPlay) 276 while (xs_status.isPlaying && doPlay)
296 { 277 {
297 pthread_mutex_lock(&xs_mutex); 278 XS_MUTEX_LOCK(xs_status);
298 myStatus.currSong = xs_status.currSong; 279 myStatus.currSong = xs_status.currSong;
299 pthread_mutex_unlock(&xs_mutex); 280 XS_MUTEX_UNLOCK(xs_status);
281 XS_MUTEX_LOCK(xs_subctrl);
300 xs_subctrl_update(); 282 xs_subctrl_update();
283 XS_MUTEX_UNLOCK(xs_subctrl);
301 284
302 XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong); 285 XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong);
303 286
304 songLength = myTune->subTunes[myStatus.currSong - 1].tuneLength; 287 songLength = myTune->subTunes[myStatus.currSong - 1].tuneLength;
305 288
306 /* Check minimum playtime */ 289 /* Check minimum playtime */
290 XS_MUTEX_LOCK(xs_cfg);
307 if (xs_cfg.playMinTimeEnable) 291 if (xs_cfg.playMinTimeEnable)
308 { 292 {
309 if (songLength < xs_cfg.playMinTime) 293 if (songLength < xs_cfg.playMinTime)
310 songLength = xs_cfg.playMinTime; 294 songLength = xs_cfg.playMinTime;
311 } 295 }
296 XS_MUTEX_UNLOCK(xs_cfg);
312 297
313 /* Initialize song */ 298 /* Initialize song */
314 if (!xs_player->plrInitSong(&myStatus)) 299 if (!myStatus.sidPlayer->plrInitSong(&myStatus))
315 { 300 {
316 XSERR("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n", 301 XSERR("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n",
317 myTune->tuneFilename, myStatus.currSong); 302 myTune->sidFilename, myStatus.currSong);
318 goto xs_err_exit; 303 goto xs_err_exit;
319 } 304 }
320 305
321 306
322 /* Get song information for current subtune */ 307 /* Get song information for current subtune */
331 /* Open the audio output */ 316 /* Open the audio output */
332 if (!xs_plugin_ip.output->open_audio(myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels)) 317 if (!xs_plugin_ip.output->open_audio(myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels))
333 { 318 {
334 XSERR("Couldn't open XMMS audio output (fmt=%x, freq=%i, nchan=%i)!\n", 319 XSERR("Couldn't open XMMS audio output (fmt=%x, freq=%i, nchan=%i)!\n",
335 myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels); 320 myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels);
336 pthread_mutex_lock(&xs_mutex); 321
322 XS_MUTEX_LOCK(xs_status);
337 xs_status.isError = TRUE; 323 xs_status.isError = TRUE;
338 pthread_mutex_unlock(&xs_mutex); 324 XS_MUTEX_UNLOCK(xs_status);
339 goto xs_err_exit; 325 goto xs_err_exit;
340 } 326 }
341 327
342 audioOpen = TRUE; 328 audioOpen = TRUE;
343 329
345 * Play the subtune 331 * Play the subtune
346 */ 332 */
347 while (xs_status.isPlaying && myStatus.isPlaying && (xs_status.currSong == myStatus.currSong)) 333 while (xs_status.isPlaying && myStatus.isPlaying && (xs_status.currSong == myStatus.currSong))
348 { 334 {
349 /* Render audio data */ 335 /* Render audio data */
350 audioGot = xs_player->plrFillBuffer(&myStatus, audioBuffer, XS_BUFSIZE); 336 audioGot = myStatus.sidPlayer->plrFillBuffer(&myStatus, audioBuffer, XS_BUFSIZE);
351 337
352 /* I <3 visualice/haujobb */ 338 /* I <3 visualice/haujobb */
353 xs_plugin_ip.add_vis_pcm( 339 xs_plugin_ip.add_vis_pcm(
354 xs_plugin_ip.output->written_time(), 340 xs_plugin_ip.output->written_time(),
355 myStatus.audioFormat, myStatus.audioChannels, 341 myStatus.audioFormat, myStatus.audioChannels,
364 /* Output audio */ 350 /* Output audio */
365 if (xs_status.isPlaying && (xs_status.currSong == myStatus.currSong)) 351 if (xs_status.isPlaying && (xs_status.currSong == myStatus.currSong))
366 xs_plugin_ip.output->write_audio(audioBuffer, audioGot); 352 xs_plugin_ip.output->write_audio(audioBuffer, audioGot);
367 353
368 /* Check if we have played enough */ 354 /* Check if we have played enough */
355 XS_MUTEX_LOCK(xs_cfg);
369 if (xs_cfg.playMaxTimeEnable) 356 if (xs_cfg.playMaxTimeEnable)
370 { 357 {
371 if (xs_cfg.playMaxTimeUnknown) 358 if (xs_cfg.playMaxTimeUnknown)
372 { 359 {
373 if ((songLength == -1) && 360 if ((songLength == -1) &&
376 } else { 363 } else {
377 if (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000)) 364 if (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000))
378 myStatus.isPlaying = FALSE; 365 myStatus.isPlaying = FALSE;
379 } 366 }
380 } 367 }
368 XS_MUTEX_UNLOCK(xs_cfg);
381 369
382 if (songLength > 0) 370 if (songLength > 0)
383 { 371 {
384 if (xs_plugin_ip.output->output_time() >= (songLength * 1000)) 372 if (xs_plugin_ip.output->output_time() >= (songLength * 1000))
385 myStatus.isPlaying = FALSE; 373 myStatus.isPlaying = FALSE;
409 } 397 }
410 398
411 /* Exit the playing thread */ 399 /* Exit the playing thread */
412 XSDEBUG("exiting thread, bye.\n"); 400 XSDEBUG("exiting thread, bye.\n");
413 401
414 pthread_mutex_lock(&xs_mutex); 402 XS_MUTEX_LOCK(xs_status);
415 xs_status.isPlaying = FALSE; 403 xs_status.isPlaying = FALSE;
416 pthread_mutex_unlock(&xs_mutex); 404 XS_MUTEX_UNLOCK(xs_status);
417 pthread_exit(NULL); 405 pthread_exit(NULL);
418 } 406 }
419 407
420 408
421 /* 409 /*
424 * Usually you would also initialize the output-plugin, but 412 * Usually you would also initialize the output-plugin, but
425 * this is XMMS-SID and we do it on the player thread instead. 413 * this is XMMS-SID and we do it on the player thread instead.
426 */ 414 */
427 void xs_play_file(gchar *pcFilename) 415 void xs_play_file(gchar *pcFilename)
428 { 416 {
417 assert(xs_status.sidPlayer);
418
429 XSDEBUG("play '%s'\n", pcFilename); 419 XSDEBUG("play '%s'\n", pcFilename);
430 420
431 /* Get tune information */ 421 /* Get tune information */
432 if ((xs_status.pTune = xs_player->plrGetSIDInfo(pcFilename)) == NULL) 422 if ((xs_status.tuneInfo = xs_status.sidPlayer->plrGetSIDInfo(pcFilename)) == NULL)
433 return; 423 return;
434 424
435 /* Initialize the tune */ 425 /* Initialize the tune */
436 if (!xs_player->plrLoadSID(&xs_status, pcFilename)) 426 if (!xs_status.sidPlayer->plrLoadSID(&xs_status, pcFilename))
437 { 427 {
438 xs_tune_free(xs_status.pTune); 428 xs_tuneinfo_free(xs_status.tuneInfo);
439 xs_status.pTune = NULL; 429 xs_status.tuneInfo = NULL;
440 return; 430 return;
441 } 431 }
442 432
443 XSDEBUG("load ok\n"); 433 XSDEBUG("load ok\n");
444 434
445 /* Set general status information */ 435 /* Set general status information */
446 xs_status.isPlaying = TRUE; 436 xs_status.isPlaying = TRUE;
447 xs_status.isError = FALSE; 437 xs_status.isError = FALSE;
448 xs_status.currSong = xs_status.pTune->startTune; 438 xs_status.currSong = xs_status.tuneInfo->startTune;
449 439
450 /* Start the playing thread! */ 440 /* Start the playing thread! */
451 if (pthread_create(&xs_decode_thread, NULL, xs_play_loop, NULL) < 0) 441 if (pthread_create(&xs_decode_thread, NULL, xs_play_loop, NULL) < 0)
452 { 442 {
453 XSERR("Couldn't start playing thread! Possible reason reported by system: %s\n", strerror(errno)); 443 XSERR("Couldn't start playing thread! Possible reason reported by system: %s\n", strerror(errno));
454 xs_tune_free(xs_status.pTune); 444 xs_tuneinfo_free(xs_status.tuneInfo);
455 xs_status.pTune = NULL; 445 xs_status.tuneInfo = NULL;
456 xs_player->plrDeleteSID(&xs_status); 446 xs_status.sidPlayer->plrDeleteSID(&xs_status);
457 } 447 }
458 448
459 XSDEBUG("systems should be up?\n"); 449 XSDEBUG("systems should be up?\n");
460 } 450 }
461 451
477 467
478 if (xs_status.isPlaying) 468 if (xs_status.isPlaying)
479 { 469 {
480 /* Stop playing */ 470 /* Stop playing */
481 XSDEBUG("stopping...\n"); 471 XSDEBUG("stopping...\n");
482 pthread_mutex_lock(&xs_mutex); 472 XS_MUTEX_LOCK(xs_status);
483 xs_status.isPlaying = FALSE; 473 xs_status.isPlaying = FALSE;
484 pthread_mutex_unlock(&xs_mutex); 474 XS_MUTEX_UNLOCK(xs_status);
485 pthread_join(xs_decode_thread, NULL); 475 pthread_join(xs_decode_thread, NULL);
486 } 476 }
487 477
488 /* Free tune information */ 478 /* Free tune information */
489 xs_player->plrDeleteSID(&xs_status); 479 xs_status.sidPlayer->plrDeleteSID(&xs_status);
490 xs_tune_free(xs_status.pTune); 480 xs_tuneinfo_free(xs_status.tuneInfo);
491 xs_status.pTune = NULL; 481 xs_status.tuneInfo = NULL;
492 482
493 /* Update subtune control */ 483 /* Update subtune control */
494 xs_subctrl_update(); 484 xs_subctrl_update();
495 } 485 }
496 486
504 xs_plugin_ip.output->pause(pauseState); 494 xs_plugin_ip.output->pause(pauseState);
505 } 495 }
506 496
507 497
508 /* 498 /*
499 * Set or change sub-tune
500 */
501 void xs_set_subtune(int n)
502 {
503 XS_MUTEX_LOCK(xs_status);
504
505 if (xs_status.tuneInfo && xs_status.isPlaying)
506 {
507 if ((n >= 1) && (n <= xs_status.tuneInfo->nsubTunes))
508 xs_status.currSong = n;
509 }
510
511 XS_MUTEX_UNLOCK(xs_status);
512
513 xs_subctrl_update();
514 }
515
516
517 void xs_change_subtune(int n)
518 {
519 XS_MUTEX_LOCK(xs_status);
520
521 if (xs_status.tuneInfo && xs_status.isPlaying)
522 {
523 n += xs_status.currSong;
524
525 if ((n >= 1) && (n <= xs_status.tuneInfo->nsubTunes))
526 xs_status.currSong = n;
527 }
528
529 XS_MUTEX_UNLOCK(xs_status);
530
531 xs_subctrl_update();
532 }
533
534
535 /*
509 * Pop-up subtune selector 536 * Pop-up subtune selector
510 */ 537 */
511 #define LUW(x...) lookup_widget(xs_fileinfowin, ## x) 538 void xs_subctrl_setsong(void)
539 {
540 xs_set_subtune(GTK_ADJUSTMENT(xs_subctrl_adj)->value);
541 }
542
543
544 void xs_subctrl_prevsong(void)
545 {
546 xs_change_subtune(-1);
547 }
548
549
550 void xs_subctrl_nextsong(void)
551 {
552 xs_change_subtune( 1);
553 }
554
512 555
513 void xs_subctrl_update(void) 556 void xs_subctrl_update(void)
514 { 557 {
515 GtkAdjustment *tmpAdj; 558 GtkAdjustment *tmpAdj;
516 gboolean isEnabled; 559 gboolean isEnabled;
560
561 XS_MUTEX_LOCK(xs_status);
517 562
518 /* Check if control window exists, we are currently playing and have a tune */ 563 /* Check if control window exists, we are currently playing and have a tune */
519 if (xs_subctrl) 564 if (xs_subctrl)
520 { 565 {
521 if (xs_status.pTune && xs_status.isPlaying) 566 if (xs_status.tuneInfo && xs_status.isPlaying)
522 { 567 {
568 XS_MUTEX_LOCK(xs_subctrl);
523 tmpAdj = GTK_ADJUSTMENT(xs_subctrl_adj); 569 tmpAdj = GTK_ADJUSTMENT(xs_subctrl_adj);
524 570
525 tmpAdj->value = xs_status.currSong; 571 tmpAdj->value = xs_status.currSong;
526 tmpAdj->lower = 1; 572 tmpAdj->lower = 1;
527 tmpAdj->upper = xs_status.pTune->nsubTunes; 573 tmpAdj->upper = xs_status.tuneInfo->nsubTunes;
528 gtk_adjustment_value_changed(tmpAdj); 574 gtk_adjustment_value_changed(tmpAdj);
575 XS_MUTEX_UNLOCK(xs_subctrl);
529 } else 576 } else
530 xs_subctrl_close(); 577 xs_subctrl_close();
531 } 578 }
532 579
533 if (xs_fileinfowin) 580 XS_MUTEX_UNLOCK(xs_status);
534 {
535 /* Check if we are currently playing and have a tune */
536 if (xs_status.pTune && xs_status.isPlaying && (xs_status.pTune->nsubTunes > 1))
537 {
538 tmpAdj = gtk_range_get_adjustment(GTK_RANGE(LUW("fileinfo_subctrl_adj")));
539
540 tmpAdj->value = xs_status.currSong;
541 tmpAdj->lower = 1;
542 tmpAdj->upper = xs_status.pTune->nsubTunes;
543 gtk_adjustment_value_changed(tmpAdj);
544 isEnabled = TRUE;
545 } else
546 isEnabled = FALSE;
547
548 /* Enable or disable subtune-control in fileinfo window */
549 gtk_widget_set_sensitive(LUW("fileinfo_subctrl_prev"), isEnabled);
550 gtk_widget_set_sensitive(LUW("fileinfo_subctrl_adj"), isEnabled);
551 gtk_widget_set_sensitive(LUW("fileinfo_subctrl_next"), isEnabled);
552 }
553 }
554
555
556 void xs_fileinfo_setsong(void)
557 {
558 pthread_mutex_lock(&xs_mutex);
559 xs_status.currSong = gtk_range_get_adjustment(GTK_RANGE(LUW("fileinfo_subctrl_adj")))->value;
560 pthread_mutex_unlock(&xs_mutex);
561 }
562
563
564 void xs_subctrl_setsong(void)
565 {
566 pthread_mutex_lock(&xs_mutex);
567 xs_status.currSong = GTK_ADJUSTMENT(xs_subctrl_adj)->value;
568 pthread_mutex_unlock(&xs_mutex);
569 }
570
571
572 void xs_subctrl_prevsong(void)
573 {
574 if (xs_status.pTune && xs_status.isPlaying)
575 {
576 pthread_mutex_lock(&xs_mutex);
577 if (xs_status.currSong > 1)
578 xs_status.currSong--;
579 pthread_mutex_unlock(&xs_mutex);
580 }
581
582 xs_subctrl_update();
583 }
584
585
586 void xs_subctrl_nextsong(void)
587 {
588 if (xs_status.pTune && xs_status.isPlaying)
589 {
590 pthread_mutex_lock(&xs_mutex);
591 if (xs_status.currSong < xs_status.pTune->nsubTunes)
592 xs_status.currSong++;
593 pthread_mutex_unlock(&xs_mutex);
594 }
595
596 xs_subctrl_update();
597 } 581 }
598 582
599 583
600 void xs_subctrl_close(void) 584 void xs_subctrl_close(void)
601 { 585 {
586 XS_MUTEX_LOCK(xs_subctrl);
602 if (xs_subctrl) 587 if (xs_subctrl)
603 { 588 {
604 gtk_widget_destroy(xs_subctrl); 589 gtk_widget_destroy(xs_subctrl);
605 xs_subctrl = NULL; 590 xs_subctrl = NULL;
606 } 591 }
592 XS_MUTEX_UNLOCK(xs_subctrl);
607 } 593 }
608 594
609 595
610 gboolean xs_subctrl_keypress(GtkWidget *win, GdkEventKey *ev) 596 gboolean xs_subctrl_keypress(GtkWidget *win, GdkEventKey *ev)
611 { 597 {
618 604
619 void xs_subctrl_open() 605 void xs_subctrl_open()
620 { 606 {
621 GtkWidget *frame25, *hbox15, *subctrl_prev, *subctrl_current, *subctrl_next; 607 GtkWidget *frame25, *hbox15, *subctrl_prev, *subctrl_current, *subctrl_next;
622 608
623 if (!xs_status.pTune || !xs_status.isPlaying || 609 XS_MUTEX_LOCK(xs_subctrl);
624 xs_subctrl || (xs_status.pTune->nsubTunes <= 1)) return; 610
611 if (!xs_status.tuneInfo || !xs_status.isPlaying ||
612 xs_subctrl || (xs_status.tuneInfo->nsubTunes <= 1))
613 {
614 XS_MUTEX_UNLOCK(xs_subctrl);
615 return;
616 }
625 617
626 /* Create the pop-up window */ 618 /* Create the pop-up window */
627 xs_subctrl = gtk_window_new (GTK_WINDOW_DIALOG); 619 xs_subctrl = gtk_window_new (GTK_WINDOW_DIALOG);
628 gtk_widget_set_name (xs_subctrl, "xs_subctrl"); 620 gtk_widget_set_name (xs_subctrl, "xs_subctrl");
629 gtk_object_set_data (GTK_OBJECT (xs_subctrl), "xs_subctrl", xs_subctrl); 621 gtk_object_set_data (GTK_OBJECT (xs_subctrl), "xs_subctrl", xs_subctrl);
654 646
655 subctrl_prev = gtk_button_new_with_label (" < "); 647 subctrl_prev = gtk_button_new_with_label (" < ");
656 gtk_widget_set_name (subctrl_prev, "subctrl_prev"); 648 gtk_widget_set_name (subctrl_prev, "subctrl_prev");
657 gtk_box_pack_start (GTK_BOX (hbox15), subctrl_prev, FALSE, FALSE, 0); 649 gtk_box_pack_start (GTK_BOX (hbox15), subctrl_prev, FALSE, FALSE, 0);
658 650
659 xs_subctrl_adj = gtk_adjustment_new (xs_status.currSong, 1, xs_status.pTune->nsubTunes, 1, 1, 0); 651 xs_subctrl_adj = gtk_adjustment_new (xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes, 1, 1, 0);
660 gtk_signal_connect (GTK_OBJECT (xs_subctrl_adj), "value_changed", 652 gtk_signal_connect (GTK_OBJECT (xs_subctrl_adj), "value_changed",
661 GTK_SIGNAL_FUNC (xs_subctrl_setsong), NULL); 653 GTK_SIGNAL_FUNC (xs_subctrl_setsong), NULL);
662 654
663 subctrl_current = gtk_hscale_new (GTK_ADJUSTMENT(xs_subctrl_adj)); 655 subctrl_current = gtk_hscale_new (GTK_ADJUSTMENT(xs_subctrl_adj));
664 gtk_widget_set_name (subctrl_current, "subctrl_current"); 656 gtk_widget_set_name (subctrl_current, "subctrl_current");
679 671
680 gtk_signal_connect (GTK_OBJECT (xs_subctrl), "key_press_event", 672 gtk_signal_connect (GTK_OBJECT (xs_subctrl), "key_press_event",
681 GTK_SIGNAL_FUNC (xs_subctrl_keypress), NULL); 673 GTK_SIGNAL_FUNC (xs_subctrl_keypress), NULL);
682 674
683 gtk_widget_show_all(xs_subctrl); 675 gtk_widget_show_all(xs_subctrl);
676
677 XS_MUTEX_UNLOCK(xs_subctrl);
684 } 678 }
685 679
686 680
687 /* 681 /*
688 * Set the time-seek position 682 * Set the time-seek position
694 * other method of seeking is used (keyboard, etc.) 688 * other method of seeking is used (keyboard, etc.)
695 */ 689 */
696 void xs_seek(gint iTime) 690 void xs_seek(gint iTime)
697 { 691 {
698 /* Check status */ 692 /* Check status */
699 if (!xs_status.pTune || !xs_status.isPlaying) return; 693 XS_MUTEX_LOCK(xs_status);
700 694 if (!xs_status.tuneInfo || !xs_status.isPlaying)
701 /* Act according to settings */ 695 {
696 XS_MUTEX_UNLOCK(xs_status);
697 return;
698 }
699
700 /* Act according to settings */
701 XS_MUTEX_LOCK(xs_cfg);
702 switch (xs_cfg.subsongControl) { 702 switch (xs_cfg.subsongControl) {
703 case XS_SSC_SEEK: 703 case XS_SSC_SEEK:
704 if (iTime < xs_status.lastTime) 704 if (iTime < xs_status.lastTime)
705 xs_subctrl_prevsong(); 705 xs_change_subtune(-1);
706 else 706 else
707 if (iTime > xs_status.lastTime) 707 if (iTime > xs_status.lastTime)
708 xs_subctrl_nextsong(); 708 xs_change_subtune(1);
709 break; 709 break;
710 710
711 case XS_SSC_POPUP: 711 case XS_SSC_POPUP:
712 xs_subctrl_open(); 712 xs_subctrl_open();
713 break; 713 break;
714 714
715 /* If we have song-position patch, check settings */ 715 /* If we have song-position patch, check settings */
716 #ifdef HAVE_SONG_POSITION 716 #ifdef HAVE_SONG_POSITION
717 case XS_SSC_PATCH: 717 case XS_SSC_PATCH:
718 pthread_mutex_lock(&xs_mutex); 718 if ((iTime > 0) && (iTime <= xs_status.tuneInfo->nsubTunes))
719
720 if ((iTime > 0) && (iTime <= xs_status.pTune->nsubTunes))
721 xs_status.currSong = iTime; 719 xs_status.currSong = iTime;
722
723 pthread_mutex_unlock(&xs_mutex);
724 break; 720 break;
725 #endif 721 #endif
726
727 default:
728 break;
729 } 722 }
723
724 XS_MUTEX_UNLOCK(xs_cfg);
725 XS_MUTEX_UNLOCK(xs_status);
730 } 726 }
731 727
732 728
733 /* 729 /*
734 * Return the playing "position/time" 730 * Return the playing "position/time"
738 * error dialog. -1 means end of song (if one was playing currently). 734 * error dialog. -1 means end of song (if one was playing currently).
739 */ 735 */
740 gint xs_get_time(void) 736 gint xs_get_time(void)
741 { 737 {
742 /* If errorflag is set, return -2 to signal it to XMMS's idle callback */ 738 /* If errorflag is set, return -2 to signal it to XMMS's idle callback */
739 XS_MUTEX_LOCK(xs_status);
740
743 if (xs_status.isError) 741 if (xs_status.isError)
742 {
743 XS_MUTEX_UNLOCK(xs_status);
744 return -2; 744 return -2;
745 }
745 746
746 /* If there is no tune, return -1 */ 747 /* If there is no tune, return -1 */
747 if (!xs_status.pTune) 748 if (!xs_status.tuneInfo)
749 {
750 XS_MUTEX_UNLOCK(xs_status);
748 return -1; 751 return -1;
752 }
749 753
750 /* If tune has ended, return -1 */ 754 /* If tune has ended, return -1 */
751 if (!xs_status.isPlaying) 755 if (!xs_status.isPlaying)
756 {
757 XS_MUTEX_UNLOCK(xs_status);
752 return -1; 758 return -1;
759 }
753 760
754 /* Let's see what we do */ 761 /* Let's see what we do */
762 XS_MUTEX_LOCK(xs_cfg);
755 switch (xs_cfg.subsongControl) { 763 switch (xs_cfg.subsongControl) {
756 case XS_SSC_SEEK: 764 case XS_SSC_SEEK:
757 xs_status.lastTime = (xs_plugin_ip.output->output_time() / 1000); 765 xs_status.lastTime = (xs_plugin_ip.output->output_time() / 1000);
758 break; 766 break;
759 767
760 #ifdef HAVE_SONG_POSITION 768 #ifdef HAVE_SONG_POSITION
761 case XS_SSC_PATCH: 769 case XS_SSC_PATCH:
762 pthread_mutex_lock(&xs_mutex); 770 set_song_position(xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes);
763 set_song_position(xs_status.currSong, 1, xs_status.pTune->nsubTunes);
764 pthread_mutex_unlock(&xs_mutex);
765 break; 771 break;
766 #endif 772 #endif
767 } 773 }
768 774
775 XS_MUTEX_UNLOCK(xs_cfg);
776 XS_MUTEX_UNLOCK(xs_status);
777
769 /* Return output time reported by audio output plugin */ 778 /* Return output time reported by audio output plugin */
770 return xs_plugin_ip.output->output_time(); 779 return xs_plugin_ip.output->output_time();
771 } 780 }
772 781
773 782
777 * Subsequent changes to information are made by the player thread, 786 * Subsequent changes to information are made by the player thread,
778 * which uses xs_plugin_ip.set_info(); 787 * which uses xs_plugin_ip.set_info();
779 */ 788 */
780 void xs_get_song_info(gchar *songFilename, gchar **songTitle, gint *songLength) 789 void xs_get_song_info(gchar *songFilename, gchar **songTitle, gint *songLength)
781 { 790 {
782 t_xs_tune *pInfo; 791 t_xs_tuneinfo *pInfo;
783 gint tmpInt; 792 gint tmpInt;
784 793
785 /* Get tune information from emulation engine */ 794 /* Get tune information from emulation engine */
786 pInfo = xs_player->plrGetSIDInfo(songFilename); 795 pInfo = xs_status.sidPlayer->plrGetSIDInfo(songFilename);
787 if (!pInfo) return; 796 if (!pInfo) return;
788 797
789 /* Get sub-tune information, if available */ 798 /* Get sub-tune information, if available */
790 if ((pInfo->startTune >= 0) && (pInfo->startTune <= pInfo->nsubTunes)) 799 if ((pInfo->startTune >= 0) && (pInfo->startTune <= pInfo->nsubTunes))
791 { 800 {
797 else 806 else
798 (*songLength) = (tmpInt * 1000); 807 (*songLength) = (tmpInt * 1000);
799 } 808 }
800 809
801 /* Free tune information */ 810 /* Free tune information */
802 xs_tune_free(pInfo); 811 xs_tuneinfo_free(pInfo);
803 } 812 }
804 813
805 814
806 /* 815 /* Allocate a new tune information structure
807 * Allocate a new tune structure 816 */
808 */ 817 t_xs_tuneinfo *xs_tuneinfo_new(gchar *pcFilename, gint nsubTunes, gint startTune,
809 t_xs_tune *xs_tune_new(gchar *pcFilename, gint nsubTunes, gint startTune, 818 gchar *sidName, gchar *sidComposer, gchar *sidCopyright,
810 gchar *tuneName, gchar *tuneComposer, gchar *tuneCopyright) 819 gint loadAddr, gint initAddr, gint playAddr, gint dataFileLen)
811 { 820 {
812 t_xs_tune *pResult; 821 t_xs_tuneinfo *pResult;
813 822
814 pResult = (t_xs_tune *) g_malloc0(sizeof(t_xs_tune)); 823 pResult = (t_xs_tuneinfo *) g_malloc0(sizeof(t_xs_tuneinfo));
815 if (!pResult) return NULL; 824 if (!pResult) return NULL;
816 825
817 pResult->tuneFilename = g_strdup(pcFilename); 826 pResult->sidFilename = g_strdup(pcFilename);
818 if (!pResult->tuneFilename) 827 if (!pResult->sidFilename)
819 { 828 {
820 g_free(pResult); 829 g_free(pResult);
821 return NULL; 830 return NULL;
822 } 831 }
823 832
824 pResult->tuneName = g_strdup(tuneName); 833 pResult->sidName = g_strdup(sidName);
825 pResult->tuneComposer = g_strdup(tuneComposer); 834 pResult->sidComposer = g_strdup(sidComposer);
826 pResult->tuneCopyright = g_strdup(tuneCopyright); 835 pResult->sidCopyright = g_strdup(sidCopyright);
827 pResult->nsubTunes = nsubTunes; 836 pResult->nsubTunes = nsubTunes;
828 pResult->startTune = startTune; 837 pResult->startTune = startTune;
838
839 pResult->loadAddr = loadAddr;
840 pResult->initAddr = initAddr;
841 pResult->playAddr = playAddr;
842 pResult->dataFileLen = dataFileLen;
829 843
830 return pResult; 844 return pResult;
831 } 845 }
832 846
833 847
834 /* 848 /* Free given tune information structure
835 * Free tune information 849 */
836 */ 850 void xs_tuneinfo_free(t_xs_tuneinfo *pTune)
837 void xs_tune_free(t_xs_tune *pTune)
838 { 851 {
839 gint i; 852 gint i;
840 if (!pTune) return; 853 if (!pTune) return;
841 854
842 g_free(pTune->tuneFilename); pTune->tuneFilename = NULL; 855 g_free(pTune->sidFilename); pTune->sidFilename = NULL;
843 g_free(pTune->tuneName); pTune->tuneName = NULL; 856 g_free(pTune->sidName); pTune->sidName = NULL;
844 g_free(pTune->tuneComposer); pTune->tuneComposer = NULL; 857 g_free(pTune->sidComposer); pTune->sidComposer = NULL;
845 g_free(pTune->tuneCopyright); pTune->tuneCopyright = NULL; 858 g_free(pTune->sidCopyright); pTune->sidCopyright = NULL;
846 859
847 for (i = 0; i < pTune->nsubTunes; i++) 860 for (i = 0; i < pTune->nsubTunes; i++)
848 { 861 {
849 if (pTune->subTunes[i].tuneTitle) 862 if (pTune->subTunes[i].tuneTitle)
850 { 863 {
854 } 867 }
855 868
856 g_free(pTune); 869 g_free(pTune);
857 } 870 }
858 871
872
873 void xs_fileinfo_ok(void)
874 {
875 }