xref: /haiku/src/add-ons/media/media-add-ons/mixer/Resampler.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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 
22 template<typename inType, typename outType, int gnum, int gden,
23 	int inMiddle, int outMiddle, int32 min, int32 max> static void
24 kernel(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 
71 Resampler::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 
130 Resampler::Resampler()
131 	:
132 	fFunc(0)
133 {
134 }
135 
136 
137