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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b3c39690 was 5cbccd4, checked in by Ondřej Hlavatý <aearsis@…>, 9 years ago

xhci: register structures

  • Property mode set to 100644
File size: 10.0 KB
RevLine 
[737b4c0]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>
[43c40a3]39#include <macros.h>
[bb67def]40#include <stdio.h>
[737b4c0]41
[ea6c838]42#include "format.h"
[737b4c0]43
[43c40a3]44#define int8_t_le2host(x) (x)
45#define host2int8_t_le(x) (x)
46
47#define int16_t_le2host(x) uint16_t_le2host(x)
48#define host2int16_t_le(x) host2uint16_t_le(x)
49
50#define int32_t_le2host(x) uint32_t_le2host(x)
51#define host2int32_t_le(x) host2uint32_t_le(x)
52
53#define int8_t_be2host(x) (x)
54#define host2int8_t_be(x) (x)
55
56#define int16_t_be2host(x) uint16_t_be2host(x)
57#define host2int16_t_be(x) host2uint16_t_be(x)
58
59#define int32_t_be2host(x) uint32_t_be2host(x)
60#define host2int32_t_be(x) host2uint32_t_be(x)
61
[bb67def]62// TODO float endian?
63#define float_le2host(x) (x)
64#define float_be2host(x) (x)
65
66#define host2float_le(x) (x)
67#define host2float_be(x) (x)
68
69#define from(x, type, endian) (float)(type ## _ ## endian ## 2host(x))
70#define to(x, type, endian) (float)(host2 ## type ## _ ## endian(x))
71
[b1dfe13]72/** Default linear PCM format */
[fe0b448]73const pcm_format_t AUDIO_FORMAT_DEFAULT = {
74 .channels = 2,
75 .sampling_rate = 44100,
76 .sample_format = PCM_SAMPLE_SINT16_LE,
77 };
78
[b1dfe13]79/** Special ANY PCM format.
80 * This format is used if the real format is no know or important.
81 */
[fe0b448]82const pcm_format_t AUDIO_FORMAT_ANY = {
83 .channels = 0,
84 .sampling_rate = 0,
85 .sample_format = 0,
86 };
87
[bb67def]88static float get_normalized_sample(const void *buffer, size_t size,
[ea6c838]89 unsigned frame, unsigned channel, const pcm_format_t *f);
[bb67def]90
[5a6f362]91/**
92 * Compare PCM format attribtues.
93 * @param a Format description.
94 * @param b Format description.
95 * @return True if a and b describe the same format, false otherwise.
96 */
[ea6c838]97bool pcm_format_same(const pcm_format_t *a, const pcm_format_t* b)
[737b4c0]98{
99 assert(a);
100 assert(b);
101 return
102 a->sampling_rate == b->sampling_rate &&
103 a->channels == b->channels &&
104 a->sample_format == b->sample_format;
105}
106
[5a6f362]107/**
108 * Fill audio buffer with silence in the specified format.
109 * @param dst Destination audio buffer.
110 * @param size Size of the destination audio buffer.
111 * @param f Pointer to the format description.
112 */
[e6bba8f]113void pcm_format_silence(void *dst, size_t size, const pcm_format_t *f)
114{
115#define SET_NULL(type, endian, nullv) \
116do { \
117 type *buffer = dst; \
118 const size_t sample_count = size / sizeof(type); \
119 for (unsigned i = 0; i < sample_count; ++i) { \
120 buffer[i] = to((type)nullv, type, endian); \
121 } \
122} while (0)
123
124 switch (f->sample_format) {
125 case PCM_SAMPLE_UINT8:
126 SET_NULL(uint8_t, le, INT8_MIN); break;
127 case PCM_SAMPLE_SINT8:
128 SET_NULL(int8_t, le, 0); break;
129 case PCM_SAMPLE_UINT16_LE:
130 SET_NULL(uint16_t, le, INT16_MIN); break;
131 case PCM_SAMPLE_SINT16_LE:
132 SET_NULL(int16_t, le, 0); break;
133 case PCM_SAMPLE_UINT16_BE:
134 SET_NULL(uint16_t, be, INT16_MIN); break;
135 case PCM_SAMPLE_SINT16_BE:
136 SET_NULL(int16_t, be, 0); break;
137 case PCM_SAMPLE_UINT32_LE:
138 SET_NULL(uint32_t, le, INT32_MIN); break;
139 case PCM_SAMPLE_SINT32_LE:
140 SET_NULL(int32_t, le, 0); break;
141 case PCM_SAMPLE_UINT32_BE:
142 SET_NULL(uint32_t, be, INT32_MIN); break;
143 case PCM_SAMPLE_SINT32_BE:
144 SET_NULL(int32_t, le, 0); break;
145 case PCM_SAMPLE_UINT24_32_LE:
146 case PCM_SAMPLE_SINT24_32_LE:
147 case PCM_SAMPLE_UINT24_32_BE:
148 case PCM_SAMPLE_SINT24_32_BE:
149 case PCM_SAMPLE_UINT24_LE:
150 case PCM_SAMPLE_SINT24_LE:
151 case PCM_SAMPLE_UINT24_BE:
152 case PCM_SAMPLE_SINT24_BE:
153 case PCM_SAMPLE_FLOAT32:
154 default: ;
155 }
156#undef SET_NULL
157}
158
[5a6f362]159/**
160 * Mix audio data of the same format and size.
161 * @param dst Destination buffer
162 * @param src Source buffer
163 * @param size Size of both the destination and the source buffer
164 * @param f Pointer to the format descriptor.
165 * @return Error code.
166 */
[ea6c838]167int pcm_format_mix(void *dst, const void *src, size_t size, const pcm_format_t *f)
[737b4c0]168{
[ea6c838]169 return pcm_format_convert_and_mix(dst, size, src, size, f, f);
[950110ee]170}
[5a6f362]171
172/**
173 * Add and mix audio data.
174 * @param dst Destination audio buffer
175 * @param dst_size Size of the destination buffer
176 * @param src Source audio buffer
177 * @param src_size Size of the source buffer.
178 * @param sf Pointer to the source format descriptor.
179 * @param df Pointer to the destination format descriptor.
180 * @return Error code.
181 *
182 * Buffers must contain entire frames. Destination buffer is always filled.
183 * If there are not enough data in the source buffer silent data is assumed.
184 */
[ea6c838]185int pcm_format_convert_and_mix(void *dst, size_t dst_size, const void *src,
186 size_t src_size, const pcm_format_t *sf, const pcm_format_t *df)
[950110ee]187{
188 if (!dst || !src || !sf || !df)
[737b4c0]189 return EINVAL;
[ea6c838]190 const size_t src_frame_size = pcm_format_frame_size(sf);
[950110ee]191 if ((src_size % src_frame_size) != 0)
192 return EINVAL;
193
[ea6c838]194 const size_t dst_frame_size = pcm_format_frame_size(df);
[5a6f362]195 if ((dst_size % dst_frame_size) != 0)
[737b4c0]196 return EINVAL;
197
198 /* This is so ugly it eats kittens, and puppies, and ducklings,
199 * and all little fluffy things...
[bb67def]200 */
201#define LOOP_ADD(type, endian, low, high) \
[737b4c0]202do { \
[950110ee]203 const unsigned frame_count = dst_size / dst_frame_size; \
[bb67def]204 for (size_t i = 0; i < frame_count; ++i) { \
[950110ee]205 for (unsigned j = 0; j < df->channels; ++j) { \
[bb67def]206 const float a = \
[1f7da3b]207 get_normalized_sample(dst, dst_size, i, j, df);\
[bb67def]208 const float b = \
[1f7da3b]209 get_normalized_sample(src, src_size, i, j, sf);\
[bb67def]210 float c = (a + b); \
211 if (c < -1.0) c = -1.0; \
212 if (c > 1.0) c = 1.0; \
213 c += 1.0; \
214 c *= ((float)(type)high - (float)(type)low) / 2; \
215 c += (float)(type)low; \
216 type *dst_buf = dst; \
[950110ee]217 const unsigned pos = i * df->channels + j; \
218 if (pos < (dst_size / sizeof(type))) \
[bb67def]219 dst_buf[pos] = to((type)c, type, endian); \
220 } \
[737b4c0]221 } \
222} while (0)
223
[950110ee]224 switch (df->sample_format) {
[bb67def]225 case PCM_SAMPLE_UINT8:
226 LOOP_ADD(uint8_t, le, UINT8_MIN, UINT8_MAX); break;
227 case PCM_SAMPLE_SINT8:
228 LOOP_ADD(uint8_t, le, INT8_MIN, INT8_MAX); break;
[737b4c0]229 case PCM_SAMPLE_UINT16_LE:
[bb67def]230 LOOP_ADD(uint16_t, le, UINT16_MIN, UINT16_MAX); break;
[737b4c0]231 case PCM_SAMPLE_SINT16_LE:
[bb67def]232 LOOP_ADD(int16_t, le, INT16_MIN, INT16_MAX); break;
[737b4c0]233 case PCM_SAMPLE_UINT16_BE:
[bb67def]234 LOOP_ADD(uint16_t, be, UINT16_MIN, UINT16_MAX); break;
[737b4c0]235 case PCM_SAMPLE_SINT16_BE:
[bb67def]236 LOOP_ADD(int16_t, be, INT16_MIN, INT16_MAX); break;
[737b4c0]237 case PCM_SAMPLE_UINT24_32_LE:
[bb67def]238 case PCM_SAMPLE_UINT32_LE: // TODO this are not right for 24bit
239 LOOP_ADD(uint32_t, le, UINT32_MIN, UINT32_MAX); break;
[43c40a3]240 case PCM_SAMPLE_SINT24_32_LE:
[737b4c0]241 case PCM_SAMPLE_SINT32_LE:
[bb67def]242 LOOP_ADD(int32_t, le, INT32_MIN, INT32_MAX); break;
[737b4c0]243 case PCM_SAMPLE_UINT24_32_BE:
244 case PCM_SAMPLE_UINT32_BE:
[bb67def]245 LOOP_ADD(uint32_t, be, UINT32_MIN, UINT32_MAX); break;
[43c40a3]246 case PCM_SAMPLE_SINT24_32_BE:
[737b4c0]247 case PCM_SAMPLE_SINT32_BE:
[bb67def]248 LOOP_ADD(int32_t, be, INT32_MIN, INT32_MAX); break;
[737b4c0]249 case PCM_SAMPLE_UINT24_LE:
250 case PCM_SAMPLE_SINT24_LE:
251 case PCM_SAMPLE_UINT24_BE:
252 case PCM_SAMPLE_SINT24_BE:
253 case PCM_SAMPLE_FLOAT32:
254 default:
255 return ENOTSUP;
256 }
257 return EOK;
[bb67def]258#undef LOOP_ADD
[737b4c0]259}
260
[5a6f362]261/**
262 * Converts all sample formats to float <-1,1>
263 * @param buffer Audio data
264 * @param size Size of the buffer
265 * @param frame Index of the frame to read
266 * @param channel Channel within the frame
267 * @param f Pointer to a format descriptor
268 * @return Normalized sample <-1,1>, 0.0 if the data could not be read
269 */
[bb67def]270static float get_normalized_sample(const void *buffer, size_t size,
[ea6c838]271 unsigned frame, unsigned channel, const pcm_format_t *f)
[bb67def]272{
273 assert(f);
[aef1799]274 assert(buffer);
[bb67def]275 if (channel >= f->channels)
276 return 0.0f;
277#define GET(type, endian, low, high) \
278do { \
279 const type *src = buffer; \
280 const size_t sample_count = size / sizeof(type); \
281 const size_t sample_pos = frame * f->channels + channel; \
282 if (sample_pos >= sample_count) {\
283 return 0.0f; \
284 } \
285 float sample = from(src[sample_pos], type, endian); \
286 /* This makes it positive */ \
287 sample -= (float)(type)low; \
288 /* This makes it <0,2> */ \
289 sample /= (((float)(type)high - (float)(type)low) / 2.0f); \
290 return sample - 1.0f; \
291} while (0)
292
293 switch (f->sample_format) {
294 case PCM_SAMPLE_UINT8:
295 GET(uint8_t, le, UINT8_MIN, UINT8_MAX);
296 case PCM_SAMPLE_SINT8:
297 GET(int8_t, le, INT8_MIN, INT8_MAX);
298 case PCM_SAMPLE_UINT16_LE:
299 GET(uint16_t, le, UINT16_MIN, UINT16_MAX);
300 case PCM_SAMPLE_SINT16_LE:
301 GET(int16_t, le, INT16_MIN, INT16_MAX);
302 case PCM_SAMPLE_UINT16_BE:
303 GET(uint16_t, be, UINT16_MIN, UINT16_MAX);
304 case PCM_SAMPLE_SINT16_BE:
305 GET(int16_t, be, INT16_MIN, INT16_MAX);
306 case PCM_SAMPLE_UINT24_32_LE:
307 case PCM_SAMPLE_UINT32_LE:
308 GET(uint32_t, le, UINT32_MIN, UINT32_MAX);
309 case PCM_SAMPLE_SINT24_32_LE:
310 case PCM_SAMPLE_SINT32_LE:
311 GET(int32_t, le, INT32_MIN, INT32_MAX);
312 case PCM_SAMPLE_UINT24_32_BE:
313 case PCM_SAMPLE_UINT32_BE:
314 GET(uint32_t, be, UINT32_MIN, UINT32_MAX);
315 case PCM_SAMPLE_SINT24_32_BE:
316 case PCM_SAMPLE_SINT32_BE:
317 GET(int32_t, le, INT32_MIN, INT32_MAX);
318 case PCM_SAMPLE_UINT24_LE:
319 case PCM_SAMPLE_SINT24_LE:
320 case PCM_SAMPLE_UINT24_BE:
321 case PCM_SAMPLE_SINT24_BE:
322 case PCM_SAMPLE_FLOAT32:
323 default: ;
324 }
325 return 0;
326#undef GET
327}
[737b4c0]328/**
329 * @}
330 */
Note: See TracBrowser for help on using the repository browser.