diff --git a/readme.txt b/readme.txt index 4aea9c06..d5b9bfa3 100644 --- a/readme.txt +++ b/readme.txt @@ -133,6 +133,7 @@ File types supported by this version of vgmstream: - .psh (PS2 ADPCM) - .vig (PS2 ADPCM) - .sfl (loop info for .ogg); +- .um3 (Ogg Vorbis) Enjoy! -hcs diff --git a/src/meta/ogg_vorbis_file.c b/src/meta/ogg_vorbis_file.c index 9b6cc5ce..e20f380f 100644 --- a/src/meta/ogg_vorbis_file.c +++ b/src/meta/ogg_vorbis_file.c @@ -28,6 +28,33 @@ static size_t read_func(void *ptr, size_t size, size_t nmemb, void * datasource) return items_read; } +static size_t read_func_um3(void *ptr, size_t size, size_t nmemb, void * datasource) +{ + ogg_vorbis_streamfile * const ov_streamfile = datasource; + size_t items_read; + + size_t bytes_read; + + bytes_read = read_streamfile(ptr, ov_streamfile->offset, size * nmemb, + ov_streamfile->streamfile); + + items_read = bytes_read / size; + + /* first 0x800 bytes of um3 are xor'd with 0xff */ + if (ov_streamfile->offset < 0x800) { + int num_crypt = 0x800-ov_streamfile->offset; + int i; + + if (num_crypt > bytes_read) num_crypt=bytes_read; + for (i=0;ioffset += items_read * size; + + return items_read; +} + static int seek_func(void *datasource, ogg_int64_t offset, int whence) { ogg_vorbis_streamfile * const ov_streamfile = datasource; ogg_int64_t base_offset; @@ -63,7 +90,7 @@ static long tell_func(void * datasource) { } /* setting close_func in ov_callbacks to NULL doesn't seem to work */ -int close_func(void * datasource) { +static int close_func(void * datasource) { return 0; } @@ -89,6 +116,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { int loop_end_found = 0; int32_t loop_end = 0; + int um3_ogg = 0; + /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); @@ -98,9 +127,20 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { though. */ if (strcasecmp("logg",filename_extension(filename)) && strcasecmp("ogg",filename_extension(filename)) - ) goto fail; + ) { + if(!strcasecmp("um3",filename_extension(filename))) { + um3_ogg = 1; + } + else goto fail; + } - callbacks.read_func = read_func; + /* not all um3-ogg are crypted */ + if (um3_ogg && read_32bitBE(0x0,streamFile)==0x4f676753) um3_ogg = 0; + + if (um3_ogg) + callbacks.read_func = read_func_um3; + else + callbacks.read_func = read_func; callbacks.seek_func = seek_func; callbacks.close_func = close_func; callbacks.tell_func = tell_func; @@ -153,10 +193,13 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { strstr(comment->user_comments[i],"COMMENT=LOOPPOINT=")== comment->user_comments[i] || strstr(comment->user_comments[i],"LOOPSTART=")== + comment->user_comments[i] || + strstr(comment->user_comments[i],"um3.stream.looppoint.start=")== comment->user_comments[i] ) { loop_start=atol(strrchr(comment->user_comments[i],'=')+1); - loop_flag=1; + if (loop_start >= 0) + loop_flag=1; } else if (strstr(comment->user_comments[i],"LOOPLENGTH=")== comment->user_comments[i]) { @@ -199,7 +242,10 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { } vgmstream->coding_type = coding_ogg_vorbis; vgmstream->layout_type = layout_ogg_vorbis; - vgmstream->meta_type = meta_ogg_vorbis; + if (um3_ogg) + vgmstream->meta_type = meta_um3_ogg; + else + vgmstream->meta_type = meta_ogg_vorbis; return vgmstream; diff --git a/src/vgmstream.c b/src/vgmstream.c index feb4bf72..467290d1 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1262,6 +1262,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { case meta_OGG_SFL: snprintf(temp,TEMPSIZE,"Ogg Vorbis with SFPL for looping"); break; + case meta_um3_ogg: + snprintf(temp,TEMPSIZE,"Ogg Vorbis, Ultramarine3 \"encryption\""); + break; #endif case meta_DSP_SADB: snprintf(temp,TEMPSIZE,"sadb header"); diff --git a/src/vgmstream.h b/src/vgmstream.h index 46f76fcc..491a172f 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -219,6 +219,7 @@ typedef enum { meta_OGG_SLI, /* Ogg Vorbis file w/ companion .sli for looping */ meta_OGG_SLI2, /* Ogg Vorbis file w/ different styled .sli for looping */ meta_OGG_SFL, /* Ogg Vorbis file w/ .sfl (RIFF SFPL) for looping */ + meta_um3_ogg, /* Ogg Vorbis with first 0x800 bytes XOR 0xFF */ #endif meta_AIFC, /* Audio Interchange File Format AIFF-C */ diff --git a/unix/data.c b/unix/data.c index ae1dae60..adfa6dc4 100644 --- a/unix/data.c +++ b/unix/data.c @@ -94,6 +94,7 @@ gchar *vgmstream_exts [] = { "lwav", "vig", "sfl", + "um3", /* terminator */ NULL }; diff --git a/winamp/in_vgmstream.c b/winamp/in_vgmstream.c index 43d38986..9f521180 100644 --- a/winamp/in_vgmstream.c +++ b/winamp/in_vgmstream.c @@ -158,6 +158,7 @@ char * extension_list[] = { "lwav\0LWAV Audio File (*.LWAV)\0", "vig\0VIG Audio File (*.VIG)\0", "sfl\0SFL Audio File (*.SFL)\0", + "um3\0UM3 Audio File (*.UM3)\0", }; void about(HWND hwndParent) {