xref: /haiku/src/add-ons/media/media-add-ons/mixer/Resampler.cpp (revision cfe72209cf7efc2b6aad94912d4e39a75247bee2)
1a9cf57cfSAxel Dörfler /*
2a9cf57cfSAxel Dörfler  * Copyright 2003 Marcus Overhagen
3a9cf57cfSAxel Dörfler  * Distributed under the terms of the MIT License.
4575526ffSbeveloper  */
5575526ffSbeveloper 
6a9cf57cfSAxel Dörfler 
7575526ffSbeveloper #include "Resampler.h"
8a9cf57cfSAxel Dörfler 
9a9cf57cfSAxel Dörfler #include <MediaDefs.h>
10a9cf57cfSAxel Dörfler 
11f916862cSMarcus Overhagen #include "MixerDebug.h"
12575526ffSbeveloper 
13a9cf57cfSAxel Dörfler 
14a9cf57cfSAxel Dörfler /*!	A simple resampling class for the audio mixer.
15a9cf57cfSAxel Dörfler 	You pick the conversion function on object creation,
16a9cf57cfSAxel Dörfler 	and then call the Resample() function, specifying data pointer,
17a9cf57cfSAxel Dörfler 	offset (in bytes) to the next sample, and count of samples for
18a9cf57cfSAxel Dörfler 	both source and destination.
19a9cf57cfSAxel Dörfler */
20a9cf57cfSAxel Dörfler 
21a9cf57cfSAxel Dörfler 
22*cfe72209SMáximo Castañeda template<typename inType, typename outType, int gnum, int gden,
23*cfe72209SMáximo Castañeda 	int inMiddle, int outMiddle, int32 min, int32 max> static void
2427606daeSAdrien Destugues kernel(Resampler* object, const void *_src, int32 srcSampleOffset,
2527606daeSAdrien Destugues 	int32 srcSampleCount, void *_dest, int32 destSampleOffset,
2627606daeSAdrien Destugues 	int32 destSampleCount, float _gain)
2727606daeSAdrien Destugues {
2827606daeSAdrien Destugues 	register const char * src = (const char *)_src;
2927606daeSAdrien Destugues 	register char * dest = (char *)_dest;
3027606daeSAdrien Destugues 	register int32 count = destSampleCount;
3127606daeSAdrien Destugues 	register float gain = _gain * gnum / gden;
3227606daeSAdrien Destugues 
3327606daeSAdrien Destugues 	if (srcSampleCount == destSampleCount) {
3427606daeSAdrien Destugues 		// optimized case for no resampling
3527606daeSAdrien Destugues 		while (count--) {
36*cfe72209SMáximo Castañeda 			float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
3727606daeSAdrien Destugues 			if (tmp < min) tmp = min;
3827606daeSAdrien Destugues 			if (tmp > max) tmp = max;
3927606daeSAdrien Destugues 			*(outType *)dest = (outType)tmp;
4027606daeSAdrien Destugues 			src += srcSampleOffset;
4127606daeSAdrien Destugues 			dest += destSampleOffset;
4227606daeSAdrien Destugues 		}
4327606daeSAdrien Destugues 		return;
4427606daeSAdrien Destugues 	}
4527606daeSAdrien Destugues 
4627606daeSAdrien Destugues 	register float delta = float(srcSampleCount) / float(destSampleCount);
4727606daeSAdrien Destugues 	register float current = 0.0f;
4827606daeSAdrien Destugues 
4927606daeSAdrien Destugues 	// downsample
5027606daeSAdrien Destugues 	while (count--) {
51*cfe72209SMáximo Castañeda 		float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
5227606daeSAdrien Destugues 		if (tmp < min) tmp = min;
5327606daeSAdrien Destugues 		if (tmp > max) tmp = max;
5427606daeSAdrien Destugues 		*(outType *)dest = (outType)tmp;
5527606daeSAdrien Destugues 
5627606daeSAdrien Destugues 		dest += destSampleOffset;
5727606daeSAdrien Destugues 		current += delta;
5827606daeSAdrien Destugues 		register int32 skipcount = (int32)current;
5927606daeSAdrien Destugues 		current -= skipcount;
6027606daeSAdrien Destugues 		src += skipcount * srcSampleOffset;
6127606daeSAdrien Destugues 	}
6227606daeSAdrien Destugues }
6327606daeSAdrien Destugues 
6427606daeSAdrien Destugues 
65f0a85f97SJérôme Duval Resampler::Resampler(uint32 src_format, uint32 dst_format)
66a9cf57cfSAxel Dörfler 	:
6778341a93SJohn Scipione 	fFunc(0)
68575526ffSbeveloper {
69575526ffSbeveloper 	if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) {
70575526ffSbeveloper 		switch (src_format) {
71575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_FLOAT:
72*cfe72209SMáximo Castañeda 				fFunc = &kernel<float, float, 1, 1, 0, 0, -1, 1>;
73575526ffSbeveloper 				return;
74575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_INT:
75*cfe72209SMáximo Castañeda 				fFunc = &kernel<int32, float, 1, INT32_MAX, 0, 0, -1, 1>;
76575526ffSbeveloper 				return;
77575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_SHORT:
78*cfe72209SMáximo Castañeda 				fFunc = &kernel<int16, float, 1, INT16_MAX, 0, 0, -1, 1>;
79575526ffSbeveloper 				return;
80575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_CHAR:
81*cfe72209SMáximo Castañeda 				fFunc = &kernel<int8, float, 1, INT8_MAX, 0, 0, -1, 1>;
82575526ffSbeveloper 				return;
83575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_UCHAR:
84*cfe72209SMáximo Castañeda 				fFunc = &kernel<uint8, float, 2, UINT8_MAX, 128, 0, -1, 1>;
85575526ffSbeveloper 				return;
86575526ffSbeveloper 			default:
87a9cf57cfSAxel Dörfler 				ERROR("Resampler::Resampler: unknown source format 0x%x\n",
88a9cf57cfSAxel Dörfler 					src_format);
89575526ffSbeveloper 				return;
90575526ffSbeveloper 		}
91575526ffSbeveloper 	}
92575526ffSbeveloper 
93575526ffSbeveloper 	if (src_format == media_raw_audio_format::B_AUDIO_FLOAT) {
94575526ffSbeveloper 		switch (dst_format) {
95575526ffSbeveloper 			// float=>float already handled above
96575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_INT:
97*cfe72209SMáximo Castañeda 				fFunc = &kernel<float, int32, INT32_MAX, 1, 0, 0,
9827606daeSAdrien Destugues 					INT32_MIN, INT32_MAX>;
99575526ffSbeveloper 				return;
100575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_SHORT:
101*cfe72209SMáximo Castañeda 				fFunc = &kernel<float, int16, INT16_MAX, 1, 0, 0,
10227606daeSAdrien Destugues 					INT16_MIN, INT16_MAX>;
103575526ffSbeveloper 				return;
104575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_CHAR:
105*cfe72209SMáximo Castañeda 				fFunc = &kernel<float, int8, INT8_MAX, 1, 0, 0,
10627606daeSAdrien Destugues 					INT8_MIN, INT8_MAX>;
107575526ffSbeveloper 				return;
108575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_UCHAR:
109*cfe72209SMáximo Castañeda 				fFunc = &kernel<float, uint8, UINT8_MAX, 2, 0, 128,
11027606daeSAdrien Destugues 					0, UINT8_MAX>;
111575526ffSbeveloper 				return;
112575526ffSbeveloper 			default:
11327606daeSAdrien Destugues 				ERROR("Resampler::Resampler: unknown destination format 0x%x\n",
11427606daeSAdrien Destugues 					dst_format);
115575526ffSbeveloper 				return;
116575526ffSbeveloper 		}
117575526ffSbeveloper 	}
118575526ffSbeveloper 
119a9cf57cfSAxel Dörfler 	ERROR("Resampler::Resampler: source or destination format must be "
120a9cf57cfSAxel Dörfler 		"B_AUDIO_FLOAT\n");
121575526ffSbeveloper }
122575526ffSbeveloper 
123a9cf57cfSAxel Dörfler 
12427606daeSAdrien Destugues Resampler::Resampler()
12527606daeSAdrien Destugues 	:
12627606daeSAdrien Destugues 	fFunc(0)
127575526ffSbeveloper {
128575526ffSbeveloper }
129575526ffSbeveloper 
130a9cf57cfSAxel Dörfler 
131