svn merge -r39781:39792 https://svn.blender.org/svnroot/bf-blender/trunk/blender...
[blender-staging.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_ResampleReader(reader, specs.rate),
42         m_channels(reader->getSpecs().channels),
43         m_cache_pos(0),
44         m_cache_ok(false)
45 {
46         specs.channels = m_channels;
47         m_cache.resize(2 * AUD_SAMPLE_SIZE(specs));
48 }
49
50 void AUD_LinearResampleReader::seek(int position)
51 {
52         position = floor(position * double(m_reader->getSpecs().rate) / double(m_rate));
53         m_reader->seek(position);
54         m_cache_ok = false;
55         m_cache_pos = 0;
56 }
57
58 int AUD_LinearResampleReader::getLength() const
59 {
60         return floor(m_reader->getLength() * double(m_rate) / double(m_reader->getSpecs().rate));
61 }
62
63 int AUD_LinearResampleReader::getPosition() const
64 {
65         return floor((m_reader->getPosition() + (m_cache_ok ? m_cache_pos - 1 : 0))
66                                  * m_rate / m_reader->getSpecs().rate);
67 }
68
69 AUD_Specs AUD_LinearResampleReader::getSpecs() const
70 {
71         AUD_Specs specs = m_reader->getSpecs();
72         specs.rate = m_rate;
73         return specs;
74 }
75
76 void AUD_LinearResampleReader::read(int& length, bool& eos, sample_t* buffer)
77 {
78         if(length == 0)
79                 return;
80
81         AUD_Specs specs = m_reader->getSpecs();
82
83         int samplesize = AUD_SAMPLE_SIZE(specs);
84         int size = length;
85         float factor = m_rate / m_reader->getSpecs().rate;
86         float spos;
87         sample_t low, high;
88         eos = false;
89
90         // check for channels changed
91
92         if(specs.channels != m_channels)
93         {
94                 m_cache.resize(2 * samplesize);
95                 m_channels = specs.channels;
96                 m_cache_ok = false;
97         }
98
99         if(factor == 1 && (!m_cache_ok || m_cache_pos == 1))
100         {
101                 // can read directly!
102                 m_reader->read(length, eos, buffer);
103
104                 if(length > 0)
105                 {
106                         memcpy(m_cache.getBuffer() + m_channels, buffer + m_channels * (length - 1), samplesize);
107                         m_cache_pos = 1;
108                         m_cache_ok = true;
109                 }
110
111                 return;
112         }
113
114         int len;
115         sample_t* buf;
116
117         if(m_cache_ok)
118         {
119                 int need = ceil(length / factor + m_cache_pos) - 1;
120
121                 len = need;
122
123                 m_buffer.assureSize((len + 2) * samplesize);
124                 buf = m_buffer.getBuffer();
125
126                 memcpy(buf, m_cache.getBuffer(), 2 * samplesize);
127                 m_reader->read(len, eos, buf + 2 * m_channels);
128
129                 if(len < need)
130                         length = floor((len + 1 - m_cache_pos) * factor);
131         }
132         else
133         {
134                 m_cache_pos = 1 - 1 / factor;
135
136                 int need = ceil(length / factor + m_cache_pos);
137
138                 len = need;
139
140                 m_buffer.assureSize((len + 1) * samplesize);
141                 buf = m_buffer.getBuffer();
142
143                 memset(buf, 0, samplesize);
144                 m_reader->read(len, eos, buf + m_channels);
145
146                 if(len == 0)
147                 {
148                         length = 0;
149                         return;
150                 }
151
152                 if(len < need)
153                 {
154                         length = floor((len - m_cache_pos) * factor);
155                 }
156
157                 m_cache_ok = true;
158         }
159
160         for(int channel = 0; channel < m_channels; channel++)
161         {
162                 for(int i = 0; i < length; i++)
163                 {
164                         spos = (i + 1) / factor + m_cache_pos;
165
166                         low = buf[(int)floor(spos) * CC];
167                         high = buf[(int)ceil(spos) * CC];
168
169                         buffer[i * CC] = low + (spos - floor(spos)) * (high - low);
170                 }
171         }
172
173         if(floor(spos) == spos)
174         {
175                 memcpy(m_cache.getBuffer() + m_channels, buf + int(floor(spos)) * m_channels, samplesize);
176                 m_cache_pos = 1;
177         }
178         else
179         {
180                 memcpy(m_cache.getBuffer(), buf + int(floor(spos)) * m_channels, 2 * samplesize);
181                 m_cache_pos = spos - floor(spos);
182         }
183
184         eos &= length < size;
185 }