Imported Upstream version 1.2
[platform/upstream/alure.git] / src / codec_dumb.cpp
1 /*
2  * ALURE  OpenAL utility library
3  * Copyright (c) 2009-2010 by Chris Robinson.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23
24 #include "config.h"
25
26 #include "main.h"
27
28 #include <string.h>
29 #include <assert.h>
30
31 #include <istream>
32
33 #include <dumb.h>
34
35
36 #ifdef DYNLOAD
37 static void *dumb_handle;
38 #define MAKE_FUNC(x) static typeof(x)* p##x
39 MAKE_FUNC(dumbfile_open_ex);
40 MAKE_FUNC(dumbfile_close);
41 MAKE_FUNC(dumb_read_mod);
42 MAKE_FUNC(dumb_read_s3m);
43 MAKE_FUNC(dumb_read_xm);
44 MAKE_FUNC(dumb_read_it);
45 MAKE_FUNC(dumb_silence);
46 MAKE_FUNC(duh_sigrenderer_generate_samples);
47 MAKE_FUNC(duh_get_it_sigrenderer);
48 MAKE_FUNC(duh_end_sigrenderer);
49 MAKE_FUNC(unload_duh);
50 MAKE_FUNC(dumb_it_start_at_order);
51 MAKE_FUNC(dumb_it_set_loop_callback);
52 MAKE_FUNC(dumb_it_sr_get_speed);
53 MAKE_FUNC(dumb_it_sr_set_speed);
54 #undef MAKE_FUNC
55
56 #define dumbfile_open_ex pdumbfile_open_ex
57 #define dumbfile_close pdumbfile_close
58 #define dumb_read_mod pdumb_read_mod
59 #define dumb_read_s3m pdumb_read_s3m
60 #define dumb_read_xm pdumb_read_xm
61 #define dumb_read_it pdumb_read_it
62 #define dumb_silence pdumb_silence
63 #define duh_sigrenderer_generate_samples pduh_sigrenderer_generate_samples
64 #define duh_get_it_sigrenderer pduh_get_it_sigrenderer
65 #define duh_end_sigrenderer pduh_end_sigrenderer
66 #define unload_duh punload_duh
67 #define dumb_it_start_at_order pdumb_it_start_at_order
68 #define dumb_it_set_loop_callback pdumb_it_set_loop_callback
69 #define dumb_it_sr_get_speed pdumb_it_sr_get_speed
70 #define dumb_it_sr_set_speed pdumb_it_sr_set_speed
71 #else
72 #define dumb_handle 1
73 #endif
74
75
76 struct dumbStream : public alureStream {
77 private:
78     DUMBFILE_SYSTEM vfs;
79     DUMBFILE *dumbFile;
80     DUH *duh;
81     DUH_SIGRENDERER *renderer;
82     std::vector<sample_t> sampleBuf;
83     ALuint lastOrder;
84     ALenum format;
85     ALCint samplerate;
86
87 public:
88 #ifdef DYNLOAD
89     static void Init()
90     {
91 #ifdef _WIN32
92 #define DUMB_LIB "libdumb.dll"
93 #elif defined(__APPLE__)
94 #define DUMB_LIB "libdumb.dylib"
95 #else
96 #define DUMB_LIB "libdumb.so"
97 #endif
98
99         dumb_handle = OpenLib(DUMB_LIB);
100         if(!dumb_handle) return;
101
102         LOAD_FUNC(dumb_handle, dumbfile_open_ex);
103         LOAD_FUNC(dumb_handle, dumbfile_close);
104         LOAD_FUNC(dumb_handle, dumb_read_mod);
105         LOAD_FUNC(dumb_handle, dumb_read_s3m);
106         LOAD_FUNC(dumb_handle, dumb_read_xm);
107         LOAD_FUNC(dumb_handle, dumb_read_it);
108         LOAD_FUNC(dumb_handle, dumb_silence);
109         LOAD_FUNC(dumb_handle, duh_sigrenderer_generate_samples);
110         LOAD_FUNC(dumb_handle, duh_get_it_sigrenderer);
111         LOAD_FUNC(dumb_handle, duh_end_sigrenderer);
112         LOAD_FUNC(dumb_handle, unload_duh);
113         LOAD_FUNC(dumb_handle, dumb_it_start_at_order);
114         LOAD_FUNC(dumb_handle, dumb_it_set_loop_callback);
115         LOAD_FUNC(dumb_handle, dumb_it_sr_get_speed);
116         LOAD_FUNC(dumb_handle, dumb_it_sr_set_speed);
117     }
118     static void Deinit()
119     {
120         if(dumb_handle)
121             CloseLib(dumb_handle);
122         dumb_handle = NULL;
123     }
124 #else
125     static void Init() { }
126     static void Deinit() { }
127 #endif
128
129     virtual bool IsValid()
130     { return renderer != NULL; }
131
132     virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
133     {
134         if(format == AL_NONE)
135         {
136             format = GetSampleFormat(2, 32, true);
137             if(format == AL_NONE)
138                 format = AL_FORMAT_STEREO16;
139         }
140         *fmt = format;
141         *frequency = samplerate;
142         *blockalign = 2 * ((format==AL_FORMAT_STEREO16) ? sizeof(ALshort) :
143                                                           sizeof(ALfloat));
144         return true;
145     }
146
147     virtual ALuint GetData(ALubyte *data, ALuint bytes)
148     {
149         ALuint ret = 0;
150
151         if(dumb_it_sr_get_speed(duh_get_it_sigrenderer(renderer)) == 0)
152             return 0;
153
154         ALuint sample_count = bytes / ((format==AL_FORMAT_STEREO16) ?
155                                        sizeof(ALshort) : sizeof(ALfloat));
156
157         sampleBuf.resize(sample_count);
158         sample_t *samples[] = {
159             &sampleBuf[0]
160         };
161
162         dumb_silence(samples[0], sample_count);
163         ret = duh_sigrenderer_generate_samples(renderer, 1.0f, 65536.0f/samplerate, sample_count/2, samples);
164         ret *= 2;
165         if(format == AL_FORMAT_STEREO16)
166         {
167             for(ALuint i = 0;i < ret;i++)
168                 ((ALshort*)data)[i] = clamp(samples[0][i]>>8, -32768, 32767);
169         }
170         else
171         {
172             for(ALuint i = 0;i < ret;i++)
173                 ((ALfloat*)data)[i] = samples[0][i] * (1.0/8388607.0);
174         }
175         ret *= ((format==AL_FORMAT_STEREO16) ? sizeof(ALshort) : sizeof(ALfloat));
176
177         return ret;
178     }
179
180     virtual bool Rewind()
181     {
182         DUH_SIGRENDERER *newrenderer = dumb_it_start_at_order(duh, 2, lastOrder);
183         if(!newrenderer)
184         {
185             SetError("Could not start renderer");
186             return false;
187         }
188         duh_end_sigrenderer(renderer);
189         renderer = newrenderer;
190         return true;
191     }
192
193     virtual bool SetOrder(ALuint order)
194     {
195         DUH_SIGRENDERER *newrenderer = dumb_it_start_at_order(duh, 2, order);
196         if(!newrenderer)
197         {
198             SetError("Could not set order");
199             return false;
200         }
201         duh_end_sigrenderer(renderer);
202         renderer = newrenderer;
203
204         lastOrder = order;
205         return true;
206     }
207
208     dumbStream(std::istream *_fstream)
209       : alureStream(_fstream), dumbFile(NULL), duh(NULL), renderer(NULL),
210         lastOrder(0), format(AL_NONE), samplerate(48000)
211     {
212         if(!dumb_handle) return;
213
214         ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext());
215         if(device) alcGetIntegerv(device, ALC_FREQUENCY, 1, &samplerate);
216
217         DUH* (*funcs[])(DUMBFILE*) = {
218             dumb_read_it,
219             dumb_read_xm,
220             dumb_read_s3m,
221             //dumb_read_mod,
222             NULL
223         };
224
225         vfs.open = NULL;
226         vfs.skip = skip;
227         vfs.getc = read_char;
228         vfs.getnc = read;
229         vfs.close = NULL;
230
231         for(size_t i = 0;funcs[i];i++)
232         {
233             dumbFile = dumbfile_open_ex(this, &vfs);
234             if(dumbFile)
235             {
236                 duh = funcs[i](dumbFile);
237                 if(duh)
238                 {
239                     renderer = dumb_it_start_at_order(duh, 2, lastOrder);
240                     if(renderer)
241                     {
242                         dumb_it_set_loop_callback(duh_get_it_sigrenderer(renderer), loop_cb, this);
243                         break;
244                     }
245
246                     unload_duh(duh);
247                     duh = NULL;
248                 }
249
250                 dumbfile_close(dumbFile);
251                 dumbFile = NULL;
252             }
253             fstream->clear();
254             fstream->seekg(0);
255         }
256     }
257
258     virtual ~dumbStream()
259     {
260         if(renderer)
261             duh_end_sigrenderer(renderer);
262         renderer = NULL;
263
264         if(duh)
265             unload_duh(duh);
266         duh = NULL;
267
268         if(dumbFile)
269             dumbfile_close(dumbFile);
270         dumbFile = NULL;
271     }
272
273 private:
274     // DUMBFILE iostream callbacks
275     static int skip(void *user_data, long offset)
276     {
277         std::istream *stream = static_cast<dumbStream*>(user_data)->fstream;
278         stream->clear();
279
280         if(stream->seekg(offset, std::ios_base::cur))
281             return 0;
282         return -1;
283     }
284
285     static long read(char *ptr, long size, void *user_data)
286     {
287         std::istream *stream = static_cast<dumbStream*>(user_data)->fstream;
288         stream->clear();
289
290         stream->read(ptr, size);
291         return stream->gcount();
292     }
293
294     static int read_char(void *user_data)
295     {
296         std::istream *stream = static_cast<dumbStream*>(user_data)->fstream;
297         stream->clear();
298
299         unsigned char ret;
300         stream->read(reinterpret_cast<char*>(&ret), 1);
301         if(stream->gcount() > 0)
302             return ret;
303         return -1;
304     }
305
306     static int loop_cb(void *user_data)
307     {
308         dumbStream *self = static_cast<dumbStream*>(user_data);
309         dumb_it_sr_set_speed(duh_get_it_sigrenderer(self->renderer), 0);
310         return 0;
311     }
312 };
313 // Priority = -1, because mod loading can find false-positives
314 static DecoderDecl<dumbStream,-1> dumbStream_decoder;
315 Decoder &alure_init_dumb(void)
316 { return dumbStream_decoder; }