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, bool& eos, sample_t* buffer)
75 {
76         int samplesize = AUD_SAMPLE_SIZE(m_tspecs);
77         int size = length;
78
79         m_buffer.assureSize(size * AUD_SAMPLE_SIZE(m_sspecs));
80
81         int need = ceil((m_position + length) / m_factor) + 1 - m_sposition;
82         int len = need;
83         sample_t* buf = m_buffer.getBuffer();
84
85         m_reader->read(len, eos, buf);
86
87         if(len < need)
88                 length = floor((m_sposition + len - 1) * m_factor) - m_position;
89
90         float spos;
91         sample_t low, high;
92         int channels = m_sspecs.channels;
93
94         for(int channel = 0; channel < channels; channel++)
95         {
96                 for(int i = 0; i < length; i++)
97                 {
98                         spos = (m_position + i) / m_factor - m_sposition;
99
100                         if(floor(spos) < 0)
101                         {
102                                 low = m_cache.getBuffer()[(int)(floor(spos) + 2) * CC];
103                                 if(ceil(spos) < 0)
104                                         high = m_cache.getBuffer()[(int)(ceil(spos) + 2) * CC];
105                                 else
106                                         high = buf[(int)ceil(spos) * CC];
107                         }
108                         else
109                         {
110                                         low = buf[(int)floor(spos) * CC];
111                                         high = buf[(int)ceil(spos) * CC];
112                         }
113                         buffer[i * CC] = low + (spos - floor(spos)) * (high - low);
114                 }
115         }
116
117         if(len > 1)
118                 memcpy(m_cache.getBuffer(),
119                            buf + (len - 2) * channels,
120                            2 * samplesize);
121         else if(len == 1)
122                 memcpy(m_cache.getBuffer() + 1 * channels, buf, samplesize);
123
124         m_sposition += len;
125         m_position += length;
126         eos &= length < size;
127 }