xref: /haiku/src/add-ons/media/media-add-ons/mixer/Interpolate.cpp (revision 0604d554e86e2efd500ad49d12388258bb994dbe)
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,
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 	float oldSample = ((Interpolate*)object)->fOldSample;
52 
53 	#define SRC *(const inType*)(src)
54 
55 	while (count--) {
56 		float tmp = (gain * (oldSample + (SRC - oldSample) * current - inMiddle)
57 			+ outMiddle);
58 		if (tmp <= min)
59 			*(outType *)dest = min;
60 		else if (tmp >= max)
61 			*(outType *)dest = max;
62 		else
63 			*(outType *)dest = (outType)tmp;
64 
65 		dest += destSampleOffset;
66 		current += delta;
67 		if (current >= 1.0f) {
68 			double ipart;
69 			current = modf(current, &ipart);
70 			oldSample = SRC;
71 			src += srcSampleOffset * (int)ipart;
72 		}
73 	}
74 
75 	((Interpolate*)object)->fOldSample = oldSample;
76 }
77 
78 
79 Interpolate::Interpolate(uint32 src_format, uint32 dst_format)
80 	:
81 	Resampler(),
82 	fOldSample(0)
83 {
84 	if (src_format == media_raw_audio_format::B_AUDIO_UCHAR)
85 		fOldSample = 128;
86 
87 	if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) {
88 		switch (src_format) {
89 			case media_raw_audio_format::B_AUDIO_FLOAT:
90 				fFunc = &kernel<float, float, 1, 1, 0, 0, -1, 1>;
91 				return;
92 			case media_raw_audio_format::B_AUDIO_INT:
93 				fFunc = &kernel<int32, float, 1, INT32_MAX, 0, 0, -1, 1>;
94 				return;
95 			case media_raw_audio_format::B_AUDIO_SHORT:
96 				fFunc = &kernel<int16, float, 1, INT16_MAX, 0, 0, -1, 1>;
97 				return;
98 			case media_raw_audio_format::B_AUDIO_CHAR:
99 				fFunc = &kernel<int8, float, 1, INT8_MAX, 0, 0, -1, 1>;
100 				return;
101 			case media_raw_audio_format::B_AUDIO_UCHAR:
102 				fFunc = &kernel<uint8, float, 2, UINT8_MAX, 128, 0, -1, 1>;
103 				return;
104 			default:
105 				ERROR("Resampler::Resampler: unknown source format 0x%x\n",
106 					src_format);
107 				return;
108 		}
109 	}
110 
111 	if (src_format == media_raw_audio_format::B_AUDIO_FLOAT) {
112 		switch (dst_format) {
113 			// float=>float already handled above
114 			case media_raw_audio_format::B_AUDIO_INT:
115 				fFunc = &kernel<float, int32, INT32_MAX, 1, 0, 0,
116 					INT32_MIN, INT32_MAX>;
117 				return;
118 			case media_raw_audio_format::B_AUDIO_SHORT:
119 				fFunc = &kernel<float, int16, INT16_MAX, 1, 0, 0,
120 					INT16_MIN, INT16_MAX>;
121 				return;
122 			case media_raw_audio_format::B_AUDIO_CHAR:
123 				fFunc = &kernel<float, int8, INT8_MAX, 1, 0, 0,
124 					INT8_MIN, INT8_MAX>;
125 				return;
126 			case media_raw_audio_format::B_AUDIO_UCHAR:
127 				fFunc = &kernel<float, uint8, UINT8_MAX, 2, 0, 128,
128 					0, UINT8_MAX>;
129 				return;
130 			default:
131 				ERROR("Resampler::Resampler: unknown destination format 0x%x\n",
132 					dst_format);
133 				return;
134 		}
135 	}
136 
137 	ERROR("Resampler::Resampler: source or destination format must be "
138 		"B_AUDIO_FLOAT\n");
139 }
140 
141 
142