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