1 /***************************************************************************
2 RateConverter.cpp - single channel sample rate converter
3 -------------------
4 begin : Sat Jul 11 2009
5 copyright : (C) 2009 by Thomas Eschenbacher
6 email : Thomas.Eschenbacher@gmx.de
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "config.h"
19
20 #include <math.h>
21
22 #include "libkwave/Utils.h"
23 #include "libkwave/modules/RateConverter.h"
24
25 //***************************************************************************
RateConverter()26 Kwave::RateConverter::RateConverter()
27 :Kwave::SampleSource(), m_ratio(1.0), m_converter(Q_NULLPTR),
28 m_converter_in(), m_converter_out()
29 {
30 int error = 0;
31 m_converter = src_new(SRC_SINC_MEDIUM_QUALITY, 1, &error);
32 Q_ASSERT(m_converter);
33 if (!m_converter) qWarning("creating converter failed: '%s",
34 src_strerror(error));
35 }
36
37 //***************************************************************************
~RateConverter()38 Kwave::RateConverter::~RateConverter()
39 {
40 if (m_converter) src_delete(m_converter);
41 }
42
43 //***************************************************************************
goOn()44 void Kwave::RateConverter::goOn()
45 {
46 }
47
48 //***************************************************************************
input(Kwave::SampleArray data)49 void Kwave::RateConverter::input(Kwave::SampleArray data)
50 {
51 // shortcut for ratio == 1:1
52 if ((m_ratio == 1.0) || data.isEmpty()) {
53 emit output(data);
54 return;
55 }
56
57 // normal processing
58 Kwave::SampleArray samples_out;
59 const unsigned int in_len = data.size();
60
61 // convert the input buffer into an array of floats
62 m_converter_in.resize(in_len);
63 float *f_in = m_converter_in.data();
64 const sample_t *s_in = data.constData();
65 Q_ASSERT(f_in);
66 Q_ASSERT(s_in);
67
68 // work blockwise to allow loop unrolling
69 unsigned int remaining = in_len;
70 const unsigned int block_size = 16;
71 while (remaining >= block_size) {
72 for (unsigned int i = 0; i < block_size; i++)
73 f_in[i] = sample2float(s_in[i]);
74 f_in += block_size;
75 s_in += block_size;
76 remaining -= block_size;
77 }
78 for (; remaining; remaining--)
79 (*f_in++) = sample2float(*(s_in++));
80
81 // prepare the output buffer (estimated size, rounded up)
82 // worst case would be factor 2, which means that there was a 100%
83 // leftover remaining from the previous pass
84 // just for safety we limit the extra output space to some
85 // (hopefully) reasonable range between 4096 and 16384
86 const unsigned int out_len = Kwave::toUint(
87 ceil(static_cast<double>(in_len) * m_ratio)
88 );
89 const unsigned int extra = qBound<unsigned int>(4096, out_len, 16384);
90 m_converter_out.resize(out_len + extra);
91
92 // set up the sample rate converter input
93 SRC_DATA src;
94 src.data_in = m_converter_in.data();
95 src.data_out = m_converter_out.data();
96 src.input_frames = in_len;
97 src.output_frames = out_len + extra;
98 src.input_frames_used = 0;
99 src.output_frames_gen = 0;
100 src.end_of_input = (in_len == 0) ? 1 : 0;
101 src.src_ratio = m_ratio;
102
103 // let the converter run...
104 int error = src_process(m_converter, &src);
105 if (error) qWarning("SRC error: '%s'", src_strerror(error));
106 Q_ASSERT(!error);
107
108 // convert the result back from floats to sample_t
109 unsigned int gen = Kwave::toUint(src.output_frames_gen);
110 Kwave::SampleArray out(gen);
111 const float *f_out = src.data_out;
112 sample_t *s_out = out.data();
113
114 // work blockwise to allow loop unrolling
115 remaining = gen;
116 while (remaining >= block_size) {
117 for (unsigned int i = 0; i < block_size; ++i)
118 s_out[i] = float2sample(f_out[i]);
119 s_out += block_size;
120 f_out += block_size;
121 remaining -= block_size;
122 }
123 for (; remaining; remaining--, ++s_out, ++f_out)
124 *s_out = float2sample(*f_out);
125
126 emit output(out);
127 }
128
129 //***************************************************************************
setRatio(const QVariant ratio)130 void Kwave::RateConverter::setRatio(const QVariant ratio)
131 {
132 m_ratio = QVariant(ratio).toDouble();
133 }
134
135 //***************************************************************************
136 //***************************************************************************
137