xref: /haiku/src/apps/mediaplayer/media_node_framework/audio/AudioResampler.cpp (revision 2222d0559df303a9846a2fad53741f8b20b14d7c)
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 #include "AudioResampler.h"
6 
7 #include <stdio.h>
8 
9 #include "SampleBuffer.h"
10 
11 
12 //#define TRACE_AUDIO_RESAMPLER
13 #ifdef TRACE_AUDIO_RESAMPLER
14 # define TRACE(x...)	printf(x)
15 #else
16 # define TRACE(x...)
17 #endif
18 
19 
20 AudioResampler::AudioResampler()
21 	: AudioReader(),
22 	  fSource(NULL),
23 	  fTimeScale(1.0),
24 	  fInOffset(0)
25 {
26 }
27 
28 
29 AudioResampler::AudioResampler(AudioReader* source, float frameRate,
30 		float timeScale)
31 	: AudioReader(),
32 	  fSource(NULL),
33 	  fTimeScale(timeScale),
34 	  fInOffset(0)
35 {
36 	SetSource(source);
37 	if (fSource)
38 		fFormat.u.raw_audio.frame_rate = frameRate;
39 }
40 
41 
42 AudioResampler::~AudioResampler()
43 {
44 }
45 
46 
47 //! Calculates the greatest common divider of /a/ and /b/.
48 template<typename T> inline
49 T
50 gcd(T a, T b)
51 {
52 	while (b != 0) {
53 		T r = a % b;
54 		a = b;
55 		b = r;
56 	}
57 	return a;
58 }
59 
60 
61 template<typename Buffer>
62 static void
63 resample_linear(void* _inBuffer, void* _outBuffer, uint32 channelCount,
64 	double inFrameRate, double outFrameRate, int32 frames)
65 {
66 	typedef double sample_t;
67 	Buffer inBuffer(_inBuffer);
68 	Buffer outFrameBuf(_outBuffer);
69 	for (sample_t outFrame = 0; outFrame < frames; outFrame++) {
70 		// time of the out sample
71 		sample_t outTime = outFrame / outFrameRate;
72 		// first in frame
73 		int64 inFrame = int64(outTime * inFrameRate);
74 		// time of the first and the second in frame
75 		sample_t inTime1 = (sample_t)inFrame / inFrameRate;
76 		sample_t inTime2 = (sample_t)(inFrame + 1) / inFrameRate;
77 		// differences between the out frame time and the in frame times
78 		sample_t timeDiff1 = outTime - inTime1;
79 		sample_t timeDiff2 = inTime2 - outTime;
80 		sample_t timeDiff = timeDiff1 + timeDiff2;
81 		// pointer to the first and second in frame
82 		Buffer inFrameBuf1 = inBuffer + inFrame * channelCount;
83 		Buffer inFrameBuf2 = inFrameBuf1 + channelCount;
84 		for (uint32 c = 0; c < channelCount;
85 			 c++, inFrameBuf1++, inFrameBuf2++, outFrameBuf++) {
86 			// sum weighted according to the distance to the respective other
87 			// in frame
88 			outFrameBuf.WriteSample((timeDiff2 * inFrameBuf1.ReadSample()
89 				+ timeDiff1 * inFrameBuf2.ReadSample()) / timeDiff);
90 		}
91 	}
92 }
93 
94 
95 status_t
96 AudioResampler::Read(void* buffer, int64 pos, int64 frames)
97 {
98 	TRACE("AudioResampler::Read(%p, %Ld, %Ld)\n", buffer, pos, frames);
99 
100 	status_t error = InitCheck();
101 	if (error != B_OK) {
102 		TRACE("AudioResampler::Read() done1\n");
103 		return error;
104 	}
105 	// calculate position and frames in the source data
106 	int64 sourcePos = ConvertToSource(pos);
107 	int64 sourceFrames = ConvertToSource(pos + frames) - sourcePos;
108 	// check the frame counts
109 	if (sourceFrames == frames) {
110 		TRACE("AudioResampler::Read() done2\n");
111 		return fSource->Read(buffer, sourcePos, sourceFrames);
112 	}
113 	if (sourceFrames == 0) {
114 		ReadSilence(buffer, frames);
115 		TRACE("AudioResampler::Read() done3\n");
116 		return B_OK;
117 	}
118 	// check, if playing backwards
119 	bool backward = false;
120 	if (sourceFrames < 0) {
121 		sourceFrames = -sourceFrames;
122 		sourcePos -= sourceFrames;
123 		backward = true;
124 	}
125 
126 	// we need at least two frames to interpolate
127 	sourceFrames += 2;
128 	int32 sampleSize = media_raw_audio_format::B_AUDIO_SIZE_MASK;
129 	uint32 channelCount = fFormat.u.raw_audio.channel_count;
130 	char* inBuffer = new char[sourceFrames * channelCount * sampleSize];
131 	error = fSource->Read(inBuffer, sourcePos, sourceFrames);
132 	if (error != B_OK) {
133 		TRACE("AudioResampler::_ReadLinear() done4\n");
134 		return error;
135 	}
136 	double inFrameRate = fSource->Format().u.raw_audio.frame_rate;
137 	double outFrameRate = (double)fFormat.u.raw_audio.frame_rate
138 		/ (double)fTimeScale;
139 	// choose the sample buffer to be used
140 	switch (fFormat.u.raw_audio.format) {
141 		case media_raw_audio_format::B_AUDIO_FLOAT:
142 			resample_linear< FloatSampleBuffer<double> >(inBuffer, buffer,
143 				channelCount, inFrameRate, outFrameRate, (int32)frames);
144 			break;
145 		case media_raw_audio_format::B_AUDIO_INT:
146 			resample_linear< IntSampleBuffer<double> >(inBuffer, buffer,
147 				channelCount, inFrameRate, outFrameRate, (int32)frames);
148 			break;
149 		case media_raw_audio_format::B_AUDIO_SHORT:
150 			resample_linear< ShortSampleBuffer<double> >(inBuffer, buffer,
151 				channelCount, inFrameRate, outFrameRate, (int32)frames);
152 			break;
153 		case media_raw_audio_format::B_AUDIO_UCHAR:
154 			resample_linear< UCharSampleBuffer<double> >(inBuffer, buffer,
155 				channelCount, inFrameRate, outFrameRate, (int32)frames);
156 			break;
157 		case media_raw_audio_format::B_AUDIO_CHAR:
158 			resample_linear< CharSampleBuffer<double> >(inBuffer, buffer,
159 				channelCount, inFrameRate, outFrameRate, (int32)frames);
160 			break;
161 	}
162 	// reverse the frame order if reading backwards
163 	if (backward)
164 		ReverseFrames(buffer, frames);
165 	delete[] inBuffer;
166 	TRACE("AudioResampler::Read() done\n");
167 	return B_OK;
168 }
169 
170 
171 status_t
172 AudioResampler::InitCheck() const
173 {
174 	status_t error = AudioReader::InitCheck();
175 	if (error == B_OK && !fSource)
176 		error = B_NO_INIT;
177 	return error;
178 }
179 
180 
181 void
182 AudioResampler::SetSource(AudioReader* source)
183 {
184 	if (!source) {
185 		TRACE("AudioResampler::SetSource() - NULL source\n");
186 		return;
187 	}
188 
189 	if (source->Format().type != B_MEDIA_RAW_AUDIO) {
190 		TRACE("AudioResampler::SetSource() - not B_MEDIA_RAW_AUDIO\n");
191 		return;
192 	}
193 
194 	uint32 hostByteOrder
195 		= (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
196 	if (source->Format().u.raw_audio.byte_order != hostByteOrder) {
197 		TRACE("AudioResampler::SetSource() - not host byte order\n");
198 		return;
199 	}
200 
201 	float frameRate = FrameRate();
202 		// don't overwrite previous audio frame rate
203 	fSource = source;
204 	fFormat = source->Format();
205 	fFormat.u.raw_audio.frame_rate = frameRate;
206 }
207 
208 
209 void
210 AudioResampler::SetFrameRate(float frameRate)
211 {
212 	fFormat.u.raw_audio.frame_rate = frameRate;
213 }
214 
215 
216 void
217 AudioResampler::SetTimeScale(float timeScale)
218 {
219 	fTimeScale = timeScale;
220 }
221 
222 
223 AudioReader*
224 AudioResampler::Source() const
225 {
226 	return fSource;
227 }
228 
229 
230 float
231 AudioResampler::FrameRate() const
232 {
233 	return fFormat.u.raw_audio.frame_rate;
234 }
235 
236 
237 float
238 AudioResampler::TimeScale() const
239 {
240 	return fTimeScale;
241 }
242 
243 
244 void
245 AudioResampler::SetInOffset(int64 offset)
246 {
247 	fInOffset = offset;
248 }
249 
250 
251 int64
252 AudioResampler::InOffset() const
253 {
254 	return fInOffset;
255 }
256 
257 
258 int64
259 AudioResampler::ConvertFromSource(int64 pos) const
260 {
261 	double inFrameRate = fSource->Format().u.raw_audio.frame_rate;
262 	double outFrameRate = fFormat.u.raw_audio.frame_rate;
263 	return (int64)((double)(pos - fInOffset) * outFrameRate / inFrameRate
264 		/ (double)fTimeScale) - fOutOffset;
265 }
266 
267 
268 int64
269 AudioResampler::ConvertToSource(int64 pos) const
270 {
271 	double inFrameRate = fSource->Format().u.raw_audio.frame_rate;
272 	double outFrameRate = fFormat.u.raw_audio.frame_rate;
273 	return (int64)((double)(pos + fOutOffset) * inFrameRate / outFrameRate
274 		* (double)fTimeScale) + fInOffset;
275 }
276 
277