File: macros.rs

package info (click to toggle)
rust-rustdct 0.7.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 460 kB
  • sloc: makefile: 2
file content (191 lines) | stat: -rw-r--r-- 6,844 bytes parent folder | download | duplicates (6)
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
use crate::common::{compare_float_vectors, random_signal};
use rustdct::DctPlanner;

macro_rules! dct_test_with_known_data {
    ($reference_fn:ident, $naive_struct:ident, $process_fn: ident, $known_data_fn:ident) => (
        // Compare our naive struct and our reference_fn implementation against a bunch of known data
        let known_data = $known_data_fn();
        for entry in known_data {
            let len = entry.input.len();
            assert_eq!(len, entry.expected_output.len(), "Invalid test data -- input and known output are not the same length");

            let mut naive_buffer = entry.input.clone();

            let naive_dct = $naive_struct::new(len);
            naive_dct.$process_fn(&mut naive_buffer);

            let slow_output = $reference_fn(&entry.input);

            println!("input:          {:?}", entry.input);
            println!("expected output:{:?}", entry.expected_output);
            println!("naive output:   {:?}", naive_buffer);
            println!("slow output:    {:?}", slow_output);

            assert!(compare_float_vectors(&entry.expected_output, &naive_buffer));
            assert!(compare_float_vectors(&entry.expected_output, &slow_output));
        }
    )
}

macro_rules! dct_test_inverse {
    ($reference_fn:ident, $inverse_fn:ident, $inverse_scale_fn:ident, $first_size:expr) => (
        // Test that the slow fn, paired with the correct inverse fn, actually yields the original data
        for len in $first_size..20 {
            let input = random_signal(len);
            let intermediate = $reference_fn(&input);
            let inverse = $inverse_fn(&intermediate);

            let inverse_scale = $inverse_scale_fn(len);
            let scaled_inverse: Vec<f64> = inverse.into_iter().map(|entry| entry * inverse_scale).collect();

            println!("input:          {:?}", input);
            println!("scaled inverse: {:?}", scaled_inverse);

            assert!(compare_float_vectors(&input, &scaled_inverse));
        }
    )
}

macro_rules! dct_test_with_planner {
    ($reference_fn:ident, $naive_struct:ident, $process_fn: ident, $planner_fn:ident, $first_size:expr) => {
        // Compare our naive struct against the output from the planner
        for len in $first_size..20 {
            let input = random_signal(len);

            let mut naive_buffer = input.clone();
            let mut actual_buffer = input.clone();

            let naive_dct = $naive_struct::new(len);

            let mut planner = DctPlanner::new();
            let actual_dct = planner.$planner_fn(len);

            assert_eq!(
                actual_dct.len(),
                len,
                "Planner created a DCT of incorrect length. Expected {}, got {}",
                len,
                actual_dct.len()
            );

            let reference_output = $reference_fn(&input);
            naive_dct.$process_fn(&mut naive_buffer);
            actual_dct.$process_fn(&mut actual_buffer);

            println!("input:           {:?}", input);
            println!("reference output:{:?}", reference_output);
            println!("naive output:    {:?}", naive_buffer);
            println!("planned output:  {:?}", actual_buffer);

            assert!(compare_float_vectors(&reference_output, &naive_buffer));
            assert!(compare_float_vectors(&reference_output, &actual_buffer));
        }
    };
}

pub mod test_mdct {
    use super::*;
    use rustdct::{
        mdct::{Mdct, MdctNaive},
        RequiredScratch,
    };

    pub fn planned_matches_naive<F>(len: usize, window_fn: F)
    where
        F: Fn(usize) -> Vec<f32>,
    {
        let input = random_signal(len * 2);
        println!("input:          {:?}", input);

        let (input_a, input_b) = input.split_at(len);

        let mut naive_output = vec![0f32; len];
        let mut actual_output = vec![0f32; len];

        let naive_dct = MdctNaive::new(len, &window_fn);

        let mut planner = DctPlanner::new();
        let actual_dct = planner.plan_mdct(len, window_fn);

        assert_eq!(
            actual_dct.len(),
            len,
            "Planner created a DCT of incorrect length"
        );

        let mut naive_scratch = vec![0f32; naive_dct.get_scratch_len()];
        let mut fast_scratch = vec![0f32; actual_dct.get_scratch_len()];

        naive_dct.process_mdct_with_scratch(
            input_a,
            input_b,
            &mut naive_output,
            &mut naive_scratch,
        );
        actual_dct.process_mdct_with_scratch(
            input_a,
            input_b,
            &mut actual_output,
            &mut fast_scratch,
        );

        println!("Naive output:   {:?}", naive_output);
        println!("Planned output: {:?}", actual_output);

        assert!(
            compare_float_vectors(&naive_output, &actual_output),
            "len = {}",
            len
        );
    }

    pub fn test_tdac<F>(len: usize, scale_factor: f32, window_fn: F)
    where
        F: Fn(usize) -> Vec<f32>,
    {
        let mut planner = DctPlanner::new();
        let mdct = planner.plan_mdct(len, &window_fn);

        const NUM_SEGMENTS: usize = 5;

        let input = random_signal(len * (NUM_SEGMENTS + 1));
        let mut output = vec![0f32; len * NUM_SEGMENTS];
        let mut inverse = vec![0f32; len * (NUM_SEGMENTS + 1)];
        let mut scratch = vec![0f32; mdct.get_scratch_len()];

        for i in 0..NUM_SEGMENTS {
            let input_chunk = &input[len * i..(len * (i + 2))];
            let output_chunk = &mut output[len * i..(len * (i + 1))];

            let (input_a, input_b) = input_chunk.split_at(len);

            mdct.process_mdct_with_scratch(input_a, input_b, output_chunk, &mut scratch);
        }
        for i in 0..NUM_SEGMENTS {
            let input_chunk = &output[len * i..(len * (i + 1))];
            let output_chunk = &mut inverse[len * i..(len * (i + 2))];

            let (output_a, output_b) = output_chunk.split_at_mut(len);

            mdct.process_imdct_with_scratch(input_chunk, output_a, output_b, &mut scratch);
        }

        //we have to scale the inverse by 1/len
        for element in inverse.iter_mut() {
            *element = *element * scale_factor;
        }

        println!("scale:   {:?}", scale_factor);
        println!("input:   {:?}", &input[len..input.len() - len]);
        println!("inverse: {:?}", &inverse[len..input.len() - len]);

        assert!(
            compare_float_vectors(
                &input[len..input.len() - len],
                &inverse[len..inverse.len() - len],
            ),
            "len = {}",
            len
        );
    }
}