Merged changes in the trunk up to revision 54992.
[blender.git] / intern / audaspace / SRC / AUD_SRCResampleReader.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * Copyright 2009-2011 Jörg Hermann Müller
5  *
6  * This file is part of AudaSpace.
7  *
8  * Audaspace is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * AudaSpace is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Audaspace; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file audaspace/SRC/AUD_SRCResampleReader.cpp
26  *  \ingroup audsrc
27  */
28
29
30 #include "AUD_SRCResampleReader.h"
31
32 #include <cmath>
33 #include <cstring>
34 #include <cstdio>
35
36 static long src_callback(void *cb_data, float **data)
37 {
38         return ((AUD_SRCResampleReader*)cb_data)->doCallback(data);
39 }
40
41 static const char* state_error = "AUD_SRCResampleReader: SRC State couldn't be "
42                                                                  "created.";
43
44 AUD_SRCResampleReader::AUD_SRCResampleReader(AUD_Reference<AUD_IReader> reader,
45                                                                                          AUD_Specs specs) :
46                 AUD_ResampleReader(reader, specs.rate),
47                 m_channels(reader->getSpecs().channels),
48                 m_position(0)
49 {
50         int error;
51         m_src = src_callback_new(src_callback,
52                                                          SRC_SINC_MEDIUM_QUALITY,
53                                                          m_channels,
54                                                          &error,
55                                                          this);
56
57         if(!m_src)
58         {
59                 // XXX printf("%s\n", src_strerror(error));
60                 AUD_THROW(AUD_ERROR_SRC, state_error);
61         }
62 }
63
64 AUD_SRCResampleReader::~AUD_SRCResampleReader()
65 {
66         src_delete(m_src);
67 }
68
69 long AUD_SRCResampleReader::doCallback(float** data)
70 {
71         AUD_Specs specs;
72         specs.channels = m_channels;
73         specs.rate = m_rate;
74
75         int length = m_buffer.getSize() / AUD_SAMPLE_SIZE(specs);
76
77         *data = m_buffer.getBuffer();
78         m_reader->read(length, m_eos, *data);
79
80         return length;
81 }
82
83 void AUD_SRCResampleReader::seek(int position)
84 {
85         AUD_Specs specs = m_reader->getSpecs();
86         double factor = double(m_rate) / double(specs.rate);
87         m_reader->seek(position / factor);
88         src_reset(m_src);
89         m_position = position;
90 }
91
92 int AUD_SRCResampleReader::getLength() const
93 {
94         AUD_Specs specs = m_reader->getSpecs();
95         double factor = double(m_rate) / double(specs.rate);
96         return m_reader->getLength() * factor;
97 }
98
99 int AUD_SRCResampleReader::getPosition() const
100 {
101         return m_position;
102 }
103
104 AUD_Specs AUD_SRCResampleReader::getSpecs() const
105 {
106         AUD_Specs specs = m_reader->getSpecs();
107         specs.rate = m_rate;
108         return specs;
109 }
110
111 void AUD_SRCResampleReader::read(int& length, bool& eos, sample_t* buffer)
112 {
113         AUD_Specs specs = m_reader->getSpecs();
114
115         double factor = double(m_rate) / double(specs.rate);
116
117         specs.rate = m_rate;
118
119         int size = length;
120
121         m_buffer.assureSize(length * AUD_SAMPLE_SIZE(specs));
122
123         if(specs.channels != m_channels)
124         {
125                 src_delete(m_src);
126
127                 m_channels = specs.channels;
128
129                 int error;
130                 m_src = src_callback_new(src_callback,
131                                                                  SRC_SINC_MEDIUM_QUALITY,
132                                                                  m_channels,
133                                                                  &error,
134                                                                  this);
135
136                 if(!m_src)
137                 {
138                         // XXX printf("%s\n", src_strerror(error));
139                         AUD_THROW(AUD_ERROR_SRC, state_error);
140                 }
141         }
142
143         m_eos = false;
144
145         length = src_callback_read(m_src, factor, length, buffer);
146
147         m_position += length;
148
149         eos = m_eos && (length < size);
150 }