summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-07-19 13:50:36 +0200
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-07-19 13:50:36 +0200
commite89e2345859798fa596e01bd9460a63c92785f49 (patch)
treebf1f0c36b9ded842a43e6fb09a764dce9ce0311b
parentb41446ad033a52ed24176f9ba01362e3648e97ee (diff)
better format checking before adding to playlist,
more file types supported, bad files are skipped when attempted to be played
-rw-r--r--cdumb.c601
-rw-r--r--cflac.c51
-rw-r--r--cgme.c13
-rw-r--r--cmp3.c27
-rw-r--r--codec.h1
-rw-r--r--cvorbis.c42
-rw-r--r--dumb/dumb-kode54/src/it/readpsm.c2
-rw-r--r--dumb/dumb-kode54/src/it/readstm.c6
-rw-r--r--playlist.c63
-rw-r--r--playlist.h2
-rw-r--r--streamer.c160
11 files changed, 834 insertions, 134 deletions
diff --git a/cdumb.c b/cdumb.c
index ff10bfa8..aff0fea8 100644
--- a/cdumb.c
+++ b/cdumb.c
@@ -8,7 +8,7 @@
extern int sdl_player_freq; // hack!
static int dumb_initialized;
-static DUH *myduh;
+static DUH *duh;
static DUH_SIGRENDERER *renderer;
//#define DUMB_RQ_ALIASING
//#define DUMB_RQ_LINEAR
@@ -17,60 +17,84 @@ static DUH_SIGRENDERER *renderer;
extern int dumb_resampling_quality;
extern int dumb_it_max_to_mix;
-void
+static void
cdumb_free (void);
-int
+static int
cdumb_startrenderer (void);
+static DUH*
+open_module(const char *fname, const char *ext, int *start_order, int *is_it, int *is_dos);
+
int
cdumb_init (const char *fname, int track, float start, float end) {
if (!dumb_initialized) {
atexit (&dumb_exit);
}
dumb_register_stdfiles ();
+
+ int start_order = 0;
+ int is_dos, is_it;
+ const char *ext = fname + strlen (fname) - 1;
+ while (*ext != '.' && ext > fname) {
+ ext--;
+ }
+ ext++;
+ duh = open_module(fname, ext, &start_order, &is_it, &is_dos );
+
+// if (is_it) ReadIT(ptr, size, *m_info, !read_tag);
+// else ReadDUH(duh, *m_info, !read_tag, is_dos);
+//
+// // subsong magic time
+// g_cache.run( ptr, size, p_path, m_file->get_timestamp( p_abort ), m_subsong_info, p_abort );
+
+
+#if 0
const char *ext = fname + strlen (fname) - 1;
while (*ext != '.' && ext > fname) {
ext--;
}
ext++;
if (!strcasecmp (ext, "mod")) {
- myduh = dumb_load_mod_quick (fname, 0);
+ duh = dumb_load_mod_quick (fname, 0);
}
else if (!strcasecmp (ext, "s3m")) {
- myduh = dumb_load_s3m_quick (fname);
+ duh = dumb_load_s3m_quick (fname);
}
else if (!strcasecmp (ext, "it")) {
- myduh = dumb_load_it_quick (fname);
+ duh = dumb_load_it_quick (fname);
}
else if (!strcasecmp (ext, "xm")) {
- myduh = dumb_load_xm_quick (fname);
+ duh = dumb_load_xm_quick (fname);
}
else {
return -1;
}
- dumb_it_do_initial_runthrough (myduh);
+#endif
+ dumb_it_do_initial_runthrough (duh);
cdumb.info.bitsPerSample = 16;
cdumb.info.channels = 2;
cdumb.info.samplesPerSecond = sdl_player_freq;
cdumb.info.position = 0;
- cdumb.info.duration = duh_get_length (myduh)/65536.0f;
+ cdumb.info.duration = duh_get_length (duh)/65536.0f;
printf ("duration: %f\n", cdumb.info.duration);
- cdumb_startrenderer ();
+ if (cdumb_startrenderer () < 0) {
+ return -1;
+ }
return 0;
}
-int
+static int
cdumb_startrenderer (void) {
// reopen
if (renderer) {
duh_end_sigrenderer (renderer);
renderer = NULL;
}
- renderer = duh_start_sigrenderer (myduh, 0, 2, 0);
+ renderer = duh_start_sigrenderer (duh, 0, 2, 0);
if (!renderer) {
cdumb_free ();
return -1;
@@ -81,17 +105,18 @@ cdumb_startrenderer (void) {
dumb_it_set_resampling_quality (itsr, 2);
dumb_it_set_xm_speed_zero_callback (itsr, &dumb_it_callback_terminate, NULL);
dumb_it_set_global_volume_zero_callback (itsr, &dumb_it_callback_terminate, NULL);
+ return 0;
}
-void
+static void
cdumb_free (void) {
if (renderer) {
duh_end_sigrenderer (renderer);
renderer = NULL;
}
- if (myduh) {
- unload_duh (myduh);
- myduh = NULL;
+ if (duh) {
+ unload_duh (duh);
+ duh = NULL;
}
}
@@ -118,16 +143,558 @@ cdumb_seek (float time) {
return 0;
}
+static const char * exts[]=
+{
+ "mod","mdz",
+ "s3m","s3z",
+ "stm","stz",
+ "it","itz",
+ "xm","xmz",
+ "ptm","ptz",
+ "mtm","mtz",
+ "669",
+ "psm",
+ "umx",
+ "am","j2b",
+ "dsm",
+ "amf",
+ NULL
+};
+
+// derived from mod.cpp of foo_dumb source code
+static DUH * open_module(const char *fname, const char *ext, int *start_order, int *is_it, int *is_dos)
+{
+ DUH * duh = 0;
+
+ *is_it = 0;
+ *is_dos = 1;
+
+ char ptr[2000];
+ FILE *fp = fopen (fname, "rb");
+ if (!fp) {
+ return NULL;
+ }
+ int size = fread (ptr, 1, 2000, fp);
+ fclose (fp);
+
+ DUMBFILE * f = dumbfile_open (fname);
+ if (!f) {
+ return NULL;
+ }
+
+// {{{ no umr yet
+#if 0
+ if (size >= 4 &&
+ ptr[0] == 0xC1 && ptr[1] == 0x83 &&
+ ptr[2] == 0x2A && ptr[3] == 0x9E)
+ {
+ umr_mem_reader memreader(ptr, size);
+ umr::upkg pkg;
+ if (pkg.open(&memreader))
+ {
+ for (int i = 1, j = pkg.ocount(); i <= j; i++)
+ {
+ char * classname = pkg.oclassname(i);
+ if (classname && !strcmp(pkg.oclassname(i), "Music"))
+ {
+ char * type = pkg.otype(i);
+ if (!type) continue;
+ /*
+ if (!stricmp(type, "it"))
+ {
+ is_it = true;
+ ptr += memdata.offset = pkg.object_offset(i);
+ size = memdata.size = memdata.offset + pkg.object_size(i);
+ duh = dumb_read_it_quick(f);
+ break;
+ }
+ else if (!stricmp(type, "s3m"))
+ {
+ memdata.offset = pkg.object_offset(i);
+ memdata.size = memdata.offset + pkg.object_size(i);
+ duh = dumb_read_s3m_quick(f);
+ break;
+ }
+ else if (!stricmp(type, "xm"))
+ {
+ memdata.offset = pkg.object_offset(i);
+ memdata.size = memdata.offset + pkg.object_size(i);
+ duh = dumb_read_xm_quick(f);
+ break;
+ }
+ */
+ // blah, type can't be trusted
+ if (!stricmp(type, "it") || !stricmp(type, "s3m") || !stricmp(type, "xm"))
+ {
+ ptr += memdata.offset = pkg.object_offset(i);
+ size = memdata.size = memdata.offset + pkg.object_size(i);
+ if (size >= 4 && ptr[0] == 'I' && ptr[1] == 'M' && ptr[2] == 'P' && ptr[3] == 'M')
+ {
+ is_it = true;
+ duh = dumb_read_it_quick(f);
+ }
+ else if (size >= 42 && ptr[38] == 'F' && ptr[39] == 'a' && ptr[40] == 's' && ptr[41] == 't')
+ {
+ duh = dumb_read_xm_quick(f);
+ }
+ else if (size >= 48 && ptr[44] == 'S' && ptr[45] == 'C' && ptr[46] == 'R' && ptr[47] == 'M')
+ {
+ duh = dumb_read_s3m_quick(f);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+#endif
+// end of umr code
+// }}}
+ if (size >= 4 &&
+ ptr[0] == 'I' && ptr[1] == 'M' &&
+ ptr[2] == 'P' && ptr[3] == 'M')
+ {
+ *is_it = 1;
+ duh = dumb_read_it_quick(f);
+ }
+ else if (size >= 17 && !memcmp(ptr, "Extended Module: ", 17))
+ {
+ duh = dumb_read_xm_quick(f);
+ }
+ else if (size >= 0x30 &&
+ ptr[0x2C] == 'S' && ptr[0x2D] == 'C' &&
+ ptr[0x2E] == 'R' && ptr[0x2F] == 'M')
+ {
+ duh = dumb_read_s3m_quick(f);
+ }
+ else if (size >= 1168 &&
+ /*ptr[28] == 0x1A &&*/ ptr[29] == 2 &&
+ ( ! strncasecmp( ( const char * ) ptr + 20, "!Scream!", 8 ) ||
+ ! strncasecmp( ( const char * ) ptr + 20, "BMOD2STM", 8 ) ||
+ ! strncasecmp( ( const char * ) ptr + 20, "WUZAMOD!", 8 ) ) )
+ {
+ duh = dumb_read_stm_quick(f);
+ }
+ else if (size >= 2 &&
+ ((ptr[0] == 0x69 && ptr[1] == 0x66) ||
+ (ptr[0] == 0x4A && ptr[1] == 0x4E)))
+ {
+ duh = dumb_read_669_quick(f);
+ }
+ else if (size >= 0x30 &&
+ ptr[0x2C] == 'P' && ptr[0x2D] == 'T' &&
+ ptr[0x2E] == 'M' && ptr[0x2F] == 'F')
+ {
+ duh = dumb_read_ptm_quick(f);
+ }
+ else if (size >= 4 &&
+ ptr[0] == 'P' && ptr[1] == 'S' &&
+ ptr[2] == 'M' && ptr[3] == ' ')
+ {
+ duh = dumb_read_psm_quick(f, *start_order);
+ *start_order = 0;
+ }
+ else if (size >= 4 &&
+ ptr[0] == 'P' && ptr[1] == 'S' &&
+ ptr[2] == 'M' && ptr[3] == 254)
+ {
+ duh = dumb_read_old_psm_quick(f);
+ }
+ else if (size >= 3 &&
+ ptr[0] == 'M' && ptr[1] == 'T' &&
+ ptr[2] == 'M')
+ {
+ duh = dumb_read_mtm_quick(f);
+ }
+ else if ( size >= 4 &&
+ ptr[0] == 'R' && ptr[1] == 'I' &&
+ ptr[2] == 'F' && ptr[3] == 'F')
+ {
+ duh = dumb_read_riff_quick(f);
+ }
+ else if ( size >= 32 &&
+ !memcmp( ptr, "ASYLUM Music Format", 19 ) &&
+ !memcmp( ptr + 19, " V1.0", 5 ) )
+ {
+ duh = dumb_read_asy_quick(f);
+ }
+
+ if (!duh)
+ {
+ dumbfile_close(f);
+ f = dumbfile_open (fname);
+ *is_dos = 0;
+ duh = dumb_read_mod_quick (f, (!strcasecmp (ext, exts[0]) || !strcasecmp (ext, exts[1])) ? 0 : 1);
+ }
+
+ if (f) {
+ dumbfile_close(f);
+ }
+
+// {{{ no volume ramping
+#if 0
+ // XXX test
+ if (duh)
+ {
+ int ramp_mode = 0; // none
+ if (ramp_mode)
+ {
+ DUMB_IT_SIGDATA * itsd = duh_get_it_sigdata(duh);
+ if (itsd)
+ {
+ if (ramp_mode > 2)
+ {
+ if ( ( itsd->flags & ( IT_WAS_AN_XM | IT_WAS_A_MOD ) ) == IT_WAS_AN_XM )
+ ramp_mode = 2;
+ else
+ ramp_mode = 1;
+ }
+ for (int i = 0, j = itsd->n_samples; i < j; i++)
+ {
+ IT_SAMPLE * sample = &itsd->sample[i];
+ if ( sample->flags & IT_SAMPLE_EXISTS && !( sample->flags & IT_SAMPLE_LOOP ) )
+ {
+ double rate = 1. / double( sample->C5_speed );
+ double length = double( sample->length ) * rate;
+ if ( length >= .1 )
+ {
+ int k, l = sample->length;
+ if ( ramp_mode == 1 && ( ( rate * 16. ) < .01 ) )
+ {
+ if (sample->flags & IT_SAMPLE_16BIT)
+ {
+ k = l - 15;
+ signed short * data = (signed short *) sample->data;
+ if (sample->flags & IT_SAMPLE_STEREO)
+ {
+ for (int shift = 1; k < l; k++, shift++)
+ {
+ data [k * 2] >>= shift;
+ data [k * 2 + 1] >>= shift;
+ }
+ }
+ else
+ {
+ for (int shift = 1; k < l; k++, shift++)
+ {
+ data [k] >>= shift;
+ }
+ }
+ }
+ else
+ {
+ k = l - 7;
+ signed char * data = (signed char *) sample->data;
+ if (sample->flags & IT_SAMPLE_STEREO)
+ {
+ for (int shift = 1; k < l; k++, shift++)
+ {
+ data [k * 2] >>= shift;
+ data [k * 2 + 1] >>= shift;
+ }
+ }
+ else
+ {
+ for (int shift = 1; k < l; k++, shift++)
+ {
+ data [k] >>= shift;
+ }
+ }
+ }
+ }
+ else
+ {
+ int m = int( .01 * double( sample->C5_speed ) + .5 );
+ k = l - m;
+ if (sample->flags & IT_SAMPLE_16BIT)
+ {
+ signed short * data = (signed short *) sample->data;
+ if (sample->flags & IT_SAMPLE_STEREO)
+ {
+ for (; k < l; k++)
+ {
+ data [k * 2] = MulDiv( data [k * 2], l - k, m );
+ data [k * 2 + 1] = MulDiv( data [k * 2 + 1], l - k, m );
+ }
+ }
+ else
+ {
+ for (; k < l; k++)
+ {
+ data [k] = MulDiv( data [k], l - k, m );
+ }
+ }
+ }
+ else
+ {
+ signed char * data = (signed char *) sample->data;
+ if (sample->flags & IT_SAMPLE_STEREO)
+ {
+ for (; k < l; k++)
+ {
+ data [k * 2] = MulDiv( data [k * 2], l - k, m );
+ data [k * 2 + 1] = MulDiv( data [k * 2 + 1], l - k, m );
+ }
+ }
+ else
+ {
+ for (; k < l; k++)
+ {
+ data [k] = MulDiv( data [k], l - k, m );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
+// }}}
+
+// {{{ no autochip
+#if 0
+ if (duh && cfg_autochip)
+ {
+ int size_force = cfg_autochip_size_force;
+ int size_scan = cfg_autochip_size_scan;
+ int scan_threshold_8 = ((cfg_autochip_scan_threshold * 0x100) + 50) / 100;
+ int scan_threshold_16 = ((cfg_autochip_scan_threshold * 0x10000) + 50) / 100;
+ DUMB_IT_SIGDATA * itsd = duh_get_it_sigdata(duh);
+
+ if (itsd)
+ {
+ for (int i = 0, j = itsd->n_samples; i < j; i++)
+ {
+ IT_SAMPLE * sample = &itsd->sample[i];
+ if (sample->flags & IT_SAMPLE_EXISTS)
+ {
+ int channels = sample->flags & IT_SAMPLE_STEREO ? 2 : 1;
+ if (sample->length < size_force) sample->max_resampling_quality = 0;
+ else if (sample->length < size_scan)
+ {
+ if ((sample->flags & (IT_SAMPLE_LOOP|IT_SAMPLE_PINGPONG_LOOP)) == IT_SAMPLE_LOOP)
+ {
+ int loop_start = sample->loop_start * channels;
+ int loop_end = sample->loop_end * channels;
+ int s1, s2;
+ if (sample->flags & IT_SAMPLE_16BIT)
+ {
+ s1 = ((signed short *)sample->data)[loop_start];
+ s2 = ((signed short *)sample->data)[loop_end - channels];
+ if (abs(s1 - s2) > scan_threshold_16)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ if (channels == 2)
+ {
+ s1 = ((signed short *)sample->data)[loop_start + 1];
+ s2 = ((signed short *)sample->data)[loop_end - 1];
+ if (abs(s1 - s2) > scan_threshold_16)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ }
+ }
+ else
+ {
+ s1 = ((signed char *)sample->data)[loop_start];
+ s2 = ((signed char *)sample->data)[loop_end - channels];
+ if (abs(s1 - s2) > scan_threshold_8)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ if (channels == 2)
+ {
+ s1 = ((signed char *)sample->data)[loop_start + 1];
+ s2 = ((signed char *)sample->data)[loop_end - 1];
+ if (abs(s1 - s2) > scan_threshold_8)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ }
+ }
+ }
+ if ((sample->flags & (IT_SAMPLE_SUS_LOOP|IT_SAMPLE_PINGPONG_SUS_LOOP)) == IT_SAMPLE_SUS_LOOP)
+ {
+ int sus_loop_start = sample->sus_loop_start * channels;
+ int sus_loop_end = sample->sus_loop_end * channels;
+ int s1, s2;
+ if (sample->flags & IT_SAMPLE_16BIT)
+ {
+ s1 = ((signed short *)sample->data)[sus_loop_start];
+ s2 = ((signed short *)sample->data)[sus_loop_end - channels];
+ if (abs(s1 - s2) > scan_threshold_16)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ if (channels == 2)
+ {
+ s1 = ((signed short *)sample->data)[sus_loop_start + 1];
+ s2 = ((signed short *)sample->data)[sus_loop_end - 1];
+ if (abs(s1 - s2) > scan_threshold_16)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ }
+ }
+ else
+ {
+ s1 = ((signed char *)sample->data)[sus_loop_start];
+ s2 = ((signed char *)sample->data)[sus_loop_end - channels];
+ if (abs(s1 - s2) > scan_threshold_8)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ if (channels == 2)
+ {
+ s1 = ((signed char *)sample->data)[sus_loop_start + 1];
+ s2 = ((signed char *)sample->data)[sus_loop_end - 1];
+ if (abs(s1 - s2) > scan_threshold_8)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ }
+ }
+ }
+
+ int k, l = sample->length * channels;
+ if (sample->flags & IT_SAMPLE_LOOP) l = sample->loop_end * channels;
+ if (sample->flags & IT_SAMPLE_16BIT)
+ {
+ for (k = channels; k < l; k += channels)
+ {
+ if (abs(((signed short *)sample->data)[k - channels] - ((signed short *)sample->data)[k]) > scan_threshold_16)
+ {
+ break;
+ }
+ }
+ if (k < l)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ if (channels == 2)
+ {
+ for (k = 2 + 1; k < l; k += 2)
+ {
+ if (abs(((signed short *)sample->data)[k - 2] - ((signed short *)sample->data)[k]) > scan_threshold_16)
+ {
+ break;
+ }
+ }
+ }
+ if (k < l)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ }
+ else
+ {
+ for (k = channels; k < l; k += channels)
+ {
+ if (abs(((signed char *)sample->data)[k - channels] - ((signed char *)sample->data)[k]) > scan_threshold_8)
+ {
+ break;
+ }
+ }
+ if (k < l)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ if (channels == 2)
+ {
+ for (k = 2 + 1; k < l; k += 2)
+ {
+ if (abs(((signed char *)sample->data)[k - 2] - ((signed char *)sample->data)[k]) > scan_threshold_8)
+ {
+ break;
+ }
+ }
+ }
+ if (k < l)
+ {
+ sample->max_resampling_quality = 0;
+ continue;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
+// }}}
+
+// {{{ no trim
+#if 0
+ if ( duh && cfg_trim )
+ {
+ if ( dumb_it_trim_silent_patterns( duh ) < 0 )
+ {
+ unload_duh( duh );
+ duh = 0;
+ }
+ }
+#endif
+// }}}
+
+ return duh;
+}
+
int
cdumb_add (const char *fname) {
+ const char *ext = fname + strlen (fname) - 1;
+ while (*ext != '.' && ext > fname) {
+ ext--;
+ }
+ ext++;
+ int start_order = 0;
+ int is_it;
+ int is_dos;
+ dumb_register_stdfiles ();
+ DUH* duh = open_module(fname, ext, &start_order, &is_it, &is_dos);
+ if (!duh) {
+ return -1;
+ }
+ unload_duh (duh);
+ playItem_t *it = malloc (sizeof (playItem_t));
+ memset (it, 0, sizeof (playItem_t));
+ it->codec = &cdumb;
+ it->fname = strdup (fname);
+ it->tracknum = 0;
+ it->timestart = 0;
+ it->timeend = 0;
+ it->displayname = strdup (fname);
+ ps_append_item (it);
+
return 0;
}
+const char **cdumb_getexts (void) {
+ return exts;
+}
+
codec_t cdumb = {
.init = cdumb_init,
.free = cdumb_free,
.read = cdumb_read,
.seek = cdumb_seek,
- .add = cdumb_add
+ .add = cdumb_add,
+ .getexts = cdumb_getexts
};
diff --git a/cflac.c b/cflac.c
index 588cfbf2..e7b69b61 100644
--- a/cflac.c
+++ b/cflac.c
@@ -61,6 +61,9 @@ cflac_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErro
fprintf(stderr, "cflac: got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
}
+void
+cflac_free (void);
+
int
cflac_init (const char *fname, int track, float start, float end) {
FLAC__StreamDecoderInitStatus status;
@@ -71,7 +74,19 @@ cflac_init (const char *fname, int track, float start, float end) {
}
FLAC__stream_decoder_set_md5_checking(decoder, 0);
status = FLAC__stream_decoder_init_file(decoder, fname, cflac_write_callback, cflac_metadata_callback, cflac_error_callback, NULL);
- FLAC__stream_decoder_process_until_end_of_metadata (decoder);
+ if (status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ cflac_free ();
+ return -1;
+ }
+ cflac.info.samplesPerSecond = -1;
+ if (!FLAC__stream_decoder_process_until_end_of_metadata (decoder)) {
+ cflac_free ();
+ return -1;
+ }
+ if (cflac.info.samplesPerSecond == -1) { // not a FLAC stream
+ cflac_free ();
+ return -1;
+ }
timestart = start;
timeend = end;
if (timeend > timestart || timeend < 0) {
@@ -171,6 +186,28 @@ cflac_add (const char *fname) {
}
}
+ FLAC__StreamDecoderInitStatus status;
+ decoder = FLAC__stream_decoder_new();
+ if (!decoder) {
+ printf ("FLAC__stream_decoder_new failed\n");
+ return -1;
+ }
+ FLAC__stream_decoder_set_md5_checking(decoder, 0);
+ status = FLAC__stream_decoder_init_file(decoder, fname, cflac_write_callback, cflac_metadata_callback, cflac_error_callback, NULL);
+ if (status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ cflac_free ();
+ return -1;
+ }
+ cflac.info.samplesPerSecond = -1;
+ if (!FLAC__stream_decoder_process_until_end_of_metadata (decoder)) {
+ cflac_free ();
+ return -1;
+ }
+ if (cflac.info.samplesPerSecond == -1) { // not a FLAC stream
+ cflac_free ();
+ return -1;
+ }
+ cflac_free ();
playItem_t *it = malloc (sizeof (playItem_t));
memset (it, 0, sizeof (playItem_t));
it->codec = &cflac;
@@ -183,10 +220,20 @@ cflac_add (const char *fname) {
return 0;
}
+static const char * exts[]=
+{
+ "flac","ogg",NULL
+};
+
+const char **cflac_getexts (void) {
+ return exts;
+}
+
codec_t cflac = {
.init = cflac_init,
.free = cflac_free,
.read = cflac_read,
.seek = cflac_seek,
- .add = cflac_add
+ .add = cflac_add,
+ .getexts = cflac_getexts
};
diff --git a/cgme.c b/cgme.c
index 93bbe118..9ad7cd56 100644
--- a/cgme.c
+++ b/cgme.c
@@ -125,11 +125,22 @@ cgme_add (const char *fname) {
return 0;
}
+static const char * exts[]=
+{
+ "ay","gbs","gym","hes","kss","nsf","nsfe","sap","spc","vgm","vgz",NULL
+};
+
+const char **cgme_getexts (void) {
+ return exts;
+}
+
+
codec_t cgme = {
.init = cgme_init,
.free = cgme_free,
.read = cgme_read,
.seek = cgme_seek,
- .add = cgme_add
+ .add = cgme_add,
+ .getexts = cgme_getexts
};
diff --git a/cmp3.c b/cmp3.c
index d5488fbd..6e512e51 100644
--- a/cmp3.c
+++ b/cmp3.c
@@ -5,9 +5,8 @@
#include <stdlib.h>
#include "codec.h"
#include "cmp3.h"
-
-#define min(x,y) ((x)<(y)?(x):(y))
-#define max(x,y) ((x)>(y)?(x):(y))
+#include "playlist.h"
+#include "common.h"
#define READBUFFER 5*8192
#define CACHESIZE 81920
@@ -482,14 +481,34 @@ cmp3_seek (float time) {
int
cmp3_add (const char *fname) {
+ playItem_t *it = malloc (sizeof (playItem_t));
+ memset (it, 0, sizeof (playItem_t));
+ it->codec = &cmp3;
+ it->fname = strdup (fname);
+ it->tracknum = 0;
+ it->timestart = 0;
+ it->timeend = 0;
+ it->displayname = strdup (fname);
+ ps_append_item (it);
return 0;
}
+static const char * exts[]=
+{
+ "mp2","mp3",NULL
+};
+
+const char **cmp3_getexts (void) {
+ return exts;
+}
+
codec_t cmp3 = {
.init = cmp3_init,
.free = cmp3_free,
.read = cmp3_read,
- .seek = cmp3_seek
+ .seek = cmp3_seek,
+ .add = cmp3_add,
+ .getexts = cmp3_getexts
};
diff --git a/codec.h b/codec.h
index fc8e4870..9554f0a2 100644
--- a/codec.h
+++ b/codec.h
@@ -19,6 +19,7 @@ typedef struct codec_s {
int (*read) (char *bytes, int size);
int (*seek) (float time);
int (*add) (const char *fname);
+ const char ** (*getexts) (void);
} codec_t;
codec_t *get_codec_for_file (const char *fname);
diff --git a/cvorbis.c b/cvorbis.c
index 8b3acb6e..4ab49dca 100644
--- a/cvorbis.c
+++ b/cvorbis.c
@@ -5,12 +5,16 @@
#include <stdlib.h>
#include "codec.h"
#include "cvorbis.h"
+#include "playlist.h"
static FILE *file;
static OggVorbis_File vorbis_file;
static vorbis_info *vi;
static int cur_bit_stream;
+void
+cvorbis_free (void);
+
int
cvorbis_init (const char *fname, int track, float start, float end) {
file = NULL;
@@ -25,6 +29,10 @@ cvorbis_init (const char *fname, int track, float start, float end) {
memset (&cvorbis.info, 0, sizeof (fileinfo_t));
ov_open (file, &vorbis_file, NULL, 0);
vi = ov_info (&vorbis_file, -1);
+ if (!vi) { // not a vorbis stream
+ cvorbis_free ();
+ return -1;
+ }
cvorbis.info.bitsPerSample = 16;
//cvorbis.info.dataSize = ov_pcm_total (&vorbis_file, -1) * vi->channels * 2;
cvorbis.info.channels = vi->channels;
@@ -92,14 +100,46 @@ cvorbis_seek (float time) {
int
cvorbis_add (const char *fname) {
+ // check for validity
+ FILE *fp = fopen (fname, "rb");
+ if (!fp) {
+ return -1;
+ }
+ OggVorbis_File vorbis_file;
+ vorbis_info *vi;
+ ov_open (fp, &vorbis_file, NULL, 0);
+ vi = ov_info (&vorbis_file, -1);
+ ov_clear (&vorbis_file);
+ if (!vi) { // not a vorbis stream
+ return -1;
+ }
+ playItem_t *it = malloc (sizeof (playItem_t));
+ memset (it, 0, sizeof (playItem_t));
+ it->codec = &cvorbis;
+ it->fname = strdup (fname);
+ it->tracknum = 0;
+ it->timestart = 0;
+ it->timeend = 0;
+ it->displayname = strdup (fname);
+ ps_append_item (it);
return 0;
}
+static const char * exts[]=
+{
+ "ogg",NULL
+};
+
+const char **cvorbis_getexts (void) {
+ return exts;
+}
+
codec_t cvorbis = {
.init = cvorbis_init,
.free = cvorbis_free,
.read = cvorbis_read,
.seek = cvorbis_seek,
- .add = cvorbis_add
+ .add = cvorbis_add,
+ .getexts = cvorbis_getexts
};
diff --git a/dumb/dumb-kode54/src/it/readpsm.c b/dumb/dumb-kode54/src/it/readpsm.c
index a64100e0..bf30f2d0 100644
--- a/dumb/dumb-kode54/src/it/readpsm.c
+++ b/dumb/dumb-kode54/src/it/readpsm.c
@@ -1264,7 +1264,7 @@ DUH *dumb_read_psm_quick(DUMBFILE *f, int subsong)
if ( ver )
{
tag[2][0] = "FORMATVERSION";
- itoa(ver, version, 10);
+ snprintf (version, 10, "%d", ver);
tag[2][1] = (const char *) &version;
++n_tags;
}
diff --git a/dumb/dumb-kode54/src/it/readstm.c b/dumb/dumb-kode54/src/it/readstm.c
index c7424394..5972a0f7 100644
--- a/dumb/dumb-kode54/src/it/readstm.c
+++ b/dumb/dumb-kode54/src/it/readstm.c
@@ -231,9 +231,9 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/)
free( sigdata );
return NULL;
}
- if ( strnicmp( tracker_name, "!Scream!", 8 ) &&
- strnicmp( tracker_name, "BMOD2STM", 8 ) &&
- strnicmp( tracker_name, "WUZAMOD!", 8 ) )
+ if ( strncasecmp( tracker_name, "!Scream!", 8 ) &&
+ strncasecmp( tracker_name, "BMOD2STM", 8 ) &&
+ strncasecmp( tracker_name, "WUZAMOD!", 8 ) )
{
free( sigdata );
return NULL;
diff --git a/playlist.c b/playlist.c
index 8dd2a1ad..75af730e 100644
--- a/playlist.c
+++ b/playlist.c
@@ -232,30 +232,35 @@ ps_add_file (const char *fname) {
eol--;
}
eol++;
- if (!strcasecmp (eol, "ogg")) {
- codec = &cvorbis;
+
+ // match by codec
+ codec_t *codecs[] = {
+ &cdumb, &cvorbis, &cflac, &cgme, &cmp3, NULL
+ };
+ for (int i = 0; codecs[i]; i++) {
+ if (codecs[i]->getexts && codecs[i]->add) {
+ const char **exts = codecs[i]->getexts ();
+ if (exts) {
+ for (int e = 0; exts[e]; e++) {
+ if (!strcasecmp (exts[e], eol)) {
+ if (!codecs[i]->add (fname)) {
+ return 0;
+ }
+ }
+ }
+ }
+ }
}
+
+ return -1;
+#if 0
+ // add by extension (temporary hack)
// else if (!strcasecmp (eol, "wav")) {
// codec = &cwav;
// }
- else if (!strcasecmp (eol, "mod")) {
- codec = &cdumb;
- }
- else if (!strcasecmp (eol, "mp3")) {
+ if (!strcasecmp (eol, "mp3")) {
codec = &cmp3;
}
- else if (!strcasecmp (eol, "flac")) {
- codec = &cflac;
- return codec->add (fname);
- }
- else if (!strcasecmp (eol, "nsf")) {
- codec = &cgme;
- return codec->add (fname);
- }
-// else if (!strcasecmp (eol, "cue")) {
-// ps_add_cue (fname);
-// return -1;
-// }
else {
return -1;
}
@@ -277,6 +282,7 @@ ps_add_file (const char *fname) {
it->timeend = -1;
ps_append_item (it);
+#endif
}
int
@@ -409,21 +415,22 @@ ps_item_free (playItem_t *it) {
}
}
-void
+int
ps_set_current (playItem_t *it) {
+ int ret = 0;
if (it) {
// printf ("ps_set_current (%s)\n", it->displayname);
}
if (it == playlist_current_ptr) {
if (it && it->codec) {
codec_lock ();
- playlist_current_ptr->codec->seek (0);
+ ret = playlist_current_ptr->codec->seek (0);
codec_unlock ();
}
- return;
+ return ret;
}
codec_lock ();
- if (playlist_current_ptr) {
+ if (playlist_current_ptr && playlist_current_ptr->codec) {
playlist_current_ptr->codec->free ();
}
ps_item_free (&playlist_current);
@@ -433,23 +440,25 @@ ps_set_current (playItem_t *it) {
playlist_current_ptr = it;
if (it && it->codec) {
// don't do anything on fail, streamer will take care
- it->codec->init (it->fname, it->tracknum, it->timestart, it->timeend);
+ ret = it->codec->init (it->fname, it->tracknum, it->timestart, it->timeend);
+ if (ret < 0) {
+ it->codec->info.samplesPerSecond = -1;
+ }
}
if (playlist_current_ptr) {
streamer_reset ();
}
codec_unlock ();
+ return ret;
}
int
ps_nextsong (void) {
if (playlist_current_ptr && playlist_current_ptr->next) {
- ps_set_current (playlist_current_ptr->next);
- return 0;
+ return ps_set_current (playlist_current_ptr->next);
}
if (playlist_head) {
- ps_set_current (playlist_head);
- return 0;
+ return ps_set_current (playlist_head);
}
ps_set_current (NULL);
return -1;
diff --git a/playlist.h b/playlist.h
index b77b58b2..cd67d191 100644
--- a/playlist.h
+++ b/playlist.h
@@ -44,7 +44,7 @@ ps_get_idx_of (playItem_t *it);
int
ps_add_cue (const char *cuename);
-void
+int
ps_set_current (playItem_t *it);
// returns -1 if theres no next song, or playlist finished
diff --git a/streamer.c b/streamer.c
index 188a7472..32725d6f 100644
--- a/streamer.c
+++ b/streamer.c
@@ -91,89 +91,94 @@ streamer_read_async (char *bytes, int size) {
codec_unlock ();
break;
}
- int nchannels = codec->info.channels;
- int samplerate = codec->info.samplesPerSecond;
- // read and do SRC
- if (codec->info.samplesPerSecond == sdl_player_freq) {
- int i;
- if (codec->info.channels == 2) {
- bytesread = codec->read (bytes, size);
- codec_unlock ();
- }
- else {
- bytesread = codec->read (g_readbuffer, size/2);
- codec_unlock ();
- for (i = 0; i < size/4; i++) {
- int16_t sample = (int16_t)(((int32_t)(((int16_t*)g_readbuffer)[i])));
- ((int16_t*)bytes)[i*2+0] = sample;
- ((int16_t*)bytes)[i*2+1] = sample;
+ if (codec->info.samplesPerSecond != -1) {
+ int nchannels = codec->info.channels;
+ int samplerate = codec->info.samplesPerSecond;
+ // read and do SRC
+ if (codec->info.samplesPerSecond == sdl_player_freq) {
+ int i;
+ if (codec->info.channels == 2) {
+ bytesread = codec->read (bytes, size);
+ codec_unlock ();
+ }
+ else {
+ bytesread = codec->read (g_readbuffer, size/2);
+ codec_unlock ();
+ for (i = 0; i < size/4; i++) {
+ int16_t sample = (int16_t)(((int32_t)(((int16_t*)g_readbuffer)[i])));
+ ((int16_t*)bytes)[i*2+0] = sample;
+ ((int16_t*)bytes)[i*2+1] = sample;
+ }
+ bytesread *= 2;
}
- bytesread *= 2;
- }
- }
- else {
- int nsamples = size/4;
- // convert to codec samplerate
- nsamples = nsamples * samplerate / sdl_player_freq * 2;
- if (!src_is_valid_ratio ((double)sdl_player_freq/samplerate)) {
- printf ("invalid ratio! %d / %d = %f", sdl_player_freq, samplerate, (float)sdl_player_freq/samplerate);
- }
- assert (src_is_valid_ratio ((double)sdl_player_freq/samplerate));
- // read data at source samplerate (with some room for SRC)
- int nbytes = (nsamples - codecleft) * 2 * nchannels;
- if (nbytes < 0) {
- nbytes = 0;
}
else {
- //printf ("reading %d bytes from mp3\n", nbytes);
- bytesread = codec->read (g_readbuffer, nbytes);
- }
- codec_unlock ();
- // recalculate nsamples according to how many bytes we've got
- nsamples = bytesread / (2 * nchannels) + codecleft;
- // convert to float
- int i;
- float *fbuffer = g_fbuffer + codecleft*2;
- if (nchannels == 2) {
- for (i = 0; i < (nsamples - codecleft) * 2; i++) {
- fbuffer[i] = ((int16_t *)g_readbuffer)[i]/32767.f;
+ int nsamples = size/4;
+ // convert to codec samplerate
+ nsamples = nsamples * samplerate / sdl_player_freq * 2;
+ if (!src_is_valid_ratio ((double)sdl_player_freq/samplerate)) {
+ printf ("invalid ratio! %d / %d = %f", sdl_player_freq, samplerate, (float)sdl_player_freq/samplerate);
}
- }
- else if (nchannels == 1) { // convert mono to stereo
- for (i = 0; i < (nsamples - codecleft); i++) {
- fbuffer[i*2+0] = ((int16_t *)g_readbuffer)[i]/32767.f;
- fbuffer[i*2+1] = fbuffer[i*2+0];
+ assert (src_is_valid_ratio ((double)sdl_player_freq/samplerate));
+ // read data at source samplerate (with some room for SRC)
+ int nbytes = (nsamples - codecleft) * 2 * nchannels;
+ if (nbytes < 0) {
+ nbytes = 0;
}
- }
- codec_lock ();
- // convert samplerate
- srcdata.data_in = g_fbuffer;
- srcdata.data_out = g_srcbuffer;
- srcdata.input_frames = nsamples;
- srcdata.output_frames = size/4;
- srcdata.src_ratio = (double)sdl_player_freq/samplerate;
- srcdata.end_of_input = 0;
-// src_set_ratio (src, srcdata.src_ratio);
- src_process (src, &srcdata);
- codec_unlock ();
- // convert back to s16 format
- nbytes = size;
- int genbytes = srcdata.output_frames_gen * 4;
- bytesread = min(size, genbytes);
- for (i = 0; i < bytesread/2; i++) {
- float sample = g_srcbuffer[i];
- if (sample > 1) {
- sample = 1;
+ else {
+ //printf ("reading %d bytes from mp3\n", nbytes);
+ bytesread = codec->read (g_readbuffer, nbytes);
+ }
+ codec_unlock ();
+ // recalculate nsamples according to how many bytes we've got
+ nsamples = bytesread / (2 * nchannels) + codecleft;
+ // convert to float
+ int i;
+ float *fbuffer = g_fbuffer + codecleft*2;
+ if (nchannels == 2) {
+ for (i = 0; i < (nsamples - codecleft) * 2; i++) {
+ fbuffer[i] = ((int16_t *)g_readbuffer)[i]/32767.f;
+ }
}
- if (sample < -1) {
- sample = -1;
+ else if (nchannels == 1) { // convert mono to stereo
+ for (i = 0; i < (nsamples - codecleft); i++) {
+ fbuffer[i*2+0] = ((int16_t *)g_readbuffer)[i]/32767.f;
+ fbuffer[i*2+1] = fbuffer[i*2+0];
+ }
}
- ((int16_t*)bytes)[i] = (int16_t)(sample*32767.f);
+ codec_lock ();
+ // convert samplerate
+ srcdata.data_in = g_fbuffer;
+ srcdata.data_out = g_srcbuffer;
+ srcdata.input_frames = nsamples;
+ srcdata.output_frames = size/4;
+ srcdata.src_ratio = (double)sdl_player_freq/samplerate;
+ srcdata.end_of_input = 0;
+ // src_set_ratio (src, srcdata.src_ratio);
+ src_process (src, &srcdata);
+ codec_unlock ();
+ // convert back to s16 format
+ nbytes = size;
+ int genbytes = srcdata.output_frames_gen * 4;
+ bytesread = min(size, genbytes);
+ for (i = 0; i < bytesread/2; i++) {
+ float sample = g_srcbuffer[i];
+ if (sample > 1) {
+ sample = 1;
+ }
+ if (sample < -1) {
+ sample = -1;
+ }
+ ((int16_t*)bytes)[i] = (int16_t)(sample*32767.f);
+ }
+ // calculate how many unused input samples left
+ codecleft = nsamples - srcdata.input_frames_used;
+ // copy spare samples for next update
+ memmove (g_fbuffer, &g_fbuffer[srcdata.input_frames_used*2], codecleft * 8);
}
- // calculate how many unused input samples left
- codecleft = nsamples - srcdata.input_frames_used;
- // copy spare samples for next update
- memmove (g_fbuffer, &g_fbuffer[srcdata.input_frames_used*2], codecleft * 8);
+ }
+ else {
+ codec_unlock ();
}
bytes += bytesread;
size -= bytesread;
@@ -182,8 +187,9 @@ streamer_read_async (char *bytes, int size) {
}
else {
// that means EOF
- if (ps_nextsong () < 0) {
- break;
+ while (ps_nextsong () < 0) {
+ fprintf (stderr, "bad song encountered in playlist, skipping\n");
+ usleep (3000);
}
}
}