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/.
23template<typename T> inline
24T
25gcd(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
36template<typename Buffer>
37static void
38resample_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
73AudioResampler::AudioResampler()
74	:
75	AudioReader(),
76	fSource(NULL),
77	fTimeScale(1.0),
78	fInOffset(0)
79{
80}
81
82
83AudioResampler::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
97AudioResampler::~AudioResampler()
98{
99}
100
101
102bigtime_t
103AudioResampler::InitialLatency() const
104{
105	return fSource->InitialLatency();
106}
107
108
109status_t
110AudioResampler::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
185status_t
186AudioResampler::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
195void
196AudioResampler::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
223void
224AudioResampler::SetFrameRate(float frameRate)
225{
226	fFormat.u.raw_audio.frame_rate = frameRate;
227}
228
229
230void
231AudioResampler::SetTimeScale(float timeScale)
232{
233	fTimeScale = timeScale;
234}
235
236
237AudioReader*
238AudioResampler::Source() const
239{
240	return fSource;
241}
242
243
244float
245AudioResampler::FrameRate() const
246{
247	return fFormat.u.raw_audio.frame_rate;
248}
249
250
251float
252AudioResampler::TimeScale() const
253{
254	return fTimeScale;
255}
256
257
258void
259AudioResampler::SetInOffset(int64 offset)
260{
261	fInOffset = offset;
262}
263
264
265int64
266AudioResampler::InOffset() const
267{
268	return fInOffset;
269}
270
271
272int64
273AudioResampler::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
282int64
283AudioResampler::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