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; 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; 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}