aboutsummaryrefslogtreecommitdiff
path: root/sound/rate.h
blob: 31f90dc5f8902f36b2779c5f342e940e613529b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// HACK: Instead of using the full st_i.h (and then st.h and stconfig.h etc.)
// from SoX, we use this minimal variant which is just sufficient to make
// resample.c and rate.c compile.

#ifndef RATE_H
#define RATE_H

#include <stdio.h>
#include <assert.h>
#include "common/scummsys.h"
#include "common/engine.h"
#include "common/util.h"

#include "audiostream.h"

typedef int16 st_sample_t;
typedef uint16 st_volume_t;
typedef uint32 st_size_t;
typedef uint32 st_rate_t;

typedef struct {
	byte priv[1024];
} eff_struct;
typedef eff_struct *eff_t;

/* Minimum and maximum values a sample can hold. */
#define ST_SAMPLE_MAX 0x7fffL
#define ST_SAMPLE_MIN (-ST_SAMPLE_MAX - 1L)

#define ST_EOF (-1)
#define ST_SUCCESS (0)

static inline void clampedAdd(int16& a, int b) {
	int val = a + b;

	if (val > ST_SAMPLE_MAX)
		a = ST_SAMPLE_MAX;
	else if (val < ST_SAMPLE_MIN)
		a = ST_SAMPLE_MIN;
	else
		a = val;
}

// Q&D hack to get this SOX stuff to work
#define st_report warning
#define st_warn warning
#define st_fail error


class RateConverter {
protected:
	eff_struct effp;
public:
	RateConverter() {}
	virtual ~RateConverter() {}
	virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) = 0;
	virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) = 0;
};

class LinearRateConverter : public RateConverter {
public:
	LinearRateConverter(st_rate_t inrate, st_rate_t outrate);
	virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol);
	virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol);
};

class ResampleRateConverter : public RateConverter {
public:
	ResampleRateConverter(st_rate_t inrate, st_rate_t outrate, int quality);
	~ResampleRateConverter();
	virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol);
	virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol);
};

template<bool stereo>
class CopyRateConverter : public RateConverter {
public:
	virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) {
		int16 tmp;
		st_size_t len = *osamp;
		assert(input.isStereo() == stereo);
		while (!input.eof() && len--) {
			tmp = input.read() * vol / 256;
			clampedAdd(*obuf++, tmp);
			if (stereo)
				tmp = input.read() * vol / 256;
			clampedAdd(*obuf++, tmp);
		}
		return (ST_SUCCESS);
	}
	virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) {
		return (ST_SUCCESS);
	}
};

static inline RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo) {
//	printf("makeRateConverter: inrate %d, outrate %d\n", inrate, outrate);
	if (inrate != outrate) {
		return new LinearRateConverter(inrate, outrate);
		//return new ResampleRateConverter(inrate, outrate, 1);
	} else {
		if (stereo)
			return new CopyRateConverter<true>();
		else
			return new CopyRateConverter<false>();
	}
}

#endif