3D Audio GSoC:
[blender.git] / intern / audaspace / intern / AUD_LinearResampleReader.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/intern/AUD_LinearResampleReader.cpp
28  *  \ingroup audaspaceintern
29  */
30
31
32 #include "AUD_LinearResampleReader.h"
33
34 #include <cmath>
35 #include <cstring>
36
37 #define CC m_channels + channel
38
39 AUD_LinearResampleReader::AUD_LinearResampleReader(AUD_Reference<AUD_IReader> reader,
40                                                                                                    AUD_Specs specs) :
41         AUD_EffectReader(reader),
42         m_rate(specs.rate),
43         m_channels(reader->getSpecs().channels),
44         m_position(0),
45         m_cache_pos(0),
46         m_cache_ok(false)
47 {
48         specs.channels = m_channels;
49         m_cache.resize(2 * AUD_SAMPLE_SIZE(specs));
50 }
51
52 void AUD_LinearResampleReader::seek(int position)
53 {
54         position = floor(position * double(m_reader->getSpecs().rate) / double(m_rate));
55         m_reader->seek(position);
56         m_cache_ok = false;
57         m_cache_pos = 0;
58 }
59
60 int AUD_LinearResampleReader::getLength() const
61 {
62         return floor(m_reader->getLength() * double(m_rate) / double(m_reader->getSpecs().rate));
63 }
64
65 int AUD_LinearResampleReader::getPosition() const
66 {
67         return floor((m_reader->getPosition() + (m_cache_ok ? m_cache_pos - 2 : 0))
68                                  * m_rate / m_reader->getSpecs().rate);
69 }
70
71 AUD_Specs AUD_LinearResampleReader::getSpecs() const
72 {
73         AUD_Specs specs = m_reader->getSpecs();
74         specs.rate = m_rate;
75         return specs;
76 }
77
78 void AUD_LinearResampleReader::read(int& length, bool& eos, sample_t* buffer)
79 {
80         AUD_Specs specs = m_reader->getSpecs();
81
82         int samplesize = AUD_SAMPLE_SIZE(specs);
83         int size = length;
84         float factor = float(m_rate) / float(m_reader->getSpecs().rate);
85         float spos;
86         sample_t low, high;
87         eos = false;
88
89         if(factor == 1 && (!m_cache_ok || m_cache_pos == 0))
90         {
91                 // can read directly!
92                 m_reader->read(length, eos, buffer);
93                 return;
94         }
95
96         // check for channels changed
97
98         if(specs.channels != m_channels)
99         {
100                 m_cache.resize(2 * samplesize);
101                 m_channels = specs.channels;
102                 m_cache_ok = false;
103         }
104
105         int len;
106         sample_t* buf;
107
108         if(m_cache_ok)
109         {
110                 int need = ceil(length / factor - (1 - m_cache_pos));
111
112                 len = need;
113
114                 m_buffer.assureSize((len + 3) * samplesize);
115                 buf = m_buffer.getBuffer();
116
117                 memcpy(buf, m_cache.getBuffer(), 2 * samplesize);
118                 m_reader->read(len, eos, buf + 2 * m_channels);
119
120                 if(len < need)
121                         length = floor((len + (1 - m_cache_pos)) * factor);
122         }
123         else
124         {
125                 int need = ceil(length / factor) + 1;
126
127                 len = need;
128
129                 m_buffer.assureSize((len + 1) * samplesize);
130                 buf = m_buffer.getBuffer();
131
132                 m_reader->read(len, eos, buf);
133
134                 if(len < need)
135                 {
136                         if(eos)
137                         {
138                                 length = floor(len * factor);
139                                 memset(buf + len * m_channels, 0, samplesize);
140                         }
141                         else
142                                 length = ceil((len - 1) * factor);
143                 }
144                 m_cache_ok = true;
145                 m_cache_pos = 0;
146         }
147
148         for(int channel = 0; channel < m_channels; channel++)
149         {
150                 for(int i = 0; i < length; i++)
151                 {
152                         spos = (i + 1) / factor + m_cache_pos;
153
154                         low = buf[(int)floor(spos) * CC];
155                         high = buf[(int)ceil(spos) * CC];
156
157                         buffer[i * CC] = low + (spos - floor(spos)) * (high - low);
158                 }
159         }
160
161         if(floor(spos) == spos)
162         {
163                 memcpy(m_cache.getBuffer(), buf + int(floor(spos - 1)) * m_channels, 2 * samplesize);
164                 m_cache_pos = 1;
165         }
166         else
167         {
168                 memcpy(m_cache.getBuffer(), buf + int(floor(spos)) * m_channels, 2 * samplesize);
169                 m_cache_pos = spos - floor(spos);
170         }
171
172         eos &= length < size;
173 }