Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
audio.c
Go to the documentation of this file.
1 /*
2  * audio.c
3  * Copyright 2009-2012 John Lindgren, MichaƂ Lipski, and Anders Johansson
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions, and the following disclaimer in the documentation
13  * provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include <glib.h>
21 #include <stdint.h>
22 #include <math.h>
23 
24 #include "audio.h"
25 #include "config.h"
26 
27 #define FROM_INT_LOOP(NAME, TYPE, SWAP, OFFSET, RANGE) \
28 static void NAME (const TYPE * in, float * out, int samples) \
29 { \
30  const TYPE * end = in + samples; \
31  while (in < end) \
32  * out ++ = (TYPE) (SWAP (* in ++) - OFFSET) * (1.0 / (RANGE + 1.0)); \
33 }
34 
35 #define TO_INT_LOOP(NAME, TYPE, SWAP, OFFSET, RANGE) \
36 static void NAME (const float * in, TYPE * out, int samples) \
37 { \
38  const float * end = in + samples; \
39  while (in < end) \
40  { \
41  double f = (* in ++) * (RANGE + 1.0); \
42  * out ++ = SWAP (OFFSET + (TYPE) round (CLAMP (f, -RANGE - 1, RANGE))); \
43  } \
44 }
45 
46 static inline int8_t NOOP8 (int8_t i) {return i;}
47 static inline int16_t NOOP16 (int16_t i) {return i;}
48 static inline int32_t NOOP32 (int32_t i) {return i;}
49 
50 FROM_INT_LOOP (from_s8, int8_t, NOOP8, 0x00, 0x7f)
51 FROM_INT_LOOP (from_u8, int8_t, NOOP8, 0x80, 0x7f)
52 FROM_INT_LOOP (from_s16, int16_t, NOOP16, 0x0000, 0x7fff)
53 FROM_INT_LOOP (from_u16, int16_t, NOOP16, 0x8000, 0x7fff)
54 FROM_INT_LOOP (from_s24, int32_t, NOOP32, 0x000000, 0x7fffff)
55 FROM_INT_LOOP (from_u24, int32_t, NOOP32, 0x800000, 0x7fffff)
56 FROM_INT_LOOP (from_s32, int32_t, NOOP32, 0x00000000, 0x7fffffff)
57 FROM_INT_LOOP (from_u32, int32_t, NOOP32, 0x80000000, 0x7fffffff)
58 
59 TO_INT_LOOP (to_s8, int8_t, NOOP8, 0x00, 0x7f)
60 TO_INT_LOOP (to_u8, int8_t, NOOP8, 0x80, 0x7f)
61 TO_INT_LOOP (to_s16, int16_t, NOOP16, 0x0000, 0x7fff)
62 TO_INT_LOOP (to_u16, int16_t, NOOP16, 0x8000, 0x7fff)
63 TO_INT_LOOP (to_s24, int32_t, NOOP32, 0x000000, 0x7fffff)
64 TO_INT_LOOP (to_u24, int32_t, NOOP32, 0x800000, 0x7fffff)
65 TO_INT_LOOP (to_s32, int32_t, NOOP32, 0x00000000, 0x7fffffff)
66 TO_INT_LOOP (to_u32, int32_t, NOOP32, 0x80000000, 0x7fffffff)
67 
68 static inline int16_t SWAP16 (int16_t i) {return GUINT16_SWAP_LE_BE (i);}
69 static inline int32_t SWAP32 (int32_t i) {return GUINT32_SWAP_LE_BE (i);}
70 
71 FROM_INT_LOOP (from_s16_swap, int16_t, SWAP16, 0x0000, 0x7fff)
72 FROM_INT_LOOP (from_u16_swap, int16_t, SWAP16, 0x8000, 0x7fff)
73 FROM_INT_LOOP (from_s24_swap, int32_t, SWAP32, 0x000000, 0x7fffff)
74 FROM_INT_LOOP (from_u24_swap, int32_t, SWAP32, 0x800000, 0x7fffff)
75 FROM_INT_LOOP (from_s32_swap, int32_t, SWAP32, 0x00000000, 0x7fffffff)
76 FROM_INT_LOOP (from_u32_swap, int32_t, SWAP32, 0x80000000, 0x7fffffff)
77 
78 TO_INT_LOOP (to_s16_swap, int16_t, SWAP16, 0x0000, 0x7fff)
79 TO_INT_LOOP (to_u16_swap, int16_t, SWAP16, 0x8000, 0x7fff)
80 TO_INT_LOOP (to_s24_swap, int32_t, SWAP32, 0x000000, 0x7fffff)
81 TO_INT_LOOP (to_u24_swap, int32_t, SWAP32, 0x800000, 0x7fffff)
82 TO_INT_LOOP (to_s32_swap, int32_t, SWAP32, 0x00000000, 0x7fffffff)
83 TO_INT_LOOP (to_u32_swap, int32_t, SWAP32, 0x80000000, 0x7fffffff)
84 
85 typedef void (* FromFunc) (const void * in, float * out, int samples);
86 typedef void (* ToFunc) (const float * in, void * out, int samples);
87 
88 struct
89 {
90  int format;
93 }
94 convert_table [] =
95 {
96  {FMT_S8, (FromFunc) from_s8, (ToFunc) to_s8},
97  {FMT_U8, (FromFunc) from_u8, (ToFunc) to_u8},
98 
99 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
100  {FMT_S16_LE, (FromFunc) from_s16, (ToFunc) to_s16},
101  {FMT_U16_LE, (FromFunc) from_u16, (ToFunc) to_u16},
102  {FMT_S24_LE, (FromFunc) from_s24, (ToFunc) to_s24},
103  {FMT_U24_LE, (FromFunc) from_u24, (ToFunc) to_u24},
104  {FMT_S32_LE, (FromFunc) from_s32, (ToFunc) to_s32},
105  {FMT_U32_LE, (FromFunc) from_u32, (ToFunc) to_u32},
106 
107  {FMT_S16_BE, (FromFunc) from_s16_swap, (ToFunc) to_s16_swap},
108  {FMT_U16_BE, (FromFunc) from_u16_swap, (ToFunc) to_u16_swap},
109  {FMT_S24_BE, (FromFunc) from_s24_swap, (ToFunc) to_s24_swap},
110  {FMT_U24_BE, (FromFunc) from_u24_swap, (ToFunc) to_u24_swap},
111  {FMT_S32_BE, (FromFunc) from_s32_swap, (ToFunc) to_s32_swap},
112  {FMT_U32_BE, (FromFunc) from_u32_swap, (ToFunc) to_u32_swap},
113 #else
114  {FMT_S16_BE, (FromFunc) from_s16, (ToFunc) to_s16},
115  {FMT_U16_BE, (FromFunc) from_u16, (ToFunc) to_u16},
116  {FMT_S24_BE, (FromFunc) from_s24, (ToFunc) to_s24},
117  {FMT_U24_BE, (FromFunc) from_u24, (ToFunc) to_u24},
118  {FMT_S32_BE, (FromFunc) from_s32, (ToFunc) to_s32},
119  {FMT_U32_BE, (FromFunc) from_u32, (ToFunc) to_u32},
120 
121  {FMT_S16_LE, (FromFunc) from_s16_swap, (ToFunc) to_s16_swap},
122  {FMT_U16_LE, (FromFunc) from_u16_swap, (ToFunc) to_u16_swap},
123  {FMT_S24_LE, (FromFunc) from_s24_swap, (ToFunc) to_s24_swap},
124  {FMT_U24_LE, (FromFunc) from_u24_swap, (ToFunc) to_u24_swap},
125  {FMT_S32_LE, (FromFunc) from_s32_swap, (ToFunc) to_s32_swap},
126  {FMT_U32_LE, (FromFunc) from_u32_swap, (ToFunc) to_u32_swap},
127 #endif
128 };
129 
130 EXPORT void audio_from_int (const void * in, int format, float * out, int samples)
131 {
132  int entry;
133 
134  for (entry = 0; entry < G_N_ELEMENTS (convert_table); entry ++)
135  {
136  if (convert_table[entry].format == format)
137  {
138  convert_table[entry].from (in, out, samples);
139  return;
140  }
141  }
142 }
143 
144 EXPORT void audio_to_int (const float * in, void * out, int format, int samples)
145 {
146  int entry;
147 
148  for (entry = 0; entry < G_N_ELEMENTS (convert_table); entry ++)
149  {
150  if (convert_table[entry].format == format)
151  {
152  convert_table[entry].to (in, out, samples);
153  return;
154  }
155  }
156 }
157 
158 EXPORT void audio_amplify (float * data, int channels, int frames, float * factors)
159 {
160  float * end = data + channels * frames;
161  int channel;
162 
163  while (data < end)
164  {
165  for (channel = 0; channel < channels; channel ++)
166  {
167  * data = * data * factors[channel];
168  data ++;
169  }
170  }
171 }
172 
173 /* linear approximation of y = sin(x) */
174 /* contributed by Anders Johansson */
175 EXPORT void audio_soft_clip (float * data, int samples)
176 {
177  float * end = data + samples;
178 
179  while (data < end)
180  {
181  float x = * data;
182  float y = fabsf (x);
183 
184  if (y <= 0.4)
185  ; /* (0, 0.4) -> (0, 0.4) */
186  else if (y <= 0.7)
187  y = 0.8 * y + 0.08; /* (0.4, 0.7) -> (0.4, 0.64) */
188  else if (y <= 1.0)
189  y = 0.7 * y + 0.15; /* (0.7, 1) -> (0.64, 0.85) */
190  else if (y <= 1.3)
191  y = 0.4 * y + 0.45; /* (1, 1.3) -> (0.85, 0.97) */
192  else if (y <= 1.5)
193  y = 0.15 * y + 0.775; /* (1.3, 1.5) -> (0.97, 1) */
194  else
195  y = 1.0; /* (1.5, inf) -> 1 */
196 
197  * data ++ = (x > 0) ? y : -y;
198  }
199 }