Merge with trunk r37757.
[blender.git] / intern / audaspace / SRC / AUD_SRCResampleReader.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/SRC/AUD_SRCResampleReader.cpp
28  *  \ingroup audsrc
29  */
30
31
32 #include "AUD_SRCResampleReader.h"
33
34 #include <cmath>
35 #include <cstring>
36 #include <cstdio>
37
38 static long src_callback(void *cb_data, float **data)
39 {
40         return ((AUD_SRCResampleReader*)cb_data)->doCallback(data);
41 }
42
43 static const char* state_error = "AUD_SRCResampleReader: SRC State couldn't be "
44                                                                  "created.";
45
46 AUD_SRCResampleReader::AUD_SRCResampleReader(AUD_Reference<AUD_IReader> reader,
47                                                                                          AUD_Specs specs) :
48                 AUD_ResampleReader(reader, specs.rate),
49                 m_channels(reader->getSpecs().channels),
50                 m_position(0)
51 {
52         int error;
53         m_src = src_callback_new(src_callback,
54                                                          SRC_SINC_MEDIUM_QUALITY,
55                                                          m_channels,
56                                                          &error,
57                                                          this);
58
59         if(!m_src)
60         {
61                 // XXX printf("%s\n", src_strerror(error));
62                 AUD_THROW(AUD_ERROR_SRC, state_error);
63         }
64 }
65
66 AUD_SRCResampleReader::~AUD_SRCResampleReader()
67 {
68         src_delete(m_src);
69 }
70
71 long AUD_SRCResampleReader::doCallback(float** data)
72 {
73         AUD_Specs specs;
74         specs.channels = m_channels;
75         specs.rate = m_rate;
76
77         int length = m_buffer.getSize() / AUD_SAMPLE_SIZE(specs);
78
79         *data = m_buffer.getBuffer();
80         m_reader->read(length, m_eos, *data);
81
82         return length;
83 }
84
85 void AUD_SRCResampleReader::seek(int position)
86 {
87         AUD_Specs specs = m_reader->getSpecs();
88         double factor = double(m_rate) / double(specs.rate);
89         m_reader->seek(position / factor);
90         src_reset(m_src);
91         m_position = position;
92 }
93
94 int AUD_SRCResampleReader::getLength() const
95 {
96         AUD_Specs specs = m_reader->getSpecs();
97         double factor = double(m_rate) / double(specs.rate);
98         return m_reader->getLength() * factor;
99 }
100
101 int AUD_SRCResampleReader::getPosition() const
102 {
103         return m_position;
104 }
105
106 AUD_Specs AUD_SRCResampleReader::getSpecs() const
107 {
108         AUD_Specs specs = m_reader->getSpecs();
109         specs.rate = m_rate;
110         return specs;
111 }
112
113 void AUD_SRCResampleReader::read(int& length, bool& eos, sample_t* buffer)
114 {
115         AUD_Specs specs = m_reader->getSpecs();
116
117         double factor = double(m_rate) / double(specs.rate);
118
119         specs.rate = m_rate;
120
121         int size = length;
122
123         m_buffer.assureSize(length * AUD_SAMPLE_SIZE(specs));
124
125         if(specs.channels != m_channels)
126         {
127                 src_delete(m_src);
128
129                 m_channels = specs.channels;
130
131                 int error;
132                 m_src = src_callback_new(src_callback,
133                                                                  SRC_SINC_MEDIUM_QUALITY,
134                                                                  m_channels,
135                                                                  &error,
136                                                                  this);
137
138                 if(!m_src)
139                 {
140                         // XXX printf("%s\n", src_strerror(error));
141                         AUD_THROW(AUD_ERROR_SRC, state_error);
142                 }
143         }
144
145         m_eos = false;
146
147         length = src_callback_read(m_src, factor, length, buffer);
148
149         m_position += length;
150
151         eos = m_eos && (length < size);
152 }