| 55 | * Audio rate converter based on simple resampling. Used when no |
| 56 | * interpolation is required. |
| 57 | * |
| 58 | * Limited to sampling frequency <= 65535 Hz. |
| 59 | */ |
| 60 | template<bool stereo, bool reverseStereo> |
| 61 | class SimpleRateConverter : public RateConverter { |
| 62 | protected: |
| 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 | |
| 74 | public: |
| 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 | */ |
| 86 | template<bool stereo, bool reverseStereo> |
| 87 | SimpleRateConverter<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 | */ |
| 112 | template<bool stereo, bool reverseStereo> |
| 113 | int 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 | } |
| 187 | the_end: |
| 188 | return (ST_SUCCESS); |
| 189 | } |
| 190 | |
| 191 | /** |
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) |
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 | } |