source: mainline/uspace/lib/pcm/src/format.c@ fe0b448

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fe0b448 was fe0b448, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

libpcm: Move constant definitions to .c file

  • Property mode set to 100644
File size: 8.7 KB
Line 
1/*
2 * Copyright (c) 2012 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup audio
30 * @brief HelenOS sound server
31 * @{
32 */
33/** @file
34 */
35
36#include <assert.h>
37#include <byteorder.h>
38#include <errno.h>
39#include <macros.h>
40#include <stdio.h>
41
42#include "format.h"
43
44#define uint8_t_le2host(x) (x)
45#define host2uint8_t_le(x) (x)
46#define uint8_t_be2host(x) (x)
47#define host2uint8_t_be(x) (x)
48
49#define int8_t_le2host(x) (x)
50#define host2int8_t_le(x) (x)
51
52#define int16_t_le2host(x) uint16_t_le2host(x)
53#define host2int16_t_le(x) host2uint16_t_le(x)
54
55#define int32_t_le2host(x) uint32_t_le2host(x)
56#define host2int32_t_le(x) host2uint32_t_le(x)
57
58#define int8_t_be2host(x) (x)
59#define host2int8_t_be(x) (x)
60
61#define int16_t_be2host(x) uint16_t_be2host(x)
62#define host2int16_t_be(x) host2uint16_t_be(x)
63
64#define int32_t_be2host(x) uint32_t_be2host(x)
65#define host2int32_t_be(x) host2uint32_t_be(x)
66
67// TODO float endian?
68#define float_le2host(x) (x)
69#define float_be2host(x) (x)
70
71#define host2float_le(x) (x)
72#define host2float_be(x) (x)
73
74#define from(x, type, endian) (float)(type ## _ ## endian ## 2host(x))
75#define to(x, type, endian) (float)(host2 ## type ## _ ## endian(x))
76
77const pcm_format_t AUDIO_FORMAT_DEFAULT = {
78 .channels = 2,
79 .sampling_rate = 44100,
80 .sample_format = PCM_SAMPLE_SINT16_LE,
81 };
82
83const pcm_format_t AUDIO_FORMAT_ANY = {
84 .channels = 0,
85 .sampling_rate = 0,
86 .sample_format = 0,
87 };
88
89static float get_normalized_sample(const void *buffer, size_t size,
90 unsigned frame, unsigned channel, const pcm_format_t *f);
91
92bool pcm_format_same(const pcm_format_t *a, const pcm_format_t* b)
93{
94 assert(a);
95 assert(b);
96 return
97 a->sampling_rate == b->sampling_rate &&
98 a->channels == b->channels &&
99 a->sample_format == b->sample_format;
100}
101
102void pcm_format_silence(void *dst, size_t size, const pcm_format_t *f)
103{
104#define SET_NULL(type, endian, nullv) \
105do { \
106 type *buffer = dst; \
107 const size_t sample_count = size / sizeof(type); \
108 for (unsigned i = 0; i < sample_count; ++i) { \
109 buffer[i] = to((type)nullv, type, endian); \
110 } \
111} while (0)
112
113 switch (f->sample_format) {
114 case PCM_SAMPLE_UINT8:
115 SET_NULL(uint8_t, le, INT8_MIN); break;
116 case PCM_SAMPLE_SINT8:
117 SET_NULL(int8_t, le, 0); break;
118 case PCM_SAMPLE_UINT16_LE:
119 SET_NULL(uint16_t, le, INT16_MIN); break;
120 case PCM_SAMPLE_SINT16_LE:
121 SET_NULL(int16_t, le, 0); break;
122 case PCM_SAMPLE_UINT16_BE:
123 SET_NULL(uint16_t, be, INT16_MIN); break;
124 case PCM_SAMPLE_SINT16_BE:
125 SET_NULL(int16_t, be, 0); break;
126 case PCM_SAMPLE_UINT32_LE:
127 SET_NULL(uint32_t, le, INT32_MIN); break;
128 case PCM_SAMPLE_SINT32_LE:
129 SET_NULL(int32_t, le, 0); break;
130 case PCM_SAMPLE_UINT32_BE:
131 SET_NULL(uint32_t, be, INT32_MIN); break;
132 case PCM_SAMPLE_SINT32_BE:
133 SET_NULL(int32_t, le, 0); break;
134 case PCM_SAMPLE_UINT24_32_LE:
135 case PCM_SAMPLE_SINT24_32_LE:
136 case PCM_SAMPLE_UINT24_32_BE:
137 case PCM_SAMPLE_SINT24_32_BE:
138 case PCM_SAMPLE_UINT24_LE:
139 case PCM_SAMPLE_SINT24_LE:
140 case PCM_SAMPLE_UINT24_BE:
141 case PCM_SAMPLE_SINT24_BE:
142 case PCM_SAMPLE_FLOAT32:
143 default: ;
144 }
145#undef SET_NULL
146}
147
148int pcm_format_mix(void *dst, const void *src, size_t size, const pcm_format_t *f)
149{
150 return pcm_format_convert_and_mix(dst, size, src, size, f, f);
151}
152int pcm_format_convert_and_mix(void *dst, size_t dst_size, const void *src,
153 size_t src_size, const pcm_format_t *sf, const pcm_format_t *df)
154{
155 if (!dst || !src || !sf || !df)
156 return EINVAL;
157 const size_t src_frame_size = pcm_format_frame_size(sf);
158 if ((src_size % src_frame_size) != 0)
159 return EINVAL;
160
161 const size_t dst_frame_size = pcm_format_frame_size(df);
162 if ((src_size % dst_frame_size) != 0)
163 return EINVAL;
164
165 /* This is so ugly it eats kittens, and puppies, and ducklings,
166 * and all little fluffy things...
167 */
168#define LOOP_ADD(type, endian, low, high) \
169do { \
170 const unsigned frame_count = dst_size / dst_frame_size; \
171 for (size_t i = 0; i < frame_count; ++i) { \
172 for (unsigned j = 0; j < df->channels; ++j) { \
173 const float a = \
174 get_normalized_sample(dst, dst_size, i, j, df);\
175 const float b = \
176 get_normalized_sample(src, src_size, i, j, sf);\
177 float c = (a + b); \
178 if (c < -1.0) c = -1.0; \
179 if (c > 1.0) c = 1.0; \
180 c += 1.0; \
181 c *= ((float)(type)high - (float)(type)low) / 2; \
182 c += (float)(type)low; \
183 type *dst_buf = dst; \
184 const unsigned pos = i * df->channels + j; \
185 if (pos < (dst_size / sizeof(type))) \
186 dst_buf[pos] = to((type)c, type, endian); \
187 } \
188 } \
189} while (0)
190
191 switch (df->sample_format) {
192 case PCM_SAMPLE_UINT8:
193 LOOP_ADD(uint8_t, le, UINT8_MIN, UINT8_MAX); break;
194 case PCM_SAMPLE_SINT8:
195 LOOP_ADD(uint8_t, le, INT8_MIN, INT8_MAX); break;
196 case PCM_SAMPLE_UINT16_LE:
197 LOOP_ADD(uint16_t, le, UINT16_MIN, UINT16_MAX); break;
198 case PCM_SAMPLE_SINT16_LE:
199 LOOP_ADD(int16_t, le, INT16_MIN, INT16_MAX); break;
200 case PCM_SAMPLE_UINT16_BE:
201 LOOP_ADD(uint16_t, be, UINT16_MIN, UINT16_MAX); break;
202 case PCM_SAMPLE_SINT16_BE:
203 LOOP_ADD(int16_t, be, INT16_MIN, INT16_MAX); break;
204 case PCM_SAMPLE_UINT24_32_LE:
205 case PCM_SAMPLE_UINT32_LE: // TODO this are not right for 24bit
206 LOOP_ADD(uint32_t, le, UINT32_MIN, UINT32_MAX); break;
207 case PCM_SAMPLE_SINT24_32_LE:
208 case PCM_SAMPLE_SINT32_LE:
209 LOOP_ADD(int32_t, le, INT32_MIN, INT32_MAX); break;
210 case PCM_SAMPLE_UINT24_32_BE:
211 case PCM_SAMPLE_UINT32_BE:
212 LOOP_ADD(uint32_t, be, UINT32_MIN, UINT32_MAX); break;
213 case PCM_SAMPLE_SINT24_32_BE:
214 case PCM_SAMPLE_SINT32_BE:
215 LOOP_ADD(int32_t, be, INT32_MIN, INT32_MAX); break;
216 case PCM_SAMPLE_UINT24_LE:
217 case PCM_SAMPLE_SINT24_LE:
218 case PCM_SAMPLE_UINT24_BE:
219 case PCM_SAMPLE_SINT24_BE:
220 case PCM_SAMPLE_FLOAT32:
221 default:
222 return ENOTSUP;
223 }
224 return EOK;
225#undef LOOP_ADD
226}
227
228/** Converts all sample formats to float <-1,1> */
229static float get_normalized_sample(const void *buffer, size_t size,
230 unsigned frame, unsigned channel, const pcm_format_t *f)
231{
232 assert(f);
233 assert(buffer);
234 if (channel >= f->channels)
235 return 0.0f;
236#define GET(type, endian, low, high) \
237do { \
238 const type *src = buffer; \
239 const size_t sample_count = size / sizeof(type); \
240 const size_t sample_pos = frame * f->channels + channel; \
241 if (sample_pos >= sample_count) {\
242 return 0.0f; \
243 } \
244 float sample = from(src[sample_pos], type, endian); \
245 /* This makes it positive */ \
246 sample -= (float)(type)low; \
247 /* This makes it <0,2> */ \
248 sample /= (((float)(type)high - (float)(type)low) / 2.0f); \
249 return sample - 1.0f; \
250} while (0)
251
252 switch (f->sample_format) {
253 case PCM_SAMPLE_UINT8:
254 GET(uint8_t, le, UINT8_MIN, UINT8_MAX);
255 case PCM_SAMPLE_SINT8:
256 GET(int8_t, le, INT8_MIN, INT8_MAX);
257 case PCM_SAMPLE_UINT16_LE:
258 GET(uint16_t, le, UINT16_MIN, UINT16_MAX);
259 case PCM_SAMPLE_SINT16_LE:
260 GET(int16_t, le, INT16_MIN, INT16_MAX);
261 case PCM_SAMPLE_UINT16_BE:
262 GET(uint16_t, be, UINT16_MIN, UINT16_MAX);
263 case PCM_SAMPLE_SINT16_BE:
264 GET(int16_t, be, INT16_MIN, INT16_MAX);
265 case PCM_SAMPLE_UINT24_32_LE:
266 case PCM_SAMPLE_UINT32_LE:
267 GET(uint32_t, le, UINT32_MIN, UINT32_MAX);
268 case PCM_SAMPLE_SINT24_32_LE:
269 case PCM_SAMPLE_SINT32_LE:
270 GET(int32_t, le, INT32_MIN, INT32_MAX);
271 case PCM_SAMPLE_UINT24_32_BE:
272 case PCM_SAMPLE_UINT32_BE:
273 GET(uint32_t, be, UINT32_MIN, UINT32_MAX);
274 case PCM_SAMPLE_SINT24_32_BE:
275 case PCM_SAMPLE_SINT32_BE:
276 GET(int32_t, le, INT32_MIN, INT32_MAX);
277 case PCM_SAMPLE_UINT24_LE:
278 case PCM_SAMPLE_SINT24_LE:
279 case PCM_SAMPLE_UINT24_BE:
280 case PCM_SAMPLE_SINT24_BE:
281 case PCM_SAMPLE_FLOAT32:
282 default: ;
283 }
284 return 0;
285#undef GET
286}
287/**
288 * @}
289 */
Note: See TracBrowser for help on using the repository browser.