vfs: check userland buffers before reading them.
[haiku.git] / src / apps / mediaplayer / media_node_framework / audio / AudioResampler.cpp
blobf7ad2f42b61236b6f01b9c8be40116f9bca5e7e6
1 /*
2 * Copyright 2000-2006 Ingo Weinhold <ingo_weinhold@gmx.de>
3 * All rights reserved. Distributed under the terms of the MIT licensce.
4 */
7 #include "AudioResampler.h"
9 #include <stdio.h>
11 #include "SampleBuffer.h"
14 //#define TRACE_AUDIO_RESAMPLER
15 #ifdef TRACE_AUDIO_RESAMPLER
16 # define TRACE(x...) printf(x)
17 #else
18 # define TRACE(x...)
19 #endif
22 //! Calculates the greatest common divider of /a/ and /b/.
23 template<typename T> inline
25 gcd(T a, T b)
27 while (b != 0) {
28 T r = a % b;
29 a = b;
30 b = r;
32 return a;
36 template<typename Buffer>
37 static void
38 resample_linear(void* _inBuffer, void* _outBuffer, uint32 channelCount,
39 double inFrameRate, double outFrameRate, int32 frames)
41 typedef double sample_t;
42 Buffer inBuffer(_inBuffer);
43 Buffer outFrameBuf(_outBuffer);
44 for (sample_t outFrame = 0; outFrame < frames; outFrame++) {
45 // time of the out sample
46 sample_t outTime = outFrame / outFrameRate;
47 // first in frame
48 int64 inFrame = int64(outTime * inFrameRate);
49 // time of the first and the second in frame
50 sample_t inTime1 = (sample_t)inFrame / inFrameRate;
51 sample_t inTime2 = (sample_t)(inFrame + 1) / inFrameRate;
52 // differences between the out frame time and the in frame times
53 sample_t timeDiff1 = outTime - inTime1;
54 sample_t timeDiff2 = inTime2 - outTime;
55 sample_t timeDiff = timeDiff1 + timeDiff2;
56 // pointer to the first and second in frame
57 Buffer inFrameBuf1 = inBuffer + inFrame * channelCount;
58 Buffer inFrameBuf2 = inFrameBuf1 + channelCount;
59 for (uint32 c = 0; c < channelCount;
60 c++, inFrameBuf1++, inFrameBuf2++, outFrameBuf++) {
61 // sum weighted according to the distance to the respective other
62 // in frame
63 outFrameBuf.WriteSample((timeDiff2 * inFrameBuf1.ReadSample()
64 + timeDiff1 * inFrameBuf2.ReadSample()) / timeDiff);
70 // #pragma mark -
73 AudioResampler::AudioResampler()
75 AudioReader(),
76 fSource(NULL),
77 fTimeScale(1.0),
78 fInOffset(0)
83 AudioResampler::AudioResampler(AudioReader* source, float frameRate,
84 float timeScale)
86 AudioReader(),
87 fSource(NULL),
88 fTimeScale(timeScale),
89 fInOffset(0)
91 SetSource(source);
92 if (fSource)
93 fFormat.u.raw_audio.frame_rate = frameRate;
97 AudioResampler::~AudioResampler()
102 bigtime_t
103 AudioResampler::InitialLatency() const
105 return fSource->InitialLatency();
109 status_t
110 AudioResampler::Read(void* buffer, int64 pos, int64 frames)
112 TRACE("AudioResampler::Read(%p, %Ld, %Ld)\n", buffer, pos, frames);
114 status_t error = InitCheck();
115 if (error != B_OK) {
116 TRACE("AudioResampler::Read() done1\n");
117 return error;
119 // calculate position and frames in the source data
120 int64 sourcePos = ConvertToSource(pos);
121 int64 sourceFrames = ConvertToSource(pos + frames) - sourcePos;
122 // check the frame counts
123 if (sourceFrames == frames) {
124 TRACE("AudioResampler::Read() done2\n");
125 return fSource->Read(buffer, sourcePos, sourceFrames);
127 if (sourceFrames == 0) {
128 ReadSilence(buffer, frames);
129 TRACE("AudioResampler::Read() done3\n");
130 return B_OK;
132 // check, if playing backwards
133 bool backward = false;
134 if (sourceFrames < 0) {
135 sourceFrames = -sourceFrames;
136 sourcePos -= sourceFrames;
137 backward = true;
140 // we need at least two frames to interpolate
141 sourceFrames += 2;
142 int32 sampleSize = media_raw_audio_format::B_AUDIO_SIZE_MASK;
143 uint32 channelCount = fFormat.u.raw_audio.channel_count;
144 char* inBuffer = new char[sourceFrames * channelCount * sampleSize];
145 error = fSource->Read(inBuffer, sourcePos, sourceFrames);
146 if (error != B_OK) {
147 TRACE("AudioResampler::_ReadLinear() done4\n");
148 return error;
150 double inFrameRate = fSource->Format().u.raw_audio.frame_rate;
151 double outFrameRate = (double)fFormat.u.raw_audio.frame_rate
152 / (double)fTimeScale;
153 // choose the sample buffer to be used
154 switch (fFormat.u.raw_audio.format) {
155 case media_raw_audio_format::B_AUDIO_FLOAT:
156 resample_linear< FloatSampleBuffer<double> >(inBuffer, buffer,
157 channelCount, inFrameRate, outFrameRate, (int32)frames);
158 break;
159 case media_raw_audio_format::B_AUDIO_INT:
160 resample_linear< IntSampleBuffer<double> >(inBuffer, buffer,
161 channelCount, inFrameRate, outFrameRate, (int32)frames);
162 break;
163 case media_raw_audio_format::B_AUDIO_SHORT:
164 resample_linear< ShortSampleBuffer<double> >(inBuffer, buffer,
165 channelCount, inFrameRate, outFrameRate, (int32)frames);
166 break;
167 case media_raw_audio_format::B_AUDIO_UCHAR:
168 resample_linear< UCharSampleBuffer<double> >(inBuffer, buffer,
169 channelCount, inFrameRate, outFrameRate, (int32)frames);
170 break;
171 case media_raw_audio_format::B_AUDIO_CHAR:
172 resample_linear< CharSampleBuffer<double> >(inBuffer, buffer,
173 channelCount, inFrameRate, outFrameRate, (int32)frames);
174 break;
176 // reverse the frame order if reading backwards
177 if (backward)
178 ReverseFrames(buffer, frames);
179 delete[] inBuffer;
180 TRACE("AudioResampler::Read() done\n");
181 return B_OK;
185 status_t
186 AudioResampler::InitCheck() const
188 status_t error = AudioReader::InitCheck();
189 if (error == B_OK && !fSource)
190 error = B_NO_INIT;
191 return error;
195 void
196 AudioResampler::SetSource(AudioReader* source)
198 if (!source) {
199 TRACE("AudioResampler::SetSource() - NULL source\n");
200 return;
203 if (source->Format().type != B_MEDIA_RAW_AUDIO) {
204 TRACE("AudioResampler::SetSource() - not B_MEDIA_RAW_AUDIO\n");
205 return;
208 uint32 hostByteOrder
209 = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
210 if (source->Format().u.raw_audio.byte_order != hostByteOrder) {
211 TRACE("AudioResampler::SetSource() - not host byte order\n");
212 return;
215 float frameRate = FrameRate();
216 // don't overwrite previous audio frame rate
217 fSource = source;
218 fFormat = source->Format();
219 fFormat.u.raw_audio.frame_rate = frameRate;
223 void
224 AudioResampler::SetFrameRate(float frameRate)
226 fFormat.u.raw_audio.frame_rate = frameRate;
230 void
231 AudioResampler::SetTimeScale(float timeScale)
233 fTimeScale = timeScale;
237 AudioReader*
238 AudioResampler::Source() const
240 return fSource;
244 float
245 AudioResampler::FrameRate() const
247 return fFormat.u.raw_audio.frame_rate;
251 float
252 AudioResampler::TimeScale() const
254 return fTimeScale;
258 void
259 AudioResampler::SetInOffset(int64 offset)
261 fInOffset = offset;
265 int64
266 AudioResampler::InOffset() const
268 return fInOffset;
272 int64
273 AudioResampler::ConvertFromSource(int64 pos) const
275 double inFrameRate = fSource->Format().u.raw_audio.frame_rate;
276 double outFrameRate = fFormat.u.raw_audio.frame_rate;
277 return (int64)((double)(pos - fInOffset) * outFrameRate / inFrameRate
278 / (double)fTimeScale) - fOutOffset;
282 int64
283 AudioResampler::ConvertToSource(int64 pos) const
285 double inFrameRate = fSource->Format().u.raw_audio.frame_rate;
286 double outFrameRate = fFormat.u.raw_audio.frame_rate;
287 return (int64)((double)(pos + fOutOffset) * inFrameRate / outFrameRate
288 * (double)fTimeScale) + fInOffset;