1use crate::*;
2
3#[allow(unused_variables)]
7pub trait XboxADPCMEncodeSink {
8 type Error: Sized;
9
10 fn reserve(&mut self, bytes_amount: usize) -> Result<(), Self::Error> {
14 Ok(())
15 }
16
17 fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error>;
21}
22
23#[cfg(feature = "std")]
24impl XboxADPCMEncodeSink for std::vec::Vec<u8> {
25 type Error = ();
26
27 fn reserve(&mut self, bytes_amount: usize) -> Result<(), Self::Error> {
28 Ok(self.reserve_exact(bytes_amount))
29 }
30
31 fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
32 Ok(self.extend_from_slice(&bytes))
33 }
34}
35
36pub(crate) const PCM_BUFFER_EXTRA: usize = 2;
38pub(crate) const PCM_BUFFER_CAPACITY: usize = SAMPLES_PER_ADPCM_BLOCK + PCM_BUFFER_EXTRA;
39
40pub struct XboxADPCMEncoder<'a, E> {
42 channels: [ADPCMChannel; MAX_AUDIO_CHANNEL_COUNT],
44
45 num_channels: usize,
47
48 lookahead: usize,
50
51 buffer: [[i16; PCM_BUFFER_CAPACITY]; MAX_AUDIO_CHANNEL_COUNT],
53
54 buffer_size: usize,
56
57 predictors_initialized: bool,
59
60 sink: &'a mut dyn XboxADPCMEncodeSink<Error = E>
62}
63
64impl<'a, E> XboxADPCMEncoder<'a, E> where E: Sized {
65 pub fn new(num_channels: usize, lookahead: u8, sink: &'a mut dyn XboxADPCMEncodeSink<Error = E>) -> XboxADPCMEncoder<'a, E> {
73 assert!(num_channels > 0 && num_channels <= MAX_AUDIO_CHANNEL_COUNT, "num_channels must be between 1 and {}", MAX_AUDIO_CHANNEL_COUNT);
74
75 XboxADPCMEncoder {
76 channels: <[ADPCMChannel; MAX_AUDIO_CHANNEL_COUNT]>::default(),
77 num_channels,
78 lookahead: lookahead as usize,
79 buffer_size: 0,
80 buffer: [[0i16; PCM_BUFFER_CAPACITY]; MAX_AUDIO_CHANNEL_COUNT],
81 predictors_initialized: false,
82 sink
83 }
84 }
85
86 pub fn encode<B: AsRef<[C]>, C: AsRef<[i16]>>(&mut self, input: B) -> Result<(), E> {
94 let input_arr = input.as_ref();
95 assert_eq!(self.num_channels, input_arr.len(), "input channel count is incorrect");
96
97 let sample_count = input_arr[0].as_ref().len();
98 for i in 1..self.num_channels {
99 assert_eq!(sample_count, input_arr[i].as_ref().len(), "sample count of channel {i} does not match the sample count of channel 0");
100 }
101
102 let total_samples_after_this = sample_count + self.buffer_size;
104
105 if total_samples_after_this != 0 {
109 self.sink.reserve((total_samples_after_this + (SAMPLES_PER_ADPCM_BLOCK - 1)) / SAMPLES_PER_ADPCM_BLOCK * ADPCM_BLOCK_SIZE * self.num_channels)?;
110 }
111
112 let mut samples_loaded = 0;
114 while samples_loaded != sample_count {
115 let samples_left_to_load = sample_count - samples_loaded;
116 let samples_free = PCM_BUFFER_CAPACITY - self.buffer_size;
117 let samples_that_can_be_loaded = samples_free.min(samples_left_to_load);
118 for c in 0..self.num_channels {
119 let input_samples = &input_arr[c].as_ref()[samples_loaded..];
120 let buff_samples = &mut self.buffer[c][self.buffer_size..];
121 for i in 0..samples_that_can_be_loaded {
122 buff_samples[i] = input_samples[i];
123 }
124 }
125
126 samples_loaded += samples_that_can_be_loaded;
127 self.buffer_size += samples_that_can_be_loaded;
128
129 if self.buffer_size == PCM_BUFFER_CAPACITY {
130 self.initialize_predictors();
131 self.encode_block()?;
132 }
133 }
134
135 Ok(())
136 }
137
138 pub fn finish(&mut self) -> Result<(), E> {
142 if self.buffer_size != 0 {
143 self.initialize_predictors();
145
146 for c in &mut self.buffer[0..self.num_channels] {
148 for b in &mut c[self.buffer_size..PCM_BUFFER_CAPACITY] {
149 *b = 0;
150 }
151 }
152 self.buffer_size = PCM_BUFFER_CAPACITY;
153
154 self.encode_block()?;
156 }
157 self.reset();
158 Ok(())
159 }
160
161 pub fn reset(&mut self) {
165 self.predictors_initialized = false;
166 self.buffer_size = 0;
167 }
168
169 fn encode_block(&mut self) -> Result<(), E> {
171 debug_assert_eq!(PCM_BUFFER_CAPACITY, self.buffer_size, "called encode_block on a non-populated sample buffer");
172 debug_assert!(self.predictors_initialized, "called encode_block but predictors not initialized");
173
174 let mut bytes_to_write = [0u8; ADPCM_BLOCK_SIZE * MAX_AUDIO_CHANNEL_COUNT];
175 let total_bytes_to_write = ADPCM_BLOCK_SIZE * self.num_channels;
176
177 for ch in 0..self.num_channels {
179 let s = self.buffer[ch][0];
181 bytes_to_write[0 + ch * 4] = (s & 0xFF) as u8; bytes_to_write[1 + ch * 4] = ((s >> 8) & 0xFF) as u8;
183 bytes_to_write[2 + ch * 4] = self.channels[ch].index as u8;
184 self.channels[ch].pcmdata = s as i32;
185 }
186
187 self.encode_chunks(&mut bytes_to_write[self.num_channels * 4..total_bytes_to_write]);
189 for ch in 0..self.num_channels {
190 for b in 0..PCM_BUFFER_EXTRA {
191 self.buffer[ch][b] = self.buffer[ch][PCM_BUFFER_CAPACITY - PCM_BUFFER_EXTRA + b]; }
193 }
194 self.buffer_size = PCM_BUFFER_EXTRA;
195
196 self.sink.write(&bytes_to_write[..total_bytes_to_write])
198 }
199
200 fn encode_chunks(&mut self, output: &mut [u8]) {
202 const BYTES_PER_CHANNEL_PER_BLOCK: usize = SAMPLES_PER_CHUNK / 2;
203 let output_channel_stride = self.num_channels * BYTES_PER_CHANNEL_PER_BLOCK;
204
205 for chunk in 0..CHUNKS_PER_BLOCK {
206 let chunk_start = 1 + chunk * SAMPLES_PER_CHUNK;
207 let output_offset = output_channel_stride * chunk;
208 for channel in 0..self.num_channels {
209 let output_offset = output_offset + channel * BYTES_PER_CHANNEL_PER_BLOCK;
210 let chunk_samples = &self.buffer[channel][chunk_start..];
211 for i in 0..BYTES_PER_CHANNEL_PER_BLOCK {
212 let pchan = &mut self.channels[channel];
213 let buff_offset = i * 2;
214 let low = encode_sample(pchan, self.lookahead, &chunk_samples[buff_offset..]);
215 let high = encode_sample(pchan, self.lookahead, &chunk_samples[buff_offset + 1..]);
216 output[output_offset + i] = low | (high << 4);
217 }
218 }
219 }
220 }
221
222 fn initialize_predictors(&mut self) {
226 if self.predictors_initialized {
227 return
228 }
229 for c in 0..self.num_channels {
230 let mut avg = 0;
232 let buffer = &self.buffer[c];
233 for i in 1..self.buffer_size {
234 let this_sample = buffer[i] as i32;
235 let prev_sample = buffer[i-1] as i32;
236 avg = (avg + (this_sample - prev_sample)) / 8;
237 }
238
239 let mut initial_index = STEP_TABLE.len() - 1;
241 for i in 0..STEP_TABLE.len() - 1 {
242 let table_val = STEP_TABLE[i];
243 let table_val_next = STEP_TABLE[i + 1];
244 let table_avg = ((table_val as i32) + (table_val_next as i32)) / 2;
245 if avg < table_avg {
246 initial_index = i;
247 break;
248 }
249 }
250
251 self.channels[c] = ADPCMChannel {
252 pcmdata: 0,
253 index: initial_index
254 };
255 }
256 self.predictors_initialized = true
257 }
258}
259
260fn calculate_minimum_error(index: usize, pcmdata: i32, sample: i32, samples: &[i16], lookahead: usize, best_nibble: &mut u8) -> f64 {
262 let calculate_minimum_error_next = |index: usize, pcmdata: i32, nibble: u8| -> f64 {
263 let index = clamp_table_index(index as isize + INDEX_TABLE[nibble as usize & 0x7]);
264 calculate_minimum_error(index, pcmdata, samples[0] as i32, &samples[1..], lookahead - 1, &mut 0)
265 };
266
267 let delta = sample - pcmdata;
269 let step = STEP_TABLE[index] as u16;
270
271 let nibble = if delta < 0 {
273 ((-delta << 2) as u32 / step as u32).min(7) as u8 | 0x8
274 }
275 else {
276 ((delta << 2) as u32 / step as u32).min(7) as u8
277 };
278 *best_nibble = nibble;
279
280 let pcmdata_a = clamp_sample(pcmdata + calculate_delta(step, nibble));
282 let mut min_error = pcmdata_a.abs_diff(sample).pow(2) as f64;
283 if lookahead == 0 {
284 return min_error;
285 }
286 min_error += calculate_minimum_error_next(index, pcmdata_a, nibble);
287
288 for nibble2 in 0..=0xF {
290 if nibble2 == nibble {
291 continue
292 }
293
294 let pcmdata_b = clamp_sample(pcmdata + calculate_delta(step, nibble2));
295 let error = pcmdata_b.abs_diff(sample).pow(2) as f64;
296
297 if error >= min_error {
299 continue
300 }
301
302 let error = error + calculate_minimum_error_next(index, pcmdata_b, nibble2);
303 if error >= min_error {
304 continue
305 }
306
307 *best_nibble = nibble2;
308 min_error = error;
309 }
310
311 min_error
312}
313
314fn encode_sample(pchan: &mut ADPCMChannel, lookahead: usize, samples: &[i16]) -> u8 {
316 let current_sample = samples[0] as i32;
317 let next_samples = &samples[1..];
318 let step = STEP_TABLE[pchan.index];
319
320 let mut nibble = 0;
321 calculate_minimum_error(pchan.index, pchan.pcmdata, current_sample, next_samples, lookahead.min(next_samples.len()), &mut nibble);
322 pchan.index = clamp_table_index(pchan.index as isize + INDEX_TABLE[(nibble & 0x7) as usize]) as usize;
323 pchan.pcmdata = clamp_sample(pchan.pcmdata + calculate_delta(step, nibble));
324
325 nibble
326}