Specify levels in terms of 0..1 and not 0..32768.
[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 // A final scalar to get the audio within approximately the right range.
12 // Increase to _lower_ overall volume.
13 #define DAMPENING_FACTOR 5.0
14
15 // 6dB/oct per round.
16 #define FILTER_DEPTH 4
17
18 std::vector<float> level_samples(const std::vector<float> &pcm, float min_level, float lpfilter_freq, int sample_rate)
19 {
20         // filter forwards, then backwards (perfect phase filtering)
21         std::vector<float> filtered_samples, refiltered_samples, leveled_samples;
22         filtered_samples.resize(pcm.size());
23         refiltered_samples.resize(pcm.size());
24         leveled_samples.resize(pcm.size());
25
26         Filter filter = Filter::lpf(2.0 * M_PI * lpfilter_freq / sample_rate);
27         for (unsigned i = 0; i < pcm.size(); ++i) {
28                 filtered_samples[i] = filter.update(fabs(pcm[i]));
29         }
30         filter.reset();
31         for (unsigned i = pcm.size(); i --> 0; ) {
32                 refiltered_samples[i] = filter.update(filtered_samples[i]);
33         }
34
35         for (int i = 1; i < FILTER_DEPTH; ++i) {
36                 filter.reset();
37                 for (unsigned i = 0; i < pcm.size(); ++i) {
38                         filtered_samples[i] = filter.update(refiltered_samples[i]);
39                 }
40                 filter.reset();
41                 for (unsigned i = pcm.size(); i --> 0; ) {
42                         refiltered_samples[i] = filter.update(filtered_samples[i]);
43                 }
44         }
45
46         for (unsigned i = 0; i < pcm.size(); ++i) {
47                 float f = DAMPENING_FACTOR * std::max<float>(refiltered_samples[i], min_level);
48                 leveled_samples[i] = pcm[i] / f;
49         }
50
51         return leveled_samples;
52 }