diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2009-07-19 13:50:36 +0200 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2009-07-19 13:50:36 +0200 |
commit | e89e2345859798fa596e01bd9460a63c92785f49 (patch) | |
tree | bf1f0c36b9ded842a43e6fb09a764dce9ce0311b | |
parent | b41446ad033a52ed24176f9ba01362e3648e97ee (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.c | 601 | ||||
-rw-r--r-- | cflac.c | 51 | ||||
-rw-r--r-- | cgme.c | 13 | ||||
-rw-r--r-- | cmp3.c | 27 | ||||
-rw-r--r-- | codec.h | 1 | ||||
-rw-r--r-- | cvorbis.c | 42 | ||||
-rw-r--r-- | dumb/dumb-kode54/src/it/readpsm.c | 2 | ||||
-rw-r--r-- | dumb/dumb-kode54/src/it/readstm.c | 6 | ||||
-rw-r--r-- | playlist.c | 63 | ||||
-rw-r--r-- | playlist.h | 2 | ||||
-rw-r--r-- | streamer.c | 160 |
11 files changed, 834 insertions, 134 deletions
@@ -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 }; @@ -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 }; @@ -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 }; @@ -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 }; @@ -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); @@ -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;
@@ -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; @@ -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 @@ -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); } } } |