File: RateConverter.cpp

package info (click to toggle)
kwave 25.04.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 23,272 kB
  • sloc: cpp: 56,173; xml: 817; perl: 688; sh: 57; makefile: 11
file content (139 lines) | stat: -rw-r--r-- 5,056 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/***************************************************************************
      RateConverter.cpp  -  single channel sample rate converter
                             -------------------
    begin                : Sat Jul 11 2009
    copyright            : (C) 2009 by Thomas Eschenbacher
    email                : Thomas.Eschenbacher@gmx.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "config.h"

#include <math.h>

#include "libkwave/Utils.h"
#include "libkwave/modules/RateConverter.h"

//***************************************************************************
Kwave::RateConverter::RateConverter()
    :Kwave::SampleSource(), m_ratio(1.0), m_converter(nullptr),
     m_converter_in(), m_converter_out()
{
    int error = 0;
    m_converter = src_new(SRC_SINC_MEDIUM_QUALITY, 1, &error);
    Q_ASSERT(m_converter);
    if (!m_converter) qWarning("creating converter failed: '%s",
        src_strerror(error));
}

//***************************************************************************
Kwave::RateConverter::~RateConverter()
{
    src_delete(m_converter);
    m_converter = nullptr;
}

//***************************************************************************
void Kwave::RateConverter::goOn()
{
}

//***************************************************************************
void Kwave::RateConverter::input(Kwave::SampleArray data)
{
    // shortcut for ratio == 1:1
    if ((m_ratio == 1.0) || data.isEmpty()) {
        emit output(data);
        return;
    }

    // normal processing
    Kwave::SampleArray samples_out;
    const unsigned int in_len = data.size();

    // convert the input buffer into an array of floats
    m_converter_in.resize(in_len);
    float          *f_in = m_converter_in.data();
    const sample_t *s_in = data.constData();
    Q_ASSERT(f_in);
    Q_ASSERT(s_in);

    // work blockwise to allow loop unrolling
    unsigned int remaining = in_len;
    const unsigned int block_size = 16;
    while (remaining >= block_size) {
        for (unsigned int i = 0; i < block_size; i++)
            f_in[i] = sample2float(s_in[i]);
        f_in      += block_size;
        s_in      += block_size;
        remaining -= block_size;
    }
    for (; remaining; remaining--)
        (*f_in++) = sample2float(*(s_in++));

    // prepare the output buffer (estimated size, rounded up)
    // worst case would be factor 2, which means that there was a 100%
    // leftover remaining from the previous pass
    // just for safety we limit the extra output space to some
    // (hopefully) reasonable range between 4096 and 16384
    const unsigned int out_len = Kwave::toUint(
        ceil(static_cast<double>(in_len) * m_ratio)
    );
    const unsigned int extra = qBound<unsigned int>(4096, out_len, 16384);
    m_converter_out.resize(out_len + extra);

    // set up the sample rate converter input
    SRC_DATA src;
    src.data_in           = m_converter_in.data();
    src.data_out          = m_converter_out.data();
    src.input_frames      = in_len;
    src.output_frames     = out_len + extra;
    src.input_frames_used = 0;
    src.output_frames_gen = 0;
    src.end_of_input      = (in_len == 0) ? 1 : 0;
    src.src_ratio         = m_ratio;

    // let the converter run...
    int error = src_process(m_converter, &src);
    if (error) qWarning("SRC error: '%s'", src_strerror(error));
    Q_ASSERT(!error);

    // convert the result back from floats to sample_t
    unsigned int gen = Kwave::toUint(src.output_frames_gen);
    Kwave::SampleArray out(gen);
    const float *f_out = src.data_out;
    sample_t    *s_out = out.data();

    // work blockwise to allow loop unrolling
    remaining = gen;
    while (remaining >= block_size) {
        for (unsigned int i = 0; i < block_size; ++i)
            s_out[i] = float2sample(f_out[i]);
        s_out     += block_size;
        f_out     += block_size;
        remaining -= block_size;
    }
    for (; remaining; remaining--, ++s_out, ++f_out)
        *s_out = float2sample(*f_out);

    emit output(out);
}

//***************************************************************************
void Kwave::RateConverter::setRatio(const QVariant ratio)
{
    m_ratio = QVariant(ratio).toDouble();
}

//***************************************************************************
//***************************************************************************

#include "moc_RateConverter.cpp"