Add support for MIDI using FluidSynth
[alure.git] / include / main.h
blobc4c1f0800a23d694b6ec14ab7577a1ab3eebd12e
1 #ifndef MAIN_H
2 #define MAIN_H
4 #include "AL/alure.h"
5 #include "alext.h"
7 #ifdef HAS_SNDFILE
8 #include <sndfile.h>
9 #endif
10 #ifdef HAS_VORBISFILE
11 #include <vorbis/vorbisfile.h>
12 #endif
13 #ifdef HAS_FLAC
14 #include <FLAC/all.h>
15 #endif
16 #ifdef HAS_MPG123
17 #include <mpg123.h>
18 #endif
19 #ifdef HAS_DUMB
20 #include <dumb.h>
21 #endif
22 #ifdef HAS_DUMB
23 #include <fluidsynth.h>
24 #endif
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
29 #endif
30 #ifdef HAVE_SYS_WAIT_H
31 #include <sys/wait.h>
32 #endif
33 #ifdef HAVE_SIGNAL_H
34 #include <signal.h>
35 #endif
37 #ifdef HAVE_WINDOWS_H
39 #include <windows.h>
41 #else
43 #ifdef HAVE_DLFCN_H
44 #include <dlfcn.h>
45 #endif
47 #include <assert.h>
48 #include <pthread.h>
49 #ifdef HAVE_PTHREAD_NP_H
50 #include <pthread_np.h>
51 #endif
52 #include <errno.h>
54 typedef pthread_mutex_t CRITICAL_SECTION;
55 static inline void EnterCriticalSection(CRITICAL_SECTION *cs)
57 int ret;
58 ret = pthread_mutex_lock(cs);
59 assert(ret == 0);
61 static inline void LeaveCriticalSection(CRITICAL_SECTION *cs)
63 int ret;
64 ret = pthread_mutex_unlock(cs);
65 assert(ret == 0);
67 static inline void InitializeCriticalSection(CRITICAL_SECTION *cs)
69 pthread_mutexattr_t attrib;
70 int ret;
72 ret = pthread_mutexattr_init(&attrib);
73 assert(ret == 0);
75 ret = pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE);
76 #ifdef HAVE_PTHREAD_NP_H
77 if(ret != 0)
78 ret = pthread_mutexattr_setkind_np(&attrib, PTHREAD_MUTEX_RECURSIVE);
79 #endif
80 assert(ret == 0);
81 ret = pthread_mutex_init(cs, &attrib);
82 assert(ret == 0);
84 pthread_mutexattr_destroy(&attrib);
86 static inline void DeleteCriticalSection(CRITICAL_SECTION *cs)
88 int ret;
89 ret = pthread_mutex_destroy(cs);
90 assert(ret == 0);
93 #endif
95 #include <map>
96 #include <streambuf>
97 #include <istream>
98 #include <list>
99 #include <algorithm>
101 static const union {
102 int val;
103 char b[sizeof(int)];
104 } endian_test = { 1 };
105 static const bool LittleEndian = (endian_test.b[0] != 0);
106 static const bool BigEndian = !LittleEndian;
109 extern void *vorbisfile_handle;
110 extern void *flac_handle;
111 extern void *dumb_handle;
112 extern void *mp123_handle;
113 extern void *sndfile_handle;
114 extern void *fsynth_handle;
116 #define MAKE_FUNC(x) extern typeof(x)* p##x
117 #ifdef HAS_VORBISFILE
118 MAKE_FUNC(ov_clear);
119 MAKE_FUNC(ov_info);
120 MAKE_FUNC(ov_open_callbacks);
121 MAKE_FUNC(ov_pcm_seek);
122 MAKE_FUNC(ov_read);
123 #endif
124 #ifdef HAS_FLAC
125 MAKE_FUNC(FLAC__stream_decoder_get_state);
126 MAKE_FUNC(FLAC__stream_decoder_finish);
127 MAKE_FUNC(FLAC__stream_decoder_new);
128 MAKE_FUNC(FLAC__stream_decoder_seek_absolute);
129 MAKE_FUNC(FLAC__stream_decoder_delete);
130 MAKE_FUNC(FLAC__stream_decoder_process_single);
131 MAKE_FUNC(FLAC__stream_decoder_init_stream);
132 #endif
133 #ifdef HAS_DUMB
134 MAKE_FUNC(dumbfile_open_ex);
135 MAKE_FUNC(dumbfile_close);
136 MAKE_FUNC(dumb_read_mod);
137 MAKE_FUNC(dumb_read_s3m);
138 MAKE_FUNC(dumb_read_xm);
139 MAKE_FUNC(dumb_read_it);
140 MAKE_FUNC(dumb_silence);
141 MAKE_FUNC(duh_sigrenderer_generate_samples);
142 MAKE_FUNC(duh_get_it_sigrenderer);
143 MAKE_FUNC(duh_end_sigrenderer);
144 MAKE_FUNC(unload_duh);
145 MAKE_FUNC(dumb_it_start_at_order);
146 MAKE_FUNC(dumb_it_set_loop_callback);
147 MAKE_FUNC(dumb_it_sr_get_speed);
148 MAKE_FUNC(dumb_it_sr_set_speed);
149 #endif
150 #ifdef HAS_MPG123
151 MAKE_FUNC(mpg123_read);
152 MAKE_FUNC(mpg123_init);
153 MAKE_FUNC(mpg123_open_feed);
154 MAKE_FUNC(mpg123_new);
155 MAKE_FUNC(mpg123_delete);
156 MAKE_FUNC(mpg123_feed);
157 MAKE_FUNC(mpg123_exit);
158 MAKE_FUNC(mpg123_getformat);
159 MAKE_FUNC(mpg123_format_none);
160 MAKE_FUNC(mpg123_decode);
161 MAKE_FUNC(mpg123_format);
162 #endif
163 #ifdef HAS_SNDFILE
164 MAKE_FUNC(sf_close);
165 MAKE_FUNC(sf_open_virtual);
166 MAKE_FUNC(sf_readf_short);
167 MAKE_FUNC(sf_seek);
168 #endif
169 #ifdef HAS_FLUIDSYNTH
170 MAKE_FUNC(fluid_settings_setstr);
171 MAKE_FUNC(fluid_synth_program_change);
172 MAKE_FUNC(fluid_synth_sfload);
173 MAKE_FUNC(fluid_settings_setnum);
174 MAKE_FUNC(fluid_synth_sysex);
175 MAKE_FUNC(fluid_synth_cc);
176 MAKE_FUNC(fluid_synth_pitch_bend);
177 MAKE_FUNC(fluid_synth_channel_pressure);
178 MAKE_FUNC(fluid_synth_write_float);
179 MAKE_FUNC(new_fluid_synth);
180 MAKE_FUNC(delete_fluid_settings);
181 MAKE_FUNC(delete_fluid_synth);
182 MAKE_FUNC(fluid_synth_program_reset);
183 MAKE_FUNC(fluid_settings_setint);
184 MAKE_FUNC(new_fluid_settings);
185 MAKE_FUNC(fluid_synth_write_s16);
186 MAKE_FUNC(fluid_synth_noteoff);
187 MAKE_FUNC(fluid_synth_sfunload);
188 MAKE_FUNC(fluid_synth_noteon);
189 #endif
190 #undef MAKE_FUNC
192 void SetError(const char *err);
193 ALuint DetectBlockAlignment(ALenum format);
194 ALuint DetectCompressionRate(ALenum format);
195 ALenum GetSampleFormat(ALuint channels, ALuint bits, bool isFloat);
197 struct UserCallbacks {
198 void* (*open_file)(const ALchar*);
199 void* (*open_mem)(const ALubyte*,ALuint);
200 ALboolean (*get_fmt)(void*,ALenum*,ALuint*,ALuint*);
201 ALuint (*decode)(void*,ALubyte*,ALuint);
202 ALboolean (*rewind)(void*);
203 void (*close)(void*);
205 extern std::map<ALint,UserCallbacks> InstalledCallbacks;
208 struct alureStream {
209 ALubyte *data;
211 ALubyte *dataChunk;
212 ALsizei chunkLen;
214 std::istream *fstream;
216 virtual bool IsValid() = 0;
217 virtual bool GetFormat(ALenum*,ALuint*,ALuint*) = 0;
218 virtual ALuint GetData(ALubyte*,ALuint) = 0;
219 virtual bool Rewind() = 0;
220 virtual bool SetOrder(ALuint order)
222 if(!order) return Rewind();
223 SetError("Invalid order for stream");
224 return false;
227 alureStream(std::istream *_stream)
228 : data(NULL), dataChunk(NULL), fstream(_stream)
229 { StreamList.push_front(this); }
230 virtual ~alureStream()
232 delete[] data; delete[] dataChunk;
233 StreamList.erase(std::find(StreamList.begin(), StreamList.end(), this));
236 static void Clear(void)
238 while(StreamList.size() > 0)
239 alureDestroyStream(*(StreamList.begin()), 0, NULL);
242 static bool Verify(alureStream *stream)
244 ListType::iterator i = std::find(StreamList.begin(), StreamList.end(), stream);
245 return (i != StreamList.end());
248 private:
249 typedef std::list<alureStream*> ListType;
250 static ListType StreamList;
252 void StopStream(alureStream *stream);
255 struct MemDataInfo {
256 const ALubyte *Data;
257 size_t Length;
258 size_t Pos;
260 MemDataInfo() : Data(NULL), Length(0), Pos(0)
262 MemDataInfo(const MemDataInfo &inf) : Data(inf.Data), Length(inf.Length),
263 Pos(inf.Pos)
267 class MemStreamBuf : public std::streambuf {
268 MemDataInfo memInfo;
270 virtual int_type underflow();
271 virtual pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out);
272 virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out);
274 public:
275 MemStreamBuf(const MemDataInfo &data)
276 : memInfo(data)
278 memInfo.Pos /= sizeof(char_type);
279 memInfo.Length /= sizeof(char_type);
281 virtual ~MemStreamBuf() { }
284 struct UserFuncs {
285 void* (*open)(const char *filename, ALuint mode);
286 void (*close)(void *f);
287 ALsizei (*read)(void *f, ALubyte *buf, ALuint count);
288 ALsizei (*write)(void *f, const ALubyte *buf, ALuint count);
289 alureInt64 (*seek)(void *f, alureInt64 offset, int whence);
291 extern UserFuncs Funcs;
293 class FileStreamBuf : public std::streambuf {
294 void *usrFile;
295 UserFuncs fio;
297 char buffer[1024];
299 virtual int_type underflow();
300 virtual pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out);
301 virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out);
303 public:
304 bool IsOpen()
305 { return usrFile != NULL; }
307 FileStreamBuf(const char *filename, ALint mode)
308 : usrFile(NULL), fio(Funcs)
309 { usrFile = fio.open(filename, mode); }
310 virtual ~FileStreamBuf()
311 { if(usrFile) fio.close(usrFile); }
314 class InStream : public std::istream {
315 public:
316 InStream(const char *filename)
317 : std::istream(new FileStreamBuf(filename, 0))
319 if(!(static_cast<FileStreamBuf*>(rdbuf())->IsOpen()))
320 clear(failbit);
322 InStream(const MemDataInfo &memInfo)
323 : std::istream(new MemStreamBuf(memInfo))
325 virtual ~InStream()
326 { delete rdbuf(); }
330 extern CRITICAL_SECTION cs_StreamPlay;
332 alureStream *create_stream(const char *fname);
333 alureStream *create_stream(const MemDataInfo &memData);
334 alureStream *create_stream(ALvoid *userdata, ALenum format, ALuint rate, const UserCallbacks &cb);
336 template <typename T>
337 const T& clamp(const T& val, const T& min, const T& max)
338 { return std::max(std::min(val, max), min); }
340 template <typename T>
341 void swap(T &val1, T &val2)
343 val1 ^= val2;
344 val2 ^= val1;
345 val1 ^= val2;
348 #endif // MAIN_H