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
140
141
142
143
144
145
146
147
148
149
//! This is little more than a wrapper around the replaygain analysis functionality
//! provided by ffmpeg's af_replaygain. Unlike af_replaygain however, this gives you
//! the actual values instead of just printing them to the console and then throwing
//! them away. So close, yet so far.
//!
//! # Prerequisites
//!
//! * Stereo audio (no other channel counts supported)
//! * Supported sample rates: 8000, 11025, 12000, 16000, 18900, 22050, 24000, 32000,
//!   37800, __44100__, __48000__, 56000, 64000, 88200, 96000, 112000, 128000, 144000,
//!   176400, 192000 (Hz)
//! * Float encoding (endianness handled on your side)
//!
//! It sure doesn't lack irony that most users of this crate would probably actually
//! use ffmpeg to convert their audio to a compatible format.
//!
//! # Usage
//!
//! ```no_run
//! use replaygain::ReplayGain;
//! let mut rg = ReplayGain::new(44100).unwrap();
//! let samples = []; // get data from somewhere
//! rg.process_frame(&samples);
//! let (gain, peak) = rg.finish();
//! ```
//!
//! # Example
//!
//! ```no_run
//! use std::{env, io, slice};
//! use std::io::Read;
//! use replaygain::ReplayGain;
//!
//! fn main() {
//!     let mut args = env::args();
//!     args.next().unwrap(); // executable name
//!     let param1 = args.next().unwrap();
//!
//!     let sample_rate = param1.parse().unwrap();
//!     let mut rg = ReplayGain::new(sample_rate).unwrap();
//!
//!     // Just buffer everything up to keep things simple
//!     let mut input = Vec::new();
//!     {
//!         let stdin = io::stdin();
//!         let mut lock = stdin.lock();
//!         lock.read_to_end(&mut input).unwrap();
//!     }
//!
//!     // Quick and dirty conversion
//!     let floats = unsafe { slice::from_raw_parts(&input[..] as *const _ as *const f32,
//!                                                 input.len() / 4) };
//!     rg.process_samples(floats);
//!
//!     let (gain, peak) = rg.finish();
//!     println!("track_gain = {} dB", gain);
//!     println!("track_peak = {}", peak);
//! }
//! ```



mod af_replaygain;
use af_replaygain::*;

pub struct ReplayGain {
    sample_rate: usize,
    ctx: ReplayGainContext,
    buf: Vec<f32>,
}

impl ReplayGain {
    /// Create a new ReplayGain filter for the given sample rate.
    /// Returns `None` if the sample rate is not supported.
    pub fn new(sample_rate: usize) -> Option<ReplayGain>{
        freq_to_info(sample_rate).map(|x| ReplayGain {
            sample_rate,
            ctx: init_context(&x),
            buf: Vec::new(),
        })
    }

    /// Returns the size of a single audio frame (one of which we analyze at a time)
    /// in **floats**. Note that because we expect stereo audio, this means that you
    /// need to divide this by 2 to get the number of *samples*.
    pub fn frame_size(&self) -> usize {
        self.sample_rate / 20 * 2
    }

    /// Processes a single audio frame.
    ///
    /// # Panics
    ///
    /// Panics if `frame.len() != self.frame_size()` or if there's anything in
    /// `process_samples`'s buffer.
    /// If you need buffering, use `process_samples()` and **only that** instead.
    pub fn process_frame(&mut self, frame: &[f32]) {
        assert!(frame.len() == self.frame_size());
        assert!(self.buf.is_empty());

        filter_frame(&mut self.ctx, frame);
    }

    /// Processes a given amount of audio samples.
    ///
    /// Note that because we expect stereo audio, it doesn't actually make sense to pass
    /// an odd number of floats to this function but we buffer it to chunks of `frame_size()`
    /// anyways so we don't care.
    pub fn process_samples(&mut self, frame: &[f32]) {
        let frame_size = self.frame_size();
        let mut remainder = None;

        if !self.buf.is_empty() {
            // need to drain that first
            let required = frame_size - self.buf.len();
            let can_fill = frame.len() >= required;
            let input = if can_fill { required } else { frame.len() };
            self.buf.extend_from_slice(&frame[..input]);
            if can_fill {
                assert!(self.buf.len() == frame_size);
                filter_frame(&mut self.ctx, &self.buf[..]);
                self.buf.clear();
                remainder = Some(&frame[input..]);
            }
        } else {
            remainder = Some(frame);
        }

        for chunk in remainder.iter().flat_map(|x| x.chunks(frame_size)) {
            if chunk.len() == frame_size {
                assert!(self.buf.is_empty());
                filter_frame(&mut self.ctx, chunk);
            } else {
                // last one
                self.buf.extend_from_slice(chunk);
            }
        }
    }

    /// Completes the analysis and returns the two replaygain values (gain, peak).
    pub fn finish(mut self) -> (f32, f32) {
        // pass in any remaining buffer after padding with zeros
        self.buf.resize(self.frame_size(), 0.0);
        filter_frame(&mut self.ctx, &self.buf[..]);
        self.buf.clear();

        finish(&mut self.ctx)
    }
}