Skip to main content

soxr_sys/
lib.rs

1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3
4include!("soxr.rs");
5
6#[cfg(test)]
7mod tests {
8    use super::*;
9
10    #[test]
11    fn it_works() {
12        unsafe {
13            let version = soxr_version();
14            let version = std::ffi::CStr::from_ptr(version).to_str().unwrap();
15            println!("version: {}", version);
16        }
17    }
18
19    #[test]
20    fn test_stream() {
21        use std::ffi::c_void;
22        use std::ffi::CStr;
23        use std::ptr;
24
25        use hound::{WavReader, WavSpec, WavWriter};
26
27        let input_wav_path = "test-input.wav";
28        let output_wav_path = "test-output.wav";
29
30        let input_spec = WavSpec {
31            channels: 1,
32            sample_rate: 44100,
33            bits_per_sample: 16,
34            sample_format: hound::SampleFormat::Int,
35        };
36
37        let output_spec = WavSpec {
38            channels: 1,
39            sample_rate: 24000,
40            bits_per_sample: 16,
41            sample_format: hound::SampleFormat::Int,
42        };
43
44        let input_duration: u32 = 3; // 3 second of audio
45
46        let mut writer = WavWriter::create(input_wav_path, input_spec)
47            .expect("Failed to create test input WAV file");
48        for t in (0..input_spec.sample_rate * input_duration)
49            .map(|x| x as f32 / input_spec.sample_rate as f32)
50        {
51            let a4note = 440.0; // 440Hz = A4
52            let sample = (t * a4note * 2.0 * std::f32::consts::PI).sin();
53            let amplitude = i16::MAX as f32;
54            writer.write_sample((sample * amplitude) as i16).expect("Failed to write sample");
55        }
56        writer.finalize().expect("Failed to finalize test input WAV file");
57
58        let mut reader = WavReader::open(input_wav_path).expect("Failed to open input WAV file");
59
60        let wav_spec = reader.spec();
61
62        let num_channels = wav_spec.channels as u32;
63
64        let samples: Vec<i16> =
65            reader.samples::<i16>().map(|s| s.expect("Failed to read sample")).collect();
66
67        let buf_total_len = samples.len();
68        let olen = ((output_spec.sample_rate as f64 * buf_total_len as f64)
69            / (input_spec.sample_rate as f64 + output_spec.sample_rate as f64)
70            + 0.5) as usize;
71        let ilen = buf_total_len - olen;
72
73        let mut obuf = vec![0i16; olen];
74
75        let mut odone: usize = 0;
76        let mut need_input = true;
77
78        let mut error: soxr_error_t = ptr::null();
79
80        let io_spec = soxr_io_spec {
81            itype: soxr_datatype_t_SOXR_INT16_I as u32,
82            otype: soxr_datatype_t_SOXR_INT16_I as u32,
83            scale: 1.0,
84            e: ptr::null_mut(),
85            flags: 0,
86        };
87
88        let soxr = unsafe {
89            soxr_create(
90                input_spec.sample_rate as f64,
91                output_spec.sample_rate as f64,
92                num_channels,
93                &mut error,
94                &io_spec,
95                ptr::null(),
96                ptr::null(),
97            )
98        };
99
100        if error.is_null() {
101            let mut input_pos = 0;
102            let input_len = samples.len();
103
104            let mut output_samples = Vec::new();
105
106            while error.is_null() && (need_input || odone > 0) {
107                let mut ilen1 = 0;
108                let mut ibuf: Option<&[i16]> = None;
109
110                if need_input {
111                    if input_pos < input_len {
112                        let remaining_samples = input_len - input_pos;
113                        let samples_to_read = std::cmp::min(ilen, remaining_samples);
114
115                        ibuf = Some(&samples[input_pos..input_pos + samples_to_read]);
116                        ilen1 = samples_to_read;
117                        input_pos += samples_to_read;
118                    } else {
119                        ibuf = None;
120                    }
121                }
122
123                let in_ptr = match ibuf {
124                    Some(slice) => slice.as_ptr() as *const c_void,
125                    None => ptr::null(),
126                };
127
128                let process_error = unsafe {
129                    soxr_process(
130                        soxr,
131                        in_ptr,
132                        ilen1,
133                        ptr::null_mut(),
134                        obuf.as_mut_ptr() as *mut c_void,
135                        olen,
136                        &mut odone,
137                    )
138                };
139
140                if !process_error.is_null() {
141                    break;
142                }
143
144                if odone > 0 {
145                    output_samples.extend_from_slice(&obuf[..odone]);
146                }
147
148                need_input = (odone < olen) && ibuf.is_some();
149            }
150
151            let mut writer = WavWriter::create(output_wav_path, output_spec)
152                .expect("Failed to create output WAV file");
153
154            for sample in output_samples {
155                writer.write_sample(sample).expect("Failed to write sample");
156            }
157
158            writer.finalize().expect("Failed to finalize WAV file");
159
160            println!("Resampling completed successfully.");
161        } else {
162            let error_str = unsafe { CStr::from_ptr(error) };
163            eprintln!("Error creating resampler: {}", error_str.to_string_lossy());
164        }
165
166        unsafe {
167            soxr_delete(soxr);
168        }
169
170        std::fs::remove_file(input_wav_path).expect("Failed to remove test input file");
171        std::fs::remove_file(output_wav_path).expect("Failed to remove test output file");
172    }
173}