1 /*
2 
3 Boost Software License - Version 1.0 - August 17th, 2003
4 
5 Permission is hereby granted, free of charge, to any person or organization
6 obtaining a copy of the software and accompanying documentation covered by
7 this license (the "Software") to use, reproduce, display, distribute,
8 execute, and transmit the Software, and to prepare derivative works of the
9 Software, and to permit third-parties to whom the Software is furnished to
10 do so, all subject to the following:
11 
12 The copyright notices in the Software and this entire statement, including
13 the above license grant, this restriction and the following disclaimer,
14 must be included in all copies of the Software, in whole or in part, and
15 all derivative works of the Software, unless such copies or derivative
16 works are solely in the form of machine-executable object code generated by
17 a source language processor.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 
27 */
28 module derelict.vorbis.file;
29 
30 private {
31     import core.stdc.config;
32     import std.stdio;
33     import derelict.util.loader;
34     import derelict.util.system;
35     import derelict.ogg.ogg;
36     import derelict.vorbis.codec;
37 
38     static if(Derelict_OS_Windows)
39         enum libNames = "vorbisfile.dll, libvorbisfile-3.dll, libvorbisfile.dll";
40     else static if(Derelict_OS_Mac)
41         enum libNames = "libvorbisfile.dylib, libvorbisfile.0.dylib";
42     else static if(Derelict_OS_Posix)
43         enum libNames = "libvorbisfile.so, libvorbisfile.so.3, libvorbisfile.so.3.1.0";
44     else
45         static assert(0, "Need to implement libvorbisfile libnames for this operating system.");
46 }
47 
48 struct ov_callbacks {
49     extern(C) nothrow {
50         size_t function(void*, size_t, size_t, void*) read_func;
51         int function(void*, ogg_int64_t, int) seek_func;
52         int function(void*) close_func;
53         c_long function(void*) tell_func;
54     }
55 }
56 
57 enum {
58     NOTOPEN =0,
59     PARTOPEN =1,
60     OPENED =2,
61     STREAMSET =3,
62     INITSET =4,
63 }
64 
65 struct OggVorbis_File {
66     void* datasource;
67     int seekable;
68     ogg_int64_t offset;
69     ogg_int64_t end;
70     ogg_sync_state oy;
71     int links;
72     ogg_int64_t* offsets;
73     ogg_int64_t* dataoffsets;
74     c_long* serialnos;
75     ogg_int64_t* pcmlengths;
76     vorbis_info* vi;
77     vorbis_comment* vc;
78     ogg_int64_t pcm_offset;
79     int ready_state;
80     c_long current_serialno;
81     int current_link;
82     double bittrack;
83     double samptrack;
84     ogg_stream_state os;
85     vorbis_dsp_state vd;
86     vorbis_block vb;
87     ov_callbacks callbacks;
88 }
89 
90 extern(C) @nogc nothrow {
91     alias da_ov_clear = int function(OggVorbis_File*);
92     alias da_ov_fopen = int function(const(char)*, OggVorbis_File*);
93     alias da_ov_open_callbacks = int function(void* datasource, OggVorbis_File*, const(char)*, c_long, ov_callbacks);
94     alias da_ov_test_callbacks = int function(void*, OggVorbis_File*, const(char)*, c_long, ov_callbacks);
95     alias da_ov_test_open = int function(OggVorbis_File*);
96     alias da_ov_bitrate = c_long function(OggVorbis_File*, int);
97     alias da_ov_bitrate_instant = c_long function(OggVorbis_File*);
98     alias da_ov_streams = c_long function(OggVorbis_File*);
99     alias da_ov_seekable = c_long function(OggVorbis_File*);
100     alias da_ov_serialnumber = c_long function(OggVorbis_File*, int);
101     alias da_ov_raw_total = ogg_int64_t function(OggVorbis_File*, int);
102     alias da_ov_pcm_total = ogg_int64_t function(OggVorbis_File*, int);
103     alias da_ov_time_total = double function(OggVorbis_File*, int);
104     alias da_ov_raw_seek = int function(OggVorbis_File*, ogg_int64_t);
105     alias da_ov_pcm_seek = int function(OggVorbis_File*, ogg_int64_t);
106     alias da_ov_pcm_seek_page = int function(OggVorbis_File*, ogg_int64_t);
107     alias da_ov_time_seek = int function(OggVorbis_File*, double);
108     alias da_ov_time_seek_page = int function(OggVorbis_File*, double);
109     alias da_ov_raw_seek_lap = int function(OggVorbis_File*, ogg_int64_t);
110     alias da_ov_pcm_seek_lap = int function(OggVorbis_File*, ogg_int64_t);
111     alias da_ov_pcm_seek_page_lap = int function(OggVorbis_File*, ogg_int64_t);
112     alias da_ov_time_seek_lap = int function(OggVorbis_File*, double);
113     alias da_ov_time_seek_page_lap = int function(OggVorbis_File*, double);
114     alias da_ov_raw_tell = ogg_int64_t function(OggVorbis_File*);
115     alias da_ov_pcm_tell = ogg_int64_t function(OggVorbis_File*);
116     alias da_ov_time_tell = double function(OggVorbis_File*);
117     alias da_ov_info = vorbis_info* function(OggVorbis_File*, int);
118     alias da_ov_comment = vorbis_comment* function(OggVorbis_File*, int);
119     alias da_ov_read_float = c_long function(OggVorbis_File*, float***, int, int*);
120     alias da_ov_read = c_long function(OggVorbis_File*, byte*, int, int, int, int, int*);
121     alias da_ov_crosslap = int function(OggVorbis_File*, OggVorbis_File*);
122     alias da_ov_halfrate = int function(OggVorbis_File*, int);
123     alias da_ov_halfrate_p = int function(OggVorbis_File*);
124 }
125 
126 private extern (C) nothrow {
127     size_t Derelict_VorbisRead(void* ptr, size_t byteSize, size_t sizeToRead, void* datasource) {
128         return fread(ptr, byteSize, sizeToRead, cast(FILE*)datasource);
129     }
130 
131     int Derelict_VorbisSeek(void* datasource, ogg_int64_t offset, int whence) {
132         return fseek(cast(FILE*)datasource, cast(int)offset, whence);
133     }
134 
135     int Derelict_VorbisClose(void* datasource) {
136         return fclose(cast(FILE*)datasource);
137     }
138 
139     c_long Derelict_VorbisTell(void* datasource) {
140         return cast(c_long)ftell(cast(FILE*)datasource);
141     }
142 }
143 
144 // ov_open is rewritten below because of incompatibility between compilers with FILE struct
145 // Using this wrapper, it *should* work exactly as it would in c++. --JoeCoder
146 int ov_open(FILE* f, OggVorbis_File* vf, const(char)* initial, c_long ibytes)
147 {
148     // Fill the ov_callbacks structure
149     ov_callbacks vorbisCallbacks;    // Structure to hold pointers to callback functions
150     vorbisCallbacks.read_func  = &Derelict_VorbisRead;
151     vorbisCallbacks.close_func = &Derelict_VorbisClose;
152     vorbisCallbacks.seek_func  = &Derelict_VorbisSeek;
153     vorbisCallbacks.tell_func  = &Derelict_VorbisTell;
154 
155     return ov_open_callbacks(cast(void*)f, vf, initial, cast(int)ibytes, vorbisCallbacks);
156 }
157 
158 // ditto for ov_test
159 int ov_test(FILE* f, OggVorbis_File* vf, const(char)* initial, c_long ibytes)
160 {
161     // Fill the ov_callbacks structure
162     ov_callbacks vorbisCallbacks;    // Structure to hold pointers to callback functions
163     vorbisCallbacks.read_func  = &Derelict_VorbisRead;
164     vorbisCallbacks.close_func = &Derelict_VorbisClose;
165     vorbisCallbacks.seek_func  = &Derelict_VorbisSeek;
166     vorbisCallbacks.tell_func  = &Derelict_VorbisTell;
167 
168     return ov_test_callbacks(cast(void*)f, vf, initial, cast(int)ibytes, vorbisCallbacks);
169 }
170 
171 __gshared {
172     da_ov_clear ov_clear;
173     da_ov_fopen ov_fopen;
174     da_ov_open_callbacks ov_open_callbacks;
175     da_ov_test_callbacks ov_test_callbacks;
176     da_ov_test_open ov_test_open;
177     da_ov_bitrate ov_bitrate;
178     da_ov_bitrate_instant ov_bitrate_instant;
179     da_ov_streams ov_streams;
180     da_ov_seekable ov_seekable;
181     da_ov_serialnumber ov_serialnumber;
182     da_ov_raw_total ov_raw_total;
183     da_ov_pcm_total ov_pcm_total;
184     da_ov_time_total ov_time_total;
185     da_ov_raw_seek ov_raw_seek;
186     da_ov_pcm_seek ov_pcm_seek;
187     da_ov_pcm_seek_page ov_pcm_seek_page;
188     da_ov_time_seek ov_time_seek;
189     da_ov_time_seek_page ov_time_seek_page;
190     da_ov_raw_seek_lap ov_raw_seek_lap;
191     da_ov_pcm_seek_lap ov_pcm_seek_lap;
192     da_ov_pcm_seek_page_lap ov_pcm_seek_page_lap;
193     da_ov_time_seek_lap ov_time_seek_lap;
194     da_ov_time_seek_page_lap ov_time_seek_page_lap;
195     da_ov_raw_tell ov_raw_tell;
196     da_ov_pcm_tell ov_pcm_tell;
197     da_ov_time_tell ov_time_tell;
198     da_ov_info ov_info;
199     da_ov_comment ov_comment;
200     da_ov_read_float ov_read_float;
201     da_ov_read ov_read;
202     da_ov_crosslap ov_crosslap;
203     da_ov_halfrate ov_halfrate;
204     da_ov_halfrate_p ov_halfrate_p;
205 }
206 
207 class DerelictVorbisFileLoader : SharedLibLoader {
208     public this() {
209         super(libNames);
210     }
211 
212     protected override void loadSymbols() {
213         bindFunc(cast(void**)&ov_clear, "ov_clear");
214         bindFunc(cast(void**)&ov_fopen, "ov_fopen");
215         bindFunc(cast(void**)&ov_open_callbacks, "ov_open_callbacks");
216         bindFunc(cast(void**)&ov_test_callbacks, "ov_test_callbacks");
217         bindFunc(cast(void**)&ov_test_open, "ov_test_open");
218         bindFunc(cast(void**)&ov_bitrate, "ov_bitrate");
219         bindFunc(cast(void**)&ov_bitrate_instant, "ov_bitrate_instant");
220         bindFunc(cast(void**)&ov_streams, "ov_streams");
221         bindFunc(cast(void**)&ov_seekable, "ov_seekable");
222         bindFunc(cast(void**)&ov_serialnumber, "ov_serialnumber");
223         bindFunc(cast(void**)&ov_raw_total, "ov_raw_total");
224         bindFunc(cast(void**)&ov_pcm_total, "ov_pcm_total");
225         bindFunc(cast(void**)&ov_time_total, "ov_time_total");
226         bindFunc(cast(void**)&ov_raw_seek, "ov_raw_seek");
227         bindFunc(cast(void**)&ov_pcm_seek, "ov_pcm_seek");
228         bindFunc(cast(void**)&ov_pcm_seek_page, "ov_pcm_seek_page");
229         bindFunc(cast(void**)&ov_time_seek, "ov_time_seek");
230         bindFunc(cast(void**)&ov_time_seek_page, "ov_time_seek_page");
231         bindFunc(cast(void**)&ov_raw_seek_lap, "ov_raw_seek_lap");
232         bindFunc(cast(void**)&ov_pcm_seek_lap, "ov_pcm_seek_lap");
233         bindFunc(cast(void**)&ov_pcm_seek_page_lap, "ov_pcm_seek_page_lap");
234         bindFunc(cast(void**)&ov_time_seek_lap, "ov_time_seek_lap");
235         bindFunc(cast(void**)&ov_time_seek_page_lap, "ov_time_seek_page_lap");
236         bindFunc(cast(void**)&ov_raw_tell, "ov_raw_tell");
237         bindFunc(cast(void**)&ov_pcm_tell, "ov_pcm_tell");
238         bindFunc(cast(void**)&ov_time_tell, "ov_time_tell");
239         bindFunc(cast(void**)&ov_info, "ov_info");
240         bindFunc(cast(void**)&ov_comment, "ov_comment");
241         bindFunc(cast(void**)&ov_read_float, "ov_read_float");
242         bindFunc(cast(void**)&ov_read, "ov_read");
243         bindFunc(cast(void**)&ov_crosslap, "ov_crosslap");
244         bindFunc(cast(void**)&ov_halfrate, "ov_halfrate");
245         bindFunc(cast(void**)&ov_halfrate_p, "ov_halfrate_p");
246     }
247 }
248 
249 __gshared DerelictVorbisFileLoader DerelictVorbisFile;
250 
251 shared static this() {
252     DerelictVorbisFile = new DerelictVorbisFileLoader();
253 }