]> git.sesse.net Git - c64tapwav/blob - level.cpp
6e63d263ba4d295edae88548c4ad0208b282e5d7
[c64tapwav] / level.cpp
1 // A small program to try to even out the audio levels within a file
2 // (essentially a compressor with infinite lookahead).
3
4 #include <stdio.h>
5 #include <math.h>
6 #include <vector>
7 #include <algorithm>
8
9 #include "filter.h"
10
11 // The frequency to filter on, in Hertz. Larger values makes the
12 // compressor react faster, but if it is too large, you'll
13 // ruin the waveforms themselves.
14 #define LPFILTER_FREQ 50.0
15
16 // A final scalar to get the audio within approximately the right range.
17 // Increase to _lower_ overall volume.
18 #define DAMPENING_FACTOR 5.0
19
20 // 6dB/oct per round.
21 #define FILTER_DEPTH 4
22
23 std::vector<float> level_samples(const std::vector<float> &pcm, float min_level, int sample_rate)
24 {
25         // filter forwards, then backwards (perfect phase filtering)
26         std::vector<float> filtered_samples, refiltered_samples, leveled_samples;
27         filtered_samples.resize(pcm.size());
28         refiltered_samples.resize(pcm.size());
29         leveled_samples.resize(pcm.size());
30
31         Filter filter = Filter::lpf(M_PI * LPFILTER_FREQ / sample_rate);
32         for (unsigned i = 0; i < pcm.size(); ++i) {
33                 filtered_samples[i] = filter.update(fabs(pcm[i]));
34         }
35         filter.reset();
36         for (unsigned i = pcm.size(); i --> 0; ) {
37                 refiltered_samples[i] = filter.update(filtered_samples[i]);
38         }
39
40         for (int i = 1; i < FILTER_DEPTH; ++i) {
41                 filter.reset();
42                 for (unsigned i = 0; i < pcm.size(); ++i) {
43                         filtered_samples[i] = filter.update(refiltered_samples[i]);
44                 }
45                 filter.reset();
46                 for (unsigned i = pcm.size(); i --> 0; ) {
47                         refiltered_samples[i] = filter.update(filtered_samples[i]);
48                 }
49         }
50
51         for (unsigned i = 0; i < pcm.size(); ++i) {
52                 float f = DAMPENING_FACTOR * std::max<float>(refiltered_samples[i], min_level);
53                 leveled_samples[i] = pcm[i] / f;
54         }
55
56         return leveled_samples;
57 }