Home | History | Annotate | Download | only in audio
      1 /*
      2  * QEMU Mixing engine
      3  *
      4  * Copyright (c) 2004-2005 Vassili Karpov (malc)
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 /*
     26  * Tusen tack till Mike Nordell
     27  * dec++'ified by Dscho
     28  */
     29 
     30 #ifndef SIGNED
     31 #define HALF (IN_MAX >> 1)
     32 #endif
     33 
     34 #ifdef CONFIG_MIXEMU
     35 #ifdef FLOAT_MIXENG
     36 #define VOL(a, b) ((a) * (b))
     37 #else
     38 #define VOL(a, b) ((a) * (b)) >> 32
     39 #endif
     40 #else
     41 #define VOL(a, b) a
     42 #endif
     43 
     44 #define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
     45 
     46 #ifdef FLOAT_MIXENG
     47 static mixeng_real inline glue (conv_, ET) (IN_T v)
     48 {
     49     IN_T nv = ENDIAN_CONVERT (v);
     50 
     51 #ifdef RECIPROCAL
     52 #ifdef SIGNED
     53     return nv * (1.f / (mixeng_real) (IN_MAX - IN_MIN));
     54 #else
     55     return (nv - HALF) * (1.f / (mixeng_real) IN_MAX);
     56 #endif
     57 #else  /* !RECIPROCAL */
     58 #ifdef SIGNED
     59     return nv / (mixeng_real) (IN_MAX - IN_MIN);
     60 #else
     61     return (nv - HALF) / (mixeng_real) IN_MAX;
     62 #endif
     63 #endif
     64 }
     65 
     66 static IN_T inline glue (clip_, ET) (mixeng_real v)
     67 {
     68     if (v >= 0.5) {
     69         return IN_MAX;
     70     }
     71     else if (v < -0.5) {
     72         return IN_MIN;
     73     }
     74 
     75 #ifdef SIGNED
     76     return ENDIAN_CONVERT ((IN_T) (v * (IN_MAX - IN_MIN)));
     77 #else
     78     return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
     79 #endif
     80 }
     81 
     82 #else  /* !FLOAT_MIXENG */
     83 
     84 static inline int64_t glue (conv_, ET) (IN_T v)
     85 {
     86     IN_T nv = ENDIAN_CONVERT (v);
     87 #ifdef SIGNED
     88     return ((int64_t) nv) << (32 - SHIFT);
     89 #else
     90     return ((int64_t) nv - HALF) << (32 - SHIFT);
     91 #endif
     92 }
     93 
     94 static inline IN_T glue (clip_, ET) (int64_t v)
     95 {
     96     if (v >= 0x7f000000) {
     97         return IN_MAX;
     98     }
     99     else if (v < -2147483648LL) {
    100         return IN_MIN;
    101     }
    102 
    103 #ifdef SIGNED
    104     return ENDIAN_CONVERT ((IN_T) (v >> (32 - SHIFT)));
    105 #else
    106     return ENDIAN_CONVERT ((IN_T) ((v >> (32 - SHIFT)) + HALF));
    107 #endif
    108 }
    109 #endif
    110 
    111 static void glue (glue (conv_, ET), _to_stereo)
    112     (struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
    113 {
    114     struct st_sample *out = dst;
    115     IN_T *in = (IN_T *) src;
    116 #ifdef CONFIG_MIXEMU
    117     if (vol->mute) {
    118         mixeng_clear (dst, samples);
    119         return;
    120     }
    121 #else
    122     (void) vol;
    123 #endif
    124     while (samples--) {
    125         out->l = VOL (glue (conv_, ET) (*in++), vol->l);
    126         out->r = VOL (glue (conv_, ET) (*in++), vol->r);
    127         out += 1;
    128     }
    129 }
    130 
    131 static void glue (glue (conv_, ET), _to_mono)
    132     (struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
    133 {
    134     struct st_sample *out = dst;
    135     IN_T *in = (IN_T *) src;
    136 #ifdef CONFIG_MIXEMU
    137     if (vol->mute) {
    138         mixeng_clear (dst, samples);
    139         return;
    140     }
    141 #else
    142     (void) vol;
    143 #endif
    144     while (samples--) {
    145         out->l = VOL (glue (conv_, ET) (in[0]), vol->l);
    146         out->r = out->l;
    147         out += 1;
    148         in += 1;
    149     }
    150 }
    151 
    152 static void glue (glue (clip_, ET), _from_stereo)
    153     (void *dst, const struct st_sample *src, int samples)
    154 {
    155     const struct st_sample *in = src;
    156     IN_T *out = (IN_T *) dst;
    157     while (samples--) {
    158         *out++ = glue (clip_, ET) (in->l);
    159         *out++ = glue (clip_, ET) (in->r);
    160         in += 1;
    161     }
    162 }
    163 
    164 static void glue (glue (clip_, ET), _from_mono)
    165     (void *dst, const struct st_sample *src, int samples)
    166 {
    167     const struct st_sample *in = src;
    168     IN_T *out = (IN_T *) dst;
    169     while (samples--) {
    170         *out++ = glue (clip_, ET) (in->l + in->r);
    171         in += 1;
    172     }
    173 }
    174 
    175 #undef ET
    176 #undef HALF
    177 #undef VOL
    178