refactor pcm reader framework
[fdkaac.git] / src / pcm_native_converter.c
1 /*
2 * Copyright (C) 2013 nu774
3 * For conditions of distribution and use, see copyright notice in COPYING
4 */
5 #if HAVE_CONFIG_H
6 # include "config.h"
7 #endif
8 #include <stdlib.h>
9 #include <string.h>
10 #if HAVE_STDINT_H
11 # include <stdint.h>
12 #endif
13 #include "m4af_endian.h"
14 #include "pcm_reader.h"
15
16 static
17 inline float pcm_i2f(int32_t n)
18 {
19 union {
20 int32_t ivalue;
21 float fvalue;
22 } u;
23 u.ivalue = n;
24 return u.fvalue;
25 }
26 static
27 inline double pcm_i2d(int64_t n)
28 {
29 union {
30 int64_t ivalue;
31 double fvalue;
32 } u;
33 u.ivalue = n;
34 return u.fvalue;
35 }
36 static
37 inline int32_t pcm_s8_to_s32(int8_t n)
38 {
39 return n << 24;
40 }
41 static
42 inline int32_t pcm_u8_to_s32(uint8_t n)
43 {
44 return (n << 24) ^ 0x80000000;
45 }
46 static
47 inline int32_t pcm_s16le_to_s32(int16_t n)
48 {
49 return m4af_ltoh16(n) << 16;
50 }
51 static
52 inline int32_t pcm_s16be_to_s32(int16_t n)
53 {
54 return m4af_btoh16(n) << 16;
55 }
56 static
57 inline int32_t pcm_u16le_to_s32(uint16_t n)
58 {
59 return (m4af_ltoh16(n) << 16) ^ 0x80000000;
60 }
61 static
62 inline int32_t pcm_u16be_to_s32(uint16_t n)
63 {
64 return (m4af_btoh16(n) << 16) ^ 0x80000000;
65 }
66 static
67 inline int32_t pcm_s24le_to_s32(uint8_t *p)
68 {
69 return p[0]<<8 | p[1]<<16 | p[2]<<24;
70 }
71 static
72 inline int32_t pcm_s24be_to_s32(uint8_t *p)
73 {
74 return p[0]<<24 | p[1]<<16 | p[2]<<8;
75 }
76 static
77 inline int32_t pcm_u24le_to_s32(uint8_t *p)
78 {
79 return pcm_s24le_to_s32(p) ^ 0x80000000;
80 }
81 static
82 inline int32_t pcm_u24be_to_s32(uint8_t *p)
83 {
84 return pcm_s24be_to_s32(p) ^ 0x80000000;
85 }
86 static
87 inline int32_t pcm_s32le_to_s32(int32_t n)
88 {
89 return m4af_ltoh32(n);
90 }
91 static
92 inline int32_t pcm_s32be_to_s32(int32_t n)
93 {
94 return m4af_btoh32(n);
95 }
96 static
97 inline int32_t pcm_u32le_to_s32(int32_t n)
98 {
99 return m4af_ltoh32(n) ^ 0x80000000;
100 }
101 static
102 inline int32_t pcm_u32be_to_s32(int32_t n)
103 {
104 return m4af_btoh32(n) ^ 0x80000000;
105 }
106 static
107 inline float pcm_f32le_to_f32(int32_t n)
108 {
109 return pcm_i2f(m4af_ltoh32(n));
110 }
111 static
112 inline float pcm_f32be_to_f32(int32_t n)
113 {
114 return pcm_i2f(m4af_btoh32(n));
115 }
116 static
117 inline float pcm_f64le_to_f32(int64_t n)
118 {
119 return pcm_i2d(m4af_ltoh64(n));
120 }
121 static
122 inline float pcm_f64be_to_f32(int64_t n)
123 {
124 return pcm_i2d(m4af_btoh64(n));
125 }
126
127 static
128 int pcm_convert_to_native(const pcm_sample_description_t *format,
129 const void *input, uint32_t nframes,
130 void *result)
131 {
132 #define CONVERT(type, rtype, conv) \
133 do { \
134 unsigned i; \
135 type *ip = (type *)input; \
136 for (i = 0; i < count; ++i) { \
137 ((rtype *)result)[i] = conv(ip[i]); \
138 } \
139 } while(0)
140
141 #define CONVERT_BYTES(rtype, conv) \
142 do { \
143 unsigned i, bytes_per_channel; \
144 uint8_t *ip = (uint8_t *)input; \
145 bytes_per_channel = PCM_BYTES_PER_CHANNEL(format); \
146 for (i = 0; i < count; ++i) { \
147 ((rtype *)result)[i] = conv(ip); \
148 ip += bytes_per_channel; \
149 } \
150 } while(0)
151
152 uint32_t count = nframes * format->channels_per_frame;
153 if (!count)
154 return 0;
155 switch (PCM_BYTES_PER_CHANNEL(format) | format->sample_type<<4) {
156 case 1 | PCM_TYPE_SINT<<4:
157 CONVERT(int8_t, int32_t, pcm_s8_to_s32); break;
158 case 1 | PCM_TYPE_UINT<<4:
159 CONVERT(uint8_t, int32_t, pcm_u8_to_s32); break;
160 case 2 | PCM_TYPE_SINT<<4:
161 CONVERT(int16_t, int32_t, pcm_s16le_to_s32); break;
162 case 2 | PCM_TYPE_UINT<<4:
163 CONVERT(uint16_t, int32_t, pcm_u16le_to_s32); break;
164 case 2 | PCM_TYPE_SINT_BE<<4:
165 CONVERT(int16_t, int32_t, pcm_s16be_to_s32); break;
166 case 2 | PCM_TYPE_UINT_BE<<4:
167 CONVERT(int16_t, int32_t, pcm_u16be_to_s32); break;
168 case 3 | PCM_TYPE_SINT<<4:
169 CONVERT_BYTES(int32_t, pcm_s24le_to_s32); break;
170 case 3 | PCM_TYPE_UINT<<4:
171 CONVERT_BYTES(int32_t, pcm_u24le_to_s32); break;
172 case 3 | PCM_TYPE_SINT_BE<<4:
173 CONVERT_BYTES(int32_t, pcm_s24be_to_s32); break;
174 case 3 | PCM_TYPE_UINT_BE<<4:
175 CONVERT_BYTES(int32_t, pcm_u24be_to_s32); break;
176 case 4 | PCM_TYPE_SINT<<4:
177 CONVERT(int32_t, int32_t, pcm_s32le_to_s32); break;
178 case 4 | PCM_TYPE_UINT<<4:
179 CONVERT(uint32_t, int32_t, pcm_u32le_to_s32); break;
180 case 4 | PCM_TYPE_FLOAT<<4:
181 CONVERT(int32_t, float, pcm_f32le_to_f32); break;
182 case 4 | PCM_TYPE_SINT_BE<<4:
183 CONVERT(int32_t, int32_t, pcm_s32be_to_s32); break;
184 case 4 | PCM_TYPE_UINT_BE<<4:
185 CONVERT(uint32_t, int32_t, pcm_u32be_to_s32); break;
186 case 4 | PCM_TYPE_FLOAT_BE<<4:
187 CONVERT(int32_t, float, pcm_f32be_to_f32); break;
188 case 8 | PCM_TYPE_FLOAT<<4:
189 CONVERT(int64_t, float, pcm_f64le_to_f32); break;
190 case 8 | PCM_TYPE_FLOAT_BE<<4:
191 CONVERT(int64_t, float, pcm_f64be_to_f32); break;
192 default:
193 return -1;
194 }
195 return 0;
196 }
197
198 typedef struct pcm_native_converter_t {
199 pcm_reader_vtbl_t *vtbl;
200 pcm_reader_t *src;
201 pcm_sample_description_t format;
202 void *pivot;
203 unsigned capacity;
204 } pcm_native_converter_t;
205
206 static inline pcm_reader_t *get_source(pcm_reader_t *reader)
207 {
208 return ((pcm_native_converter_t *)reader)->src;
209 }
210
211 static const
212 pcm_sample_description_t *get_format(pcm_reader_t *reader)
213 {
214 return &((pcm_native_converter_t *)reader)->format;
215 }
216
217 static int64_t get_length(pcm_reader_t *reader)
218 {
219 return pcm_get_length(get_source(reader));
220 }
221
222 static int64_t get_position(pcm_reader_t *reader)
223 {
224 return pcm_get_position(get_source(reader));
225 }
226
227 static int read_frames(pcm_reader_t *reader, void *buffer, unsigned nframes)
228 {
229 pcm_native_converter_t *self = (pcm_native_converter_t *)reader;
230 const pcm_sample_description_t *sfmt = pcm_get_format(self->src);
231 unsigned bytes = nframes * sfmt->bytes_per_frame;
232
233 if (self->capacity < bytes) {
234 void *p = realloc(self->pivot, bytes);
235 if (!p) return -1;
236 self->pivot = p;
237 self->capacity = bytes;
238 }
239 nframes = pcm_read_frames(self->src, self->pivot, nframes);
240 if (pcm_convert_to_native(sfmt, self->pivot, nframes, buffer) < 0)
241 return -1;
242 return nframes;
243 }
244
245 static void teardown(pcm_reader_t **reader)
246 {
247 pcm_native_converter_t *self = (pcm_native_converter_t *)*reader;
248 pcm_teardown(&self->src);
249 free(self->pivot);
250 free(self);
251 *reader = 0;
252 }
253
254 static pcm_reader_vtbl_t my_vtable = {
255 get_format, get_length, get_position, read_frames, teardown
256 };
257
258 pcm_reader_t *pcm_open_native_converter(pcm_reader_t *reader)
259 {
260 pcm_native_converter_t *self = 0;
261 pcm_sample_description_t *fmt;
262
263 if ((self = calloc(1, sizeof(pcm_native_converter_t))) == 0)
264 return 0;
265 self->src = reader;
266 self->vtbl = &my_vtable;
267 memcpy(&self->format, pcm_get_format(reader), sizeof(self->format));
268 fmt = &self->format;
269 fmt->sample_type = PCM_IS_FLOAT(fmt) ? PCM_TYPE_FLOAT : PCM_TYPE_SINT;
270 fmt->bytes_per_frame = 4 * fmt->channels_per_frame;
271 return (pcm_reader_t *)self;
272 }
This page took 0.029858 seconds and 4 git commands to generate.