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