Skip to main content

mp3lame_encoder/
lib.rs

1//!High level wrapper over [mp3lame-sys](https://crates.io/crates/mp3lame-sys)
2//!
3//!## Example
4//!
5//!```rust
6//!use mp3lame_encoder::{Builder, Id3Tag, DualPcm, FlushNoGap};
7//!
8//!let id3tag = Id3Tag {
9//!    title: b"My title",
10//!    artist: &[],
11//!    album: b"My album",
12//!    album_art: &[],
13//!    year: b"Current year",
14//!    comment: b"Just my comment",
15//!};
16//!
17//!//Methods prefixed with `with_*` return Self for convenience
18//!let mut mp3_encoder = Builder::new().expect("Create LAME builder")
19//!    .with_num_channels(2).expect("set channels")
20//!    .with_sample_rate(44_100).expect("set sample rate")
21//!    .with_brate(mp3lame_encoder::Bitrate::Kbps192).expect("set brate")
22//!    .with_quality(mp3lame_encoder::Quality::Best).expect("set quality")
23//!    .with_vbr_mode(mp3lame_encoder::VbrMode::Mtrh).expect("set VBR")
24//!    .with_vbr_quality(mp3lame_encoder::Quality::Best).expect("set VBR quality")
25//!    .with_to_write_vbr_tag(true).expect("set to write VBR tag")
26//!    .with_id3_tag(id3tag).expect("set tags")
27//!    .build().expect("To initialize LAME encoder");
28//!
29//!//use actual PCM data
30//!let input = DualPcm {
31//!    left: &[0u16, 1024],
32//!    right: &[0u16, 1024],
33//!};
34//!
35//!let mut mp3_out_buffer = Vec::new();
36//!mp3_out_buffer.reserve(mp3lame_encoder::max_required_buffer_size(input.left.len()));
37//!let encoded_size = mp3_encoder.encode(input, mp3_out_buffer.spare_capacity_mut()).expect("To encode");
38//!unsafe {
39//!    mp3_out_buffer.set_len(mp3_out_buffer.len().wrapping_add(encoded_size));
40//!}
41//!
42//!let encoded_size = mp3_encoder.flush::<FlushNoGap>(mp3_out_buffer.spare_capacity_mut()).expect("to flush");
43//!unsafe {
44//!    mp3_out_buffer.set_len(mp3_out_buffer.len().wrapping_add(encoded_size));
45//!}
46//!//At this point your mp3_out_buffer should have full MP3 data, ready to be written on file system or whatever
47//!
48//!if mp3_encoder.lame_tag_size() > 0 {
49//!   let id3v2_tag_boundary = mp3_encoder.id3v2_tag_size();
50//!   assert_eq!(id3v2_tag_boundary, 158);
51//!   let mut lame_tag = [core::mem::MaybeUninit::uninit(); 1024];
52//!   assert!(lame_tag.len() >= mp3_encoder.lame_tag_size(), "Increase buffer size");
53//!   let lame_tag_size = mp3_encoder.lame_tag_encode(&mut lame_tag).expect("to write lame tag");
54//!   assert_eq!(mp3_encoder.lame_tag_size(), lame_tag_size.get());
55//!
56//!   //If you need VBR tag then you need to write mp3 file in following order
57//!   //- id3v2 tag
58//!   //- VBR tag
59//!   //- actual mp3 content
60//!   let chunks_to_write = [
61//!       &mp3_out_buffer[..id3v2_tag_boundary],
62//!       unsafe {
63//!           core::slice::from_raw_parts(lame_tag.as_ptr() as *const u8, lame_tag_size.get())
64//!       },
65//!       &mp3_out_buffer[id3v2_tag_boundary..],
66//!   ];
67//!} else {
68//!   let chunks_to_write = [
69//!       &mp3_out_buffer[..]
70//!   ];
71//!}
72//!```
73
74#![no_std]
75#![warn(missing_docs)]
76#![allow(clippy::style)]
77#![allow(clippy::missing_safety_doc)]
78#![cfg_attr(rustfmt, rustfmt_skip)]
79
80#[cfg(feature = "std")]
81extern crate std;
82
83extern crate alloc;
84
85pub use mp3lame_sys as ffi;
86
87use alloc::vec::Vec;
88use core::mem::{self, MaybeUninit};
89use core::num::{NonZeroU32, NonZeroUsize};
90use core::ptr::{self, NonNull};
91use core::{cmp, fmt};
92use core::ffi::c_int;
93
94mod input;
95pub use input::*;
96
97///Maximum size of album art
98pub const MAX_ALBUM_ART_SIZE: usize = 128 * 1024;
99
100///Calculates maximum required size for specified number of samples.
101///
102///Note that actual requirement may vary depending on encoder parameters,
103///but this size should be generally enough for encoding given number of samples
104pub const fn max_required_buffer_size(sample_number: usize) -> usize {
105    //add 25% sample number + mp3 frame size 7200
106    let mut sample_extra_size = sample_number / 4;
107    if (sample_number % 4) > 0 {
108        sample_extra_size = sample_extra_size.wrapping_add(1);
109    }
110    sample_number.wrapping_add(sample_extra_size).wrapping_add(7200)
111}
112
113#[derive(Debug, Copy, Clone, Eq, PartialEq)]
114///ID3 setter errors
115pub enum Id3TagError {
116    ///Specified buffer exceed limit of 128kb
117    AlbumArtOverflow,
118}
119
120#[derive(Debug, Copy, Clone, Eq, PartialEq)]
121///Encoder builder errors
122pub enum BuildError {
123    ///Generic error, indicates invalid input or state
124    Generic,
125    ///Failed to allocate memory
126    NoMem,
127    ///Invalid brate
128    BadBRate,
129    ///Invalid sample frequency
130    BadSampleFreq,
131    ///Internal error
132    InternalError,
133    ///Other errors, most likely unexpected.
134    Other(c_int),
135}
136
137impl BuildError {
138    #[inline(always)]
139    fn from_c_int(code: c_int) -> Result<(), Self> {
140        if code >= 0 {
141            return Ok(())
142        }
143
144        match code {
145            -1 => Err(Self::Generic),
146            -10 => Err(Self::NoMem),
147            -11 => Err(Self::BadBRate),
148            -12 => Err(Self::BadSampleFreq),
149            -13 => Err(Self::InternalError),
150            _ => Err(Self::Other(code)),
151        }
152    }
153}
154
155#[cfg(feature = "std")]
156impl std::error::Error for BuildError {
157}
158
159impl fmt::Display for BuildError {
160    #[inline]
161    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
162        match self {
163            Self::Generic => fmt.write_str("error"),
164            Self::NoMem => fmt.write_str("alloc failure"),
165            Self::BadBRate => fmt.write_str("bad bitrate"),
166            Self::BadSampleFreq => fmt.write_str("bad sample frequency"),
167            Self::InternalError => fmt.write_str("internal error"),
168            Self::Other(code) => fmt.write_fmt(format_args!("error code={code}")),
169        }
170    }
171}
172
173#[derive(Debug, Copy, Clone, Eq, PartialEq)]
174///Encoder errors
175pub enum EncodeError {
176    ///Indicates output buffer is insufficient.
177    ///
178    ///Consider using [max_required_buffer_size] to determine required
179    ///space to alloc.
180    BufferTooSmall,
181    ///Failed to allocate memory
182    NoMem,
183    ///Invalid encoder state
184    ///
185    ///Should not happen if encoder created through builder
186    InvalidState,
187    ///Psycho acoustic problems, whatever it means.
188    PsychoAcoustic,
189    ///Other errors, most likely unexpected.
190    Other(c_int),
191}
192
193impl EncodeError {
194    #[inline(always)]
195    fn from_c_int(code: c_int) -> Result<usize, Self> {
196        if code >= 0 {
197            return Ok(code as usize)
198        }
199
200        match code {
201            -1 => Err(Self::BufferTooSmall),
202            -2 => Err(Self::NoMem),
203            -3 => Err(Self::InvalidState),
204            -4 => Err(Self::PsychoAcoustic),
205            _ => Err(Self::Other(code)),
206        }
207    }
208}
209
210#[cfg(feature = "std")]
211impl std::error::Error for EncodeError {
212}
213
214impl fmt::Display for EncodeError {
215    #[inline]
216    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
217        match self {
218            Self::BufferTooSmall => fmt.write_str("output buffer is insufficient for encoder output"),
219            Self::NoMem => fmt.write_str("alloc failure"),
220            Self::InvalidState => fmt.write_str("attempt to use uninitialized encoder"),
221            Self::PsychoAcoustic => fmt.write_str("psycho acoustic problems"),
222            Self::Other(code) => fmt.write_fmt(format_args!("error code={code}")),
223        }
224    }
225}
226
227
228///Enumeration of valid values for `set_brate`
229#[derive(Copy, Clone)]
230#[repr(u16)]
231pub enum Bitrate {
232    ///8_000
233    Kbps8 = 8,
234    ///16_000
235    Kbps16 = 16,
236    ///24_000
237    Kbps24 = 24,
238    ///32_000
239    Kbps32 = 32,
240    ///40_000
241    Kbps40 = 40,
242    ///48_000
243    Kbps48 = 48,
244    ///64_000
245    Kbps64 = 64,
246    ///80_000
247    Kbps80 = 80,
248    ///96_000
249    Kbps96 = 96,
250    ///112_000
251    Kbps112 = 112,
252    ///128_000
253    Kbps128 = 128,
254    ///160_000
255    Kbps160 = 160,
256    ///192_000
257    Kbps192 = 192,
258    ///224_000
259    Kbps224 = 224,
260    ///256_000
261    Kbps256 = 256,
262    ///320_000
263    Kbps320 = 320,
264}
265
266///Alias to `Bitrate` with incorrect spelling
267pub use Bitrate as Birtate;
268
269#[derive(Copy, Clone)]
270#[repr(u8)]
271///Possible VBR types
272pub enum VbrMode {
273    ///Off.
274    Off = ffi::vbr_mode::vbr_off as u8,
275    ///MT.
276    Mt = ffi::vbr_mode::vbr_mt as u8,
277    ///RH.
278    Rh = ffi::vbr_mode::vbr_rh as u8,
279    ///ABR.
280    Abr = ffi::vbr_mode::vbr_abr as u8,
281    ///MTRH.
282    Mtrh = ffi::vbr_mode::vbr_mtrh as u8,
283}
284
285impl Default for VbrMode {
286    #[inline(always)]
287    fn default() -> Self {
288        Self::Mtrh
289    }
290}
291
292#[derive(Copy, Clone)]
293#[repr(u8)]
294///Possible modes for encoder
295pub enum Mode {
296    ///Mono.
297    Mono = ffi::MPEG_mode::MONO as u8,
298    ///Stereo.
299    Stereo = ffi::MPEG_mode::STEREO as u8,
300    ///Joint stereo.
301    JointStereo = ffi::MPEG_mode::JOINT_STEREO as u8,
302    ///Dual channel
303    ///
304    ///Unsupported so far.
305    DaulChannel = ffi::MPEG_mode::DUAL_CHANNEL as u8,
306    ///Not set.
307    NotSet = ffi::MPEG_mode::NOT_SET as u8,
308}
309
310///Possible quality parameter.
311///From best(0) to worst(9)
312#[derive(Copy, Clone)]
313#[repr(u8)]
314pub enum Quality {
315    ///Best possible quality
316    Best = 0,
317    ///Second best
318    SecondBest = 1,
319    ///Close to best
320    NearBest = 2,
321    ///Very nice
322    VeryNice = 3,
323    ///Nice
324    Nice = 4,
325    ///Good
326    Good = 5,
327    ///Decent
328    Decent = 6,
329    ///Okayish
330    Ok = 7,
331    ///Almost worst
332    SecondWorst = 8,
333    ///Worst
334    Worst = 9,
335}
336
337#[derive(Copy, Clone)]
338///ID3 tag as raw bytes.
339///
340///Use empty slice for `None`
341///
342///At the current moment, only up to 250 characters will be copied.
343pub struct Id3Tag<'a> {
344    ///Track's Title
345    pub title: &'a [u8],
346    ///Artist name
347    pub artist: &'a [u8],
348    ///Album name
349    pub album: &'a [u8],
350    ///Album art
351    ///
352    ///Must be image data.
353    ///
354    ///Allowed formats: PNG, JPG, GIF
355    ///
356    ///Maximum size is defined by constant MAX_ALBUM_ART_SIZE
357    ///When setting this metadata, make sure allocate at least MAX_ALBUM_ART_SIZE
358    pub album_art: &'a [u8],
359    ///Year
360    pub year: &'a [u8],
361    ///Comment
362    pub comment: &'a [u8],
363}
364
365impl Id3Tag<'_> {
366    #[inline(always)]
367    ///Returns true if any is set
368    pub const fn is_any_set(&self) -> bool {
369        !self.title.is_empty() || !self.artist.is_empty() || !self.album.is_empty() || !self.album_art.is_empty() || !self.year.is_empty() || !self.comment.is_empty()
370    }
371}
372
373///Builder of C LAME encoder.
374pub struct Builder {
375    inner: NonNull<ffi::lame_global_flags>,
376}
377
378impl Builder {
379    #[inline]
380    ///Creates new encoder with default parameters: J-Stereo, 44.1khz 128kbps CBR mp3 file at quality 5
381    ///
382    ///Returns `None` if unable to allocate struct.
383    pub fn new() -> Option<Self> {
384        let ptr = unsafe {
385            ffi::lame_init()
386        };
387
388        NonNull::new(ptr).map(|inner| Self {
389            inner
390        })
391    }
392
393    #[inline(always)]
394    ///Get access to underlying LAME structure, without dropping ownership.
395    ///
396    ///User must guarantee not to close or dealloc this pointer
397    pub unsafe fn as_ptr(&mut self) -> *mut ffi::lame_global_flags {
398        self.ptr()
399    }
400
401    #[inline(always)]
402    fn ptr(&mut self) -> *mut ffi::lame_global_flags {
403        self.inner.as_ptr()
404    }
405
406    #[inline]
407    ///Sets output sample rate.
408    ///
409    ///The default `None` allows LAME to pick the best value.
410    ///The supported values are:
411    /// - MPEG1: `32_000`, `44_100` and `48_000`
412    /// - MPEG2: `16_000`, `22_050` and `24_000`
413    /// - MPEG2.5: `8_000`, `11_025` and `12_000`
414    ///
415    ///Returns `Ok(())` the requested value is supported and was set successfully.
416    pub fn set_output_sample_rate(&mut self, rate: Option<NonZeroU32>) -> Result<(), BuildError> {
417        let rate = rate.map_or(0, NonZeroU32::get).try_into().unwrap_or(c_int::MAX);
418
419        let res = unsafe {
420             ffi::lame_set_out_samplerate(self.ptr(), rate)
421        };
422
423        BuildError::from_c_int(res)
424    }
425
426    #[inline]
427    ///Sets output sample rate using the builder pattern.
428    ///
429    ///The default `None` allows LAME to pick the best value.
430    ///The supported values are:
431    /// - MPEG1: `32_000`, `44_100` and `48_000`
432    /// - MPEG2: `16_000`, `22_050` and `24_000`
433    /// - MPEG2.5: `8_000`, `11_025` and `12_000`
434    ///
435    ///Returns `Ok(())` the requested value is supported and was set successfully.
436    pub fn with_output_sample_rate(mut self, rate: Option<NonZeroU32>) -> Result<Self, BuildError> {
437        self.set_output_sample_rate(rate)?;
438        Ok(self)
439    }
440
441    #[inline]
442    ///Sets input sample rate.
443    ///
444    ///Defaults to 44_100.
445    ///
446    ///Returns whether it is supported or not.
447    pub fn set_sample_rate(&mut self, rate: u32) -> Result<(), BuildError> {
448        let res = unsafe {
449            ffi::lame_set_in_samplerate(self.ptr(), rate.try_into().unwrap_or(c_int::MAX))
450        };
451
452        BuildError::from_c_int(res)
453    }
454
455    #[inline]
456    ///Sets input sample rate using the builder pattern.
457    ///
458    ///Defaults to 44_100.
459    ///
460    ///Returns an error if it is not supported.
461    pub fn with_sample_rate(mut self, rate: u32) -> Result<Self, BuildError> {
462        self.set_sample_rate(rate)?;
463        Ok(self)
464    }
465
466    #[inline]
467    ///Sets number of channels.
468    ///
469    ///Defaults to 2.
470    ///
471    ///Returns whether it is supported or not.
472    pub fn set_num_channels(&mut self, num: u8) -> Result<(), BuildError> {
473        let res = unsafe {
474            ffi::lame_set_num_channels(self.ptr(), num as _)
475        };
476
477        BuildError::from_c_int(res)
478    }
479
480    #[inline]
481    ///Sets sample rate using the builder pattern.
482    ///
483    ///Defaults to 2.
484    ///
485    ///Returns an error if it is not supported.
486    pub fn with_num_channels(mut self, num: u8) -> Result<Self, BuildError> {
487        self.set_num_channels(num)?;
488        Ok(self)
489    }
490
491    #[inline]
492    ///Sets bitrate (as kbps).
493    ///
494    ///Defaults to compression ratio of 11.
495    ///
496    ///Returns whether it is supported or not.
497    pub fn set_brate(&mut self, brate: Bitrate) -> Result<(), BuildError> {
498        let res = unsafe {
499            ffi::lame_set_brate(self.ptr(), brate as _)
500        };
501
502        BuildError::from_c_int(res)
503    }
504
505    #[inline]
506    ///Sets bitrate (as kbps) using the builder pattern.
507    ///
508    ///Defaults to compression ratio of 11.
509    ///
510    ///Returns an error if it is not supported.
511    pub fn with_brate(mut self, brate: Bitrate) -> Result<Self, BuildError> {
512        self.set_brate(brate)?;
513        Ok(self)
514    }
515
516    #[inline]
517    ///Sets MPEG mode.
518    ///
519    ///Default is picked by LAME depending on compression ration and input channels.
520    ///
521    ///Returns whether it is supported or not.
522    pub fn set_mode(&mut self, mode: Mode) -> Result<(), BuildError> {
523        let res = unsafe {
524            ffi::lame_set_mode(self.ptr(), mode as _)
525        };
526
527        BuildError::from_c_int(res)
528    }
529
530    #[inline]
531    ///Sets MPEG mode using the builder pattern.
532    ///
533    ///Default is picked by LAME depending on compression ration and input channels.
534    ///
535    ///Returns an error if it is not supported.
536    pub fn with_mode(mut self, mode: Mode) -> Result<Self, BuildError> {
537        self.set_mode(mode)?;
538        Ok(self)
539    }
540
541    #[inline]
542    ///Sets quality.
543    ///
544    ///Default is good one(5)
545    ///
546    ///Returns whether it is supported or not.
547    pub fn set_quality(&mut self, quality: Quality) -> Result<(), BuildError> {
548        let res = unsafe {
549            ffi::lame_set_quality(self.ptr(), quality as _)
550        };
551
552        BuildError::from_c_int(res)
553    }
554
555    #[inline]
556    ///Sets quality using the builder pattern.
557    ///
558    ///Default is good one(5)
559    ///
560    ///Returns an error if it is not supported.
561    pub fn with_quality(mut self, quality: Quality) -> Result<Self, BuildError> {
562        self.set_quality(quality)?;
563        Ok(self)
564    }
565
566    #[inline]
567    ///Sets VBR quality.
568    ///
569    ///Returns whether it is supported or not.
570    pub fn set_vbr_quality(&mut self, quality: Quality) -> Result<(), BuildError> {
571        let res = unsafe {
572            ffi::lame_set_VBR_q(self.ptr(), quality as _)
573        };
574
575        BuildError::from_c_int(res)
576    }
577
578    #[inline]
579    ///Sets VBR quality using the builder pattern.
580    ///
581    ///Returns an error if it is not supported.
582    pub fn with_vbr_quality(mut self, quality: Quality) -> Result<Self, BuildError> {
583        self.set_vbr_quality(quality)?;
584        Ok(self)
585    }
586
587    #[inline]
588    ///Sets whether to write VBR tag.
589    ///
590    ///Default is true.
591    ///
592    ///Returns whether it is supported or not.
593    pub fn set_to_write_vbr_tag(&mut self, value: bool) -> Result<(), BuildError> {
594        let res = unsafe {
595            ffi::lame_set_bWriteVbrTag(self.ptr(), value as _)
596        };
597
598        BuildError::from_c_int(res)
599    }
600
601    #[inline]
602    ///Sets whether to write VBR tag using the builder pattern.
603    ///
604    ///Default is true.
605    ///
606    ///Returns an error if it is not supported.
607    pub fn with_to_write_vbr_tag(mut self, value: bool) -> Result<Self, BuildError> {
608        self.set_to_write_vbr_tag(value)?;
609        Ok(self)
610    }
611
612    #[inline]
613    ///Sets VBR mode.
614    ///
615    ///Default is off (i.e. CBR)
616    ///
617    ///Returns whether it is supported or not.
618    pub fn set_vbr_mode(&mut self, value: VbrMode) -> Result<(), BuildError> {
619        let res = unsafe {
620            ffi::lame_set_VBR(self.ptr(), value as _)
621        };
622
623        BuildError::from_c_int(res)
624    }
625
626    #[inline]
627    ///Sets VBR mode using the bulder pattern.
628    ///
629    ///Default is off (i.e. CBR)
630    ///
631    ///Returns an error if it is not supported.
632    pub fn with_vbr_mode(mut self, value: VbrMode) -> Result<Self, BuildError> {
633        self.set_vbr_mode(value)?;
634        Ok(self)
635    }
636
637    #[inline]
638    ///Sets id3tag tag.
639    ///
640    ///If [FlushGap] is used, then `v1` will not be added.
641    ///But `v2` is always added at the beginning.
642    ///
643    ///Returns whether it is supported or not.
644    pub fn set_id3_tag(&mut self, value: Id3Tag<'_>) -> Result<(), Id3TagError> {
645        if !value.is_any_set() {
646            return Ok(());
647        }
648
649        const MAX_BUFFER: usize = 250;
650        let mut buffer = [0u8; MAX_BUFFER + 1];
651
652        unsafe {
653            ffi::id3tag_init(self.ptr());
654            ffi::id3tag_add_v2(self.ptr());
655
656            if !value.album_art.is_empty() {
657                let size = value.album_art.len();
658                if size > MAX_ALBUM_ART_SIZE {
659                    return Err(Id3TagError::AlbumArtOverflow);
660                }
661                let ptr = value.album_art.as_ptr();
662                ffi::id3tag_set_albumart(self.ptr(), ptr as _, size);
663            }
664
665            if !value.title.is_empty() {
666                let size = cmp::min(MAX_BUFFER, value.title.len());
667                ptr::copy_nonoverlapping(value.title.as_ptr(), buffer.as_mut_ptr(), size);
668                buffer[size] = 0;
669                ffi::id3tag_set_title(self.ptr(), buffer.as_ptr() as _);
670            }
671
672            if !value.album.is_empty() {
673                let size = cmp::min(MAX_BUFFER, value.album.len());
674                ptr::copy_nonoverlapping(value.album.as_ptr(), buffer.as_mut_ptr(), size);
675                buffer[size] = 0;
676                ffi::id3tag_set_album(self.ptr(), buffer.as_ptr() as _);
677            }
678
679            if !value.artist.is_empty() {
680                let size = cmp::min(MAX_BUFFER, value.artist.len());
681                ptr::copy_nonoverlapping(value.artist.as_ptr(), buffer.as_mut_ptr(), size);
682                buffer[size] = 0;
683                ffi::id3tag_set_artist(self.ptr(), buffer.as_ptr() as _);
684            }
685
686            if !value.year.is_empty() {
687                let size = cmp::min(MAX_BUFFER, value.year.len());
688                ptr::copy_nonoverlapping(value.year.as_ptr(), buffer.as_mut_ptr(), size);
689                buffer[size] = 0;
690                ffi::id3tag_set_year(self.ptr(), buffer.as_ptr() as _);
691            }
692
693            if !value.comment.is_empty() {
694                let size = cmp::min(MAX_BUFFER, value.comment.len());
695                ptr::copy_nonoverlapping(value.comment.as_ptr(), buffer.as_mut_ptr(), size);
696                buffer[size] = 0;
697                ffi::id3tag_set_comment(self.ptr(), buffer.as_ptr() as _);
698            }
699        }
700
701        Ok(())
702    }
703
704    #[inline]
705    ///Sets id3tag tag using the builder pattern.
706    ///
707    ///If [FlushGap] is used, then `v1` will not be added.
708    ///
709    ///Returns an error if it is not supported.
710    pub fn with_id3_tag(mut self, value: Id3Tag<'_>) -> Result<Self, Id3TagError> {
711        self.set_id3_tag(value)?;
712        Ok(self)
713    }
714
715    #[inline]
716    ///Attempts to initialize encoder with specified parameters.
717    ///
718    ///Returns `None` if parameters are invalid or incompatible.
719    pub fn build(mut self) -> Result<Encoder, BuildError> {
720        let res = unsafe {
721            ffi::lame_init_params(self.ptr())
722        };
723
724        match BuildError::from_c_int(res) {
725            Ok(()) => {
726                let inner = self.inner;
727                mem::forget(self);
728                Ok(Encoder { inner })
729            },
730            Err(error) => Err(error),
731        }
732    }
733}
734
735impl Drop for Builder {
736    #[inline]
737    fn drop(&mut self) {
738        unsafe {
739            ffi::lame_close(self.ptr())
740        };
741    }
742}
743
744///LAME Encoder.
745pub struct Encoder {
746    inner: NonNull<ffi::lame_global_flags>,
747}
748
749impl Encoder {
750    #[inline(always)]
751    fn ptr(&self) -> *mut ffi::lame_global_flags {
752        self.inner.as_ptr()
753    }
754
755    #[inline]
756    ///Returns sample rate.
757    pub fn sample_rate(&self) -> u32 {
758        unsafe {
759            ffi::lame_get_in_samplerate(self.ptr()) as u32
760        }
761    }
762
763    #[inline]
764    ///Returns number of channels.
765    pub fn num_channels(&self) -> u8 {
766        unsafe {
767            ffi::lame_get_num_channels(self.ptr()) as u8
768        }
769    }
770
771    #[inline]
772    ///Returns indication whether encoder is configured to write LAME tag
773    pub fn is_lame_tag_written(&self) -> bool {
774        unsafe {
775            ffi::lame_get_bWriteVbrTag(self.ptr()) != 0
776        }
777    }
778
779    #[inline]
780    ///Returns size of ths [Id3Tag] written, if any
781    pub fn id3v2_tag_size(&self) -> usize {
782        unsafe {
783            ffi::lame_get_id3v2_tag(self.ptr(), ptr::null_mut(), 0)
784        }
785    }
786
787    #[inline]
788    ///Retrieves size of the lame tag
789    pub fn lame_tag_size(&self) -> usize {
790        unsafe {
791            ffi::lame_get_lametag_frame(self.ptr(), ptr::null_mut(), 0)
792        }
793    }
794
795    #[inline]
796    ///Attempts to write lame tag into `output` returning number of written bytes in case of success
797    ///
798    ///Note that if you write [Id3Tag] you must not write this tag at the start.
799    ///Instead you must insert Lame Tag after [Id3Tag] position.
800    ///
801    ///To determine where [Id3Tag] ends in output stream, you can use [Encoder::id3v2_tag_size]
802    ///which returns full size of [Id3Tag] metadata written (therefore indicating where actual mp3
803    ///content is starting)
804    pub fn lame_tag_encode(&self, output: &mut [MaybeUninit<u8>]) -> Option<NonZeroUsize> {
805        //lame_get_lametag_frame() returns full required size in case `output` is not sufficient,
806        //so first manually check buffer size
807        if output.len() < self.lame_tag_size() {
808            None
809        } else {
810            NonZeroUsize::new(unsafe {
811                ffi::lame_get_lametag_frame(self.ptr(), output.as_mut_ptr() as _, output.len())
812            })
813        }
814    }
815
816    #[inline]
817    ///Attempts to write lame tag into `output` returning number of written bytes in case of success
818    ///
819    ///Refer to [Encoder::lame_tag_encode] for details
820    pub fn lame_tag_encode_to_vec(&self, output: &mut Vec<u8>) -> Option<NonZeroUsize> {
821        let original_len = output.len();
822        match self.lame_tag_encode(output.spare_capacity_mut()) {
823            Some(written) => {
824                unsafe {
825                    output.set_len(original_len.saturating_add(written.get()));
826                }
827                Some(written)
828            },
829            None => None
830        }
831    }
832
833    #[inline]
834    ///Attempts to encode PCM data, writing whatever available onto `output` buffer
835    ///
836    ///### Arguments:
837    ///
838    /// - `input` - Data input. Can be [MonoPcm], [DualPcm] or [InterleavedPcm]
839    /// - `output` - Output buffer to write into.
840    ///
841    ///### Result:
842    ///On success, returns number of bytes written (can be 0).
843    ///Otherwise returns error indicating potential issue.
844    pub fn encode(&mut self, input: impl EncoderInput, output: &mut [MaybeUninit<u8>]) -> Result<usize, EncodeError> {
845        let output_len = output.len();
846        let output_buf = output.as_mut_ptr();
847
848        let result = input.encode(self, output_buf as _, output_len);
849
850        EncodeError::from_c_int(result)
851    }
852
853    #[inline(always)]
854    ///Attempts to encode PCM data, writing whatever available onto `output` buffer
855    ///
856    ///`output` size is adjusted on success only
857    ///
858    ///Refer for details to `encode()`
859    pub fn encode_to_vec(&mut self, input: impl EncoderInput, output: &mut Vec<u8>) -> Result<usize, EncodeError> {
860        let original_len = output.len();
861        match self.encode(input, output.spare_capacity_mut()) {
862            Ok(written) => {
863                unsafe {
864                    output.set_len(original_len.saturating_add(written));
865                }
866                Ok(written)
867            },
868            Err(error) => Err(error),
869        }
870    }
871
872    #[inline]
873    ///Attempts flush all data, writing whatever available onto `output` buffer
874    ///Padding with 0 to complete MP3
875    ///
876    ///### Type:
877    ///
878    ///- [FlushNoGap] - performs flush, using ancillary data to fill gaps;
879    ///- [FlushGap] - performs flush, padding with 0;
880    ///
881    ///### Arguments:
882    ///
883    /// - `output` - Output buffer to write into. As it is final action, you need at least 7200 bytes to hold at MP3 data.
884    ///
885    ///### Result:
886    ///On success, returns number of bytes written (can be 0).
887    ///Otherwise returns error indicating potential issue.
888    pub fn flush<T: EncoderFlush>(&mut self, output: &mut [MaybeUninit<u8>]) -> Result<usize, EncodeError> {
889        let output_len = output.len();
890        let output_buf = output.as_mut_ptr();
891
892        let result = T::flush(self, output_buf as _, output_len);
893
894        EncodeError::from_c_int(result)
895    }
896
897    #[inline(always)]
898    ///Attempts flush all data, writing whatever available onto `output` buffer.
899    ///
900    ///`output` size is adjusted on success only
901    ///
902    ///Refer for details to `flush()`
903    pub fn flush_to_vec<T: EncoderFlush>(&mut self, output: &mut Vec<u8>) -> Result<usize, EncodeError> {
904        let original_len = output.len();
905        match self.flush::<T>(output.spare_capacity_mut()) {
906            Ok(written) => {
907                unsafe {
908                    output.set_len(original_len.saturating_add(written));
909                }
910                Ok(written)
911            },
912            Err(error) => Err(error),
913        }
914    }
915}
916
917impl Drop for Encoder {
918    #[inline]
919    fn drop(&mut self) {
920        unsafe {
921            ffi::lame_close(self.ptr())
922        };
923    }
924}
925
926/// According to LAME 3.99.5 HACKING, it is thread-safe.
927unsafe impl Send for Encoder {}
928/// According to LAME 3.99.5 HACKING, it is thread-safe.
929unsafe impl Sync for Encoder {}
930
931///Creates default encoder with 192kbps bitrate and best possible quality.
932pub fn encoder() -> Result<Encoder, BuildError> {
933    match Builder::new() {
934        Some(mut builder) => {
935            builder.set_brate(Bitrate::Kbps192)?;
936            builder.set_quality(Quality::Best)?;
937            builder.build()
938        },
939        None => Err(BuildError::NoMem)
940    }
941}