4 * ***** BEGIN LGPL LICENSE BLOCK *****
6 * Copyright 2009 Jörg Hermann Müller
8 * This file is part of AudaSpace.
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.
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.
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/>.
23 * ***** END LGPL LICENSE BLOCK *****
26 #include "AUD_SndFileReader.h"
27 #include "AUD_Buffer.h"
31 // This function transforms a SampleFormat to our own sample format
32 static inline AUD_SampleFormat SNDFILE_TO_AUD(int fmt)
34 switch(fmt & SF_FORMAT_SUBMASK)
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
45 return AUD_FORMAT_FLOAT32;
49 sf_count_t AUD_SndFileReader::vio_get_filelen(void *user_data)
51 AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
52 return reader->m_membuffer.get()->getSize();
55 sf_count_t AUD_SndFileReader::vio_seek(sf_count_t offset, int whence, void *user_data)
57 AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
62 reader->m_memoffset = offset;
65 reader->m_memoffset = reader->m_memoffset + offset;
68 reader->m_memoffset = reader->m_membuffer.get()->getSize() + offset;
72 return reader->m_memoffset;
75 sf_count_t AUD_SndFileReader::vio_read(void *ptr, sf_count_t count, void *user_data)
77 AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
79 if(reader->m_memoffset + count > reader->m_membuffer.get()->getSize())
80 count = reader->m_membuffer.get()->getSize() - reader->m_memoffset;
82 memcpy(ptr, reader->m_membuffer.get()->getBuffer() + reader->m_memoffset, count);
83 reader->m_memoffset += count;
88 sf_count_t AUD_SndFileReader::vio_tell(void *user_data)
90 AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
92 return reader->m_memoffset;
95 AUD_SndFileReader::AUD_SndFileReader(const char* filename)
100 m_sndfile = sf_open(filename, SFM_READ, &sfinfo);
103 AUD_THROW(AUD_ERROR_FILE);
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;
112 switch(m_specs.format)
115 m_read = (sf_read_f) sf_readf_short;
118 m_read = (sf_read_f) sf_readf_int;
120 case AUD_FORMAT_FLOAT64:
121 m_read = (sf_read_f) sf_readf_double;
124 m_read = (sf_read_f) sf_readf_float;
127 m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
130 AUD_SndFileReader::AUD_SndFileReader(AUD_Reference<AUD_Buffer> buffer)
132 m_membuffer = buffer;
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;
144 m_sndfile = sf_open_virtual(&m_vio, SFM_READ, &sfinfo, this);
147 AUD_THROW(AUD_ERROR_FILE);
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;
156 switch(m_specs.format)
159 m_read = (sf_read_f) sf_readf_short;
162 m_read = (sf_read_f) sf_readf_int;
164 case AUD_FORMAT_FLOAT64:
165 m_read = (sf_read_f) sf_readf_double;
168 m_read = (sf_read_f) sf_readf_float;
171 m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
174 AUD_SndFileReader::~AUD_SndFileReader()
178 delete m_buffer; AUD_DELETE("buffer")
181 bool AUD_SndFileReader::isSeekable()
186 void AUD_SndFileReader::seek(int position)
190 position = sf_seek(m_sndfile, position, SEEK_SET);
191 m_position = position;
195 int AUD_SndFileReader::getLength()
200 int AUD_SndFileReader::getPosition()
205 AUD_Specs AUD_SndFileReader::getSpecs()
210 AUD_ReaderType AUD_SndFileReader::getType()
212 return AUD_TYPE_STREAM;
215 bool AUD_SndFileReader::notify(AUD_Message &message)
220 void AUD_SndFileReader::read(int & length, sample_t* & buffer)
222 int sample_size = AUD_SAMPLE_SIZE(m_specs);
224 // resize output buffer if necessary
225 if(m_buffer->getSize() < length*sample_size)
226 m_buffer->resize(length*sample_size);
228 buffer = m_buffer->getBuffer();
230 length = m_read(m_sndfile, buffer, length);
232 m_position += length;