Audio file loading backend libsndfile!
[blender.git] / intern / audaspace / sndfile / AUD_SndFileReader.cpp
1 /*
2  * $Id: AUD_FFMPEGReader.cpp 22328 2009-08-09 23:23:19Z gsrb3d $
3  *
4  * ***** BEGIN LGPL LICENSE BLOCK *****
5  *
6  * Copyright 2009 Jörg Hermann Müller
7  *
8  * This file is part of AudaSpace.
9  *
10  * AudaSpace is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * AudaSpace is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with AudaSpace.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * ***** END LGPL LICENSE BLOCK *****
24  */
25
26 #include "AUD_SndFileReader.h"
27 #include "AUD_Buffer.h"
28
29 #include <cstring>
30
31 // This function transforms a  SampleFormat to our own sample format
32 static inline AUD_SampleFormat SNDFILE_TO_AUD(int fmt)
33 {
34         switch(fmt & SF_FORMAT_SUBMASK)
35         {
36         // only read s16, s32 and double as they are
37         case SF_FORMAT_PCM_16:
38                 return AUD_FORMAT_S16;
39         case SF_FORMAT_PCM_32:
40                 return AUD_FORMAT_S32;
41         case SF_FORMAT_DOUBLE:
42                 return AUD_FORMAT_FLOAT64;
43         // read all other formats as floats
44         default:
45                 return AUD_FORMAT_FLOAT32;
46         }
47 }
48
49 sf_count_t AUD_SndFileReader::vio_get_filelen(void *user_data)
50 {
51         AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
52         return reader->m_membuffer.get()->getSize();
53 }
54
55 sf_count_t AUD_SndFileReader::vio_seek(sf_count_t offset, int whence, void *user_data)
56 {
57         AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
58
59         switch(whence)
60         {
61         case SEEK_SET:
62                 reader->m_memoffset = offset;
63                 break;
64         case SEEK_CUR:
65                 reader->m_memoffset = reader->m_memoffset + offset;
66                 break;
67         case SEEK_END:
68                 reader->m_memoffset = reader->m_membuffer.get()->getSize() + offset;
69                 break;
70         }
71
72         return reader->m_memoffset;
73 }
74
75 sf_count_t AUD_SndFileReader::vio_read(void *ptr, sf_count_t count, void *user_data)
76 {
77         AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
78
79         if(reader->m_memoffset + count > reader->m_membuffer.get()->getSize())
80                 count = reader->m_membuffer.get()->getSize() - reader->m_memoffset;
81
82         memcpy(ptr, reader->m_membuffer.get()->getBuffer() + reader->m_memoffset, count);
83         reader->m_memoffset += count;
84
85         return count;
86 }
87
88 sf_count_t AUD_SndFileReader::vio_tell(void *user_data)
89 {
90         AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
91
92         return reader->m_memoffset;
93 }
94
95 AUD_SndFileReader::AUD_SndFileReader(const char* filename)
96 {
97         SF_INFO sfinfo;
98
99         sfinfo.format = 0;
100         m_sndfile = sf_open(filename, SFM_READ, &sfinfo);
101
102         if(!m_sndfile)
103                 AUD_THROW(AUD_ERROR_FILE);
104
105         m_specs.channels = (AUD_Channels) sfinfo.channels;
106         m_specs.format = SNDFILE_TO_AUD(sfinfo.format);
107         m_specs.rate = (AUD_SampleRate) sfinfo.samplerate;
108         m_length = sfinfo.frames;
109         m_seekable = sfinfo.seekable;
110         m_position = 0;
111
112         switch(m_specs.format)
113         {
114         case AUD_FORMAT_S16:
115                 m_read = (sf_read_f) sf_readf_short;
116                 break;
117         case AUD_FORMAT_S32:
118                 m_read = (sf_read_f) sf_readf_int;
119                 break;
120         case AUD_FORMAT_FLOAT64:
121                 m_read = (sf_read_f) sf_readf_double;
122                 break;
123         default:
124                 m_read = (sf_read_f) sf_readf_float;
125         }
126
127         m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
128 }
129
130 AUD_SndFileReader::AUD_SndFileReader(AUD_Reference<AUD_Buffer> buffer)
131 {
132         m_membuffer = buffer;
133         m_memoffset = 0;
134
135         m_vio.get_filelen = vio_get_filelen;
136         m_vio.read = vio_read;
137         m_vio.seek = vio_seek;
138         m_vio.tell = vio_tell;
139         m_vio.write = NULL;
140
141         SF_INFO sfinfo;
142
143         sfinfo.format = 0;
144         m_sndfile = sf_open_virtual(&m_vio, SFM_READ, &sfinfo, this);
145
146         if(!m_sndfile)
147                 AUD_THROW(AUD_ERROR_FILE);
148
149         m_specs.channels = (AUD_Channels) sfinfo.channels;
150         m_specs.format = SNDFILE_TO_AUD(sfinfo.format);
151         m_specs.rate = (AUD_SampleRate) sfinfo.samplerate;
152         m_length = sfinfo.frames;
153         m_seekable = sfinfo.seekable;
154         m_position = 0;
155
156         switch(m_specs.format)
157         {
158         case AUD_FORMAT_S16:
159                 m_read = (sf_read_f) sf_readf_short;
160                 break;
161         case AUD_FORMAT_S32:
162                 m_read = (sf_read_f) sf_readf_int;
163                 break;
164         case AUD_FORMAT_FLOAT64:
165                 m_read = (sf_read_f) sf_readf_double;
166                 break;
167         default:
168                 m_read = (sf_read_f) sf_readf_float;
169         }
170
171         m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
172 }
173
174 AUD_SndFileReader::~AUD_SndFileReader()
175 {
176         sf_close(m_sndfile);
177
178         delete m_buffer; AUD_DELETE("buffer")
179 }
180
181 bool AUD_SndFileReader::isSeekable()
182 {
183         return m_seekable;
184 }
185
186 void AUD_SndFileReader::seek(int position)
187 {
188         if(m_seekable)
189         {
190                 position = sf_seek(m_sndfile, position, SEEK_SET);
191                 m_position = position;
192         }
193 }
194
195 int AUD_SndFileReader::getLength()
196 {
197         return m_length;
198 }
199
200 int AUD_SndFileReader::getPosition()
201 {
202         return m_position;
203 }
204
205 AUD_Specs AUD_SndFileReader::getSpecs()
206 {
207         return m_specs;
208 }
209
210 AUD_ReaderType AUD_SndFileReader::getType()
211 {
212         return AUD_TYPE_STREAM;
213 }
214
215 bool AUD_SndFileReader::notify(AUD_Message &message)
216 {
217         return false;
218 }
219
220 void AUD_SndFileReader::read(int & length, sample_t* & buffer)
221 {
222         int sample_size = AUD_SAMPLE_SIZE(m_specs);
223
224         // resize output buffer if necessary
225         if(m_buffer->getSize() < length*sample_size)
226                 m_buffer->resize(length*sample_size);
227
228         buffer = m_buffer->getBuffer();
229
230         length = m_read(m_sndfile, buffer, length);
231
232         m_position += length;
233 }