resample.cc 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. * Copyright (C) 2018-2020 Stefan Westerfeld
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "resample.hh"
  18. #include <assert.h>
  19. #include <math.h>
  20. #include <zita-resampler/resampler.h>
  21. #include <zita-resampler/vresampler.h>
  22. using std::vector;
  23. template<class R>
  24. static void
  25. process_resampler (R& resampler, const vector<float>& in, vector<float>& out)
  26. {
  27. resampler.out_count = out.size() / resampler.nchan();
  28. resampler.out_data = &out[0];
  29. /* avoid timeshift: zita needs k/2 - 1 samples before the actual input */
  30. resampler.inp_count = resampler.inpsize () / 2 - 1;
  31. resampler.inp_data = nullptr;
  32. resampler.process();
  33. resampler.inp_count = in.size() / resampler.nchan();
  34. resampler.inp_data = (float *) &in[0];
  35. resampler.process();
  36. /* zita needs k/2 samples after the actual input */
  37. resampler.inp_count = resampler.inpsize() / 2;
  38. resampler.inp_data = nullptr;
  39. resampler.process();
  40. }
  41. WavData
  42. resample (const WavData& wav_data, int rate)
  43. {
  44. /* in our application, resampling should only be called if it is necessary
  45. * since using the resampler with input rate == output rate would be slow
  46. */
  47. assert (rate != wav_data.sample_rate());
  48. const int hlen = 16;
  49. const double ratio = double (rate) / wav_data.sample_rate();
  50. const vector<float>& in = wav_data.samples();
  51. vector<float> out (lrint (in.size() / wav_data.n_channels() * ratio) * wav_data.n_channels());
  52. /* zita-resampler provides two resampling algorithms
  53. *
  54. * a fast optimized version: Resampler
  55. * this is an optimized version, which works for many common cases,
  56. * like resampling between 22050, 32000, 44100, 48000, 96000 Hz
  57. *
  58. * a slower version: VResampler
  59. * this works for arbitary rates (like 33333 -> 44100 resampling)
  60. *
  61. * so we try using Resampler, and if that fails fall back to VResampler
  62. */
  63. Resampler resampler;
  64. if (resampler.setup (wav_data.sample_rate(), rate, wav_data.n_channels(), hlen) == 0)
  65. {
  66. process_resampler (resampler, in, out);
  67. return WavData (out, wav_data.n_channels(), rate, wav_data.bit_depth());
  68. }
  69. VResampler vresampler;
  70. if (vresampler.setup (ratio, wav_data.n_channels(), hlen) == 0)
  71. {
  72. process_resampler (vresampler, in, out);
  73. return WavData (out, wav_data.n_channels(), rate, wav_data.bit_depth());
  74. }
  75. error ("audiowmark: resampling from rate %d to rate %d not supported.\n", wav_data.sample_rate(), rate);
  76. exit (1);
  77. }
  78. WavData
  79. resample_ratio (const WavData& wav_data, double ratio, int new_rate)
  80. {
  81. const int hlen = 16;
  82. const vector<float>& in = wav_data.samples();
  83. vector<float> out (lrint (in.size() / wav_data.n_channels() * ratio) * wav_data.n_channels());
  84. VResampler vresampler;
  85. if (vresampler.setup (ratio, wav_data.n_channels(), hlen) != 0)
  86. {
  87. error ("audiowmark: failed to setup vresampler with ratio=%f\n", ratio);
  88. exit (1);
  89. }
  90. process_resampler (vresampler, in, out);
  91. return WavData (out, wav_data.n_channels(), new_rate, wav_data.bit_depth());
  92. }