Restore context for another EOS callback call
[alure.git] / src / codec_sndfile.cpp
blob0ba9dd9aa85f334281b794bed07eb399a8e5c6f0
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 <sndfile.h>
36 #ifdef _WIN32
37 #define SNDFILE_LIB "libsndfile-1.dll"
38 #elif defined(__APPLE__)
39 #define SNDFILE_LIB "libsndfile.1.dylib"
40 #else
41 #define SNDFILE_LIB "libsndfile.so.1"
42 #endif
44 static void *sndfile_handle;
45 #define MAKE_FUNC(x) static typeof(x)* p##x
46 MAKE_FUNC(sf_close);
47 MAKE_FUNC(sf_open_virtual);
48 MAKE_FUNC(sf_readf_short);
49 MAKE_FUNC(sf_seek);
50 #undef MAKE_FUNC
53 struct sndStream : public alureStream {
54 private:
55 SNDFILE *sndFile;
56 SF_INFO sndInfo;
57 ALenum format;
59 public:
60 static void Init()
62 sndfile_handle = OpenLib(SNDFILE_LIB);
63 if(!sndfile_handle) return;
65 LOAD_FUNC(sndfile_handle, sf_close);
66 LOAD_FUNC(sndfile_handle, sf_open_virtual);
67 LOAD_FUNC(sndfile_handle, sf_readf_short);
68 LOAD_FUNC(sndfile_handle, sf_seek);
70 static void Deinit()
72 if(sndfile_handle)
73 CloseLib(sndfile_handle);
74 sndfile_handle = NULL;
77 virtual bool IsValid()
78 { return sndFile != NULL; }
80 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
82 if(format == AL_NONE)
83 format = GetSampleFormat(sndInfo.channels, 16, false);
84 *fmt = format;
85 *frequency = sndInfo.samplerate;
86 *blockalign = sndInfo.channels*2;
87 return true;
90 virtual ALuint GetData(ALubyte *data, ALuint bytes)
92 const ALuint frameSize = 2*sndInfo.channels;
93 return psf_readf_short(sndFile, (short*)data, bytes/frameSize) * frameSize;
96 virtual bool Rewind()
98 if(psf_seek(sndFile, 0, SEEK_SET) != -1)
99 return true;
101 SetError("Seek failed");
102 return false;
105 sndStream(std::istream *_fstream)
106 : alureStream(_fstream), sndFile(NULL), format(AL_NONE)
108 memset(&sndInfo, 0, sizeof(sndInfo));
110 if(!sndfile_handle) return;
112 static SF_VIRTUAL_IO streamIO = {
113 get_filelen, seek,
114 read, write, tell
116 sndFile = psf_open_virtual(&streamIO, SFM_READ, &sndInfo, this);
119 virtual ~sndStream()
121 if(sndFile)
122 psf_close(sndFile);
123 sndFile = NULL;
126 private:
127 // libSndFile iostream callbacks
128 static sf_count_t get_filelen(void *user_data)
130 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
131 stream->clear();
133 std::streampos len = -1;
134 std::streampos pos = stream->tellg();
135 if(stream->seekg(0, std::ios_base::end))
137 len = stream->tellg();
138 stream->seekg(pos);
141 return len;
144 static sf_count_t seek(sf_count_t offset, int whence, void *user_data)
146 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
147 stream->clear();
149 if((whence == SEEK_CUR && stream->seekg(offset, std::ios_base::cur)) ||
150 (whence == SEEK_SET && stream->seekg(offset, std::ios_base::beg)) ||
151 (whence == SEEK_END && stream->seekg(offset, std::ios_base::end)))
152 return stream->tellg();
154 return -1;
157 static sf_count_t read(void *ptr, sf_count_t count, void *user_data)
159 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
160 stream->clear();
161 stream->read(static_cast<char*>(ptr), count);
162 return stream->gcount();
165 static sf_count_t write(const void*, sf_count_t, void*)
166 { return -1; }
168 static sf_count_t tell(void *user_data)
170 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
171 stream->clear();
172 return stream->tellg();
175 static DecoderDecl<sndStream,0> sndStream_decoder;
176 Decoder &alure_init_sndfile(void)
177 { return sndStream_decoder; }