strip added smb:// shares of their user/pass when adding, and instead store that...
[vuplus_xbmc] / xbmc / cores / AudioEngine / Utils / AEUtil.cpp
1 /*
2  *      Copyright (C) 2010-2012 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21 #ifndef __STDC_LIMIT_MACROS
22   #define __STDC_LIMIT_MACROS
23 #endif
24
25 #include "utils/StdString.h"
26 #include "AEUtil.h"
27 #include "utils/log.h"
28 #include "utils/TimeUtils.h"
29
30 using namespace std;
31
32 /* declare the rng seed and initialize it */
33 unsigned int CAEUtil::m_seed = (unsigned int)(CurrentHostCounter() / 1000.0f);
34 #ifdef __SSE__
35   /* declare the SSE seed and initialize it */
36   MEMALIGN(16, __m128i CAEUtil::m_sseSeed) = _mm_set_epi32(CAEUtil::m_seed, CAEUtil::m_seed+1, CAEUtil::m_seed, CAEUtil::m_seed+1);
37 #endif
38
39 CAEChannelInfo CAEUtil::GuessChLayout(const unsigned int channels)
40 {
41   CLog::Log(LOGWARNING, "CAEUtil::GuessChLayout - This method should really never be used, please fix the code that called this");
42
43   CAEChannelInfo result;
44   if (channels < 1 || channels > 8)
45     return result;
46
47   switch (channels)
48   {
49     case 1: result = AE_CH_LAYOUT_1_0; break;
50     case 2: result = AE_CH_LAYOUT_2_0; break;
51     case 3: result = AE_CH_LAYOUT_3_0; break;
52     case 4: result = AE_CH_LAYOUT_4_0; break;
53     case 5: result = AE_CH_LAYOUT_5_0; break;
54     case 6: result = AE_CH_LAYOUT_5_1; break;
55     case 7: result = AE_CH_LAYOUT_7_0; break;
56     case 8: result = AE_CH_LAYOUT_7_1; break;
57   }
58
59   return result;
60 }
61
62 const char* CAEUtil::GetStdChLayoutName(const enum AEStdChLayout layout)
63 {
64   if (layout < 0 || layout >= AE_CH_LAYOUT_MAX)
65     return "UNKNOWN";
66
67   static const char* layouts[AE_CH_LAYOUT_MAX] =
68   {
69     "1.0",
70     "2.0", "2.1", "3.0", "3.1", "4.0",
71     "4.1", "5.0", "5.1", "7.0", "7.1"
72   };
73
74   return layouts[layout];
75 }
76
77 const unsigned int CAEUtil::DataFormatToBits(const enum AEDataFormat dataFormat)
78 {
79   if (dataFormat < 0 || dataFormat >= AE_FMT_MAX)
80     return 0;
81
82   static const unsigned int formats[AE_FMT_MAX] =
83   {
84     8,                   /* U8     */
85     8,                   /* S8     */
86
87     16,                  /* S16BE  */
88     16,                  /* S16LE  */
89     16,                  /* S16NE  */
90
91     32,                  /* S32BE  */
92     32,                  /* S32LE  */
93     32,                  /* S32NE  */
94
95     32,                  /* S24BE  */
96     32,                  /* S24LE  */
97     32,                  /* S24NE  */
98
99     24,                  /* S24BE3 */
100     24,                  /* S24LE3 */
101     24,                  /* S24NE3 */
102
103     sizeof(double) << 3, /* DOUBLE */
104     sizeof(float ) << 3, /* FLOAT  */
105
106     8,                   /* AAC    */
107     8,                   /* AC3    */
108     8,                   /* DTS    */
109     8,                   /* EAC3   */
110     8,                   /* TRUEHD */
111     8,                   /* DTS-HD */
112     32                   /* LPCM   */
113   };
114
115   return formats[dataFormat];
116 }
117
118 const char* CAEUtil::DataFormatToStr(const enum AEDataFormat dataFormat)
119 {
120   if (dataFormat < 0 || dataFormat >= AE_FMT_MAX)
121     return "UNKNOWN";
122
123   static const char *formats[AE_FMT_MAX] =
124   {
125     "AE_FMT_U8",
126     "AE_FMT_S8",
127
128     "AE_FMT_S16BE",
129     "AE_FMT_S16LE",
130     "AE_FMT_S16NE",
131
132     "AE_FMT_S32BE",
133     "AE_FMT_S32LE",
134     "AE_FMT_S32NE",
135
136     "AE_FMT_S24BE4",
137     "AE_FMT_S24LE4",
138     "AE_FMT_S24NE4",  /* S24 in 4 bytes */
139
140     "AE_FMT_S24BE3",
141     "AE_FMT_S24LE3",
142     "AE_FMT_S24NE3", /* S24 in 3 bytes */
143
144     "AE_FMT_DOUBLE",
145     "AE_FMT_FLOAT",
146
147     /* for passthrough streams and the like */
148     "AE_FMT_AAC",
149     "AE_FMT_AC3",
150     "AE_FMT_DTS",
151     "AE_FMT_EAC3",
152     "AE_FMT_TRUEHD",
153     "AE_FMT_DTSHD",
154     "AE_FMT_LPCM"
155   };
156
157   return formats[dataFormat];
158 }
159
160 #ifdef __SSE__
161 void CAEUtil::SSEMulArray(float *data, const float mul, uint32_t count)
162 {
163   const __m128 m = _mm_set_ps1(mul);
164
165   /* work around invalid alignment */
166   while (((uintptr_t)data & 0xF) && count > 0)
167   {
168     data[0] *= mul;
169     ++data;
170     --count;
171   }
172
173   uint32_t even = count & ~0x3;
174   for (uint32_t i = 0; i < even; i+=4, data+=4)
175   {
176     __m128 to      = _mm_load_ps(data);
177     *(__m128*)data = _mm_mul_ps (to, m);
178   }
179
180   if (even != count)
181   {
182     uint32_t odd = count - even;
183     if (odd == 1)
184       data[0] *= mul;
185     else
186     {
187       __m128 to;
188       if (odd == 2)
189       {
190         to = _mm_setr_ps(data[0], data[1], 0, 0);
191         __m128 ou = _mm_mul_ps(to, m);
192         data[0] = ((float*)&ou)[0];
193         data[1] = ((float*)&ou)[1];
194       }
195       else
196       {
197         to = _mm_setr_ps(data[0], data[1], data[2], 0);
198         __m128 ou = _mm_mul_ps(to, m);
199         data[0] = ((float*)&ou)[0];
200         data[1] = ((float*)&ou)[1];
201         data[2] = ((float*)&ou)[2];
202       }
203     }
204   }
205 }
206
207 void CAEUtil::SSEMulAddArray(float *data, float *add, const float mul, uint32_t count)
208 {
209   const __m128 m = _mm_set_ps1(mul);
210
211   /* work around invalid alignment */
212   while ((((uintptr_t)data & 0xF) || ((uintptr_t)add & 0xF)) && count > 0)
213   {
214     data[0] += add[0] * mul;
215     ++add;
216     ++data;
217     --count;
218   }
219
220   uint32_t even = count & ~0x3;
221   for (uint32_t i = 0; i < even; i+=4, data+=4, add+=4)
222   {
223     __m128 ad      = _mm_load_ps(add );
224     __m128 to      = _mm_load_ps(data);
225     *(__m128*)data = _mm_add_ps (to, _mm_mul_ps(ad, m));
226   }
227
228   if (even != count)
229   {
230     uint32_t odd = count - even;
231     if (odd == 1)
232       data[0] += add[0] * mul;
233     else
234     {
235       __m128 ad;
236       __m128 to;
237       if (odd == 2)
238       {
239         ad = _mm_setr_ps(add [0], add [1], 0, 0);
240         to = _mm_setr_ps(data[0], data[1], 0, 0);
241         __m128 ou = _mm_add_ps(to, _mm_mul_ps(ad, m));
242         data[0] = ((float*)&ou)[0];
243         data[1] = ((float*)&ou)[1];
244       }
245       else
246       {
247         ad = _mm_setr_ps(add [0], add [1], add [2], 0);
248         to = _mm_setr_ps(data[0], data[1], data[2], 0);
249         __m128 ou = _mm_add_ps(to, _mm_mul_ps(ad, m));
250         data[0] = ((float*)&ou)[0];
251         data[1] = ((float*)&ou)[1];
252         data[2] = ((float*)&ou)[2];
253       }
254     }
255   }
256 }
257 #endif
258
259 inline float CAEUtil::SoftClamp(const float x)
260 {
261 #if 1
262     /*
263        This is a rational function to approximate a tanh-like soft clipper.
264        It is based on the pade-approximation of the tanh function with tweaked coefficients.
265        See: http://www.musicdsp.org/showone.php?id=238
266     */
267     if (x < -3.0f)
268       return -1.0f;
269     else if (x >  3.0f)
270       return 1.0f;
271     float y = x * x;
272     return x * (27.0f + y) / (27.0f + 9.0f * y);
273 #else
274     /* slower method using tanh, but more accurate */
275
276     static const double k = 0.9f;
277     /* perform a soft clamp */
278     if (x >  k)
279       x = (float) (tanh((x - k) / (1 - k)) * (1 - k) + k);
280     else if (x < -k)
281       x = (float) (tanh((x + k) / (1 - k)) * (1 - k) - k);
282
283     /* hard clamp anything still outside the bounds */
284     if (x >  1.0f)
285       return  1.0f;
286     if (x < -1.0f)
287       return -1.0f;
288
289     /* return the final sample */
290     return x;
291 #endif
292 }
293
294 void CAEUtil::ClampArray(float *data, uint32_t count)
295 {
296 #ifndef __SSE__
297   for (uint32_t i = 0; i < count; ++i)
298     data[i] = SoftClamp(data[i]);
299
300 #else
301   const __m128 c1 = _mm_set_ps1(27.0f);
302   const __m128 c2 = _mm_set_ps1(27.0f + 9.0f);
303
304   /* work around invalid alignment */
305   while (((uintptr_t)data & 0xF) && count > 0)
306   {
307     data[0] = SoftClamp(data[0]);
308     ++data;
309     --count;
310   }
311
312   uint32_t even = count & ~0x3;
313   for (uint32_t i = 0; i < even; i+=4, data+=4)
314   {
315     /* tanh approx clamp */
316     __m128 dt = _mm_load_ps(data);
317     __m128 tmp     = _mm_mul_ps(dt, dt);
318     *(__m128*)data = _mm_div_ps(
319       _mm_mul_ps(
320         dt,
321         _mm_add_ps(c1, tmp)
322       ),
323       _mm_add_ps(c2, tmp)
324     );
325   }
326
327   if (even != count)
328   {
329     uint32_t odd = count - even;
330     if (odd == 1)
331       data[0] = SoftClamp(data[0]);
332     else
333     {
334       __m128 dt;
335       __m128 tmp;
336       __m128 out;
337       if (odd == 2)
338       {
339         /* tanh approx clamp */
340         dt  = _mm_setr_ps(data[0], data[1], 0, 0);
341         tmp = _mm_mul_ps(dt, dt);
342         out = _mm_div_ps(
343           _mm_mul_ps(
344             dt,
345             _mm_add_ps(c1, tmp)
346           ),
347           _mm_add_ps(c2, tmp)
348         );
349
350         data[0] = ((float*)&out)[0];
351         data[1] = ((float*)&out)[1];
352       }
353       else
354       {
355         /* tanh approx clamp */
356         dt  = _mm_setr_ps(data[0], data[1], data[2], 0);
357         tmp = _mm_mul_ps(dt, dt);
358         out = _mm_div_ps(
359           _mm_mul_ps(
360             dt,
361             _mm_add_ps(c1, tmp)
362           ),
363           _mm_add_ps(c2, tmp)
364         );
365
366         data[0] = ((float*)&out)[0];
367         data[1] = ((float*)&out)[1];
368         data[2] = ((float*)&out)[2];
369       }
370     }
371   }
372 #endif
373 }
374
375 /*
376   Rand implementations based on:
377   http://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor/
378   This is NOT safe for crypto work, but perfectly fine for audio usage (dithering)
379 */
380 float CAEUtil::FloatRand1(const float min, const float max)
381 {
382   const float delta  = (max - min) / 2;
383   const float factor = delta / (float)INT32_MAX;
384   return ((float)(m_seed = (214013 * m_seed + 2531011)) * factor) - delta;
385 }
386
387 void CAEUtil::FloatRand4(const float min, const float max, float result[4], __m128 *sseresult/* = NULL */)
388 {
389   #ifdef __SSE__
390     /*
391       this method may be called from other SSE code, we need
392       to calculate the delta & factor using SSE as the FPU
393       state is unknown and _mm_clear() is expensive.
394     */
395     MEMALIGN(16, static const __m128 point5  ) = _mm_set_ps1(0.5f);
396     MEMALIGN(16, static const __m128 int32max) = _mm_set_ps1((const float)INT32_MAX);
397     MEMALIGN(16, __m128 f) = _mm_div_ps(
398       _mm_mul_ps(
399         _mm_sub_ps(
400           _mm_set_ps1(max),
401           _mm_set_ps1(min)
402         ),
403         point5
404       ),
405       int32max
406     );
407
408     MEMALIGN(16, __m128i cur_seed_split);
409     MEMALIGN(16, __m128i multiplier);
410     MEMALIGN(16, __m128i adder);
411     MEMALIGN(16, __m128i mod_mask);
412     MEMALIGN(16, __m128 res);
413     MEMALIGN(16, static const unsigned int mult  [4]) = {214013, 17405, 214013, 69069};
414     MEMALIGN(16, static const unsigned int gadd  [4]) = {2531011, 10395331, 13737667, 1};
415     MEMALIGN(16, static const unsigned int mask  [4]) = {0xFFFFFFFF, 0, 0xFFFFFFFF, 0};
416
417     adder          = _mm_load_si128((__m128i*)gadd);
418     multiplier     = _mm_load_si128((__m128i*)mult);
419     mod_mask       = _mm_load_si128((__m128i*)mask);
420     cur_seed_split = _mm_shuffle_epi32(m_sseSeed, _MM_SHUFFLE(2, 3, 0, 1));
421
422     m_sseSeed      = _mm_mul_epu32(m_sseSeed, multiplier);
423     multiplier     = _mm_shuffle_epi32(multiplier, _MM_SHUFFLE(2, 3, 0, 1));
424     cur_seed_split = _mm_mul_epu32(cur_seed_split, multiplier);
425
426     m_sseSeed      = _mm_and_si128(m_sseSeed, mod_mask);
427     cur_seed_split = _mm_and_si128(cur_seed_split, mod_mask);
428     cur_seed_split = _mm_shuffle_epi32(cur_seed_split, _MM_SHUFFLE(2, 3, 0, 1));
429     m_sseSeed      = _mm_or_si128(m_sseSeed, cur_seed_split);
430     m_sseSeed      = _mm_add_epi32(m_sseSeed, adder);
431
432     /* adjust the value to the range requested */
433     res = _mm_cvtepi32_ps(m_sseSeed);
434     if (sseresult)
435       *sseresult = _mm_mul_ps(res, f);
436     else
437     {
438       res = _mm_mul_ps(res, f);
439       _mm_storeu_ps(result, res);
440
441       /* returning a float array, so cleanup */
442       _mm_empty();
443     }
444
445   #else
446     const float delta  = (max - min) / 2.0f;
447     const float factor = delta / (float)INT32_MAX;
448
449     /* cant return sseresult if we are not using SSE intrinsics */
450     ASSERT(result && !sseresult);
451
452     result[0] = ((float)(m_seed = (214013 * m_seed + 2531011)) * factor) - delta;
453     result[1] = ((float)(m_seed = (214013 * m_seed + 2531011)) * factor) - delta;
454     result[2] = ((float)(m_seed = (214013 * m_seed + 2531011)) * factor) - delta;
455     result[3] = ((float)(m_seed = (214013 * m_seed + 2531011)) * factor) - delta;
456   #endif
457 }