msg_tool\utils/
flac.rs

1//! FLAC audio utilities.
2use super::pcm::*;
3use crate::ext::io::*;
4use crate::scripts::base::*;
5use crate::types::*;
6use anyhow::Result;
7use libflac_sys::*;
8use std::ffi::CStr;
9use std::io::{Read, Seek, Write};
10
11extern "C" fn write_callback(
12    _encoder: *const FLAC__StreamEncoder,
13    buffer: *const u8,
14    bytes: usize,
15    _samples: u32,
16    _current_frame: u32,
17    client_data: *mut std::ffi::c_void,
18) -> FLAC__StreamEncoderWriteStatus {
19    let writer = unsafe { &mut *(client_data as *mut &mut dyn WriteSeek) };
20    let slice = unsafe { std::slice::from_raw_parts(buffer, bytes) };
21    match writer.write_all(slice) {
22        Ok(_) => FLAC__STREAM_ENCODER_WRITE_STATUS_OK,
23        Err(_) => FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR,
24    }
25}
26
27extern "C" fn tell_callback(
28    _encoder: *const FLAC__StreamEncoder,
29    absolute_byte_offset: *mut u64,
30    client_data: *mut std::ffi::c_void,
31) -> FLAC__StreamEncoderTellStatus {
32    if absolute_byte_offset.is_null() {
33        return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
34    }
35    let writer = unsafe { &mut *(client_data as *mut &mut dyn WriteSeek) };
36    match writer.stream_position() {
37        Ok(pos) => {
38            unsafe {
39                *absolute_byte_offset = pos;
40            }
41            FLAC__STREAM_ENCODER_TELL_STATUS_OK
42        }
43        Err(_) => FLAC__STREAM_ENCODER_TELL_STATUS_ERROR,
44    }
45}
46
47extern "C" fn seek_callback(
48    _encoder: *const FLAC__StreamEncoder,
49    absolute_byte_offset: u64,
50    client_data: *mut std::ffi::c_void,
51) -> FLAC__StreamEncoderSeekStatus {
52    let writer = unsafe { &mut *(client_data as *mut &mut dyn WriteSeek) };
53    match writer.seek(std::io::SeekFrom::Start(absolute_byte_offset)) {
54        Ok(_) => FLAC__STREAM_ENCODER_SEEK_STATUS_OK,
55        Err(_) => FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR,
56    }
57}
58
59fn handle_init_error(status: u32) -> Result<()> {
60    if status == 0 {
61        return Ok(());
62    }
63    let index = status as usize;
64    let s = unsafe { CStr::from_ptr(FLAC__StreamEncoderInitStatusString[index]) };
65    Err(anyhow::anyhow!(
66        "FLAC encoder error: {}",
67        s.to_string_lossy()
68    ))
69}
70
71struct EncoderHandle {
72    encoder: *mut FLAC__StreamEncoder,
73}
74
75impl Drop for EncoderHandle {
76    fn drop(&mut self) {
77        unsafe {
78            FLAC__stream_encoder_delete(self.encoder);
79        }
80    }
81}
82
83/// Writes lossless audio data to a flac file.
84///
85/// * `header` - The PCM format header.
86/// * `reader` - The reader to read audio data from.
87/// * `writer` - The writer to write audio data to.
88/// * `config` - Extra configuration options.
89pub fn write_flac<W: Write + Seek, R: Read>(
90    header: &PcmFormat,
91    mut reader: R,
92    mut writer: W,
93    config: &ExtraConfig,
94) -> Result<()> {
95    if header.bits_per_sample > 32 {
96        return Err(anyhow::anyhow!(
97            "FLAC supports up to 32 bits per sample, got {}",
98            header.bits_per_sample
99        ));
100    }
101    let encoder = unsafe { FLAC__stream_encoder_new() };
102    if encoder.is_null() {
103        return Err(anyhow::anyhow!("Failed to create FLAC encoder"));
104    }
105    let encoder = EncoderHandle { encoder };
106    unsafe {
107        FLAC__stream_encoder_set_channels(encoder.encoder, header.channels as u32);
108        FLAC__stream_encoder_set_compression_level(encoder.encoder, config.flac_compression_level);
109        FLAC__stream_encoder_set_bits_per_sample(encoder.encoder, header.bits_per_sample as u32);
110        FLAC__stream_encoder_set_sample_rate(encoder.encoder, header.sample_rate);
111        FLAC__stream_encoder_set_verify(encoder.encoder, 1);
112    }
113    let mut raw_writer: &mut dyn WriteSeek = &mut writer;
114    let raw_writer = &mut raw_writer as *mut _;
115    handle_init_error(unsafe {
116        FLAC__stream_encoder_init_stream(
117            encoder.encoder,
118            Some(write_callback),
119            Some(seek_callback),
120            Some(tell_callback),
121            None,
122            raw_writer as *mut std::ffi::c_void,
123        )
124    })?;
125    let mut buf = Vec::<i32>::with_capacity(1024 * header.channels as usize);
126    buf.resize(buf.capacity(), 0);
127    let mut read_buf = Vec::<u8>::with_capacity(
128        (header.bits_per_sample / 8) as usize * 1024 * header.channels as usize,
129    );
130    read_buf.resize(read_buf.capacity(), 0);
131    loop {
132        let readed = reader.read(&mut read_buf)?;
133        if readed == 0 {
134            break;
135        }
136        let mut r = MemReaderRef::new(&read_buf[..readed]);
137        let samples =
138            readed as usize / (header.bits_per_sample as usize / 8) / header.channels as usize;
139        let mut i = 0;
140        for _ in 0..samples {
141            for _ in 0..header.channels {
142                let sample = match header.bits_per_sample {
143                    8 => r.read_i8()? as i32,
144                    16 => r.read_i16()? as i32,
145                    24 => {
146                        let b1 = r.read_u8()? as i32;
147                        let b2 = r.read_u8()? as i32;
148                        let b3 = r.read_u8()? as i32;
149                        let mut val = (b3 << 16) | (b2 << 8) | b1;
150                        // Sign extend from 24 bits to 32
151                        if val & 0x800000 != 0 {
152                            val |= !0xffffff;
153                        }
154                        val
155                    }
156                    32 => r.read_i32()?,
157                    _ => {
158                        return Err(anyhow::anyhow!(
159                            "Unsupported bits per sample: {}",
160                            header.bits_per_sample
161                        ));
162                    }
163                };
164                buf[i] = sample;
165                i += 1;
166            }
167        }
168        if samples == 0 {
169            break;
170        }
171        if unsafe {
172            FLAC__stream_encoder_process_interleaved(encoder.encoder, buf.as_ptr(), samples as u32)
173        } == 0
174        {
175            let state = unsafe { FLAC__stream_encoder_get_state(encoder.encoder) };
176            let s = unsafe { CStr::from_ptr(FLAC__StreamEncoderStateString[state as usize]) };
177            return Err(anyhow::anyhow!(
178                "FLAC encoding error: {}",
179                s.to_string_lossy()
180            ));
181        }
182    }
183    if unsafe { FLAC__stream_encoder_finish(encoder.encoder) } == 0 {
184        let state = unsafe { FLAC__stream_encoder_get_state(encoder.encoder) };
185        let s = unsafe { CStr::from_ptr(FLAC__StreamEncoderStateString[state as usize]) };
186        return Err(anyhow::anyhow!(
187            "FLAC encoding error: {}",
188            s.to_string_lossy()
189        ));
190    }
191    Ok(())
192}