1/*
2 * Copyright 2003 Marcus Overhagen
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "Resampler.h"
8
9#include <MediaDefs.h>
10
11#include "MixerDebug.h"
12
13
14/*!	A simple resampling class for the audio mixer.
15	You pick the conversion function on object creation,
16	and then call the Resample() function, specifying data pointer,
17	offset (in bytes) to the next sample, and count of samples for
18	both source and destination.
19*/
20
21
22template<typename inType, typename outType, int gnum, int gden,
23	int inMiddle, int outMiddle, int32 min, int32 max> static void
24kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
25	int32 srcSampleCount, void *_dest, int32 destSampleOffset,
26	int32 destSampleCount, float _gain)
27{
28	const char * src = (const char *)_src;
29	char * dest = (char *)_dest;
30	int32 count = destSampleCount;
31	float gain = _gain * gnum / gden;
32
33	if (srcSampleCount == destSampleCount) {
34		// optimized case for no resampling
35		while (count--) {
36			float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
37			if (tmp <= min)
38				*(outType *)dest = min;
39			else if (tmp >= max)
40				*(outType *)dest = max;
41			else
42				*(outType *)dest = (outType)tmp;
43			src += srcSampleOffset;
44			dest += destSampleOffset;
45		}
46		return;
47	}
48
49	float delta = float(srcSampleCount) / float(destSampleCount);
50	float current = 0.0f;
51
52	// downsample
53	while (count--) {
54		float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
55		if (tmp <= min)
56			*(outType *)dest = min;
57		else if (tmp >= max)
58			*(outType *)dest = max;
59		else
60			*(outType *)dest = (outType)tmp;
61
62		dest += destSampleOffset;
63		current += delta;
64		int32 skipcount = (int32)current;
65		current -= skipcount;
66		src += skipcount * srcSampleOffset;
67	}
68}
69
70
71Resampler::Resampler(uint32 src_format, uint32 dst_format)
72	:
73	fFunc(0)
74{
75	if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) {
76		switch (src_format) {
77			case media_raw_audio_format::B_AUDIO_FLOAT:
78				fFunc = &kernel<float, float, 1, 1, 0, 0, -1, 1>;
79				return;
80			case media_raw_audio_format::B_AUDIO_INT:
81				fFunc = &kernel<int32, float, 1, INT32_MAX, 0, 0, -1, 1>;
82				return;
83			case media_raw_audio_format::B_AUDIO_SHORT:
84				fFunc = &kernel<int16, float, 1, INT16_MAX, 0, 0, -1, 1>;
85				return;
86			case media_raw_audio_format::B_AUDIO_CHAR:
87				fFunc = &kernel<int8, float, 1, INT8_MAX, 0, 0, -1, 1>;
88				return;
89			case media_raw_audio_format::B_AUDIO_UCHAR:
90				fFunc = &kernel<uint8, float, 2, UINT8_MAX, 128, 0, -1, 1>;
91				return;
92			default:
93				ERROR("Resampler::Resampler: unknown source format 0x%x\n",
94					src_format);
95				return;
96		}
97	}
98
99	if (src_format == media_raw_audio_format::B_AUDIO_FLOAT) {
100		switch (dst_format) {
101			// float=>float already handled above
102			case media_raw_audio_format::B_AUDIO_INT:
103				fFunc = &kernel<float, int32, INT32_MAX, 1, 0, 0,
104					INT32_MIN, INT32_MAX>;
105				return;
106			case media_raw_audio_format::B_AUDIO_SHORT:
107				fFunc = &kernel<float, int16, INT16_MAX, 1, 0, 0,
108					INT16_MIN, INT16_MAX>;
109				return;
110			case media_raw_audio_format::B_AUDIO_CHAR:
111				fFunc = &kernel<float, int8, INT8_MAX, 1, 0, 0,
112					INT8_MIN, INT8_MAX>;
113				return;
114			case media_raw_audio_format::B_AUDIO_UCHAR:
115				fFunc = &kernel<float, uint8, UINT8_MAX, 2, 0, 128,
116					0, UINT8_MAX>;
117				return;
118			default:
119				ERROR("Resampler::Resampler: unknown destination format 0x%x\n",
120					dst_format);
121				return;
122		}
123	}
124
125	ERROR("Resampler::Resampler: source or destination format must be "
126		"B_AUDIO_FLOAT\n");
127}
128
129
130Resampler::Resampler()
131	:
132	fFunc(0)
133{
134}
135
136
137