Restore context for another EOS callback call
[alure.git] / src / codec_dumb.cpp
blobe66e8a91535365031a1cc6d45df4d2571ccd6e4a
1 /*
2 * ALURE OpenAL utility library
3 * Copyright (c) 2009-2010 by Chris Robinson.
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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.
24 #include "config.h"
26 #include "main.h"
28 #include <string.h>
29 #include <assert.h>
31 #include <istream>
33 #include <dumb.h>
36 #ifdef _WIN32
37 #define DUMB_LIB "libdumb.dll"
38 #elif defined(__APPLE__)
39 #define DUMB_LIB "libdumb.dylib"
40 #else
41 #define DUMB_LIB "libdumb.so"
42 #endif
44 static void *dumb_handle;
45 #define MAKE_FUNC(x) static typeof(x)* p##x
46 MAKE_FUNC(dumbfile_open_ex);
47 MAKE_FUNC(dumbfile_close);
48 MAKE_FUNC(dumb_read_mod);
49 MAKE_FUNC(dumb_read_s3m);
50 MAKE_FUNC(dumb_read_xm);
51 MAKE_FUNC(dumb_read_it);
52 MAKE_FUNC(dumb_silence);
53 MAKE_FUNC(duh_sigrenderer_generate_samples);
54 MAKE_FUNC(duh_get_it_sigrenderer);
55 MAKE_FUNC(duh_end_sigrenderer);
56 MAKE_FUNC(unload_duh);
57 MAKE_FUNC(dumb_it_start_at_order);
58 MAKE_FUNC(dumb_it_set_loop_callback);
59 MAKE_FUNC(dumb_it_sr_get_speed);
60 MAKE_FUNC(dumb_it_sr_set_speed);
61 #undef MAKE_FUNC
64 struct dumbStream : public alureStream {
65 private:
66 DUMBFILE_SYSTEM vfs;
67 DUMBFILE *dumbFile;
68 DUH *duh;
69 DUH_SIGRENDERER *renderer;
70 std::vector<sample_t> sampleBuf;
71 ALuint lastOrder;
72 ALenum format;
73 ALCint samplerate;
75 public:
76 static void Init()
78 dumb_handle = OpenLib(DUMB_LIB);
79 if(!dumb_handle) return;
81 LOAD_FUNC(dumb_handle, dumbfile_open_ex);
82 LOAD_FUNC(dumb_handle, dumbfile_close);
83 LOAD_FUNC(dumb_handle, dumb_read_mod);
84 LOAD_FUNC(dumb_handle, dumb_read_s3m);
85 LOAD_FUNC(dumb_handle, dumb_read_xm);
86 LOAD_FUNC(dumb_handle, dumb_read_it);
87 LOAD_FUNC(dumb_handle, dumb_silence);
88 LOAD_FUNC(dumb_handle, duh_sigrenderer_generate_samples);
89 LOAD_FUNC(dumb_handle, duh_get_it_sigrenderer);
90 LOAD_FUNC(dumb_handle, duh_end_sigrenderer);
91 LOAD_FUNC(dumb_handle, unload_duh);
92 LOAD_FUNC(dumb_handle, dumb_it_start_at_order);
93 LOAD_FUNC(dumb_handle, dumb_it_set_loop_callback);
94 LOAD_FUNC(dumb_handle, dumb_it_sr_get_speed);
95 LOAD_FUNC(dumb_handle, dumb_it_sr_set_speed);
97 static void Deinit()
99 if(dumb_handle)
100 CloseLib(dumb_handle);
101 dumb_handle = NULL;
104 virtual bool IsValid()
105 { return renderer != NULL; }
107 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
109 if(format == AL_NONE)
111 format = GetSampleFormat(2, 32, true);
112 if(format == AL_NONE)
113 format = AL_FORMAT_STEREO16;
115 *fmt = format;
116 *frequency = samplerate;
117 *blockalign = 2 * ((format==AL_FORMAT_STEREO16) ? sizeof(ALshort) :
118 sizeof(ALfloat));
119 return true;
122 virtual ALuint GetData(ALubyte *data, ALuint bytes)
124 ALuint ret = 0;
126 if(pdumb_it_sr_get_speed(pduh_get_it_sigrenderer(renderer)) == 0)
127 return 0;
129 ALuint sample_count = bytes / ((format==AL_FORMAT_STEREO16) ?
130 sizeof(ALshort) : sizeof(ALfloat));
132 sampleBuf.resize(sample_count);
133 sample_t *samples[] = {
134 &sampleBuf[0]
137 pdumb_silence(samples[0], sample_count);
138 ret = pduh_sigrenderer_generate_samples(renderer, 1.0f, 65536.0f/samplerate, sample_count/2, samples);
139 ret *= 2;
140 if(format == AL_FORMAT_STEREO16)
142 for(ALuint i = 0;i < ret;i++)
143 ((ALshort*)data)[i] = clamp(samples[0][i]>>8, -32768, 32767);
145 else
147 for(ALuint i = 0;i < ret;i++)
148 ((ALfloat*)data)[i] = samples[0][i] * (1.0/8388607.0);
150 ret *= ((format==AL_FORMAT_STEREO16) ? sizeof(ALshort) : sizeof(ALfloat));
152 return ret;
155 virtual bool Rewind()
157 DUH_SIGRENDERER *newrenderer = pdumb_it_start_at_order(duh, 2, lastOrder);
158 if(!newrenderer)
160 SetError("Could not start renderer");
161 return false;
163 pduh_end_sigrenderer(renderer);
164 renderer = newrenderer;
165 return true;
168 virtual bool SetOrder(ALuint order)
170 DUH_SIGRENDERER *newrenderer = pdumb_it_start_at_order(duh, 2, order);
171 if(!newrenderer)
173 SetError("Could not set order");
174 return false;
176 pduh_end_sigrenderer(renderer);
177 renderer = newrenderer;
179 lastOrder = order;
180 return true;
183 dumbStream(std::istream *_fstream)
184 : alureStream(_fstream), dumbFile(NULL), duh(NULL), renderer(NULL),
185 lastOrder(0), format(AL_NONE), samplerate(48000)
187 if(!dumb_handle) return;
189 ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext());
190 if(device)
191 alcGetIntegerv(device, ALC_FREQUENCY, 1, &samplerate);
193 DUH* (*funcs[])(DUMBFILE*) = {
194 pdumb_read_it,
195 pdumb_read_xm,
196 pdumb_read_s3m,
197 //pdumb_read_mod,
198 NULL
201 vfs.open = NULL;
202 vfs.skip = skip;
203 vfs.getc = read_char;
204 vfs.getnc = read;
205 vfs.close = NULL;
207 for(size_t i = 0;funcs[i];i++)
209 dumbFile = pdumbfile_open_ex(this, &vfs);
210 if(dumbFile)
212 duh = funcs[i](dumbFile);
213 if(duh)
215 renderer = pdumb_it_start_at_order(duh, 2, lastOrder);
216 if(renderer)
218 pdumb_it_set_loop_callback(pduh_get_it_sigrenderer(renderer), loop_cb, this);
219 break;
222 punload_duh(duh);
223 duh = NULL;
226 pdumbfile_close(dumbFile);
227 dumbFile = NULL;
229 fstream->clear();
230 fstream->seekg(0);
234 virtual ~dumbStream()
236 if(renderer)
237 pduh_end_sigrenderer(renderer);
238 renderer = NULL;
240 if(duh)
241 punload_duh(duh);
242 duh = NULL;
244 if(dumbFile)
245 pdumbfile_close(dumbFile);
246 dumbFile = NULL;
249 private:
250 // DUMBFILE iostream callbacks
251 static int skip(void *user_data, long offset)
253 std::istream *stream = static_cast<dumbStream*>(user_data)->fstream;
254 stream->clear();
256 if(stream->seekg(offset, std::ios_base::cur))
257 return 0;
258 return -1;
261 static long read(char *ptr, long size, void *user_data)
263 std::istream *stream = static_cast<dumbStream*>(user_data)->fstream;
264 stream->clear();
266 stream->read(ptr, size);
267 return stream->gcount();
270 static int read_char(void *user_data)
272 std::istream *stream = static_cast<dumbStream*>(user_data)->fstream;
273 stream->clear();
275 unsigned char ret;
276 stream->read(reinterpret_cast<char*>(&ret), 1);
277 if(stream->gcount() > 0)
278 return ret;
279 return -1;
282 static int loop_cb(void *user_data)
284 dumbStream *self = static_cast<dumbStream*>(user_data);
285 pdumb_it_sr_set_speed(pduh_get_it_sigrenderer(self->renderer), 0);
286 return 0;
289 // Priority = -1, because mod loading can find false-positives
290 static DecoderDecl<dumbStream,-1> dumbStream_decoder;
291 Decoder &alure_init_dumb(void)
292 { return dumbStream_decoder; }