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