comparison music2/koedec_ogg.cc @ 0:223b71206888

Initial import
author thib
date Fri, 01 Aug 2008 16:32:45 +0000
parents
children 422f3cb3614b
comparison
equal deleted inserted replaced
-1:000000000000 0:223b71206888
1 /*
2 * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include<stdio.h>
29 #include<string.h>
30 #include<stdlib.h>
31 #include"music.h"
32 #include"wavfile.h"
33
34 extern int is_koe_ogg(char* head);
35 extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len);
36
37 extern int is_koe_ogg(char* head) {
38 #if HAVE_LIBVORBISFILE || HAVE_LIBVORBISIDEC
39 if (strncmp(head, "OggS", 4) == 0) return 1;
40 else
41 #endif
42 return 0;
43 }
44
45 #if HAVE_LIBVORBISFILE || HAVE_LIBVORBISIDEC
46
47 #if HAVE_LIBVORBISFILE
48 #include<vorbis/vorbisfile.h>
49 #else /* HAVE_LIBVORBISIDEC */
50 #include<tremor/ivorbiscodec.h>
51 #include<tremor/ivorbisfile.h>
52 #endif
53
54 #define INITSIZE 65536
55
56 static int cur_size = 0;
57 static char* out = 0;
58 static void Resize(void) {
59 char* new_out = (char*)realloc(out, cur_size+INITSIZE);
60 if (new_out == 0) {
61 new_out = (char*)malloc(cur_size+INITSIZE);
62 memcpy(new_out, out, cur_size);
63 free(out);
64 }
65 out = new_out;
66 cur_size += INITSIZE;
67 }
68
69 struct OggInfo {
70 FILE* stream;
71 int length;
72 int offset;
73 };
74 /* ogg stream 読み込み用の dummy callback */
75 static size_t ogg_readfunc(void* ptr, size_t size, size_t nmemb, void* datasource) {
76 OggInfo* info = (OggInfo*)datasource;
77 int pt = ftell(info->stream) - info->offset;
78 if (pt+size*nmemb > info->length) {
79 nmemb = (info->length-pt) / size;
80 }
81 return fread(ptr, size, nmemb, info->stream);
82 }
83 static int ogg_seekfunc(void* datasource, ogg_int64_t new_offset, int whence) {
84 int pt;
85 OggInfo* info = (OggInfo*)datasource;
86 if (whence == SEEK_SET) pt = info->offset + new_offset;
87 else if (whence == SEEK_CUR) pt = ftell(info->stream) + new_offset;
88 else if (whence == SEEK_END) pt = info->offset + info->length + new_offset;
89 int r = fseek(info->stream, pt, 0);
90 return r;
91 }
92 static long ogg_tellfunc(void* datasource) {
93 OggInfo* info = (OggInfo*)datasource;
94 int pos = ftell(info->stream);
95 if (pos == -1) return -1;
96 return pos-info->offset;
97 }
98 static int ogg_closefunc(void* datasource) {
99 return 0;
100 }
101
102 extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len) {
103 if (info.stream == 0) return 0;
104 // Voice ファイルを直接指定すると全ストリームを再生してしまうので
105 // 必要な部分だけ切り出して callback 経由で帰す
106 fseek(info.stream, info.offset, 0);
107
108 ov_callbacks callback;
109 callback.read_func = &ogg_readfunc;
110 callback.seek_func = &ogg_seekfunc;
111 callback.close_func = &ogg_closefunc;
112 callback.tell_func = &ogg_tellfunc;
113
114 OggInfo oinfo;
115 oinfo.stream = info.stream;
116 oinfo.length = info.length;
117 oinfo.offset = info.offset;
118
119 OggVorbis_File vf;
120 int r = ov_open_callbacks((void*)&oinfo, &vf, 0, 0, callback);
121 if (r != 0) {
122 fprintf(stderr,"ogg stream err: %d\n",r);
123 return 0;
124 }
125 vorbis_info* vinfo = ov_info(&vf, 0);
126 info.rate = vinfo->rate;
127 int channels = vinfo->channels;
128
129 int cur = 0x2c;
130 cur_size = INITSIZE;
131 out = (char*)malloc(cur_size);
132
133 int current_section;
134 do {
135 #if HAVE_LIBVORBISFILE
136 r = ov_read(&vf, out+cur, cur_size-cur, 0, 2, 1, 0);
137 #else /* HAVE_LIBVORBISIDEC */
138 r = ov_read(&vf, out+cur, cur_size-cur, &current_section);
139 #endif
140 if (r <= 0) break;
141 cur += r;
142 if (cur_size-INITSIZE/4 < cur) Resize();
143 } while(1);
144 ov_clear(&vf);
145
146 *dest_len = cur; // うまくコンバートできてるのかなあ……
147 const char* header = MakeWavHeader(info.rate, channels, 2, cur);
148 memcpy(out, header, 0x2c);
149
150 char* ret = out;
151 out = 0;
152
153 return ret;
154 }
155 struct OggFILE_impl {
156 OggVorbis_File vf;
157 ov_callbacks callback;
158 OggInfo oinfo;
159 OggFILE_impl(FILE*, int);
160 };
161
162 OggFILE_impl::OggFILE_impl(FILE* stream, int length) {
163 callback.read_func = &ogg_readfunc;
164 callback.seek_func = &ogg_seekfunc;
165 callback.close_func = &ogg_closefunc;
166 callback.tell_func = &ogg_tellfunc;
167 oinfo.stream = stream;
168 oinfo.length = length;
169 oinfo.offset = ftell(stream);
170 }
171
172 OggFILE::OggFILE(FILE* stream, int len) {
173 pimpl = new OggFILE_impl(stream, len);
174 int r = ov_open_callbacks( (void*)&(pimpl->oinfo), &(pimpl->vf), 0, 0, pimpl->callback);
175 if (r != 0) {
176 delete pimpl;
177 pimpl = 0;
178 return;
179 }
180 vorbis_info* vinfo = ov_info(&(pimpl->vf), 0);
181 wavinfo.SamplingRate = vinfo->rate;
182 wavinfo.Channels = vinfo->channels;
183 wavinfo.DataBits = 16;
184 }
185 OggFILE::~OggFILE() {
186 if (pimpl) {
187 ov_clear(&(pimpl->vf));
188 fclose(pimpl->oinfo.stream);
189 delete pimpl;
190 }
191 }
192 int OggFILE::Read(char* buf, int blksize, int blklen) {
193 if (pimpl == 0) return -1;
194 int current_section;
195 #if HAVE_LIBVORBISFILE
196 int r = ov_read( &(pimpl->vf), buf, blksize*blklen, 0, 2, 1, 0);
197 #else /* HAVE_LIBVORBISIDEC */
198 int r = ov_read( &(pimpl->vf), buf, blksize*blklen, &current_section);
199 #endif
200 if (r <= 0) { // end of file
201 return -1;
202 }
203 while(r < blksize*blklen) {
204 #if HAVE_LIBVORBISFILE
205 int dr = ov_read(&(pimpl->vf), buf+r, blksize*blklen-r, 0, 2, 1, 0);
206 #else /* HAVE_LIBVORBISIDEC */
207 int dr = ov_read(&(pimpl->vf), buf+r, blksize*blklen-r, &current_section);
208 #endif
209 if (dr <= 0) break;
210 r += dr;
211 }
212 return r / blksize;
213 }
214 void OggFILE::Seek(int count) {
215 ov_pcm_seek(&(pimpl->vf), count);
216 return;
217 }
218 #else
219 extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len) {
220 return 0;
221 }
222 OggFILE::OggFILE(FILE* stream, int a) {pimpl = 0;}
223 OggFILE::~OggFILE(){}
224 void OggFILE::Seek(int count){}
225 int OggFILE::Read(char* buf, int blksize, int blklen){return -1;}
226 #endif