Ticket #8659: diff

File diff, 11.2 KB (added by SF/robinwatts, 14 years ago)

Diff to rate controller code

  • sound/rate.cpp

     
    5252
    5353
    5454/**
     55 * Audio rate converter based on simple resampling. Used when no
     56 * interpolation is required.
     57 *
     58 * Limited to sampling frequency <= 65535 Hz.
     59 */
     60template<bool stereo, bool reverseStereo>
     61class SimpleRateConverter : public RateConverter {
     62protected:
     63        st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
     64        const st_sample_t *inPtr;
     65        int inLen;
     66
     67        /** position of how far output is ahead of input */
     68        /** Holds what would have been opos-ipos */
     69        long opos;
     70
     71        /** fractional position increment in the output stream */
     72        long opos_inc;
     73
     74public:
     75        SimpleRateConverter(st_rate_t inrate, st_rate_t outrate);
     76        int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
     77        int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
     78                return (ST_SUCCESS);
     79        }
     80};
     81
     82
     83/*
     84 * Prepare processing.
     85 */
     86template<bool stereo, bool reverseStereo>
     87SimpleRateConverter<stereo, reverseStereo>::SimpleRateConverter(st_rate_t inrate, st_rate_t outrate) {
     88        if (inrate == outrate) {
     89                error("Input and Output rates must be different to use rate effect");
     90        }
     91
     92        if ((inrate % outrate) != 0) {
     93                error("Input rate must be a multiple of Output rate to use rate effect");
     94        }
     95
     96        if (inrate >= 65536 || outrate >= 65536) {
     97                error("rate effect can only handle rates < 65536");
     98        }
     99
     100        opos = 1;
     101
     102        /* increment */
     103        opos_inc = inrate / outrate;
     104
     105        inLen = 0;
     106}
     107
     108/*
     109 * Processed signed long samples from ibuf to obuf.
     110 * Return number of samples processed.
     111 */
     112template<bool stereo, bool reverseStereo>
     113int SimpleRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
     114        st_sample_t *ostart, *oend;
     115        st_sample_t out[2];
     116
     117        ostart = obuf;
     118        oend = obuf + osamp * 2;
     119
     120        if ((vol_l != Audio::Mixer::kMaxMixerVolume) ||
     121            (vol_r != Audio::Mixer::kMaxMixerVolume))
     122        {
     123                while (obuf < oend) {
     124
     125                        // read enough input samples so that ipos > opos
     126                        do {
     127                                // Check if we have to refill the buffer
     128                                if (inLen == 0) {
     129                                        inPtr = inBuf;
     130                                        inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
     131                                        if (inLen <= 0)
     132                                                goto the_end;
     133                                }
     134                                inLen -= (stereo ? 2 : 1);
     135                                opos--;
     136                                if (opos >= 0)
     137                                {
     138                                        inPtr += (stereo ? 2 : 1);
     139                                }
     140                        }
     141                        while (opos >= 0);
     142                        out[reverseStereo] = *inPtr++;
     143                        out[reverseStereo^1] = (stereo ? *inPtr++ : out[reverseStereo]);
     144
     145                        // Increment output position
     146                        opos += opos_inc;
     147
     148                        // output left channel
     149                        clampedAdd(*obuf++, (out[0] * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
     150
     151                        // output right channel
     152                        clampedAdd(*obuf++, (out[1] * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
     153                }
     154        } else {
     155                while (obuf < oend) {
     156
     157                        // read enough input samples so that ipos > opos
     158                        do {
     159                                // Check if we have to refill the buffer
     160                                if (inLen == 0) {
     161                                        inPtr = inBuf;
     162                                        inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
     163                                        if (inLen <= 0)
     164                                                goto the_end;
     165                                }
     166                                inLen -= (stereo ? 2 : 1);
     167                                opos--;
     168                                if (opos >= 0)
     169                                {
     170                                        inPtr += (stereo ? 2 : 1);
     171                                }
     172                        }
     173                        while (opos >= 0);
     174                        out[reverseStereo] = *inPtr++;
     175                        out[reverseStereo^1] = (stereo ? *inPtr++ : out[reverseStereo]);
     176
     177                        // Increment output position
     178                        opos += opos_inc;
     179
     180                        // output left channel
     181                        clampedAdd(*obuf++, out[0]);
     182
     183                        // output right channel
     184                        clampedAdd(*obuf++, out[1]);
     185                }
     186        }
     187the_end:
     188        return (ST_SUCCESS);
     189}
     190
     191/**
    55192 * Audio rate converter based on simple linear Interpolation.
    56193 *
    57194 * The use of fractional increment allows us to use no buffer. It
     
    70207        int inLen;
    71208
    72209        /** fractional position of the output stream in input stream unit */
    73         unsigned long opos, opos_frac;
     210        long opos, opos_frac;
    74211
    75212        /** fractional position increment in the output stream */
    76         unsigned long opos_inc, opos_inc_frac;
     213        long opos_inc, opos_inc_frac;
    77214
    78         /** position in the input stream (integer) */
    79         unsigned long ipos;
    80 
    81215        /** last sample(s) in the input stream (left/right channel) */
    82216        st_sample_t ilast[2];
    83217        /** current sample(s) in the input stream (left/right channel) */
     
    116250        opos_inc_frac = incr & ((1UL << FRAC_BITS) - 1);
    117251        opos_inc = incr >> FRAC_BITS;
    118252
    119         ipos = 0;
    120 
    121253        ilast[0] = ilast[1] = 0;
    122254        icur[0] = icur[1] = 0;
    123255
     
    133265        st_sample_t *ostart, *oend;
    134266        st_sample_t out[2];
    135267
    136         const int numChannels = stereo ? 2 : 1;
    137         int i;
    138 
    139268        ostart = obuf;
    140269        oend = obuf + osamp * 2;
    141270
    142         while (obuf < oend) {
     271        if ((vol_l != Audio::Mixer::kMaxMixerVolume) ||
     272            (vol_r != Audio::Mixer::kMaxMixerVolume))
     273        {
     274                while (obuf < oend) {
    143275
    144                 // read enough input samples so that ipos > opos
    145                 while (ipos <= opos) {
    146                         // Check if we have to refill the buffer
    147                         if (inLen == 0) {
    148                                 inPtr = inBuf;
    149                                 inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
    150                                 if (inLen <= 0)
     276                        // read enough input samples so that ipos > opos
     277                        while (0 <= opos) {
     278                                // Check if we have to refill the buffer
     279                                if (inLen == 0) {
     280                                        inPtr = inBuf;
     281                                        inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
     282                                        if (inLen <= 0)
     283                                                goto the_end;
     284                                }
     285                                inLen -= (stereo ? 2 : 1);
     286                                ilast[0] = icur[0];
     287                                icur[0] = *inPtr++;
     288                                if (stereo) {
     289                                        ilast[1] = icur[1];
     290                                        icur[1] = *inPtr++;
     291                                }
     292                                opos--;
     293                        }
     294
     295                        // Loop as long as the outpos trails behind, and as long as there is
     296                        // still space in the output buffer.
     297                        while (0 > opos) {
     298
     299                                // interpolate
     300                                out[reverseStereo] = (st_sample_t)(ilast[0] + (((icur[0] - ilast[0]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS));
     301                                out[reverseStereo^1] = (stereo ? (st_sample_t)(ilast[1] + (((icur[1] - ilast[1]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS)) : out[reverseStereo]);
     302
     303                                // output left channel
     304                                clampedAdd(*obuf++, (out[0] * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
     305
     306                                // output right channel
     307                                clampedAdd(*obuf++, (out[1] * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
     308
     309                                // Increment output position
     310                                long tmp = opos_frac + opos_inc_frac;
     311                                opos += opos_inc + (tmp >> FRAC_BITS);
     312                                opos_frac = tmp & ((1UL << FRAC_BITS) - 1);
     313
     314                                // Abort if we reached the end of the output buffer
     315                                if (obuf >= oend)
    151316                                        goto the_end;
    152317                        }
    153                         for (i = 0; i < numChannels; i++) {
    154                                 ilast[i] = icur[i];
    155                                 icur[i] = *inPtr++;
    156                                 inLen--;
    157                         }
    158                         ipos++;
    159318                }
     319        } else {
     320                while (obuf < oend) {
    160321
    161                 // Loop as long as the outpos trails behind, and as long as there is
    162                 // still space in the output buffer.
    163                 while (ipos > opos) {
     322                        // read enough input samples so that ipos > opos
     323                        while (0 <= opos) {
     324                                // Check if we have to refill the buffer
     325                                if (inLen == 0) {
     326                                        inPtr = inBuf;
     327                                        inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
     328                                        if (inLen <= 0)
     329                                                goto the_end;
     330                                }
     331                                inLen -= (stereo ? 2 : 1);
     332                                ilast[0] = icur[0];
     333                                icur[0] = *inPtr++;
     334                                if (stereo) {
     335                                        ilast[1] = icur[1];
     336                                        icur[1] = *inPtr++;
     337                                }
     338                                opos--;
     339                        }
    164340
    165                         // interpolate
    166                         out[0] = out[1] = (st_sample_t)(ilast[0] + (((icur[0] - ilast[0]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS));
     341                        // Loop as long as the outpos trails behind, and as long as there is
     342                        // still space in the output buffer.
     343                        while (0 > opos) {
    167344
    168                         if (stereo) {
    169345                                // interpolate
    170                                 out[reverseStereo ? 0 : 1] = (st_sample_t)(ilast[1] + (((icur[1] - ilast[1]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS));
    171                         }
     346                                out[reverseStereo] = (st_sample_t)(ilast[0] + (((icur[0] - ilast[0]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS));
     347                                out[reverseStereo^1] = (stereo ? (st_sample_t)(ilast[1] + (((icur[1] - ilast[1]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS)) : out[reverseStereo]);
    172348
    173                         // output left channel
    174                         clampedAdd(*obuf++, (out[0] * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
     349                                // output left channel
     350                                clampedAdd(*obuf++, out[0]);
    175351
    176                         // output right channel
    177                         clampedAdd(*obuf++, (out[1] * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
     352                                // output right channel
     353                                clampedAdd(*obuf++, out[1]);
    178354
    179                         // Increment output position
    180                         unsigned long tmp = opos_frac + opos_inc_frac;
    181                         opos += opos_inc + (tmp >> FRAC_BITS);
    182                         opos_frac = tmp & ((1UL << FRAC_BITS) - 1);
     355                                // Increment output position
     356                                long tmp = opos_frac + opos_inc_frac;
     357                                opos += opos_inc + (tmp >> FRAC_BITS);
     358                                opos_frac = tmp & ((1UL << FRAC_BITS) - 1);
    183359
    184                         // Abort if we reached the end of the output buffer
    185                         if (obuf >= oend)
    186                                 goto the_end;
     360                                // Abort if we reached the end of the output buffer
     361                                if (obuf >= oend)
     362                                        goto the_end;
     363                        }
    187364                }
    188365        }
    189 
    190366the_end:
    191367        return (ST_SUCCESS);
    192368}
     
    229405
    230406                // Mix the data into the output buffer
    231407                ptr = _buffer;
    232                 while (len-- > 0) {
    233                         st_sample_t tmp0, tmp1;
    234                         tmp0 = tmp1 = *ptr++;
    235                         if (stereo) {
    236                                 if (reverseStereo)
    237                                         tmp0 = *ptr++;
    238                                 else
    239                                         tmp1 = *ptr++;
    240                                 len--;
     408                if ((vol_l != Audio::Mixer::kMaxMixerVolume) ||
     409                    (vol_r != Audio::Mixer::kMaxMixerVolume))
     410                {
     411                        while (len > 0) {
     412                                st_sample_t tmp[2];
     413                                len -= (stereo ? 2 : 1);
     414                                tmp[reverseStereo  ] = *ptr++;
     415                                tmp[reverseStereo^1] = (stereo ? *ptr++ : tmp[reverseStereo]);
     416
     417                                // output left channel
     418                                clampedAdd(*obuf++, (tmp[0] * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
     419
     420                                // output right channel
     421                                clampedAdd(*obuf++, (tmp[1] * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
    241422                        }
     423                } else {
     424                        while (len > 0) {
     425                                st_sample_t tmp[2];
     426                                len -= (stereo ? 2 : 1);
     427                                tmp[reverseStereo  ] = *ptr++;
     428                                tmp[reverseStereo^1] = (stereo ? *ptr++ : tmp[reverseStereo]);
    242429
    243                         // output left channel
    244                         clampedAdd(*obuf++, (tmp0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
     430                                // output left channel
     431                                clampedAdd(*obuf++, tmp[0]);
    245432
    246                         // output right channel
    247                         clampedAdd(*obuf++, (tmp1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
     433                                // output right channel
     434                                clampedAdd(*obuf++, tmp[1]);
     435                        }
    248436                }
    249437                return (ST_SUCCESS);
    250438        }
     
    262450 */
    263451RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) {
    264452        if (inrate != outrate) {
    265                 if (stereo) {
    266                         if (reverseStereo)
    267                                 return new LinearRateConverter<true, true>(inrate, outrate);
    268                         else
    269                                 return new LinearRateConverter<true, false>(inrate, outrate);
    270                 } else
    271                         return new LinearRateConverter<false, false>(inrate, outrate);
    272                 //return new ResampleRateConverter(inrate, outrate, 1);
     453                if ((inrate % outrate) == 0) {
     454                        if (stereo) {
     455                                if (reverseStereo)
     456                                        return new SimpleRateConverter<true, true>(inrate, outrate);
     457                                else
     458                                        return new SimpleRateConverter<true, false>(inrate, outrate);
     459                        } else
     460                                return new SimpleRateConverter<false, false>(inrate, outrate);
     461                } else {
     462                        if (stereo) {
     463                                if (reverseStereo)
     464                                        return new LinearRateConverter<true, true>(inrate, outrate);
     465                                else
     466                                        return new LinearRateConverter<true, false>(inrate, outrate);
     467                        } else
     468                                return new LinearRateConverter<false, false>(inrate, outrate);
     469                 }
    273470        } else {
    274471                if (stereo) {
    275472                        if (reverseStereo)