Merge with trunk r37757.
[blender.git] / intern / audaspace / sndfile / AUD_SndFileReader.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * Copyright 2009-2011 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 General Public License as published by
12  * the Free Software Foundation; either version 2 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 General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Audaspace; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file audaspace/sndfile/AUD_SndFileReader.cpp
28  *  \ingroup audsndfile
29  */
30
31
32 #include "AUD_SndFileReader.h"
33
34 #include <cstring>
35
36 sf_count_t AUD_SndFileReader::vio_get_filelen(void *user_data)
37 {
38         AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
39         return reader->m_membuffer->getSize();
40 }
41
42 sf_count_t AUD_SndFileReader::vio_seek(sf_count_t offset, int whence,
43                                                                            void *user_data)
44 {
45         AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
46
47         switch(whence)
48         {
49         case SEEK_SET:
50                 reader->m_memoffset = offset;
51                 break;
52         case SEEK_CUR:
53                 reader->m_memoffset = reader->m_memoffset + offset;
54                 break;
55         case SEEK_END:
56                 reader->m_memoffset = reader->m_membuffer->getSize() + offset;
57                 break;
58         }
59
60         return reader->m_memoffset;
61 }
62
63 sf_count_t AUD_SndFileReader::vio_read(void *ptr, sf_count_t count,
64                                                                            void *user_data)
65 {
66         AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
67
68         if(reader->m_memoffset + count > reader->m_membuffer->getSize())
69                 count = reader->m_membuffer->getSize() - reader->m_memoffset;
70
71         memcpy(ptr, ((data_t*)reader->m_membuffer->getBuffer()) +
72                    reader->m_memoffset, count);
73         reader->m_memoffset += count;
74
75         return count;
76 }
77
78 sf_count_t AUD_SndFileReader::vio_tell(void *user_data)
79 {
80         AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
81
82         return reader->m_memoffset;
83 }
84
85 static const char* fileopen_error = "AUD_SndFileReader: File couldn't be "
86                                                                         "read.";
87
88 AUD_SndFileReader::AUD_SndFileReader(std::string filename) :
89         m_position(0)
90 {
91         SF_INFO sfinfo;
92
93         sfinfo.format = 0;
94         m_sndfile = sf_open(filename.c_str(), SFM_READ, &sfinfo);
95
96         if(!m_sndfile)
97                 AUD_THROW(AUD_ERROR_FILE, fileopen_error);
98
99         m_specs.channels = (AUD_Channels) sfinfo.channels;
100         m_specs.rate = (AUD_SampleRate) sfinfo.samplerate;
101         m_length = sfinfo.frames;
102         m_seekable = sfinfo.seekable;
103 }
104
105 AUD_SndFileReader::AUD_SndFileReader(AUD_Reference<AUD_Buffer> buffer) :
106         m_position(0),
107         m_membuffer(buffer),
108         m_memoffset(0)
109 {
110         m_vio.get_filelen = vio_get_filelen;
111         m_vio.read = vio_read;
112         m_vio.seek = vio_seek;
113         m_vio.tell = vio_tell;
114         m_vio.write = NULL;
115
116         SF_INFO sfinfo;
117
118         sfinfo.format = 0;
119         m_sndfile = sf_open_virtual(&m_vio, SFM_READ, &sfinfo, this);
120
121         if(!m_sndfile)
122                 AUD_THROW(AUD_ERROR_FILE, fileopen_error);
123
124         m_specs.channels = (AUD_Channels) sfinfo.channels;
125         m_specs.rate = (AUD_SampleRate) sfinfo.samplerate;
126         m_length = sfinfo.frames;
127         m_seekable = sfinfo.seekable;
128 }
129
130 AUD_SndFileReader::~AUD_SndFileReader()
131 {
132         sf_close(m_sndfile);
133 }
134
135 bool AUD_SndFileReader::isSeekable() const
136 {
137         return m_seekable;
138 }
139
140 void AUD_SndFileReader::seek(int position)
141 {
142         if(m_seekable)
143         {
144                 position = sf_seek(m_sndfile, position, SEEK_SET);
145                 m_position = position;
146         }
147 }
148
149 int AUD_SndFileReader::getLength() const
150 {
151         return m_length;
152 }
153
154 int AUD_SndFileReader::getPosition() const
155 {
156         return m_position;
157 }
158
159 AUD_Specs AUD_SndFileReader::getSpecs() const
160 {
161         return m_specs;
162 }
163
164 void AUD_SndFileReader::read(int& length, bool& eos, sample_t* buffer)
165 {
166         int olen = length;
167
168         length = sf_readf_float(m_sndfile, buffer, length);
169
170         m_position += length;
171
172         eos = length < olen;
173 }