1 /* audio.c
2 * stereo->mono downmixing
3 * resampling
4 *
5 * $Id: audio.c,v 1.10 2003/08/01 22:38:04 karl Exp $
6 *
7 * Copyright (c) 2001 Michael Smith <msmith@xiph.org>
8 *
9 * This program is distributed under the terms of the GNU General
10 * Public License, version 2. You may use, modify, and redistribute
11 * it under the terms of this license. A copy should be included
12 * with this source.
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include <config.h>
17 #endif
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "cfgparse.h"
24 #include "audio.h"
25
26 #include "resample.h"
27
28 #define MODULE "audio/"
29 #include "logging.h"
30
downmix_initialise(void)31 downmix_state *downmix_initialise(void) {
32 downmix_state *state = calloc(1, sizeof(downmix_state));
33
34 LOG_INFO0("Enabling stereo->mono downmixing");
35
36 return state;
37 }
38
downmix_clear(downmix_state * s)39 void downmix_clear(downmix_state *s) {
40 if(s) {
41 if (s->buffer)
42 free(s->buffer);
43 free(s);
44 }
45 }
46
downmix_buffer_float(downmix_state * s,float ** buf,int samples)47 void downmix_buffer_float(downmix_state *s, float **buf, int samples)
48 {
49 int i;
50
51 if(samples > s->buflen) {
52 void *tmp = realloc(s->buffer, samples * sizeof(float));
53 if (tmp==NULL)
54 return;
55 s->buffer = tmp;
56 s->buflen = samples;
57 }
58
59 for(i=0; i < samples; i++) {
60 s->buffer[i] = (buf[0][i] + buf[1][i])*0.5;
61 }
62
63 }
64
65
downmix_buffer(downmix_state * s,signed char * buf,int len,int be)66 void downmix_buffer(downmix_state *s, signed char *buf, int len, int be)
67 {
68 int samples = len/4;
69 int i;
70
71 if(samples > s->buflen) {
72 void *tmp = realloc(s->buffer, samples * sizeof(float));
73 if (tmp==NULL)
74 return;
75 s->buffer = tmp;
76 s->buflen = samples;
77 }
78
79 if(be) {
80 for(i=0; i < samples; i++) {
81 s->buffer[i] = (((buf[4*i]<<8) | (buf[4*i + 1]&0xff)) +
82 ((buf[4*i + 2]<<8) | (buf[4*i + 3]&0xff)))/65536.f;
83 }
84 }
85 else {
86 for(i=0; i < samples; i++) {
87 s->buffer[i] = (((buf[4*i + 1]<<8) | (buf[4*i]&0xff)) +
88 ((buf[4*i + 3]<<8) | (buf[4*i + 2]&0xff)))/65536.f;
89 }
90 }
91 }
92
resample_initialise(int channels,int infreq,int outfreq)93 resample_state *resample_initialise(int channels, int infreq, int outfreq)
94 {
95 resample_state *state = calloc(1, sizeof(resample_state));
96 int failed = 1;
97
98 do
99 {
100 if (state==NULL)
101 break;
102 if (resampler_init(&state->resampler, channels, outfreq, infreq, RES_END)) {
103 LOG_ERROR0("Couldn't initialise resampler to specified frequency");
104 return NULL;
105 }
106
107 if ((state->buffers = calloc(channels, sizeof(float *))) == NULL)
108 break;
109 if ((state->convbuf = calloc(channels, sizeof(float *))) == NULL)
110 break;
111 failed = 0;
112 }
113 while (0); /* not a loop */
114
115 if (failed)
116 {
117 LOG_ERROR0("Couldn't initialise resampler due to memory allocation failure");
118 resample_clear (state);
119 return NULL;
120 }
121 state->channels = channels;
122
123 LOG_INFO3("Initialised resampler for %d channels, from %d Hz to %d Hz",
124 channels, infreq, outfreq);
125
126 return state;
127 }
128
resample_clear(resample_state * s)129 void resample_clear(resample_state *s)
130 {
131 int c;
132
133 if(s) {
134 if(s->buffers) {
135 for(c=0; c<s->channels; c++)
136 if (s->buffers[c])
137 free(s->buffers[c]);
138 free(s->buffers);
139 }
140 if(s->convbuf) {
141 for(c=0; c<s->channels; c++)
142 if (s->convbuf[c])
143 free(s->convbuf[c]);
144 free(s->convbuf);
145 }
146 resampler_clear(&s->resampler);
147 free(s);
148 }
149 }
150
resample_buffer(resample_state * s,signed char * buf,int buflen,int be)151 void resample_buffer(resample_state *s, signed char *buf, int buflen, int be)
152 {
153 int c,i;
154 buflen /= 2*s->channels; /* bytes -> samples conversion */
155
156 if(s->convbuflen < buflen) {
157 s->convbuflen = buflen;
158 for(c=0; c < s->channels; c++)
159 s->convbuf[c] = realloc(s->convbuf[c], buflen * sizeof(float));
160 }
161
162 if(be) {
163 for(i=0; i < buflen; i++) {
164 for(c=0; c < s->channels; c++) {
165 s->convbuf[c][i] = ((buf[2*(i*s->channels + c)]<<8) |
166 (0x00ff&(int)buf[2*(i*s->channels + c)+1]))/
167 32768.f;
168 }
169 }
170 }
171 else {
172 for(i=0; i < buflen; i++) {
173 for(c=0; c < s->channels; c++) {
174 s->convbuf[c][i] = ((buf[2*(i*s->channels + c) + 1]<<8) |
175 (0x00ff&(int)buf[2*(i*s->channels + c)]))/
176 32768.f;
177 }
178 }
179 }
180
181 resample_buffer_float(s, s->convbuf, buflen);
182 }
183
resample_buffer_float(resample_state * s,float ** buf,int buflen)184 void resample_buffer_float(resample_state *s, float **buf, int buflen)
185 {
186 int c;
187 int res;
188
189 s->buffill = resampler_push_check(&s->resampler, buflen);
190 if(s->buffill <= 0) {
191 LOG_ERROR1("Fatal reencoding error: resampler_push_check returned %d",
192 s->buffill);
193 }
194
195 if(s->bufsize < s->buffill) {
196 s->bufsize = s->buffill;
197 for(c=0; c<s->channels; c++)
198 s->buffers[c] = realloc(s->buffers[c], s->bufsize * sizeof(float));
199 }
200
201 if((res = resampler_push(&s->resampler, s->buffers, (float const **)buf, buflen))
202 != s->buffill) {
203 LOG_ERROR2("Internal error in resampling: returned number of samples %d"
204 ", expected %d", res, s->buffill);
205 s->buffill = res;
206 return;
207 }
208
209 }
210
resample_finish(resample_state * s)211 void resample_finish(resample_state *s)
212 {
213 int ret;
214
215 if(!s->buffers[0])
216 return;
217
218 ret = resampler_drain(&s->resampler, s->buffers);
219
220 if(ret > s->bufsize) {
221 LOG_ERROR0("Fatal error in resampler: buffers too small");
222 return;
223 }
224
225 s->buffill = ret;
226 }
227