| Chris@297 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | 
| Chris@297 | 2 /* | 
| Chris@297 | 3     Sonic Visualiser | 
| Chris@297 | 4     An audio file viewer and annotation editor. | 
| Chris@297 | 5     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@297 | 6 | 
| Chris@297 | 7     This program is free software; you can redistribute it and/or | 
| Chris@297 | 8     modify it under the terms of the GNU General Public License as | 
| Chris@297 | 9     published by the Free Software Foundation; either version 2 of the | 
| Chris@297 | 10     License, or (at your option) any later version.  See the file | 
| Chris@297 | 11     COPYING included with this distribution for more information. | 
| Chris@297 | 12 */ | 
| Chris@297 | 13 | 
| Chris@297 | 14 /* | 
| Chris@297 | 15    This is a modified version of a source file from the | 
| Chris@297 | 16    Rubber Band audio timestretcher library. | 
| Chris@297 | 17    This file copyright 2007 Chris Cannam. | 
| Chris@297 | 18 */ | 
| Chris@297 | 19 | 
| Chris@297 | 20 #include "Resampler.h" | 
| Chris@297 | 21 | 
| Chris@297 | 22 #include <cstdlib> | 
| Chris@297 | 23 #include <cmath> | 
| Chris@297 | 24 | 
| Chris@297 | 25 #include <iostream> | 
| Chris@297 | 26 | 
| Chris@297 | 27 #include <samplerate.h> | 
| Chris@297 | 28 | 
| Chris@297 | 29 class Resampler::D | 
| Chris@297 | 30 { | 
| Chris@297 | 31 public: | 
| Chris@297 | 32     D(Quality quality, size_t channels, size_t chunkSize); | 
| Chris@297 | 33     ~D(); | 
| Chris@297 | 34 | 
| Chris@297 | 35     size_t resample(float **in, float **out, | 
| Chris@297 | 36                     size_t incount, float ratio, | 
| Chris@297 | 37                     bool final); | 
| Chris@297 | 38 | 
| Chris@297 | 39     size_t resampleInterleaved(float *in, float *out, | 
| Chris@297 | 40                                size_t incount, float ratio, | 
| Chris@297 | 41                                bool final); | 
| Chris@297 | 42 | 
| Chris@297 | 43     void reset(); | 
| Chris@297 | 44 | 
| Chris@297 | 45 protected: | 
| Chris@297 | 46     SRC_STATE *m_src; | 
| Chris@297 | 47     float *m_iin; | 
| Chris@297 | 48     float *m_iout; | 
| Chris@297 | 49     size_t m_channels; | 
| Chris@297 | 50     size_t m_iinsize; | 
| Chris@297 | 51     size_t m_ioutsize; | 
| Chris@297 | 52 }; | 
| Chris@297 | 53 | 
| Chris@297 | 54 Resampler::D::D(Quality quality, size_t channels, size_t chunkSize) : | 
| Chris@297 | 55     m_src(0), | 
| Chris@297 | 56     m_iin(0), | 
| Chris@297 | 57     m_iout(0), | 
| Chris@297 | 58     m_channels(channels), | 
| Chris@297 | 59     m_iinsize(0), | 
| Chris@297 | 60     m_ioutsize(0) | 
| Chris@297 | 61 { | 
| Chris@297 | 62     int err = 0; | 
| Chris@297 | 63     m_src = src_new(quality == Best ? SRC_SINC_BEST_QUALITY : | 
| Chris@297 | 64                     quality == Fastest ? SRC_LINEAR : | 
| Chris@297 | 65                     SRC_SINC_FASTEST, | 
| Chris@297 | 66                     channels, &err); | 
| Chris@297 | 67 | 
| Chris@297 | 68     //!!! check err, throw | 
| Chris@297 | 69 | 
| Chris@297 | 70     if (chunkSize > 0 && m_channels > 1) { | 
| Chris@297 | 71         //!!! alignment? | 
| Chris@297 | 72         m_iinsize = chunkSize * m_channels; | 
| Chris@297 | 73         m_ioutsize = chunkSize * m_channels * 2; | 
| Chris@297 | 74         m_iin = (float *)malloc(m_iinsize * sizeof(float)); | 
| Chris@297 | 75         m_iout = (float *)malloc(m_ioutsize * sizeof(float)); | 
| Chris@297 | 76     } | 
| Chris@297 | 77 } | 
| Chris@297 | 78 | 
| Chris@297 | 79 Resampler::D::~D() | 
| Chris@297 | 80 { | 
| Chris@297 | 81     src_delete(m_src); | 
| Chris@297 | 82     if (m_iinsize > 0) { | 
| Chris@297 | 83         free(m_iin); | 
| Chris@297 | 84     } | 
| Chris@297 | 85     if (m_ioutsize > 0) { | 
| Chris@297 | 86         free(m_iout); | 
| Chris@297 | 87     } | 
| Chris@297 | 88 } | 
| Chris@297 | 89 | 
| Chris@297 | 90 size_t | 
| Chris@297 | 91 Resampler::D::resample(float **in, float **out, | 
| Chris@297 | 92                        size_t incount, float ratio, | 
| Chris@297 | 93                        bool final) | 
| Chris@297 | 94 { | 
| Chris@297 | 95     if (m_channels == 1) { | 
| Chris@297 | 96         return resampleInterleaved(*in, *out, incount, ratio, final); | 
| Chris@297 | 97     } | 
| Chris@297 | 98 | 
| Chris@297 | 99     size_t outcount = lrintf(ceilf(incount * ratio)); | 
| Chris@297 | 100 | 
| Chris@297 | 101     if (incount * m_channels > m_iinsize) { | 
| Chris@297 | 102         m_iinsize = incount * m_channels; | 
| Chris@297 | 103         m_iin = (float *)realloc(m_iin, m_iinsize * sizeof(float)); | 
| Chris@297 | 104     } | 
| Chris@297 | 105     if (outcount * m_channels > m_ioutsize) { | 
| Chris@297 | 106         m_ioutsize = outcount * m_channels; | 
| Chris@297 | 107         m_iout = (float *)realloc(m_iout, m_ioutsize * sizeof(float)); | 
| Chris@297 | 108     } | 
| Chris@297 | 109     for (size_t i = 0; i < incount; ++i) { | 
| Chris@297 | 110         for (size_t c = 0; c < m_channels; ++c) { | 
| Chris@297 | 111             m_iin[i * m_channels + c] = in[c][i]; | 
| Chris@297 | 112         } | 
| Chris@297 | 113     } | 
| Chris@297 | 114 | 
| Chris@297 | 115     size_t gen = resampleInterleaved(m_iin, m_iout, incount, ratio, final); | 
| Chris@297 | 116 | 
| Chris@297 | 117     for (size_t i = 0; i < gen; ++i) { | 
| Chris@297 | 118         for (size_t c = 0; c < m_channels; ++c) { | 
| Chris@297 | 119             out[c][i] = m_iout[i * m_channels + c]; | 
| Chris@297 | 120         } | 
| Chris@297 | 121     } | 
| Chris@297 | 122 | 
| Chris@297 | 123     return gen; | 
| Chris@297 | 124 } | 
| Chris@297 | 125 | 
| Chris@297 | 126 size_t | 
| Chris@297 | 127 Resampler::D::resampleInterleaved(float *in, float *out, | 
| Chris@297 | 128                                   size_t incount, float ratio, | 
| Chris@297 | 129                                   bool final) | 
| Chris@297 | 130 { | 
| Chris@297 | 131     SRC_DATA data; | 
| Chris@297 | 132 | 
| Chris@297 | 133     size_t outcount = lrintf(ceilf(incount * ratio)); | 
| Chris@297 | 134 | 
| Chris@297 | 135     data.data_in = in; | 
| Chris@297 | 136     data.data_out = out; | 
| Chris@297 | 137     data.input_frames = incount; | 
| Chris@297 | 138     data.output_frames = outcount; | 
| Chris@297 | 139     data.src_ratio = ratio; | 
| Chris@297 | 140     data.end_of_input = (final ? 1 : 0); | 
| Chris@297 | 141 | 
| Chris@297 | 142     int err = src_process(m_src, &data); | 
| Chris@297 | 143 | 
| Chris@297 | 144     //!!! check err, respond appropriately | 
| Chris@297 | 145 | 
| Chris@297 | 146     return data.output_frames_gen; | 
| Chris@297 | 147 } | 
| Chris@297 | 148 | 
| Chris@297 | 149 void | 
| Chris@297 | 150 Resampler::D::reset() | 
| Chris@297 | 151 { | 
| Chris@297 | 152     src_reset(m_src); | 
| Chris@297 | 153 } | 
| Chris@297 | 154 | 
| Chris@297 | 155 Resampler::Resampler(Quality quality, size_t channels, size_t chunkSize) | 
| Chris@297 | 156 { | 
| Chris@297 | 157     m_d = new D(quality, channels, chunkSize); | 
| Chris@297 | 158 } | 
| Chris@297 | 159 | 
| Chris@297 | 160 Resampler::~Resampler() | 
| Chris@297 | 161 { | 
| Chris@297 | 162     delete m_d; | 
| Chris@297 | 163 } | 
| Chris@297 | 164 | 
| Chris@297 | 165 size_t | 
| Chris@297 | 166 Resampler::resample(float **in, float **out, | 
| Chris@297 | 167                     size_t incount, float ratio, | 
| Chris@297 | 168                     bool final) | 
| Chris@297 | 169 { | 
| Chris@297 | 170     return m_d->resample(in, out, incount, ratio, final); | 
| Chris@297 | 171 } | 
| Chris@297 | 172 | 
| Chris@297 | 173 size_t | 
| Chris@297 | 174 Resampler::resampleInterleaved(float *in, float *out, | 
| Chris@297 | 175                     size_t incount, float ratio, | 
| Chris@297 | 176                     bool final) | 
| Chris@297 | 177 { | 
| Chris@297 | 178     return m_d->resampleInterleaved(in, out, incount, ratio, final); | 
| Chris@297 | 179 } | 
| Chris@297 | 180 | 
| Chris@297 | 181 void | 
| Chris@297 | 182 Resampler::reset() | 
| Chris@297 | 183 { | 
| Chris@297 | 184     m_d->reset(); | 
| Chris@297 | 185 } | 
| Chris@297 | 186 |