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
22template<typename inType, typename outType, int gnum, int gden,
23	int inMiddle, int outMiddle, int32 min, int32 max> static void
24kernel(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
79Interpolate::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