New upstream version 1.0.0
[fdkaac.git] / src / pcm_native_converter.c
CommitLineData
a7e00a42 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
16static
17inline 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}
26static
27inline 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}
36static
37inline int32_t pcm_s8_to_s32(int8_t n)
38{
39 return n << 24;
40}
41static
42inline int32_t pcm_u8_to_s32(uint8_t n)
43{
44 return (n << 24) ^ 0x80000000;
45}
46static
47inline int32_t pcm_s16le_to_s32(int16_t n)
48{
49 return m4af_ltoh16(n) << 16;
50}
51static
52inline int32_t pcm_s16be_to_s32(int16_t n)
53{
54 return m4af_btoh16(n) << 16;
55}
56static
57inline int32_t pcm_u16le_to_s32(uint16_t n)
58{
59 return (m4af_ltoh16(n) << 16) ^ 0x80000000;
60}
61static
62inline int32_t pcm_u16be_to_s32(uint16_t n)
63{
64 return (m4af_btoh16(n) << 16) ^ 0x80000000;
65}
66static
67inline int32_t pcm_s24le_to_s32(uint8_t *p)
68{
69 return p[0]<<8 | p[1]<<16 | p[2]<<24;
70}
71static
72inline int32_t pcm_s24be_to_s32(uint8_t *p)
73{
74 return p[0]<<24 | p[1]<<16 | p[2]<<8;
75}
76static
77inline int32_t pcm_u24le_to_s32(uint8_t *p)
78{
79 return pcm_s24le_to_s32(p) ^ 0x80000000;
80}
81static
82inline int32_t pcm_u24be_to_s32(uint8_t *p)
83{
84 return pcm_s24be_to_s32(p) ^ 0x80000000;
85}
86static
87inline int32_t pcm_s32le_to_s32(int32_t n)
88{
89 return m4af_ltoh32(n);
90}
91static
92inline int32_t pcm_s32be_to_s32(int32_t n)
93{
94 return m4af_btoh32(n);
95}
96static
97inline int32_t pcm_u32le_to_s32(int32_t n)
98{
99 return m4af_ltoh32(n) ^ 0x80000000;
100}
101static
102inline int32_t pcm_u32be_to_s32(int32_t n)
103{
104 return m4af_btoh32(n) ^ 0x80000000;
105}
106static
107inline float pcm_f32le_to_f32(int32_t n)
108{
109 return pcm_i2f(m4af_ltoh32(n));
110}
111static
112inline float pcm_f32be_to_f32(int32_t n)
113{
114 return pcm_i2f(m4af_btoh32(n));
115}
116static
117inline float pcm_f64le_to_f32(int64_t n)
118{
119 return pcm_i2d(m4af_ltoh64(n));
120}
121static
122inline float pcm_f64be_to_f32(int64_t n)
123{
124 return pcm_i2d(m4af_btoh64(n));
125}
126
127static
128int 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
198typedef 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
206static inline pcm_reader_t *get_source(pcm_reader_t *reader)
207{
208 return ((pcm_native_converter_t *)reader)->src;
209}
210
211static const
212pcm_sample_description_t *get_format(pcm_reader_t *reader)
213{
214 return &((pcm_native_converter_t *)reader)->format;
215}
216
217static int64_t get_length(pcm_reader_t *reader)
218{
219 return pcm_get_length(get_source(reader));
220}
221
222static int64_t get_position(pcm_reader_t *reader)
223{
224 return pcm_get_position(get_source(reader));
225}
226
227static 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
245static 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
254static pcm_reader_vtbl_t my_vtable = {
255 get_format, get_length, get_position, read_frames, teardown
256};
257
258pcm_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.023631 seconds and 4 git commands to generate.