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 channels + channel
38
39 AUD_LinearResampleReader::AUD_LinearResampleReader(AUD_Reference<AUD_IReader> reader,
40                                                                                                    AUD_Specs specs) :
41         AUD_EffectReader(reader),
42         m_sspecs(reader->getSpecs()),
43         m_factor(float(specs.rate) / float(m_sspecs.rate)),
44         m_tspecs(specs),
45         m_position(0),
46         m_sposition(0)
47 {
48         m_tspecs.channels = m_sspecs.channels;
49         m_cache.resize(2 * AUD_SAMPLE_SIZE(m_tspecs));
50 }
51
52 void AUD_LinearResampleReader::seek(int position)
53 {
54         m_position = position;
55         m_sposition = floor(position / m_factor);
56         m_reader->seek(m_sposition);
57 }
58
59 int AUD_LinearResampleReader::getLength() const
60 {
61         return m_reader->getLength() * m_factor;
62 }
63
64 int AUD_LinearResampleReader::getPosition() const
65 {
66         return m_position;
67 }
68
69 AUD_Specs AUD_LinearResampleReader::getSpecs() const
70 {
71         return m_tspecs;
72 }
73
74 void AUD_LinearResampleReader::read(int & length, sample_t* buffer)
75 {
76         int samplesize = AUD_SAMPLE_SIZE(m_tspecs);
77         int size = length * AUD_SAMPLE_SIZE(m_sspecs);
78
79         if(m_buffer.getSize() < size)
80                 m_buffer.resize(size);
81
82         int need = ceil((m_position + length) / m_factor) + 1 - m_sposition;
83         int len = need;
84         sample_t* buf = m_buffer.getBuffer();
85
86         m_reader->read(len, buf);
87
88         if(len < need)
89                 length = floor((m_sposition + len - 1) * m_factor) - m_position;
90
91         float spos;
92         sample_t low, high;
93         int channels = m_sspecs.channels;
94
95         for(int channel = 0; channel < channels; channel++)
96         {
97                 for(int i = 0; i < length; i++)
98                 {
99                         spos = (m_position + i) / m_factor - m_sposition;
100
101                         if(floor(spos) < 0)
102                         {
103                                 low = m_cache.getBuffer()[(int)(floor(spos) + 2) * CC];
104                                 if(ceil(spos) < 0)
105                                         high = m_cache.getBuffer()[(int)(ceil(spos) + 2) * CC];
106                                 else
107                                         high = buf[(int)ceil(spos) * CC];
108                         }
109                         else
110                         {
111                                         low = buf[(int)floor(spos) * CC];
112                                         high = buf[(int)ceil(spos) * CC];
113                         }
114                         buffer[i * CC] = low + (spos - floor(spos)) * (high - low);
115                 }
116         }
117
118         if(len > 1)
119                 memcpy(m_cache.getBuffer(),
120                            buf + (len - 2) * channels,
121                            2 * samplesize);
122         else if(len == 1)
123                 memcpy(m_cache.getBuffer() + 1 * channels, buf, samplesize);
124
125         m_sposition += len;
126         m_position += length;
127 }