Mercurial > otakunoraifu
view music2/koedec_ogg.cc @ 52:15a18fbe6f21
* Known bugs added to the README
* Code cleaning (0 -> NULL when needed, indentation, spaces, ...)
author | thib |
---|---|
date | Sat, 18 Apr 2009 18:35:39 +0000 |
parents | 53a311ea8289 |
children | 4416cfac86ae |
line wrap: on
line source
/* * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include "music.h" #include "wavfile.h" extern int is_koe_ogg(char* head); extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len); extern int is_koe_ogg(char* head) { #if HAVE_LIBVORBISFILE || HAVE_LIBVORBISIDEC if (strncmp(head, "OggS", 4) == 0) return 1; else #endif return 0; } #if HAVE_LIBVORBISFILE || HAVE_LIBVORBISIDEC #if HAVE_LIBVORBISFILE #include <vorbis/vorbisfile.h> #else /* HAVE_LIBVORBISIDEC */ #include <tremor/ivorbiscodec.h> #include <tremor/ivorbisfile.h> #endif #define INITSIZE 65536 static int cur_size = 0; static char* out = NULL; static void Resize(void) { char* new_out = (char*)realloc(out, cur_size+INITSIZE); if (new_out == NULL) { new_out = (char*)malloc(cur_size+INITSIZE); memcpy(new_out, out, cur_size); free(out); } out = new_out; cur_size += INITSIZE; } struct OggInfo { FILE* stream; int length; int offset; }; /* ogg stream 読み込み用の dummy callback */ static size_t ogg_readfunc(void* ptr, size_t size, size_t nmemb, void* datasource) { OggInfo* info = (OggInfo*)datasource; int pt = ftell(info->stream) - info->offset; if (pt+size*nmemb > info->length) { nmemb = (info->length-pt) / size; } return fread(ptr, size, nmemb, info->stream); } static int ogg_seekfunc(void* datasource, ogg_int64_t new_offset, int whence) { int pt; OggInfo* info = (OggInfo*)datasource; if (whence == SEEK_SET) pt = info->offset + new_offset; else if (whence == SEEK_CUR) pt = ftell(info->stream) + new_offset; else if (whence == SEEK_END) pt = info->offset + info->length + new_offset; int r = fseek(info->stream, pt, SEEK_SET); return r; } static long ogg_tellfunc(void* datasource) { OggInfo* info = (OggInfo*)datasource; int pos = ftell(info->stream); if (pos == -1) return -1; return pos-info->offset; } static int ogg_closefunc(void* datasource) { return 0; } static int fseek_wrap(FILE *f,ogg_int64_t off,int whence){ if (f == NULL) return(-1); return fseek(f, off, whence); } extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len) { if (info.stream == NULL) return NULL; // Voice ファイルを直接指定すると全ストリームを再生してしまうので // 必要な部分だけ切り出して callback 経由で帰す fseek(info.stream, info.offset, SEEK_SET); ov_callbacks callback; callback.read_func = &ogg_readfunc; callback.seek_func = &ogg_seekfunc; callback.close_func = &ogg_closefunc; callback.tell_func = &ogg_tellfunc; OggInfo oinfo; oinfo.stream = info.stream; oinfo.length = info.length; oinfo.offset = info.offset; OggVorbis_File vf; int r = ov_open_callbacks((void*)&oinfo, &vf, 0, 0, callback); if (r != 0) { fprintf(stderr,"ogg stream err: %d\n",r); return NULL; } vorbis_info* vinfo = ov_info(&vf, 0); info.rate = vinfo->rate; int channels = vinfo->channels; int cur = 0x2c; cur_size = INITSIZE; out = (char*)malloc(cur_size); do { #if HAVE_LIBVORBISFILE r = ov_read(&vf, out+cur, cur_size-cur, 0, 2, 1, NULL); #else /* HAVE_LIBVORBISIDEC */ r = ov_read(&vf, out+cur, cur_size-cur, NULL); #endif if (r <= 0) break; cur += r; if (cur_size-INITSIZE/4 < cur) Resize(); } while(1); ov_clear(&vf); *dest_len = cur; // うまくコンバートできてるのかなあ…… const char* header = MakeWavHeader(info.rate, channels, 2, cur); memcpy(out, header, 0x2c); char* ret = out; out = NULL; return ret; } struct OggFILE_impl { OggVorbis_File vf; ov_callbacks callback; OggInfo oinfo; OggFILE_impl(FILE*, int); }; OggFILE_impl::OggFILE_impl(FILE* stream, int length) { callback.read_func = &ogg_readfunc; callback.seek_func = &ogg_seekfunc; callback.close_func = &ogg_closefunc; callback.tell_func = &ogg_tellfunc; oinfo.stream = stream; oinfo.length = length; oinfo.offset = ftell(stream); } OggFILE::OggFILE(FILE* stream, int len) { pimpl = new OggFILE_impl(stream, len); int r = ov_open_callbacks( (void*)&(pimpl->oinfo), &(pimpl->vf), 0, 0, pimpl->callback); if (r != 0) { delete pimpl; pimpl = NULL; return; } vorbis_info* vinfo = ov_info(&(pimpl->vf), 0); wavinfo.SamplingRate = vinfo->rate; wavinfo.Channels = vinfo->channels; wavinfo.DataBits = 16; } OggFILE::~OggFILE() { if (pimpl != NULL) { ov_clear(&(pimpl->vf)); fclose(pimpl->oinfo.stream); delete pimpl; } } int OggFILE::Read(char* buf, int blksize, int blklen) { if (pimpl == NULL) return -1; #if HAVE_LIBVORBISFILE int r = ov_read( &(pimpl->vf), buf, blksize*blklen, 0, 2, 1, NULL); #else /* HAVE_LIBVORBISIDEC */ int r = ov_read( &(pimpl->vf), buf, blksize*blklen, NULL); #endif if (r <= 0) { // end of file return -1; } while(r < blksize*blklen) { #if HAVE_LIBVORBISFILE int dr = ov_read(&(pimpl->vf), buf+r, blksize*blklen-r, 0, 2, 1, NULL); #else /* HAVE_LIBVORBISIDEC */ int dr = ov_read(&(pimpl->vf), buf+r, blksize*blklen-r, NULL); #endif if (dr <= 0) break; r += dr; } return r / blksize; } void OggFILE::Seek(int count) { ov_pcm_seek(&(pimpl->vf), count); return; } #else extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len) { return NULL; } OggFILE::OggFILE(FILE* stream, int a) {pimpl = NULL;} OggFILE::~OggFILE(){} void OggFILE::Seek(int count){} int OggFILE::Read(char* buf, int blksize, int blklen){return -1;} #endif