# HG changeset patch # User Matti Hamalainen # Date 1054638420 0 # Node ID 5b7009eef767e09fa1b0873e877b70dfb606e3ee # Parent 4bb09e405eab5f237dcfc96f1dcc85ce03a4de15 Updated to 0.8 diff -r 4bb09e405eab -r 5b7009eef767 src/Makefile.am --- a/src/Makefile.am Tue Jun 03 11:03:04 2003 +0000 +++ b/src/Makefile.am Tue Jun 03 11:07:00 2003 +0000 @@ -1,23 +1,23 @@ # Generated libraries -lib_LTLIBRARIES = libsid.la +lib_LTLIBRARIES = libxmmssid.la # Generals - -CFLAGS = -O2 -W -Wall -I$(top_builddir) -I$(top_srcdir) -I$(includedir) -D_REENTRANT @GTK_CFLAGS@ @SIDPLAY_CFLAGS@ -lstdc++ +CFLAGS = -D_REENTRANT @GTK_CFLAGS@ @SIDPLAY_CFLAGS@ CXXFLAGS = $(CFLAGS) -LIBS = -lsidplay -libsid_la_LDFLAGS = -module -avoid-version -libsid_la_LIBADD = @GTK_LIBS@ @PTHREAD_LIBS@ +libxmmssid_la_LDFLAGS = -module -avoid-version +libxmmssid_la_LIBADD = @GTK_LIBS@ @PTHREAD_LIBS@ @SIDPLAY_LIBS@ -lstdc++ # Plugin sources -libsid_la_SOURCES = \ - xmms-sid.cc \ +libxmmssid_la_SOURCES = \ + xmms-sid.cpp xmms-sid.h \ xs_init.c \ - xs_config.c \ - xs_fileinfo.cc \ - xs_stil.c \ - xs_about.c \ - xmms-sid.h \ - xmms-sid-logo.xpm - + xs_title.cpp \ + xs_support.c xs_support.h \ + xs_config.c xs_config.h \ + xs_md5.c xs_md5.h \ + xs_length.c xs_length.h \ + xs_stil.c xs_stil.h \ + xs_genui.c xs_genui.h \ + xs_glade.c xs_glade.h \ + xs_interface.c xs_interface.h diff -r 4bb09e405eab -r 5b7009eef767 src/xmms-sid.cc --- a/src/xmms-sid.cc Tue Jun 03 11:03:04 2003 +0000 +++ b/src/xmms-sid.cc Tue Jun 03 11:07:00 2003 +0000 @@ -1,10 +1,10 @@ /* - xmms-sid - SIDPlay input plugin for X MultiMedia System (XMMS) + XMMS-SID - SIDPlay input plugin for X MultiMedia System (XMMS) Main source file - Originally by Willem Monsuwe - Additions, fixes, etc by Matti "ccr" Hamalainen + Written by Matti "ccr" Hamalainen + (few bits may still be by Willem Monsuwe) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,13 +26,13 @@ #include #include - extern "C" { #include #include #include #include +#include #include #include @@ -40,235 +40,302 @@ /* - * General variables + * Global variables */ static struct emuConfig xs_emuConf; static emuEngine xs_emuEngine; static pthread_t xs_decode_thread; -static int xs_error = 0, xs_going = 0, xs_songs = 0; -struct T_sid_cfg xs_cfg; +struct t_xs_cfg xs_cfg; + +struct { + int s_error, s_playing, s_songs, s_allownext; + sidTune *s_tune; + gchar *s_fname; +} xs_status; + +pthread_mutex_t xs_mutex = PTHREAD_MUTEX_INITIALIZER; /* - * Initialize xmms-sid plugin + * Initialize XMMS-SID */ void xs_init(void) { + XSDEBUG("xs_init()\n"); - if (!xs_emuEngine) { - xs_error = 1; - XSERR("Couldn't start SIDPlay emulator engine!\n"); - return; + /* Try to initialize libSIDPlay */ + if (!xs_emuEngine) + { + XSERR("Couldn't start SIDPlay emulator engine!\n"); + return; } - if (!xs_emuEngine.verifyEndianess()) { - xs_error = 1; - XSERR("Wrong hardware endianess (SIDPlay error)!\n"); - return; + if (!xs_emuEngine.verifyEndianess()) + { + XSERR("Wrong hardware endianess (SIDPlay error)!\n"); + return; } - // Initialize STIL structures - memset(&xs_stil_info, 0, sizeof(xs_stil_info)); - xs_stil_clear(); - - // Get configuration - xs_get_configure(); -} - + /* Initialize and get configuration */ + memset(&xs_cfg, 0, sizeof(xs_cfg)); + xs_get_configure(); -/* - * Special, custom hand-made strcpy with smooth leather coating. - */ -int xs_strcpy(char *dest, const char *src, unsigned int *j) -{ - unsigned int i; + xs_status.s_error = 0; + xs_status.s_playing = 0; + xs_status.s_songs = 0; + xs_status.s_allownext = 1; // Initialize to TRUE to allow first song + xs_status.s_tune = NULL; + xs_status.s_fname = NULL; + + /* Initialize STIL structures */ +// FIXME FIXME FIx ME - if ((dest == NULL) || (src == NULL)) return -1; - - for (i = 0; i < strlen(src); i++) { - dest[(*j)++] = src[i]; - } - - return 0; + /* Create sub-song control window */ +// FIX ME FIXME } /* - Create the SID-tune description string from the - tune's information formatted by the user-specified - format-string. -*/ -static char * xs_make_filedesc(struct sidTuneInfo *s) + * Shut down XMMS-SID + */ +void xs_close(void) { - unsigned int i, len, j; - char *result; - - /* Check the info strings */ - if (s->numberOfInfoStrings != 3) { - if (s->numberOfInfoStrings < 1) { - return 0; - } - return g_strdup(s->infoString[0]); - } - - /* Check the format-string for NULL */ - if (xs_cfg.fileInfo == NULL) { - return g_strdup_printf("%s - %s", s->nameString, s->authorString); - } + XSDEBUG("shutting down...\n"); - /* Pre-calculate the length of the result-string */ - len = 2; - for (i = 0; i < strlen(xs_cfg.fileInfo); i++) { - if (xs_cfg.fileInfo[i] == '%') { - switch (xs_cfg.fileInfo[++i]) { - case '1': len += strlen(s->authorString); break; - case '2': len += strlen(s->nameString); break; - case '3': len += strlen(s->copyrightString); break; - case '4': len += strlen(s->formatString); break; - } - } else len++; - } - - /* Allocate the result-string */ - result = (char *) g_malloc(len); + /* Stop playing */ + xmms_sid_ip.stop(); - /* Construct the final result info */ - j = 0; - for (i = 0; i < strlen(xs_cfg.fileInfo); i++) { + /* Free allocated memory */ - if (xs_cfg.fileInfo[i] == '%') { - switch (xs_cfg.fileInfo[++i]) { - case '1': xs_strcpy(result, s->authorString, &j); break; - case '2': xs_strcpy(result, s->nameString, &j); break; - case '3': xs_strcpy(result, s->copyrightString, &j); break; - case '4': xs_strcpy(result, s->formatString, &j); break; - } + // FIXME FIXME: STIL-entries, songlendb - } else { - result[j++] = xs_cfg.fileInfo[i]; - } /* if */ - - } /* for */ - - result[j] = '\0'; - - return result; } /* * Check whether the given file is handled by this plugin */ -int xs_is_our_file(char *filename) +gint xs_is_our_file(char *fileName) { - if (xs_cfg.detectMagic) { - sidTune *t = new sidTune(filename); + char *pcExt; + + /* Check the filename */ + if (fileName == NULL) + return FALSE; + + /* Try to detect via libSIDPlay's detection routine, if required */ + if (xs_cfg.detectMagic) { - if (!t->getStatus()) { - delete t; - return FALSE; - } + sidTune *testTune = new sidTune(fileName); - delete t; - return TRUE; + if (!testTune) return FALSE; + if (!testTune->getStatus()) + { + delete testTune; + return FALSE; + } + + delete testTune; + return TRUE; } - char *ext = strrchr(filename, '.'); - if (ext) { - ext++; - if (!strcasecmp(ext, "psid")) return TRUE; - if (!strcasecmp(ext, "sid")) return TRUE; - if (!strcasecmp(ext, "dat")) return TRUE; - if (!strcasecmp(ext, "inf")) return TRUE; - if (!strcasecmp(ext, "info")) return TRUE; + + /* Detect just by checking filename extension */ + pcExt = strrchr(fileName, '.'); + if (pcExt) + { + pcExt++; + if (!strcasecmp(pcExt, "psid")) return TRUE; + if (!strcasecmp(pcExt, "sid")) return TRUE; + if (!strcasecmp(pcExt, "dat")) return TRUE; + if (!strcasecmp(pcExt, "inf")) return TRUE; + if (!strcasecmp(pcExt, "info")) return TRUE; } - return FALSE; + + return FALSE; } /* * Playing thread loop function */ -static void * xs_play_loop(void *arg) +static void *xs_play_loop(void *argPointer) { - sidTune *tune = (sidTune *)arg; - char data[XMMS_SID_BUFSIZE]; - int fxlen, tn; - struct sidTuneInfo sidInf; - char *name; - enum AFormat fmt = (xs_emuConf.bitsPerSample == 16) ? FMT_S16_NE : FMT_U8; - gint chn = xs_emuConf.channels; + gchar plr_data[XMMS_SID_BUFSIZE]; + struct sidTuneInfo plr_sidInf; + gchar *plr_tune_title = NULL; + gint plr_fxlen; + enum AFormat plr_fmt; + gint plr_tune_num; + gint32 plr_tune_len; + + + /* Don't allow next song to be set yet */ + pthread_mutex_lock(&xs_mutex); + xs_status.s_allownext = 0; + pthread_mutex_unlock(&xs_mutex); + + + /* Check tune number */ + plr_tune_num = xs_status.s_playing; + + if (plr_tune_num <= 0) + plr_tune_num = 1; + +XSDEBUG("xs_play_loop(%d, %d)\n", plr_tune_num, xs_status.s_playing); + + /* Get song information */ + xs_status.s_tune->getInfo(plr_sidInf); + plr_tune_len = xs_get_length(xs_status.s_fname, plr_tune_num); + plr_tune_title = xs_get_filetitle(&plr_sidInf, plr_tune_num); - tune->getInfo(sidInf); - name = xs_make_filedesc(&sidInf); +XSDEBUG("title='%s', len=%d\n", plr_tune_title, plr_tune_len); + + + /* Initialize audio output */ + // FIXME FIXME: FMT_S16_XXX -- different architechtures?? + // the patch may break something ... + plr_fmt = (xs_emuConf.bitsPerSample == 16) ? FMT_S16_NE : FMT_U8; + -play_loop_new_tune: - tn = xs_going; - if (tn <= 0) tn = 1; - if (!xmms_sid_ip.output->open_audio(fmt, xs_emuConf.frequency, chn)) + if (!xmms_sid_ip.output->open_audio(plr_fmt, xs_emuConf.frequency, xs_emuConf.channels)) { - xs_error = 1; - XSERR("Couldn't open XMMS audio output!\n"); - delete tune; - pthread_exit(NULL); - xs_stop(); + pthread_mutex_lock(&xs_mutex); + xs_status.s_error = 1; + if (plr_tune_title) g_free(plr_tune_title); + if (xs_status.s_tune) delete xs_status.s_tune; + xs_status.s_allownext = 1; + pthread_mutex_unlock(&xs_mutex); + return NULL; + } + + + /* Initialize the SIDPlay-emulator for song */ + if (!sidEmuInitializeSong(xs_emuEngine, *xs_status.s_tune, plr_tune_num)) + { + XSERR("Couldn't initialize SIDPlay emulator engine! This may be a problem with your sound settings, or possibly a bug in XMMS-SID.\n"); + pthread_mutex_lock(&xs_mutex); + xs_status.s_error = 1; + pthread_mutex_unlock(&xs_mutex); + goto pl_cleanup; } - if (!sidEmuInitializeSong(xs_emuEngine, *tune, tn)) { - xs_error = 1; - XSERR("Couldn't initialize SIDPlay emulator engine!\n"); - delete tune; - pthread_exit(NULL); - xs_stop(); - } + + /* Set song title information */ + xmms_sid_ip.set_info( + plr_tune_title, + (plr_tune_len * 1000), + (1000 * (plr_sidInf.songSpeed ? plr_sidInf.songSpeed : (plr_sidInf.clockSpeed == SIDTUNE_CLOCK_NTSC) ? 60 : 50)), + xs_emuConf.frequency, + xs_emuConf.channels); + - tune->getInfo(sidInf); + /* Run playing loop: loop as long as xs_playing is same as current tune number */ + while (xs_status.s_playing == plr_tune_num) + { + plr_fxlen = XMMS_SID_BUFSIZE; + + /* Run emulator to fill output buffer with audio data */ + sidEmuFillBuffer(xs_emuEngine, *xs_status.s_tune, plr_data, plr_fxlen); + + /* If Max Playtime option set, check playtime */ + if (xs_cfg.playUseMaxTime) + { + if ((xmms_sid_ip.output->output_time() / 1000) >= xs_cfg.playMaxTime) + { + pthread_mutex_lock(&xs_mutex); + xs_status.s_playing = 0; + pthread_mutex_unlock(&xs_mutex); + } + } - xmms_sid_ip.set_info(name, -1, - 1000 * (sidInf.songSpeed ? sidInf.songSpeed : (sidInf.clockSpeed == SIDTUNE_CLOCK_NTSC) ? 60 : 50), - xs_emuConf.frequency, chn); + /* Check playtime against database */ + if (xs_cfg.playMethod == XMMS_SID_PMETHOD_DATABASE) + { + if ((xmms_sid_ip.output->output_time() / 1000) >= plr_tune_len) + { + pthread_mutex_lock(&xs_mutex); + xs_status.s_playing = 0; + pthread_mutex_unlock(&xs_mutex); + } + + } +#if 0 + else - while (xs_going == tn) - { - fxlen = XMMS_SID_BUFSIZE; - sidEmuFillBuffer(xs_emuEngine, *tune, data, fxlen); + /* Check for silence */ + if (xs_cfg.playMethod == XMMS_SID_PMETHOD_MAXSILENCE) + { + } + + /* Add static noise */ + + /* Muffle waveform (low-pass filter) */ +#endif + + + /* Send audio data to visualization plugin */ xmms_sid_ip.add_vis_pcm(xmms_sid_ip.output->written_time(), - fmt, chn, fxlen, data); + plr_fmt, xs_emuConf.channels, plr_fxlen, plr_data); - while ((xs_going == tn) && (xmms_sid_ip.output->buffer_free() < fxlen)) + /* Wait for a while */ + while ((xs_status.s_playing == plr_tune_num) && (xmms_sid_ip.output->buffer_free() < plr_fxlen)) xmms_usleep(10000); - if (xs_going == tn) - xmms_sid_ip.output->write_audio(data, fxlen); - } + + /* If playing, send final audio data to output plugin */ + if (xs_status.s_playing == plr_tune_num) + xmms_sid_ip.output->write_audio(plr_data, plr_fxlen); - /* Exit the playing thread */ + } /* End of playerloop */ + + +pl_cleanup: + XSDEBUG("cleaning up...\n"); + + /* Cleanup & shutdown */ xmms_sid_ip.output->close_audio(); - if (xs_going) goto play_loop_new_tune; - - g_free(name); + if (plr_tune_title) g_free(plr_tune_title); - delete tune; + pthread_mutex_lock(&xs_mutex); + xs_status.s_playing = 0; + if (xs_status.s_tune) delete xs_status.s_tune; + xs_status.s_allownext = 1; + pthread_mutex_unlock(&xs_mutex); - pthread_exit(NULL); + XSDEBUG("exiting thread, bye.\n"); + return NULL; } /* * Start playing the given file */ -void xs_play_file(char *filename) +void xs_play_file(char *fileName) { - sidTune *tune = new sidTune(filename); - struct sidTuneInfo sidInf; + sidTune *newTune; + struct sidTuneInfo sidInf; + + XSDEBUG("request to start '%s'\n", fileName); + + /* Wait until the previous song has finished for sure */ + if (!xs_status.s_allownext) + pthread_join(xs_decode_thread, NULL); - /* Get current configuration */ - xs_emuEngine.getConfig(xs_emuConf); + /* Try to get the tune */ + newTune = new sidTune(fileName); + if (newTune == NULL) return; + + XSDEBUG("tune ok, status %i\n", xs_status.s_playing); - /* Configure channels and stuff */ - switch (xs_cfg.channels) { + /* Get current configuration */ + xs_emuEngine.getConfig(xs_emuConf); + + + /* Configure channels and stuff */ + switch (xs_cfg.fmtChannels) { case XMMS_SID_CHN_AUTOPAN: xs_emuConf.channels = SIDEMU_STEREO; @@ -288,14 +355,14 @@ xs_emuConf.volumeControl = SIDEMU_NONE; break; - default:xs_error = 1; - XSERR("Internal: Invalid channels setting. Please report to author!\n"); - delete tune; - break; - } + default: + XSERR("Internal: Invalid channels setting. Possibly corrupted configuration file.\n"); + delete newTune; + return; + } - /* Memory mode settings */ - switch (xs_cfg.memoryMode) { + /* Memory mode settings */ + switch (xs_cfg.memoryMode) { case XMMS_SID_MPU_BANK_SWITCHING: xs_emuConf.memoryMode = MPU_BANK_SWITCHING; break; @@ -308,15 +375,15 @@ xs_emuConf.memoryMode = MPU_PLAYSID_ENVIRONMENT; break; - default:xs_error = 1; - XSERR("Internal: Invalid memoryMode setting. Please report to author!\n"); - delete tune; - break; - } + default: + XSERR("Internal: Invalid memoryMode setting. Possibly corrupted configuration file.\n"); + delete newTune; + return; + } - /* Clockspeed settings */ - switch (xs_cfg.clockSpeed) { + /* Clockspeed settings */ + switch (xs_cfg.clockSpeed) { case XMMS_SID_CLOCK_PAL: xs_emuConf.clockSpeed = SIDTUNE_CLOCK_PAL; break; @@ -325,101 +392,135 @@ xs_emuConf.clockSpeed = SIDTUNE_CLOCK_NTSC; break; - default:xs_error = 1; - XSERR("Internal: Invalid clockSpeed setting. Please report to author!\n"); - delete tune; - break; + default: + XSERR("Internal: Invalid clockSpeed setting. Possibly corrupted configuration file.\n"); + delete newTune; + return; + } + + + /* Configure rest of the emulation */ + xs_emuConf.bitsPerSample = xs_cfg.fmtBitsPerSample; + xs_emuConf.frequency = xs_cfg.fmtFrequency; + xs_emuConf.sampleFormat = SIDEMU_SIGNED_PCM; + xs_emuConf.mos8580 = xs_cfg.mos8580; + xs_emuConf.emulateFilter = xs_cfg.emulateFilter; + xs_emuConf.filterFs = xs_cfg.filterFs; + xs_emuConf.filterFm = xs_cfg.filterFm; + xs_emuConf.filterFt = xs_cfg.filterFt; + + XSDEBUG("configuring engine..\n"); + + /* Now set the emulator configuration */ + xs_emuEngine.setConfig(xs_emuConf); + newTune->getInfo(sidInf); + + pthread_mutex_lock(&xs_mutex); + xs_status.s_error = 0; + xs_status.s_playing = sidInf.startSong; + xs_status.s_songs = sidInf.songs; + xs_status.s_tune = newTune; + pthread_mutex_unlock(&xs_mutex); + + XSDEBUG("starting thread!\n"); + + /* Start the playing thread! */ + if (pthread_create(&xs_decode_thread, NULL, xs_play_loop, NULL) < 0) + { + XSERR("Couldn't start playing thread! Possible reason reported by system: %s\n", strerror(errno)); + delete newTune; } - /* Configure rest of the paske */ - xs_emuConf.bitsPerSample = xs_cfg.bitsPerSample; - xs_emuConf.frequency = xs_cfg.frequency; - xs_emuConf.sampleFormat = SIDEMU_SIGNED_PCM; - xs_emuConf.mos8580 = xs_cfg.mos8580; - xs_emuConf.emulateFilter = xs_cfg.emulateFilter; - xs_emuConf.filterFs = xs_cfg.filterFs; - xs_emuConf.filterFm = xs_cfg.filterFm; - xs_emuConf.filterFt = xs_cfg.filterFt; - - /* Now set the emulator configuration */ - xs_emuEngine.setConfig(xs_emuConf); - tune->getInfo(sidInf); - xs_error = 0; - xs_going = sidInf.startSong; - xs_songs = sidInf.songs; - - /* Start the playing thread! */ - if (pthread_create(&xs_decode_thread, NULL, xs_play_loop, tune) < 0) { - xs_error = 1; - XSERR("Couldn't start playing thread!\n"); - delete tune; - } + /* Exit */ } /* - * Stop playing + * Stop playing */ void xs_stop(void) { - if (xs_going) + /* If playing, stop. */ + if (xs_status.s_playing) { - xs_going = 0; - pthread_join(xs_decode_thread, NULL); + pthread_mutex_lock(&xs_mutex); + xs_status.s_playing = 0; + pthread_mutex_unlock(&xs_mutex); + + pthread_join(xs_decode_thread, NULL); } } /* - * Pause the playing + * Pause the playing */ -void xs_pause(short p) +void xs_pause(short pauseState) { - xmms_sid_ip.output->pause(p); + xmms_sid_ip.output->pause(pauseState); } /* - * Set the time-seek position - * (the playing thread will do the "seeking" aka song-change) + * Set the time-seek position + * (the playing thread will do the "seeking" aka song-change) */ -void xs_seek(int time) +void xs_seek(int iTime) { - if ((time > 0) && (time <= xs_songs)) { - xs_going = time; +#ifdef HAVE_SONG_POSITION + if ((iTime > 0) && (iTime <= xs_songs)) + { + pthread_mutex_lock(&xs_mutex); + xs_status.s_playing = iTime; + pthread_mutex_unlock(&xs_mutex); } +#endif } /* - * Return the playing "position/time" aka song number + * Return the playing "position/time" */ int xs_get_time(void) { - if (xs_error) return -2; - if (!xs_going) return -1; -#ifdef HAVE_SONG_POSITION - set_song_position(xs_going, 1, xs_songs); -#endif - return xmms_sid_ip.output->output_time(); -} - + if (xs_status.s_error) + return -2; + + if (!xs_status.s_playing) + return -1; -/* - * Return song information - */ -void xs_get_song_info(char *filename, char **title, int *length) -{ - struct sidTuneInfo sidInf; - sidTune t(filename); +#ifdef HAVE_SONG_POSITION + set_song_position(xs_status.s_playing, 1, xs_status.s_songs); +#endif - if (!t) return; - - t.getInfo(sidInf); - - *title = xs_make_filedesc(&sidInf); - - *length = -1; + return xmms_sid_ip.output->output_time(); } +/* + * Return song information + */ +void xs_get_song_info(char *songFilename, char **songTitle, int *songLength) +{ + struct sidTuneInfo sidInf; + sidTune *testTune = new sidTune(songFilename); + + /* Check if the tune exists and is readable */ + if (!testTune) return; + if (!testTune->getStatus()) + { + delete testTune; + return; + } + + /* Get general tune information */ + testTune->getInfo(sidInf); + delete testTune; + + /* Get titlestring */ + *songTitle = xs_get_filetitle(&sidInf, sidInf.startSong); + + /* Get song length (in seconds), negative if no known length */ + *songLength = xs_get_length(songFilename, sidInf.startSong); +} +