annotate base/Resampler.cpp @ 1078:ce82bcdc95d0

Fail upfront if the file is going to be too large. We expect the caller to split up large data sets into several MatrixFiles
author Chris Cannam
date Wed, 10 Jun 2015 13:10:26 +0100
parents cc27f35aa75c
children
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@843 29 #include "Debug.h"
Chris@843 30
Chris@297 31 class Resampler::D
Chris@297 32 {
Chris@297 33 public:
Chris@1038 34 D(Quality quality, int channels, sv_frame_t chunkSize);
Chris@297 35 ~D();
Chris@297 36
Chris@1038 37 sv_frame_t resample(float **in, float **out,
Chris@1038 38 sv_frame_t incount, double ratio,
Chris@1038 39 bool final);
Chris@297 40
Chris@1038 41 sv_frame_t resampleInterleaved(float *in, float *out,
Chris@1038 42 sv_frame_t incount, double ratio,
Chris@1038 43 bool final);
Chris@297 44
Chris@297 45 void reset();
Chris@297 46
Chris@297 47 protected:
Chris@297 48 SRC_STATE *m_src;
Chris@297 49 float *m_iin;
Chris@297 50 float *m_iout;
Chris@928 51 int m_channels;
Chris@1038 52 sv_frame_t m_iinsize;
Chris@1038 53 sv_frame_t m_ioutsize;
Chris@297 54 };
Chris@297 55
Chris@1038 56 Resampler::D::D(Quality quality, int channels, sv_frame_t chunkSize) :
Chris@297 57 m_src(0),
Chris@297 58 m_iin(0),
Chris@297 59 m_iout(0),
Chris@297 60 m_channels(channels),
Chris@297 61 m_iinsize(0),
Chris@297 62 m_ioutsize(0)
Chris@297 63 {
Chris@297 64 int err = 0;
Chris@297 65 m_src = src_new(quality == Best ? SRC_SINC_BEST_QUALITY :
Chris@297 66 quality == Fastest ? SRC_LINEAR :
Chris@297 67 SRC_SINC_FASTEST,
Chris@297 68 channels, &err);
Chris@297 69
Chris@297 70 //!!! check err, throw
Chris@297 71
Chris@297 72 if (chunkSize > 0 && m_channels > 1) {
Chris@297 73 //!!! alignment?
Chris@297 74 m_iinsize = chunkSize * m_channels;
Chris@297 75 m_ioutsize = chunkSize * m_channels * 2;
Chris@297 76 m_iin = (float *)malloc(m_iinsize * sizeof(float));
Chris@297 77 m_iout = (float *)malloc(m_ioutsize * sizeof(float));
Chris@297 78 }
Chris@297 79 }
Chris@297 80
Chris@297 81 Resampler::D::~D()
Chris@297 82 {
Chris@297 83 src_delete(m_src);
Chris@297 84 if (m_iinsize > 0) {
Chris@297 85 free(m_iin);
Chris@297 86 }
Chris@297 87 if (m_ioutsize > 0) {
Chris@297 88 free(m_iout);
Chris@297 89 }
Chris@297 90 }
Chris@297 91
Chris@1038 92 sv_frame_t
Chris@297 93 Resampler::D::resample(float **in, float **out,
Chris@1038 94 sv_frame_t incount, double ratio,
Chris@297 95 bool final)
Chris@297 96 {
Chris@297 97 if (m_channels == 1) {
Chris@297 98 return resampleInterleaved(*in, *out, incount, ratio, final);
Chris@297 99 }
Chris@297 100
Chris@1038 101 sv_frame_t outcount = lrint(ceil(double(incount) * ratio));
Chris@297 102
Chris@297 103 if (incount * m_channels > m_iinsize) {
Chris@297 104 m_iinsize = incount * m_channels;
Chris@297 105 m_iin = (float *)realloc(m_iin, m_iinsize * sizeof(float));
Chris@297 106 }
Chris@297 107 if (outcount * m_channels > m_ioutsize) {
Chris@297 108 m_ioutsize = outcount * m_channels;
Chris@297 109 m_iout = (float *)realloc(m_iout, m_ioutsize * sizeof(float));
Chris@297 110 }
Chris@1038 111 for (sv_frame_t i = 0; i < incount; ++i) {
Chris@928 112 for (int c = 0; c < m_channels; ++c) {
Chris@297 113 m_iin[i * m_channels + c] = in[c][i];
Chris@297 114 }
Chris@297 115 }
Chris@297 116
Chris@1038 117 sv_frame_t gen = resampleInterleaved(m_iin, m_iout, incount, ratio, final);
Chris@297 118
Chris@1038 119 for (sv_frame_t i = 0; i < gen; ++i) {
Chris@928 120 for (int c = 0; c < m_channels; ++c) {
Chris@297 121 out[c][i] = m_iout[i * m_channels + c];
Chris@297 122 }
Chris@297 123 }
Chris@297 124
Chris@297 125 return gen;
Chris@297 126 }
Chris@297 127
Chris@1038 128 sv_frame_t
Chris@297 129 Resampler::D::resampleInterleaved(float *in, float *out,
Chris@1038 130 sv_frame_t incount, double ratio,
Chris@297 131 bool final)
Chris@297 132 {
Chris@297 133 SRC_DATA data;
Chris@297 134
Chris@1038 135 sv_frame_t outcount = lrint(ceil(double(incount) * ratio));
Chris@297 136
Chris@297 137 data.data_in = in;
Chris@297 138 data.data_out = out;
Chris@297 139 data.input_frames = incount;
Chris@297 140 data.output_frames = outcount;
Chris@297 141 data.src_ratio = ratio;
Chris@297 142 data.end_of_input = (final ? 1 : 0);
Chris@297 143
Chris@297 144 int err = src_process(m_src, &data);
Chris@297 145
Chris@928 146 if (err) {
Chris@928 147 cerr << "Resampler: ERROR: src_process returned error: " <<
Chris@928 148 src_strerror(err) << endl;
Chris@928 149 return 0;
Chris@928 150 }
Chris@297 151
Chris@1038 152 if (data.input_frames_used != incount) {
Chris@843 153 cerr << "Resampler: NOTE: input_frames_used == " << data.input_frames_used << " (while incount = " << incount << ")" << endl;
Chris@756 154 }
Chris@756 155
Chris@297 156 return data.output_frames_gen;
Chris@297 157 }
Chris@297 158
Chris@297 159 void
Chris@297 160 Resampler::D::reset()
Chris@297 161 {
Chris@297 162 src_reset(m_src);
Chris@297 163 }
Chris@297 164
Chris@1038 165 Resampler::Resampler(Quality quality, int channels, sv_frame_t chunkSize)
Chris@297 166 {
Chris@297 167 m_d = new D(quality, channels, chunkSize);
Chris@297 168 }
Chris@297 169
Chris@297 170 Resampler::~Resampler()
Chris@297 171 {
Chris@297 172 delete m_d;
Chris@297 173 }
Chris@297 174
Chris@1038 175 sv_frame_t
Chris@297 176 Resampler::resample(float **in, float **out,
Chris@1038 177 sv_frame_t incount, double ratio,
Chris@297 178 bool final)
Chris@297 179 {
Chris@297 180 return m_d->resample(in, out, incount, ratio, final);
Chris@297 181 }
Chris@297 182
Chris@1038 183 sv_frame_t
Chris@297 184 Resampler::resampleInterleaved(float *in, float *out,
Chris@1038 185 sv_frame_t incount, double ratio,
Chris@1038 186 bool final)
Chris@297 187 {
Chris@297 188 return m_d->resampleInterleaved(in, out, incount, ratio, final);
Chris@297 189 }
Chris@297 190
Chris@297 191 void
Chris@297 192 Resampler::reset()
Chris@297 193 {
Chris@297 194 m_d->reset();
Chris@297 195 }
Chris@297 196