3D Audio GSoC:
[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_EffectReader(reader),
49                 m_rate(specs.rate),
50                 m_channels(reader->getSpecs().channels),
51                 m_position(0)
52 {
53         int error;
54         m_src = src_callback_new(src_callback,
55                                                          SRC_SINC_MEDIUM_QUALITY,
56                                                          m_channels,
57                                                          &error,
58                                                          this);
59
60         if(!m_src)
61         {
62                 // XXX printf("%s\n", src_strerror(error));
63                 AUD_THROW(AUD_ERROR_SRC, state_error);
64         }
65 }
66
67 AUD_SRCResampleReader::~AUD_SRCResampleReader()
68 {
69         src_delete(m_src);
70 }
71
72 long AUD_SRCResampleReader::doCallback(float** data)
73 {
74         AUD_Specs specs;
75         specs.channels = m_channels;
76         specs.rate = m_rate;
77
78         int length = m_buffer.getSize() / AUD_SAMPLE_SIZE(specs);
79
80         *data = m_buffer.getBuffer();
81         m_reader->read(length, m_eos, *data);
82
83         return length;
84 }
85
86 void AUD_SRCResampleReader::seek(int position)
87 {
88         AUD_Specs specs = m_reader->getSpecs();
89         double factor = double(m_rate) / double(specs.rate);
90         m_reader->seek(position / factor);
91         src_reset(m_src);
92         m_position = position;
93 }
94
95 int AUD_SRCResampleReader::getLength() const
96 {
97         AUD_Specs specs = m_reader->getSpecs();
98         double factor = double(m_rate) / double(specs.rate);
99         return m_reader->getLength() * factor;
100 }
101
102 int AUD_SRCResampleReader::getPosition() const
103 {
104         return m_position;
105 }
106
107 AUD_Specs AUD_SRCResampleReader::getSpecs() const
108 {
109         AUD_Specs specs = m_reader->getSpecs();
110         specs.rate = m_rate;
111         return specs;
112 }
113
114 void AUD_SRCResampleReader::read(int& length, bool& eos, sample_t* buffer)
115 {
116         AUD_Specs specs = m_reader->getSpecs();
117
118         double factor = double(m_rate) / double(specs.rate);
119
120         specs.rate = m_rate;
121
122         int size = length;
123
124         m_buffer.assureSize(length * AUD_SAMPLE_SIZE(specs));
125
126         if(specs.channels != m_channels)
127         {
128                 src_delete(m_src);
129
130                 m_channels = specs.channels;
131
132                 int error;
133                 m_src = src_callback_new(src_callback,
134                                                                  SRC_SINC_MEDIUM_QUALITY,
135                                                                  m_channels,
136                                                                  &error,
137                                                                  this);
138
139                 if(!m_src)
140                 {
141                         // XXX printf("%s\n", src_strerror(error));
142                         AUD_THROW(AUD_ERROR_SRC, state_error);
143                 }
144         }
145
146         m_eos = false;
147
148         length = src_callback_read(m_src, factor, length, buffer);
149
150         m_position += length;
151
152         eos = m_eos && (length < size);
153 }