0
|
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
|
52
|
28 #include <stdio.h>
|
|
29 #include <string.h>
|
|
30 #include <stdlib.h>
|
|
31 #include "music.h"
|
|
32 #include "wavfile.h"
|
0
|
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
|
52
|
48 #include <vorbis/vorbisfile.h>
|
0
|
49 #else /* HAVE_LIBVORBISIDEC */
|
52
|
50 #include <tremor/ivorbiscodec.h>
|
|
51 #include <tremor/ivorbisfile.h>
|
0
|
52 #endif
|
|
53
|
|
54 #define INITSIZE 65536
|
|
55
|
|
56 static int cur_size = 0;
|
52
|
57 static char* out = NULL;
|
0
|
58 static void Resize(void) {
|
|
59 char* new_out = (char*)realloc(out, cur_size+INITSIZE);
|
52
|
60 if (new_out == NULL) {
|
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 };
|
52
|
74
|
0
|
75 /* ogg stream 読み込み用の dummy callback */
|
|
76 static size_t ogg_readfunc(void* ptr, size_t size, size_t nmemb, void* datasource) {
|
|
77 OggInfo* info = (OggInfo*)datasource;
|
|
78 int pt = ftell(info->stream) - info->offset;
|
|
79 if (pt+size*nmemb > info->length) {
|
|
80 nmemb = (info->length-pt) / size;
|
|
81 }
|
|
82 return fread(ptr, size, nmemb, info->stream);
|
|
83 }
|
52
|
84
|
0
|
85 static int ogg_seekfunc(void* datasource, ogg_int64_t new_offset, int whence) {
|
|
86 int pt;
|
|
87 OggInfo* info = (OggInfo*)datasource;
|
|
88 if (whence == SEEK_SET) pt = info->offset + new_offset;
|
|
89 else if (whence == SEEK_CUR) pt = ftell(info->stream) + new_offset;
|
|
90 else if (whence == SEEK_END) pt = info->offset + info->length + new_offset;
|
52
|
91 int r = fseek(info->stream, pt, SEEK_SET);
|
0
|
92 return r;
|
|
93 }
|
52
|
94
|
0
|
95 static long ogg_tellfunc(void* datasource) {
|
|
96 OggInfo* info = (OggInfo*)datasource;
|
|
97 int pos = ftell(info->stream);
|
|
98 if (pos == -1) return -1;
|
|
99 return pos-info->offset;
|
|
100 }
|
52
|
101
|
0
|
102 static int ogg_closefunc(void* datasource) {
|
|
103 return 0;
|
|
104 }
|
18
|
105
|
|
106 static int fseek_wrap(FILE *f,ogg_int64_t off,int whence){
|
52
|
107 if (f == NULL) return(-1);
|
|
108 return fseek(f, off, whence);
|
18
|
109 }
|
|
110
|
0
|
111 extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len) {
|
52
|
112 if (info.stream == NULL) return NULL;
|
0
|
113 // Voice ファイルを直接指定すると全ストリームを再生してしまうので
|
|
114 // 必要な部分だけ切り出して callback 経由で帰す
|
52
|
115 fseek(info.stream, info.offset, SEEK_SET);
|
0
|
116
|
|
117 ov_callbacks callback;
|
|
118 callback.read_func = &ogg_readfunc;
|
|
119 callback.seek_func = &ogg_seekfunc;
|
|
120 callback.close_func = &ogg_closefunc;
|
|
121 callback.tell_func = &ogg_tellfunc;
|
|
122
|
|
123 OggInfo oinfo;
|
|
124 oinfo.stream = info.stream;
|
|
125 oinfo.length = info.length;
|
|
126 oinfo.offset = info.offset;
|
|
127
|
|
128 OggVorbis_File vf;
|
|
129 int r = ov_open_callbacks((void*)&oinfo, &vf, 0, 0, callback);
|
|
130 if (r != 0) {
|
|
131 fprintf(stderr,"ogg stream err: %d\n",r);
|
52
|
132 return NULL;
|
0
|
133 }
|
|
134 vorbis_info* vinfo = ov_info(&vf, 0);
|
|
135 info.rate = vinfo->rate;
|
|
136 int channels = vinfo->channels;
|
|
137
|
|
138 int cur = 0x2c;
|
|
139 cur_size = INITSIZE;
|
|
140 out = (char*)malloc(cur_size);
|
|
141
|
|
142 do {
|
|
143 #if HAVE_LIBVORBISFILE
|
44
|
144 r = ov_read(&vf, out+cur, cur_size-cur, 0, 2, 1, NULL);
|
0
|
145 #else /* HAVE_LIBVORBISIDEC */
|
44
|
146 r = ov_read(&vf, out+cur, cur_size-cur, NULL);
|
0
|
147 #endif
|
|
148 if (r <= 0) break;
|
|
149 cur += r;
|
|
150 if (cur_size-INITSIZE/4 < cur) Resize();
|
|
151 } while(1);
|
|
152 ov_clear(&vf);
|
|
153
|
|
154 *dest_len = cur; // うまくコンバートできてるのかなあ……
|
|
155 const char* header = MakeWavHeader(info.rate, channels, 2, cur);
|
|
156 memcpy(out, header, 0x2c);
|
|
157
|
|
158 char* ret = out;
|
52
|
159 out = NULL;
|
0
|
160
|
|
161 return ret;
|
|
162 }
|
52
|
163
|
0
|
164 struct OggFILE_impl {
|
|
165 OggVorbis_File vf;
|
|
166 ov_callbacks callback;
|
|
167 OggInfo oinfo;
|
|
168 OggFILE_impl(FILE*, int);
|
|
169 };
|
|
170
|
|
171 OggFILE_impl::OggFILE_impl(FILE* stream, int length) {
|
|
172 callback.read_func = &ogg_readfunc;
|
|
173 callback.seek_func = &ogg_seekfunc;
|
|
174 callback.close_func = &ogg_closefunc;
|
|
175 callback.tell_func = &ogg_tellfunc;
|
|
176 oinfo.stream = stream;
|
|
177 oinfo.length = length;
|
|
178 oinfo.offset = ftell(stream);
|
|
179 }
|
|
180
|
|
181 OggFILE::OggFILE(FILE* stream, int len) {
|
|
182 pimpl = new OggFILE_impl(stream, len);
|
|
183 int r = ov_open_callbacks( (void*)&(pimpl->oinfo), &(pimpl->vf), 0, 0, pimpl->callback);
|
|
184 if (r != 0) {
|
|
185 delete pimpl;
|
52
|
186 pimpl = NULL;
|
0
|
187 return;
|
|
188 }
|
|
189 vorbis_info* vinfo = ov_info(&(pimpl->vf), 0);
|
|
190 wavinfo.SamplingRate = vinfo->rate;
|
|
191 wavinfo.Channels = vinfo->channels;
|
|
192 wavinfo.DataBits = 16;
|
|
193 }
|
52
|
194
|
0
|
195 OggFILE::~OggFILE() {
|
52
|
196 if (pimpl != NULL) {
|
0
|
197 ov_clear(&(pimpl->vf));
|
|
198 fclose(pimpl->oinfo.stream);
|
|
199 delete pimpl;
|
|
200 }
|
|
201 }
|
52
|
202
|
0
|
203 int OggFILE::Read(char* buf, int blksize, int blklen) {
|
52
|
204 if (pimpl == NULL) return -1;
|
0
|
205 #if HAVE_LIBVORBISFILE
|
44
|
206 int r = ov_read( &(pimpl->vf), buf, blksize*blklen, 0, 2, 1, NULL);
|
0
|
207 #else /* HAVE_LIBVORBISIDEC */
|
44
|
208 int r = ov_read( &(pimpl->vf), buf, blksize*blklen, NULL);
|
0
|
209 #endif
|
|
210 if (r <= 0) { // end of file
|
|
211 return -1;
|
|
212 }
|
|
213 while(r < blksize*blklen) {
|
|
214 #if HAVE_LIBVORBISFILE
|
44
|
215 int dr = ov_read(&(pimpl->vf), buf+r, blksize*blklen-r, 0, 2, 1, NULL);
|
0
|
216 #else /* HAVE_LIBVORBISIDEC */
|
44
|
217 int dr = ov_read(&(pimpl->vf), buf+r, blksize*blklen-r, NULL);
|
0
|
218 #endif
|
|
219 if (dr <= 0) break;
|
|
220 r += dr;
|
|
221 }
|
|
222 return r / blksize;
|
|
223 }
|
52
|
224
|
0
|
225 void OggFILE::Seek(int count) {
|
|
226 ov_pcm_seek(&(pimpl->vf), count);
|
|
227 return;
|
|
228 }
|
52
|
229
|
0
|
230 #else
|
|
231 extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len) {
|
52
|
232 return NULL;
|
0
|
233 }
|
52
|
234
|
|
235 OggFILE::OggFILE(FILE* stream, int a) {pimpl = NULL;}
|
0
|
236 OggFILE::~OggFILE(){}
|
|
237 void OggFILE::Seek(int count){}
|
|
238 int OggFILE::Read(char* buf, int blksize, int blklen){return -1;}
|
|
239 #endif
|