xref: /haiku/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp (revision 71452e98334eaac603bf542d159e24788a46bebb)
1 /*
2  * Copyright 2010-2014 Haiku, inc.
3  * Distributed under the terms of the MIT Licence.
4  *
5  * Author: Adrien Destugues <pulkomandy@pulkomandy.tk>
6  */
7 
8 
9 #include "Interpolate.h"
10 
11 #include <cmath>
12 
13 #include <MediaDefs.h>
14 
15 #include "MixerDebug.h"
16 
17 
18 /*! Resampling class doing linear interpolation.
19 */
20 
21 
22 template<typename inType, typename outType, int gnum, int gden, int offset,
23 	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 	register const char * src = (const char *)_src;
29 	register char * dest = (char *)_dest;
30 	register int32 count = destSampleCount;
31 	register 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 * gain + offset;
37 			if (tmp < min) tmp = min;
38 			if (tmp > max) tmp = max;
39 			*(outType *)dest = (outType)tmp;
40 			src += srcSampleOffset;
41 			dest += destSampleOffset;
42 		}
43 		return;
44 	}
45 
46 	register float delta = float(srcSampleCount) / float(destSampleCount);
47 	register float current = 0.0f;
48 	float oldSample = ((Interpolate*)object)->fOldSample;
49 
50 	#define SRC *(const inType*)(src)
51 
52 	while (count--) {
53 		float tmp = (gain * (oldSample + (SRC - oldSample) * current) + offset);
54 		if (tmp < min) tmp = min;
55 		if (tmp > max) tmp = max;
56 		*(outType *)dest = (outType)tmp;
57 
58 		dest += destSampleOffset;
59 		current += delta;
60 		if (current >= 1.0f) {
61 			double ipart;
62 			current = modf(current, &ipart);
63 			oldSample = SRC;
64 			src += srcSampleOffset * (int)ipart;
65 		}
66 	}
67 
68 	((Interpolate*)object)->fOldSample = oldSample;
69 }
70 
71 
72 Interpolate::Interpolate(uint32 src_format, uint32 dst_format)
73 	:
74 	Resampler(),
75 	fOldSample(0)
76 {
77 	if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) {
78 		switch (src_format) {
79 			case media_raw_audio_format::B_AUDIO_FLOAT:
80 				fFunc = &kernel<float, float, 1, 1, 0, -1, 1>;
81 				return;
82 			case media_raw_audio_format::B_AUDIO_INT:
83 				fFunc = &kernel<int32, float, 1, INT32_MAX, 0, -1, 1>;
84 				return;
85 			case media_raw_audio_format::B_AUDIO_SHORT:
86 				fFunc = &kernel<int16, float, 1, INT16_MAX, 0, -1, 1>;
87 				return;
88 			case media_raw_audio_format::B_AUDIO_CHAR:
89 				fFunc = &kernel<int8, float, 1, INT8_MAX, 0, -1, 1>;
90 				return;
91 			case media_raw_audio_format::B_AUDIO_UCHAR:
92 				fFunc = &kernel<uint8, float, 2, UINT8_MAX, -128, -1, 1>;
93 				return;
94 			default:
95 				ERROR("Resampler::Resampler: unknown source format 0x%x\n",
96 					src_format);
97 				return;
98 		}
99 	}
100 
101 	if (src_format == media_raw_audio_format::B_AUDIO_FLOAT) {
102 		switch (dst_format) {
103 			// float=>float already handled above
104 			case media_raw_audio_format::B_AUDIO_INT:
105 				fFunc = &kernel<float, int32, INT32_MAX, 1, 0,
106 					INT32_MIN, INT32_MAX>;
107 				return;
108 			case media_raw_audio_format::B_AUDIO_SHORT:
109 				fFunc = &kernel<float, int16, INT16_MAX, 1, 0,
110 					INT16_MIN, INT16_MAX>;
111 				return;
112 			case media_raw_audio_format::B_AUDIO_CHAR:
113 				fFunc = &kernel<float, int8, INT8_MAX, 1, 0,
114 					INT8_MIN, INT8_MAX>;
115 				return;
116 			case media_raw_audio_format::B_AUDIO_UCHAR:
117 				fFunc = &kernel<float, uint8, UINT8_MAX, 2, 1,
118 					0, UINT8_MAX>;
119 				return;
120 			default:
121 				ERROR("Resampler::Resampler: unknown destination format 0x%x\n",
122 					dst_format);
123 				return;
124 		}
125 	}
126 
127 	ERROR("Resampler::Resampler: source or destination format must be "
128 		"B_AUDIO_FLOAT\n");
129 }
130 
131 
132