summaryrefslogtreecommitdiff
path: root/resample.c
blob: c77367eb0e4aa31fde2401207f50cf93aeb6bc7c (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
#include "resample.h"

#include <stdint.h>

static GQuark resample_quark() {
	return g_quark_from_string("resample");
}

SRC_STATE *resample_init(int channels, GError **error) {
	int err;
	SRC_STATE *state = src_new(SRC_LINEAR, channels, &err);
	if(!state) {
		*error = g_error_new(resample_quark(), 0, g_strdup(src_strerror(err)));
	}

	return state;
}

void resample(SRC_STATE *state, unsigned int from_rate, unsigned int to_rate, int channels,
		gpointer in_data, gsize in_size, gpointer *out_data, gsize *out_size, gboolean done, GError **error) {
	int len = in_size / 2;
	int frames = in_size / 2 / channels;
	float *temp_in = g_new(float, len);
	float *temp_out = g_new(float, len);

	src_short_to_float_array(in_data, temp_in, len);

	SRC_DATA data = {
		.data_in = temp_in,
		.data_out = temp_out,
		.input_frames = frames,
		.output_frames = frames,
		.src_ratio = (double)to_rate / (double)from_rate,
		.end_of_input = done ? 1 : 0
	};

	int err = src_process(state, &data);
	if(err) {
		*error = g_error_new(resample_quark(), 0, g_strdup(src_strerror(err)));
		goto resample_free;
	}

	*out_data = g_new(int16_t, data.output_frames_gen * channels);
	src_float_to_short_array(temp_out, *out_data, data.output_frames_gen * channels);
	*out_size = sizeof(int16_t) * data.output_frames_gen * channels;

resample_free:
	g_free(temp_in);
	g_free(temp_out);
}

void resample_free(SRC_STATE *state) {
	src_delete(state);
}