annotate base/Resampler.cpp @ 760:b6bb0ecb7958

Avoid crash on CoreAudio reader dtor after failing to open file (fixing #504)
author Chris Cannam
date Sat, 09 Mar 2013 11:45:15 +0000
parents 02390a4c2abe
children e802e550a1f2
rev   line source
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@756 146 if (data.input_frames_used != incount) {
Chris@756 147 std::cerr << "Resampler: NOTE: input_frames_used == " << data.input_frames_used << " (while incount = " << incount << ")" << std::endl;
Chris@756 148 }
Chris@756 149
Chris@297 150 return data.output_frames_gen;
Chris@297 151 }
Chris@297 152
Chris@297 153 void
Chris@297 154 Resampler::D::reset()
Chris@297 155 {
Chris@297 156 src_reset(m_src);
Chris@297 157 }
Chris@297 158
Chris@297 159 Resampler::Resampler(Quality quality, size_t channels, size_t chunkSize)
Chris@297 160 {
Chris@297 161 m_d = new D(quality, channels, chunkSize);
Chris@297 162 }
Chris@297 163
Chris@297 164 Resampler::~Resampler()
Chris@297 165 {
Chris@297 166 delete m_d;
Chris@297 167 }
Chris@297 168
Chris@297 169 size_t
Chris@297 170 Resampler::resample(float **in, float **out,
Chris@297 171 size_t incount, float ratio,
Chris@297 172 bool final)
Chris@297 173 {
Chris@297 174 return m_d->resample(in, out, incount, ratio, final);
Chris@297 175 }
Chris@297 176
Chris@297 177 size_t
Chris@297 178 Resampler::resampleInterleaved(float *in, float *out,
Chris@297 179 size_t incount, float ratio,
Chris@297 180 bool final)
Chris@297 181 {
Chris@297 182 return m_d->resampleInterleaved(in, out, incount, ratio, final);
Chris@297 183 }
Chris@297 184
Chris@297 185 void
Chris@297 186 Resampler::reset()
Chris@297 187 {
Chris@297 188 m_d->reset();
Chris@297 189 }
Chris@297 190