Retrieve the length from libsndfile
[alure.git] / src / codec_sndfile.cpp
blob880719c4fd399ed5de2bf4d64051efe3ecf01428
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 virtual alureInt64 GetLength()
107 if(sndInfo.frames == -1)
108 return 0;
109 return sndInfo.frames;
112 sndStream(std::istream *_fstream)
113 : alureStream(_fstream), sndFile(NULL), format(AL_NONE)
115 memset(&sndInfo, 0, sizeof(sndInfo));
117 if(!sndfile_handle) return;
119 static SF_VIRTUAL_IO streamIO = {
120 get_filelen, seek,
121 read, write, tell
123 sndFile = psf_open_virtual(&streamIO, SFM_READ, &sndInfo, this);
126 virtual ~sndStream()
128 if(sndFile)
129 psf_close(sndFile);
130 sndFile = NULL;
133 private:
134 // libSndFile iostream callbacks
135 static sf_count_t get_filelen(void *user_data)
137 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
138 stream->clear();
140 std::streampos len = -1;
141 std::streampos pos = stream->tellg();
142 if(stream->seekg(0, std::ios_base::end))
144 len = stream->tellg();
145 stream->seekg(pos);
148 return len;
151 static sf_count_t seek(sf_count_t offset, int whence, void *user_data)
153 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
154 stream->clear();
156 if((whence == SEEK_CUR && stream->seekg(offset, std::ios_base::cur)) ||
157 (whence == SEEK_SET && stream->seekg(offset, std::ios_base::beg)) ||
158 (whence == SEEK_END && stream->seekg(offset, std::ios_base::end)))
159 return stream->tellg();
161 return -1;
164 static sf_count_t read(void *ptr, sf_count_t count, void *user_data)
166 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
167 stream->clear();
168 stream->read(static_cast<char*>(ptr), count);
169 return stream->gcount();
172 static sf_count_t write(const void*, sf_count_t, void*)
173 { return -1; }
175 static sf_count_t tell(void *user_data)
177 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
178 stream->clear();
179 return stream->tellg();
182 static DecoderDecl<sndStream,0> sndStream_decoder;
183 Decoder &alure_init_sndfile(void)
184 { return sndStream_decoder; }