xbadpcm/
encoder.rs

1use crate::*;
2
3/// Writer outputting ADPCM blocks.
4///
5/// This is automatically implemented for [`Vec<u8>`](std::vec::Vec) if the `"std"` feature is enabled (which it is by default).
6#[allow(unused_variables)]
7pub trait XboxADPCMEncodeSink {
8    type Error: Sized;
9
10    /// Reserve an amount of bytes at the end of the output.
11    ///
12    /// Implementing this is optional, but it can be used to hint the amount of bytes to be written for allocations such as for memory-based buffers.
13    fn reserve(&mut self, bytes_amount: usize) -> Result<(), Self::Error> {
14        Ok(())
15    }
16
17    /// Write the bytes to the end of the output.
18    ///
19    /// Implementing this is **required**.
20    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
36// Buffer size to use in the encoder. We keep extra samples at the end so we have a few extra samples to go by at the end.
37pub(crate) const PCM_BUFFER_EXTRA: usize = 2;
38pub(crate) const PCM_BUFFER_CAPACITY: usize = SAMPLES_PER_ADPCM_BLOCK + PCM_BUFFER_EXTRA;
39
40/// XboxADPCM encoder implementation.
41pub struct XboxADPCMEncoder<'a, E> {
42    /// Channel data (from adpcm-xq)
43    channels: [ADPCMChannel; MAX_AUDIO_CHANNEL_COUNT],
44
45    /// Number of channels
46    num_channels: usize,
47
48    /// Lookahead value
49    lookahead: usize,
50
51    /// Buffer containing the next samples to be processed
52    buffer: [[i16; PCM_BUFFER_CAPACITY]; MAX_AUDIO_CHANNEL_COUNT],
53
54    /// Current size of the buffer
55    buffer_size: usize,
56
57    /// Did we initialize the predictors?
58    predictors_initialized: bool,
59
60    /// Output buffer
61    sink: &'a mut dyn XboxADPCMEncodeSink<Error = E>
62}
63
64impl<'a, E> XboxADPCMEncoder<'a, E> where E: Sized {
65    /// Initialize an encoder with the given channel count, and lookahead for the given sink.
66    ///
67    /// Higher lookahead may slightly reduce noise, but it will also exponentially increase encoding time.
68    ///
69    /// # Panics
70    ///
71    /// Panics if `num_channels` is not between 1 and 8
72    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    /// Encode with the given samples using some samples.
87    ///
88    /// Note that this may not always encode all samples passed and may store some in a buffer. To flush the buffer, run [`XboxADPCMEncoder::finish`].
89    ///
90    /// # Panics
91    ///
92    /// Panics if the input has the wrong number of channels or the samples are wrong.
93    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        // Calculate how many samples we will process.
103        let total_samples_after_this = sample_count + self.buffer_size;
104
105        // Predict how many bytes we will need to reserve, always rounding up to the next block.
106        //
107        // If we have any samples, we need at least one block even if we may not immediately encode them yet.
108        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        // Process all samples.
113        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    /// Finish encoding and then resets the encoder.
139    ///
140    /// This will encode all remaining samples, filling any unused samples with silence. If a simple reset is desired without any further writes, call [`XboxADPCMEncoder::reset`] instead.
141    pub fn finish(&mut self) -> Result<(), E> {
142        if self.buffer_size != 0 {
143            // Init predictors
144            self.initialize_predictors();
145
146            // Zero-out everything at the end and set our buffer size.
147            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            // Encode what is left
155            self.encode_block()?;
156        }
157        self.reset();
158        Ok(())
159    }
160
161    /// Reset the encoder immediately without writing any more samples.
162    ///
163    /// Any samples yet to be encoded will be dropped. If this is not desired, call [`XboxADPCMEncoder::finish`] instead.
164    pub fn reset(&mut self) {
165        self.predictors_initialized = false;
166        self.buffer_size = 0;
167    }
168
169    /// Encode the contents of the buffer.
170    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        // Write the header
178        for ch in 0..self.num_channels {
179            // Get our first sample and set it since it's uncompressed.
180            let s = self.buffer[ch][0];
181            bytes_to_write[0 + ch * 4] = (s & 0xFF) as u8; // write the first sample uncompressed
182            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        // Write the chunks
188        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]; // copy the last samples back to the beginning
192            }
193        }
194        self.buffer_size = PCM_BUFFER_EXTRA;
195
196        // Write all of it
197        self.sink.write(&bytes_to_write[..total_bytes_to_write])
198    }
199
200    /// Encode all chunks
201    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    /// Initialize predictors with the contents of the buffer.
223    ///
224    /// This should be called whenever a block is encoded.
225    fn initialize_predictors(&mut self) {
226        if self.predictors_initialized {
227            return
228        }
229        for c in 0..self.num_channels {
230            // Calculate initial ADPCM predictors using decaying average
231            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            // Set our initial step index to this
240            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
260/// Calculate minimum error recursively.
261fn 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    // Get our delta!
268    let delta = sample - pcmdata;
269    let step = STEP_TABLE[index] as u16;
270
271    // Encode our nibble
272    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    // Calculate the minimum error. Return if base case.
281    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    // Calculate all other possible nibbles
289    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 the error is already too high, skip so we don't do any (possibly) slow recursion
298        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
314/// Encode the samples.
315fn 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}