forked from nu774/qaac
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompressor.cpp
More file actions
90 lines (83 loc) · 3.1 KB
/
compressor.cpp
File metadata and controls
90 lines (83 loc) · 3.1 KB
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
#include <numeric>
#include "compressor.h"
#include "cautil.h"
namespace {
template <typename T>
inline T frame_amplitude(const T *frame, unsigned nchannels)
{
return std::accumulate(frame, frame + nchannels, static_cast<T>(0),
[](T acc, T x) -> T {
return std::max(acc, std::abs(x));
});
}
}
Compressor::Compressor(const std::shared_ptr<ISource> &src,
double threshold, double ratio, double knee_width,
double attack, double release,
std::shared_ptr<FILE> statfp)
: FilterBase(src),
m_threshold(threshold),
m_slope((1.0 - ratio) / ratio),
m_knee_width(knee_width),
m_attack(attack / 1000.0),
m_release(release / 1000.0),
m_Tlo(threshold - knee_width / 2.0),
m_Thi(threshold + knee_width / 2.0),
m_knee_factor(m_slope / (knee_width * 2.0)),
m_yR(0.0),
m_yA(0.0),
m_statfile(statfp)
{
const AudioStreamBasicDescription &asbd = src->getSampleFormat();
unsigned bits = 32;
if (asbd.mBitsPerChannel > 32
|| (asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger) &&
asbd.mBitsPerChannel > 24)
bits = 64;
m_asbd = cautil::buildASBDForPCM(asbd.mSampleRate, asbd.mChannelsPerFrame,
bits, kAudioFormatFlagIsFloat);
if (m_statfile.get()) {
AudioStreamBasicDescription asbd =
cautil::buildASBDForPCM(m_asbd.mSampleRate, 1,
32, kAudioFormatFlagIsFloat);
m_statsink = std::make_shared<WaveSink>(m_statfile.get(), ~0ULL, asbd);
}
}
size_t Compressor::readSamples(void *buffer, size_t nsamples)
{
if (m_asbd.mBitsPerChannel == 64)
return readSamplesT(static_cast<double*>(buffer), nsamples);
else
return readSamplesT(static_cast<float*>(buffer), nsamples);
}
template <typename T>
size_t Compressor::readSamplesT(T *buffer, size_t nsamples)
{
const double Fs = m_asbd.mSampleRate;
unsigned nchannels = m_asbd.mChannelsPerFrame;
const double alphaA =
m_attack > 0.0 ? std::exp(-1.0 / (m_attack * Fs)) : 0.0;
const double alphaR =
m_release > 0.0 ? std::exp(-1.0 / (m_release * Fs)) : 0.0;
nsamples = readSamplesAsFloat(source(), &m_pivot, buffer, nsamples);
if (m_statbuf.size() < nsamples)
m_statbuf.resize(nsamples);
for (size_t i = 0; i < nsamples; ++i) {
T *frame = &buffer[i * nchannels];
double xL = frame_amplitude(frame, nchannels);
double xG = util::scale_to_dB(xL);
double yG = computeGain(xG);
double cG = smoothAverage(yG, alphaA, alphaR);
T cL = static_cast<T>(util::dB_to_scale(cG));
for (unsigned n = 0; n < nchannels; ++n)
frame[n] *= cL;
m_statbuf[i] = cL;
}
if (m_statsink.get()) {
m_statsink->writeSamples(m_statbuf.data(), nsamples * sizeof(float),
nsamples);
if (nsamples == 0)
m_statsink->finishWrite();
}
return nsamples;
}