Imported Upstream version 1.2
[platform/upstream/alure.git] / src / codec_sndfile.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 <sndfile.h>
34
35
36 #ifdef DYNLOAD
37 static void *sndfile_handle;
38 #define MAKE_FUNC(x) static typeof(x)* p##x
39 MAKE_FUNC(sf_close);
40 MAKE_FUNC(sf_open_virtual);
41 MAKE_FUNC(sf_readf_short);
42 MAKE_FUNC(sf_seek);
43 #undef MAKE_FUNC
44
45 #define sf_close psf_close
46 #define sf_open_virtual psf_open_virtual
47 #define sf_readf_short psf_readf_short
48 #define sf_seek psf_seek
49 #else
50 #define sndfile_handle 1
51 #endif
52
53
54 struct sndStream : public alureStream {
55 private:
56     SNDFILE *sndFile;
57     SF_INFO sndInfo;
58     ALenum format;
59
60 public:
61 #ifdef DYNLOAD
62     static void Init()
63     {
64 #ifdef _WIN32
65 #define SNDFILE_LIB "libsndfile-1.dll"
66 #elif defined(__APPLE__)
67 #define SNDFILE_LIB "libsndfile.1.dylib"
68 #else
69 #define SNDFILE_LIB "libsndfile.so.1"
70 #endif
71         sndfile_handle = OpenLib(SNDFILE_LIB);
72         if(!sndfile_handle) return;
73
74         LOAD_FUNC(sndfile_handle, sf_close);
75         LOAD_FUNC(sndfile_handle, sf_open_virtual);
76         LOAD_FUNC(sndfile_handle, sf_readf_short);
77         LOAD_FUNC(sndfile_handle, sf_seek);
78     }
79     static void Deinit()
80     {
81         if(sndfile_handle)
82             CloseLib(sndfile_handle);
83         sndfile_handle = NULL;
84     }
85 #else
86     static void Init() { }
87     static void Deinit() { }
88 #endif
89
90     virtual bool IsValid()
91     { return sndFile != NULL; }
92
93     virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
94     {
95         if(format == AL_NONE)
96             format = GetSampleFormat(sndInfo.channels, 16, false);
97         *fmt = format;
98         *frequency = sndInfo.samplerate;
99         *blockalign = sndInfo.channels*2;
100         return true;
101     }
102
103     virtual ALuint GetData(ALubyte *data, ALuint bytes)
104     {
105         const ALuint frameSize = 2*sndInfo.channels;
106         return sf_readf_short(sndFile, (short*)data, bytes/frameSize) * frameSize;
107     }
108
109     virtual bool Rewind()
110     {
111         if(sf_seek(sndFile, 0, SEEK_SET) != -1)
112             return true;
113
114         SetError("Seek failed");
115         return false;
116     }
117
118     virtual alureInt64 GetLength()
119     {
120         if(sndInfo.frames == -1)
121             return 0;
122         return sndInfo.frames;
123     }
124
125     sndStream(std::istream *_fstream)
126       : alureStream(_fstream), sndFile(NULL), format(AL_NONE)
127     {
128         memset(&sndInfo, 0, sizeof(sndInfo));
129
130         if(!sndfile_handle) return;
131
132         static SF_VIRTUAL_IO streamIO = {
133             get_filelen, seek,
134             read, write, tell
135         };
136         sndFile = sf_open_virtual(&streamIO, SFM_READ, &sndInfo, this);
137     }
138
139     virtual ~sndStream()
140     {
141         if(sndFile)
142             sf_close(sndFile);
143         sndFile = NULL;
144     }
145
146 private:
147     // libSndFile iostream callbacks
148     static sf_count_t get_filelen(void *user_data)
149     {
150         std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
151         stream->clear();
152
153         std::streampos len = -1;
154         std::streampos pos = stream->tellg();
155         if(stream->seekg(0, std::ios_base::end))
156         {
157             len = stream->tellg();
158             stream->seekg(pos);
159         }
160
161         return len;
162     }
163
164     static sf_count_t seek(sf_count_t offset, int whence, void *user_data)
165     {
166         std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
167         stream->clear();
168
169         if((whence == SEEK_CUR && stream->seekg(offset, std::ios_base::cur)) ||
170            (whence == SEEK_SET && stream->seekg(offset, std::ios_base::beg)) ||
171            (whence == SEEK_END && stream->seekg(offset, std::ios_base::end)))
172             return stream->tellg();
173
174         return -1;
175     }
176
177     static sf_count_t read(void *ptr, sf_count_t count, void *user_data)
178     {
179         std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
180         stream->clear();
181         stream->read(static_cast<char*>(ptr), count);
182         return stream->gcount();
183     }
184
185     static sf_count_t write(const void*, sf_count_t, void*)
186     { return -1; }
187
188     static sf_count_t tell(void *user_data)
189     {
190         std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
191         stream->clear();
192         return stream->tellg();
193     }
194 };
195 static DecoderDecl<sndStream,0> sndStream_decoder;
196 Decoder &alure_init_sndfile(void)
197 { return sndStream_decoder; }