1use std::{ffi::c_char, mem::zeroed, path::PathBuf, ptr::null_mut, slice::from_raw_parts};
2
3use libflac_sys::*;
4
5pub struct FlacBuilder<'data, Sample>
6where
7 Sample: IntoSample,
8{
9 data: InputData<'data, Sample>,
10 bps: BpsLevel,
11 sample_rate: u32,
12 output_path: Option<String>,
13 compression_level: u32,
14 padding: u32,
15 vorbis_commenets: Vec<(String, String)>,
16 metadata_blocks: Vec<*mut FLAC__StreamMetadata>,
17}
18
19impl<'data, Sample: IntoSample + Copy + Default> FlacBuilder<'data, Sample> {
20 pub fn from_planar(data: &'data Vec<Vec<Sample>>, sample_rate: u32) -> Self {
21 Self::new(InputData::Planar(data), sample_rate)
22 }
23
24 pub fn from_interleaved(data: &'data [Sample], channels: usize, sample_rate: u32) -> Self {
25 Self::new(InputData::Interleaved { data, channels }, sample_rate)
26 }
27
28 pub fn new(data: InputData<'data, Sample>, sample_rate: u32) -> Self {
29 FlacBuilder {
30 data,
31 sample_rate,
32 bps: BpsLevel::Bps16,
33 compression_level: 5,
34 padding: 500,
35 vorbis_commenets: vec![],
36 metadata_blocks: vec![],
37 output_path: None,
38 }
39 }
40
41 pub fn compression_level(mut self, level: u32) -> Self {
42 self.compression_level = level;
43 self
44 }
45
46 pub fn bps(mut self, bps: BpsLevel) -> Self {
47 self.bps = bps;
48 self
49 }
50
51 pub fn padding(mut self, padding: u32) -> Self {
52 self.padding = padding;
53 self
54 }
55
56 pub fn artist(self, artist: &str) -> Self {
57 self.vorbis_comment("ARTIST", artist)
58 }
59
60 pub fn album(self, album: &str) -> Self {
61 self.vorbis_comment("ALBUM", album)
62 }
63
64 pub fn title(self, title: &str) -> Self {
65 self.vorbis_comment("TITLE", title)
66 }
67
68 pub fn year(self, year: u32) -> Self {
69 self.vorbis_comment("YEAR", &year.to_string())
70 }
71
72 pub fn track_number(self, number: i32) -> Self {
73 self.vorbis_comment("TRACKNUMBER", &number.to_string())
74 }
75
76 pub fn vorbis_comment(mut self, key: &str, value: &str) -> Self {
77 self.vorbis_commenets
78 .push((format!("{}\0", key), format!("{}\0", value)));
79 self
80 }
81
82 pub fn output_path(mut self, path: PathBuf) -> Self {
83 self.output_path = Some(format!("{}\0", path.display()).to_string());
84 self
85 }
86
87 unsafe fn prepare(&mut self) -> Result<*mut FLAC__StreamEncoder, EncoderError> {
88 if self.data.total_samples() == 0 {
89 return Err(EncoderError::NoData);
90 }
91
92 let encoder = FLAC__stream_encoder_new();
93
94 if encoder.is_null() {
95 return Err(EncoderError::InitializationError);
96 }
97
98 if 0 == FLAC__stream_encoder_set_verify(encoder, 1) {
99 return Err(EncoderError::VerificationError);
100 }
101
102 if 0 == FLAC__stream_encoder_set_compression_level(encoder, self.compression_level) {
103 return Err(EncoderError::InvalidCompressionLevel);
104 }
105
106 let channels = self.data.channel_count();
107
108 if 0 == FLAC__stream_encoder_set_channels(encoder, channels as u32) {
109 return Err(EncoderError::InvalidChannelCount);
110 }
111
112 if 0 == FLAC__stream_encoder_set_bits_per_sample(encoder, self.bps.to_u32()) {
113 return Err(EncoderError::InvalidSampleType);
114 }
115
116 if 0 == FLAC__stream_encoder_set_sample_rate(encoder, self.sample_rate) {
117 return Err(EncoderError::InvalidSampleRate);
118 }
119
120 if 0 == FLAC__stream_encoder_set_total_samples_estimate(
121 encoder,
122 self.data.total_samples() as u64,
123 ) {
124 return Err(EncoderError::TooManyOrTooFewSamples);
125 }
126
127 if self.vorbis_commenets.is_empty() {
128 if 0 == FLAC__stream_encoder_set_metadata(encoder, null_mut(), 0) {
129 return Err(EncoderError::FailedToSetMetadata);
130 }
131 }
132
133 if !self.vorbis_commenets.is_empty() {
134 let metadata_block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
135
136 if metadata_block.is_null() {
137 return Err(EncoderError::InitializationError);
138 }
139
140 for (key, value) in &self.vorbis_commenets {
141 let mut entry: FLAC__StreamMetadata_VorbisComment_Entry = zeroed();
142
143 if 0 == FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(
144 &mut entry,
145 key.as_bytes().as_ptr() as *const c_char,
146 value.as_bytes().as_ptr() as *const c_char,
147 ) {
148 return Err(EncoderError::InvalidVorbisComment(key.clone()));
149 }
150
151 if 0 == FLAC__metadata_object_vorbiscomment_append_comment(metadata_block, entry, 0)
152 {
153 return Err(EncoderError::FailedToSetMetadata);
154 }
155 }
156
157 self.metadata_blocks.push(metadata_block);
158 }
159
160 let padding_block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
161 if !padding_block.is_null() {
162 (*padding_block).length = self.padding;
163 self.metadata_blocks.push(padding_block);
164 }
165
166 if 0 == FLAC__stream_encoder_set_metadata(
167 encoder,
168 self.metadata_blocks.as_mut_ptr(),
169 self.metadata_blocks.len() as u32,
170 ) {
171 return Err(EncoderError::FailedToSetMetadata);
172 }
173
174 Ok(encoder)
175 }
176
177 unsafe fn cleanup(&mut self) {
178 for block in self.metadata_blocks.iter() {
179 FLAC__metadata_object_delete(*block);
180 }
181 self.metadata_blocks.clear();
182 }
183
184 pub fn write_file<P: Into<PathBuf>>(mut self, path: P) -> Result<(), EncoderError> {
185 self.output_path = Some(format!("{}\0", path.into().display()).to_string());
186 let _ = self.build()?;
187 Ok(())
188 }
189
190 pub fn build(mut self) -> Result<Vec<u8>, EncoderError> {
191 if !self.data.channel_sizes_match() {
192 return Err(EncoderError::MismatchedSampleCountPerChannels);
193 }
194
195 unsafe {
196 let encoder = match self.prepare() {
197 Ok(encoder) => encoder,
198 Err(err) => {
199 self.cleanup();
200 return Err(err);
201 }
202 };
203
204 let mut callback_data = None;
205
206 if let Some(path) = self.output_path.clone() {
207 FLAC__stream_encoder_init_file(
208 encoder,
209 path.as_bytes().as_ptr() as *const _,
210 None,
211 null_mut(),
212 );
213 } else {
214 callback_data = Some(WriteCallbackData {
215 data: Vec::with_capacity(self.data.total_samples()),
216 cursor: 0,
217 });
218
219 FLAC__stream_encoder_init_stream(
220 encoder,
221 Some(write_callback),
222 Some(seek_callback),
223 Some(tell_callback),
224 None,
225 callback_data.as_ref().unwrap() as *const _ as *mut _,
226 );
227 }
228
229 let mut ok = 0;
230
231 let channels = self.data.channel_count();
232
233 let block_size: usize = 1024;
234 let mut input_cursor = 0;
235
236 while input_cursor < self.data.samples_per_channel() {
237 let mut input_data: Vec<FLAC__int32> = Vec::with_capacity(block_size * channels);
238
239 for block_sample_i in 0..block_size {
240 for channel_i in 0..self.data.channel_count() {
241 input_data.push(
242 match &self.data {
243 InputData::Interleaved { data, channels } => data
244 .get((input_cursor + block_sample_i) * channels + channel_i)
245 .copied()
246 .unwrap_or(Sample::default()),
247 InputData::Planar(data) => data
248 .get(channel_i)
249 .and_then(|c| c.get(input_cursor + block_sample_i))
250 .copied()
251 .unwrap_or(Sample::default()),
252 }
253 .to_bps_level(self.bps),
254 );
255 }
256 }
257
258 let remaining = self.data.total_samples() - input_cursor;
259 let used_block_size = block_size.min(remaining);
260
261 let block_ptr = input_data.as_ptr() as *const FLAC__int32;
262
263 ok |= FLAC__stream_encoder_process_interleaved(
264 encoder,
265 block_ptr,
266 (used_block_size) as u32,
267 );
268
269 input_cursor += block_size;
270 }
271
272 ok |= FLAC__stream_encoder_finish(encoder);
273
274 self.cleanup();
275
276 if ok == 0 {
277 return Err(EncoderError::EncodingError);
278 }
279
280 Ok(callback_data.map_or_else(|| vec![], |data| data.data))
281 }
282 }
283}
284
285#[derive(Debug, Clone, Copy)]
286pub enum BpsLevel {
287 Bps16,
288 Bps20,
289 Bps24,
290}
291
292impl BpsLevel {
293 pub fn to_u32(&self) -> u32 {
294 match self {
295 BpsLevel::Bps16 => 16,
296 BpsLevel::Bps20 => 20,
297 BpsLevel::Bps24 => 24,
298 }
299 }
300}
301
302pub struct WriteCallbackData {
303 pub data: Vec<u8>,
304 pub cursor: usize,
305}
306
307pub enum InputData<'a, Sample>
308where
309 Sample: IntoSample,
310{
311 Interleaved { data: &'a [Sample], channels: usize },
312 Planar(&'a Vec<Vec<Sample>>),
313}
314
315impl<'a, Sample: IntoSample> InputData<'a, Sample> {
316 fn channel_count(&self) -> usize {
317 match self {
318 InputData::Interleaved { channels, .. } => *channels,
319 InputData::Planar(data) => data.len(),
320 }
321 }
322
323 fn samples_per_channel(&self) -> usize {
324 match self {
325 InputData::Interleaved { data, channels } => data.len() / channels,
326 InputData::Planar(data) => {
327 if data.is_empty() {
328 return 0;
329 }
330 data[0].len()
331 }
332 }
333 }
334
335 fn total_samples(&self) -> usize {
336 match self {
337 InputData::Interleaved { data, .. } => data.len(),
338 InputData::Planar(data) => data.iter().map(|channel| channel.len()).sum(),
339 }
340 }
341
342 fn channel_sizes_match(&self) -> bool {
343 match self {
344 InputData::Interleaved { data, channels } => data.len() % *channels == 0,
345 InputData::Planar(data) => {
346 if data.is_empty() {
347 return true;
348 }
349 let size = data[0].len();
350 data.iter().all(|channel| channel.len() == size)
351 }
352 }
353 }
354}
355
356#[no_mangle]
357unsafe extern "C" fn write_callback(
358 _encoder: *const FLAC__StreamEncoder,
359 buffer: *const FLAC__byte,
360 bytes: usize,
361 _samples: u32,
362 _current_frame: u32,
363 client_data: *mut std::ffi::c_void,
364) -> u32 {
365 let data = unsafe { &mut *(client_data as *mut WriteCallbackData) };
366
367 if data.cursor + bytes > data.data.len() {
368 let needed = (data.cursor + bytes) - data.data.len();
369 data.data.extend(vec![0u8; needed]);
370 }
371
372 let new_data = from_raw_parts(buffer, bytes);
373
374 for i in 0..bytes {
375 data.data[data.cursor] = new_data[i];
376 data.cursor += 1;
377 }
378
379 0
380}
381
382#[no_mangle]
383unsafe extern "C" fn seek_callback(
384 _encoder: *const FLAC__StreamEncoder,
385 absolute_byte_offset: u64,
386 client_data: *mut std::ffi::c_void,
387) -> u32 {
388 let data = unsafe { &mut *(client_data as *mut WriteCallbackData) };
389
390 data.cursor = absolute_byte_offset as usize;
391
392 FLAC__STREAM_ENCODER_SEEK_STATUS_OK
393}
394
395#[no_mangle]
396unsafe extern "C" fn tell_callback(
397 _encoder: *const FLAC__StreamEncoder,
398 absolute_byte_offset: *mut u64,
399 client_data: *mut std::ffi::c_void,
400) -> u32 {
401 let data = unsafe { &mut *(client_data as *mut WriteCallbackData) };
402
403 *absolute_byte_offset = data.cursor as u64;
404
405 FLAC__STREAM_ENCODER_SEEK_STATUS_OK
406}
407
408#[derive(Debug)]
409pub enum EncoderError {
410 NoData,
411 InitializationError,
412 VerificationError,
413 InvalidCompressionLevel,
414 InvalidChannelCount,
415 InvalidSampleType,
416 TooManyOrTooFewSamples,
417 MismatchedSampleCountPerChannels,
418 FailedToInitializeEncoder,
419 InvalidVorbisComment(String),
420 FailedToSetMetadata,
421 EncodingError,
422 InvalidSampleRate,
423}
424
425pub trait IntoSample {
426 fn to_i16(&self) -> i16;
427 fn to_i20(&self) -> i32;
428 fn to_i24(&self) -> i32;
429
430 fn to_bps_level(&self, bps: BpsLevel) -> FLAC__int32 {
431 match bps {
432 BpsLevel::Bps16 => self.to_i16() as FLAC__int32,
433 BpsLevel::Bps20 => self.to_i20(),
434 BpsLevel::Bps24 => self.to_i24(),
435 }
436 }
437}
438
439impl IntoSample for f32 {
440 fn to_i16(&self) -> i16 {
441 let max = (1 << 15) - 1;
442 (self.clamp(-1.0, 1.0) * max as f32) as i16
443 }
444
445 fn to_i20(&self) -> i32 {
446 let max = (1 << 19) - 1;
447 ((self.clamp(-1.0, 1.0) * max as f32) as i32).clamp(-max, max)
448 }
449
450 fn to_i24(&self) -> i32 {
451 let max = (1 << 23) - 1;
452 ((self.clamp(-1.0, 1.0) * max as f32) as i32).clamp(-max, max)
453 }
454}
455
456impl IntoSample for f64 {
457 fn to_i16(&self) -> i16 {
458 let max = (1 << 15) - 1;
459 (self.clamp(-1.0, 1.0) * max as f64) as i16
460 }
461
462 fn to_i20(&self) -> i32 {
463 let max = (1 << 19) - 1;
464 ((self.clamp(-1.0, 1.0) * max as f64) as i32).clamp(-max, max)
465 }
466
467 fn to_i24(&self) -> i32 {
468 let max = (1 << 23) - 1;
469 ((self.clamp(-1.0, 1.0) * max as f64) as i32).clamp(-max, max)
470 }
471}