xref: /haiku/src/add-ons/media/media-add-ons/mixer/Resampler.cpp (revision da8162be21b36442f34a731873d2358a0d63c25a)
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 
22cfe72209SMáximo Castañeda template<typename inType, typename outType, int gnum, int gden,
23cfe72209SMáximo Castañeda 	int inMiddle, int outMiddle, int32 min, int32 max> static void
kernel(Resampler * object,const void * _src,int32 srcSampleOffset,int32 srcSampleCount,void * _dest,int32 destSampleOffset,int32 destSampleCount,float _gain)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 {
28*95080923SMichael Brumbelow 	const char * src = (const char *)_src;
29*95080923SMichael Brumbelow 	char * dest = (char *)_dest;
30*95080923SMichael Brumbelow 	int32 count = destSampleCount;
31*95080923SMichael Brumbelow 	float gain = _gain * gnum / gden;
3227606daeSAdrien Destugues 
3327606daeSAdrien Destugues 	if (srcSampleCount == destSampleCount) {
3427606daeSAdrien Destugues 		// optimized case for no resampling
3527606daeSAdrien Destugues 		while (count--) {
36cfe72209SMáximo Castañeda 			float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
372e68fbd2SMáximo Castañeda 			if (tmp <= min)
382e68fbd2SMáximo Castañeda 				*(outType *)dest = min;
392e68fbd2SMáximo Castañeda 			else if (tmp >= max)
402e68fbd2SMáximo Castañeda 				*(outType *)dest = max;
412e68fbd2SMáximo Castañeda 			else
4227606daeSAdrien Destugues 				*(outType *)dest = (outType)tmp;
4327606daeSAdrien Destugues 			src += srcSampleOffset;
4427606daeSAdrien Destugues 			dest += destSampleOffset;
4527606daeSAdrien Destugues 		}
4627606daeSAdrien Destugues 		return;
4727606daeSAdrien Destugues 	}
4827606daeSAdrien Destugues 
49*95080923SMichael Brumbelow 	float delta = float(srcSampleCount) / float(destSampleCount);
50*95080923SMichael Brumbelow 	float current = 0.0f;
5127606daeSAdrien Destugues 
5227606daeSAdrien Destugues 	// downsample
5327606daeSAdrien Destugues 	while (count--) {
54cfe72209SMáximo Castañeda 		float tmp = ((*(const inType*)src) - inMiddle) * gain + outMiddle;
552e68fbd2SMáximo Castañeda 		if (tmp <= min)
562e68fbd2SMáximo Castañeda 			*(outType *)dest = min;
572e68fbd2SMáximo Castañeda 		else if (tmp >= max)
582e68fbd2SMáximo Castañeda 			*(outType *)dest = max;
592e68fbd2SMáximo Castañeda 		else
6027606daeSAdrien Destugues 			*(outType *)dest = (outType)tmp;
6127606daeSAdrien Destugues 
6227606daeSAdrien Destugues 		dest += destSampleOffset;
6327606daeSAdrien Destugues 		current += delta;
64*95080923SMichael Brumbelow 		int32 skipcount = (int32)current;
6527606daeSAdrien Destugues 		current -= skipcount;
6627606daeSAdrien Destugues 		src += skipcount * srcSampleOffset;
6727606daeSAdrien Destugues 	}
6827606daeSAdrien Destugues }
6927606daeSAdrien Destugues 
7027606daeSAdrien Destugues 
Resampler(uint32 src_format,uint32 dst_format)71f0a85f97SJérôme Duval Resampler::Resampler(uint32 src_format, uint32 dst_format)
72a9cf57cfSAxel Dörfler 	:
7378341a93SJohn Scipione 	fFunc(0)
74575526ffSbeveloper {
75575526ffSbeveloper 	if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) {
76575526ffSbeveloper 		switch (src_format) {
77575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_FLOAT:
78cfe72209SMáximo Castañeda 				fFunc = &kernel<float, float, 1, 1, 0, 0, -1, 1>;
79575526ffSbeveloper 				return;
80575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_INT:
81cfe72209SMáximo Castañeda 				fFunc = &kernel<int32, float, 1, INT32_MAX, 0, 0, -1, 1>;
82575526ffSbeveloper 				return;
83575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_SHORT:
84cfe72209SMáximo Castañeda 				fFunc = &kernel<int16, float, 1, INT16_MAX, 0, 0, -1, 1>;
85575526ffSbeveloper 				return;
86575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_CHAR:
87cfe72209SMáximo Castañeda 				fFunc = &kernel<int8, float, 1, INT8_MAX, 0, 0, -1, 1>;
88575526ffSbeveloper 				return;
89575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_UCHAR:
90cfe72209SMáximo Castañeda 				fFunc = &kernel<uint8, float, 2, UINT8_MAX, 128, 0, -1, 1>;
91575526ffSbeveloper 				return;
92575526ffSbeveloper 			default:
93a9cf57cfSAxel Dörfler 				ERROR("Resampler::Resampler: unknown source format 0x%x\n",
94a9cf57cfSAxel Dörfler 					src_format);
95575526ffSbeveloper 				return;
96575526ffSbeveloper 		}
97575526ffSbeveloper 	}
98575526ffSbeveloper 
99575526ffSbeveloper 	if (src_format == media_raw_audio_format::B_AUDIO_FLOAT) {
100575526ffSbeveloper 		switch (dst_format) {
101575526ffSbeveloper 			// float=>float already handled above
102575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_INT:
103cfe72209SMáximo Castañeda 				fFunc = &kernel<float, int32, INT32_MAX, 1, 0, 0,
10427606daeSAdrien Destugues 					INT32_MIN, INT32_MAX>;
105575526ffSbeveloper 				return;
106575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_SHORT:
107cfe72209SMáximo Castañeda 				fFunc = &kernel<float, int16, INT16_MAX, 1, 0, 0,
10827606daeSAdrien Destugues 					INT16_MIN, INT16_MAX>;
109575526ffSbeveloper 				return;
110575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_CHAR:
111cfe72209SMáximo Castañeda 				fFunc = &kernel<float, int8, INT8_MAX, 1, 0, 0,
11227606daeSAdrien Destugues 					INT8_MIN, INT8_MAX>;
113575526ffSbeveloper 				return;
114575526ffSbeveloper 			case media_raw_audio_format::B_AUDIO_UCHAR:
115cfe72209SMáximo Castañeda 				fFunc = &kernel<float, uint8, UINT8_MAX, 2, 0, 128,
11627606daeSAdrien Destugues 					0, UINT8_MAX>;
117575526ffSbeveloper 				return;
118575526ffSbeveloper 			default:
11927606daeSAdrien Destugues 				ERROR("Resampler::Resampler: unknown destination format 0x%x\n",
12027606daeSAdrien Destugues 					dst_format);
121575526ffSbeveloper 				return;
122575526ffSbeveloper 		}
123575526ffSbeveloper 	}
124575526ffSbeveloper 
125a9cf57cfSAxel Dörfler 	ERROR("Resampler::Resampler: source or destination format must be "
126a9cf57cfSAxel Dörfler 		"B_AUDIO_FLOAT\n");
127575526ffSbeveloper }
128575526ffSbeveloper 
129a9cf57cfSAxel Dörfler 
Resampler()13027606daeSAdrien Destugues Resampler::Resampler()
13127606daeSAdrien Destugues 	:
13227606daeSAdrien Destugues 	fFunc(0)
133575526ffSbeveloper {
134575526ffSbeveloper }
135575526ffSbeveloper 
136a9cf57cfSAxel Dörfler 
137