]> git.sesse.net Git - c64tapwav/blobdiff - level.cpp
Make leveler minimum level configurable, since it is connected to hysteresis limit.
[c64tapwav] / level.cpp
index e14704acb9f5c475b49f760b7e3426dca272ef7e..e95b48e0f6d1c5e1f03a041760308745f0624090 100644 (file)
--- a/level.cpp
+++ b/level.cpp
@@ -6,20 +6,11 @@
 #include <vector>
 #include <algorithm>
 
-#define BUFSIZE 4096
-#define WAVE_FREQ 44100.0
-
 // The frequency to filter on, in Hertz. Larger values makes the
 // compressor react faster, but if it is too large, you'll
 // ruin the waveforms themselves.
 #define LPFILTER_FREQ 50.0
 
-// The minimum estimated sound level at any given point.
-// If you decrease this, you'll be able to amplify really silent signals
-// by more, but you'll also increase the level of silent (ie. noise-only) segments,
-// possibly caused misdetected pulses in these segments.
-#define MIN_LEVEL 0.05
-
 // A final scalar to get the audio within approximately the right range.
 // Increase to _lower_ overall volume.
 #define DAMPENING_FACTOR 5.0
 // 6dB/oct per round.
 #define FILTER_DEPTH 4
 
-struct stereo_sample {
-       short left, right;
-};
-
-inline short clip(int x)
-{
-       if (x < -32768) {
-               return x;
-       } else if (x > 32767) {
-               return 32767;
-       } else {
-               return short(x);
-       }
-}
-
 static float a1, a2, b0, b1, b2;
 static float d0, d1;
 
 static void filter_init(float cutoff_radians)
 {
        float resonance = 1.0f / sqrt(2.0f);
-       float sn, cs;
-       sincosf(cutoff_radians, &sn, &cs);
-
+       float sn = sin(cutoff_radians), cs = cos(cutoff_radians);
        float alpha = float(sn / (2 * resonance));
 
        // coefficients for lowpass filter
@@ -61,12 +35,11 @@ static void filter_init(float cutoff_radians)
         a1 = -2 * cs;
         a2 = 1 - alpha;
 
-       float invA0 = 1.0f / a0;
-       b0 *= invA0;
-       b1 *= invA0;
-       b2 *= invA0;
-       a1 *= invA0;
-       a2 *= invA0;
+       b0 /= a0;
+       b1 /= a0;
+       b2 /= a0;
+       a1 /= a0;
+       a2 /= a0;
 
        // reset filter delays
        d0 = d1 = 0.0f;
@@ -80,46 +53,38 @@ static float filter_update(float in)
        return out;
 }
 
-int main(int argc, char **argv)
+std::vector<float> level_samples(const std::vector<float> &pcm, float min_level, int sample_rate)
 {
-       std::vector<short> pcm;
-
-       while (!feof(stdin)) {
-               short buf[BUFSIZE];
-               ssize_t ret = fread(buf, sizeof(short), BUFSIZE, stdin);
-               if (ret >= 0) {
-                       pcm.insert(pcm.end(), buf, buf + ret);
-               }
-       }
-       
        // filter forwards, then backwards (perfect phase filtering)
-       std::vector<float> filtered_samples, refiltered_samples;
+       std::vector<float> filtered_samples, refiltered_samples, leveled_samples;
        filtered_samples.resize(pcm.size());
        refiltered_samples.resize(pcm.size());
+       leveled_samples.resize(pcm.size());
 
-       filter_init(M_PI * LPFILTER_FREQ / WAVE_FREQ);
+       filter_init(M_PI * LPFILTER_FREQ / sample_rate);
        for (unsigned i = 0; i < pcm.size(); ++i) {
                filtered_samples[i] = filter_update(fabs(pcm[i]));
        }
-       filter_init(M_PI * LPFILTER_FREQ / WAVE_FREQ);
+       filter_init(M_PI * LPFILTER_FREQ / sample_rate);
        for (unsigned i = pcm.size(); i --> 0; ) {
                refiltered_samples[i] = filter_update(filtered_samples[i]);
        }
 
        for (int i = 1; i < FILTER_DEPTH; ++i) {
-               filter_init(M_PI * LPFILTER_FREQ / WAVE_FREQ);
+               filter_init(M_PI * LPFILTER_FREQ / sample_rate);
                for (unsigned i = 0; i < pcm.size(); ++i) {
                        filtered_samples[i] = filter_update(refiltered_samples[i]);
                }
-               filter_init(M_PI * LPFILTER_FREQ / WAVE_FREQ);
+               filter_init(M_PI * LPFILTER_FREQ / sample_rate);
                for (unsigned i = pcm.size(); i --> 0; ) {
                        refiltered_samples[i] = filter_update(filtered_samples[i]);
                }
        }
 
        for (unsigned i = 0; i < pcm.size(); ++i) {
-               float f = DAMPENING_FACTOR * std::max(refiltered_samples[i] * (1.0 / 32768.0), MIN_LEVEL);
-               short s = clip(lrintf(pcm[i] / f));
-               fwrite(&s, sizeof(s), 1, stdout);
+               float f = DAMPENING_FACTOR * std::max<float>(refiltered_samples[i], min_level);
+               leveled_samples[i] = pcm[i] / f;
        }
+
+       return leveled_samples;
 }