xref: /haiku/src/apps/mediaplayer/media_node_framework/audio/AudioResampler.cpp (revision 425ac1b60a56f4df7a0e88bd784545c0ec4fa01f)
1 /*
2  * Copyright 2000-2006 Ingo Weinhold <ingo_weinhold@gmx.de>
3  * All rights reserved. Distributed under the terms of the MIT licensce.
4  */
5 
6 
7 #include "AudioResampler.h"
8 
9 #include <stdio.h>
10 
11 #include "SampleBuffer.h"
12 
13 
14 //#define TRACE_AUDIO_RESAMPLER
15 #ifdef TRACE_AUDIO_RESAMPLER
16 #	define TRACE(x...)	printf(x)
17 #else
18 #	define TRACE(x...)
19 #endif
20 
21 
22 //! Calculates the greatest common divider of /a/ and /b/.
23 template<typename T> inline
24 T
gcd(T a,T b)25 gcd(T a, T b)
26 {
27 	while (b != 0) {
28 		T r = a % b;
29 		a = b;
30 		b = r;
31 	}
32 	return a;
33 }
34 
35 
36 template<typename Buffer>
37 static void
resample_linear(void * _inBuffer,void * _outBuffer,uint32 channelCount,double inFrameRate,double outFrameRate,int32 frames)38 resample_linear(void* _inBuffer, void* _outBuffer, uint32 channelCount,
39 	double inFrameRate, double outFrameRate, int32 frames)
40 {
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);
65 		}
66 	}
67 }
68 
69 
70 // #pragma mark -
71 
72 
AudioResampler()73 AudioResampler::AudioResampler()
74 	:
75 	AudioReader(),
76 	fSource(NULL),
77 	fTimeScale(1.0),
78 	fInOffset(0)
79 {
80 }
81 
82 
AudioResampler(AudioReader * source,float frameRate,float timeScale)83 AudioResampler::AudioResampler(AudioReader* source, float frameRate,
84 		float timeScale)
85 	:
86 	AudioReader(),
87 	fSource(NULL),
88 	fTimeScale(timeScale),
89 	fInOffset(0)
90 {
91 	SetSource(source);
92 	if (fSource)
93 		fFormat.u.raw_audio.frame_rate = frameRate;
94 }
95 
96 
~AudioResampler()97 AudioResampler::~AudioResampler()
98 {
99 }
100 
101 
102 bigtime_t
InitialLatency() const103 AudioResampler::InitialLatency() const
104 {
105 	return fSource->InitialLatency();
106 }
107 
108 
109 status_t
Read(void * buffer,int64 pos,int64 frames)110 AudioResampler::Read(void* buffer, int64 pos, int64 frames)
111 {
112 	TRACE("AudioResampler::Read(%p, %lld, %lld)\n", buffer, pos, frames);
113 
114 	status_t error = InitCheck();
115 	if (error != B_OK) {
116 		TRACE("AudioResampler::Read() done1\n");
117 		return error;
118 	}
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);
126 	}
127 	if (sourceFrames == 0) {
128 		ReadSilence(buffer, frames);
129 		TRACE("AudioResampler::Read() done3\n");
130 		return B_OK;
131 	}
132 	// check, if playing backwards
133 	bool backward = false;
134 	if (sourceFrames < 0) {
135 		sourceFrames = -sourceFrames;
136 		sourcePos -= sourceFrames;
137 		backward = true;
138 	}
139 
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;
149 	}
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;
175 	}
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;
182 }
183 
184 
185 status_t
InitCheck() const186 AudioResampler::InitCheck() const
187 {
188 	status_t error = AudioReader::InitCheck();
189 	if (error == B_OK && !fSource)
190 		error = B_NO_INIT;
191 	return error;
192 }
193 
194 
195 void
SetSource(AudioReader * source)196 AudioResampler::SetSource(AudioReader* source)
197 {
198 	if (!source) {
199 		TRACE("AudioResampler::SetSource() - NULL source\n");
200 		return;
201 	}
202 
203 	if (source->Format().type != B_MEDIA_RAW_AUDIO) {
204 		TRACE("AudioResampler::SetSource() - not B_MEDIA_RAW_AUDIO\n");
205 		return;
206 	}
207 
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;
213 	}
214 
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;
220 }
221 
222 
223 void
SetFrameRate(float frameRate)224 AudioResampler::SetFrameRate(float frameRate)
225 {
226 	fFormat.u.raw_audio.frame_rate = frameRate;
227 }
228 
229 
230 void
SetTimeScale(float timeScale)231 AudioResampler::SetTimeScale(float timeScale)
232 {
233 	fTimeScale = timeScale;
234 }
235 
236 
237 AudioReader*
Source() const238 AudioResampler::Source() const
239 {
240 	return fSource;
241 }
242 
243 
244 float
FrameRate() const245 AudioResampler::FrameRate() const
246 {
247 	return fFormat.u.raw_audio.frame_rate;
248 }
249 
250 
251 float
TimeScale() const252 AudioResampler::TimeScale() const
253 {
254 	return fTimeScale;
255 }
256 
257 
258 void
SetInOffset(int64 offset)259 AudioResampler::SetInOffset(int64 offset)
260 {
261 	fInOffset = offset;
262 }
263 
264 
265 int64
InOffset() const266 AudioResampler::InOffset() const
267 {
268 	return fInOffset;
269 }
270 
271 
272 int64
ConvertFromSource(int64 pos) const273 AudioResampler::ConvertFromSource(int64 pos) const
274 {
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;
279 }
280 
281 
282 int64
ConvertToSource(int64 pos) const283 AudioResampler::ConvertToSource(int64 pos) const
284 {
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;
289 }
290 
291