LameMP3
NAME
Audio::Encode::LameMP3 - encode PCM data to MP3 using libmp3lame
SYNOPSIS
use Audio::Encode::LameMP3;
use Audio::Sndfile;
my $test-file = 't/data/cw_glitch_noise15.wav';
my $sndfile = Audio::Sndfile.new(filename => $test-file, :r);
my $encoder = Audio::Encode::LameMP3.new(bitrate => 128, quality => 3, in-samplerate => $sndfile.samplerate);
my $out-file = 'encoded.mp3'.IO.open(:w, :bin);
loop {
my @in-frames = $sndfile.read-short(4192);
my $buf = $encoder.encode-short(@in-frames);
$out-file.write($buf);
last if ( @in-frames / $sndfile.channels ) != 4192;
}
$sndfile.close();
my $buf = $encoder.encode-flush();
$out-file.write($buf);
$out-file.close;
See also the examples/
directory in the distribution.
DESCRIPTION
This module provides a simple binding to 'mp3lame',v0 an MP3 encoding library.
With this you can encode PCM data to MP3 at any bitrate or quality supported by the lame library.
The interface is somewhat simplified in comparison to that of lame and some of the esoteric or rarely used features may not be supported.
Because marshalling large arrays and buffers between Raku space and the
native world may be too slow for some use cases the interface provides
for passing and returning native CArrays (and their sizes) for the use
of other native bindings (e.g. Audio::Sndfile, Audio::Libshout) where
speed may prove important, which , for me at least, is quite a common
use-case. The raku-lame-encode
example demonstrates this way of using
the interface.
METHODS
All of the encode methods below have multi variants that accept appropriately
shaped CArray arguments (along with the number of frames.) With the :raw
adverb they will return a RawEncode
sub-set which is defined as an Array
of two elements the first being a CArray[uint8]
containing the encoded
data and an Int
indicating how many items there are. This is for ease of
interoperating with modules such as Audio::Sndfile and Audio::Libshout
and avoids the cost of marshalling to/from Raku Arrays where it is not needed.
method new
method new(*%attributes) returns Audio::Encode::LameMP3
The constructor of objects of this type, this can be passed any of the encoder parameters or id3 tags described below. It will set some internal defaults.
method init
method init()
This initialises the encoder ready to start the encoding. It may be called after
all the rquired parameters have been set, however it will be called for you when
the first encode method is called. It is an error to attempt to set any encoding
parameters after init
has been called.
method init-bitstream
method init-bitstream()
This can be used to re-initialise the encoder's internal state in order that it
can be re-used for the encoding of a new source (e.g. a new file.) It should only
be called after encode-flush
has been called and the result of doing otherwise
is undefined. Typically this could be used when streaming multiple files in sequence
to the the same stream endpoint for example, calling encode-flush
and init-bitstream
between each file.
This is not necessary on the first initialisation as it is called by init()
method lame-version
method lame-version() returns Version
This returns a Version object indicating the version of libmp3lame
that is
being used.
method encode-short
Encode the block of PCM data expressed as signed 16 bit integers to
MP3 returning the data as unsigned 8 bit integers. The input data
can be provided either as separate channels or in interleaved form.
The multi variants allow the data to provided as Raku arrays or as
CArray[int16]
and the number of frames ( the number of frames is the
number left channel, right channel pairs.)
If the :raw
adverb is provided then the data will be returned as a
two element array containing a CArray[uint8]
and an Int
with the
number of elements in the array. Otherwise it will return a Raku Array
with the data.
Tests seem to demonstrate that this is the fastest of the encoding methods, which is convenient as 16 bit PCM is probably the most common format for general use (being that which is used on CDs.)
multi method encode-short(@left, @right) returns Buf
multi method encode-short(@frames) returns Buf
multi method encode-short(@left, @right, :$raw!) returns RawEncode
multi method encode-short(@frames, :$raw!) returns RawEncode
multi method encode-short(CArray[int16] $left, CArray[int16] $right, Int $frames) returns Buf
multi method encode-short(CArray[int16] $frames-in, Int $frames) returns Buf
multi method encode-short(CArray[int16] $left, CArray[int16] $right, Int $frames, :$raw!) returns RawEncode
multi method encode-short(CArray[int16] $frames-in, Int $frames, :$raw!) returns RawEncode
method encode-int
Encode the block of PCM data expressed as 32 bit integers to MP3 returning
the data as unsigned 8 bit integers. The input data can be provided
either as separate channels or in interleaved form. The multi variants
allow the data to provided as Raku arrays or as CArray[int32]
and
the number of frames ( the number of frames is the number left channel,
right channel pairs.)
If the :raw
adverb is provided then the data will be returned as a
two element array containing a CArray[uint8]
and an Int
with the
number of elements in the array. Otherwise it will return a Raku Array
with the data.
libmp3lame
doesn't provide the interleaved data option for this data
type so it is emulated in Raku code so it may be slower if used like that.
The libmp3lame
documentation suggests that the scaling of the integer
encoding may not be as good as for other data types, if you need to
use this data type you should test this and provide your own scaling
if necessary.
multi method encode-int(@left, @right) returns Buf
multi method encode-int(@frames) returns Buf
multi method encode-int(@left, @right, :$raw!) returns RawEncode
multi method encode-int(@frames, :$raw!) returns RawEncode
multi method encode-int(CArray[int32] $left, CArray[int32] $right, Int $frames) returns Buf
multi method encode-int(CArray[int32] $frames-in, Int $frames) returns Buf
multi method encode-int(CArray[int32] $left, CArray[int32] $right, Int $frames, :$raw!) returns RawEncode
multi method encode-int(CArray[int32] $frames-in, Int $frames, :$raw!) returns RawEncode
method encode-long
Encode the block of PCM data expressed as 64 bit integers to MP3 returning
the data as unsigned 8 bit integers. The input data can be provided
either as separate channels or in interleaved form. The multi variants
allow the data to provided as Raku arrays or as CArray[int64]
and
the number of frames ( the number of frames is the number left channel,
right channel pairs.)
If the :raw
adverb is provided then the data will be returned as a
two element array containing a CArray[uint8]
and an Int
with the
number of elements in the array. Otherwise it will return a Raku Array
with the data.
libmp3lame
doesn't provide the interleaved data option for this data
type so it is emulated in Raku code so it may be slower if used like that.
multi method encode-long(@left, @right) returns Buf
multi method encode-long(@frames) returns Buf
multi method encode-long(@left, @right, :$raw!) returns RawEncode
multi method encode-long(@frames, :$raw!) returns RawEncode
multi method encode-long(CArray[int64] $left, CArray[int64] $right, Int $frames) returns Buf
multi method encode-long(CArray[int64] $frames-in, Int $frames) returns Buf
multi method encode-long(CArray[int64] $left, CArray[int64] $right, Int $frames, :$raw!) returns RawEncode
multi method encode-long(CArray[int64] $frames-in, Int $frames, :$raw!) returns RawEncode
method encode-float
Encode the block of PCM data expressed as 32 bit floating point numbers
to MP3 returning the data as unsigned 8 bit integers. The input data
can be provided either as separate channels or in interleaved form.
The multi variants allow the data to provided as Raku arrays or as
CArray[num32]
and the number of frames ( the number of frames is the
number left channel, right channel pairs.)
If the :raw
adverb is provided then the data will be returned as a
two element array containing a CArray[uint8]
and an Int
with the
number of elements in the array. Otherwise it will return a Raku Array
with the data.
multi method encode-float(@left, @right) returns Buf
multi method encode-float(@frames) returns Buf
multi method encode-float(@left, @right, :$raw!) returns RawEncode
multi method encode-float(@frames, :$raw!) returns RawEncode
multi method encode-float(CArray[num32] $left, CArray[num32] $right, Int $frames) returns Buf
multi method encode-float(CArray[num32] $frames-in, Int $frames) returns Buf
multi method encode-float(CArray[num32] $left, CArray[num32] $right, Int $frames, :$raw!) returns RawEncode
multi method encode-float(CArray[num32] $frames-in, Int $frames, :$raw!) returns RawEncode
method encode-double
Encode the block of PCM data expressed as 64 bit floating point numbers
to MP3 returning the data as unsigned 8 bit integers. The input data
can be provided either as separate channels or in interleaved form.
The multi variants allow the data to provided as Raku arrays or as
CArray[num64]
and the number of frames ( the number of frames is the
number left channel, right channel pairs.)
If the :raw
adverb is provided then the data will be returned as a
two element array containing a CArray[uint8]
and an Int
with the
number of elements in the array. Otherwise it will return a Raku Array
with the data.
multi method encode-double(@left, @right) returns Buf
multi method encode-double(@frames) returns Buf
multi method encode-double(@left, @right, :$raw!) returns RawEncode
multi method encode-double(@frames, :$raw!) returns RawEncode
multi method encode-double(CArray[num64] $left, CArray[num64] $right, Int $frames) returns Buf
multi method encode-double(CArray[num64] $frames-in, Int $frames) returns Buf
multi method encode-double(CArray[num64] $left, CArray[num64] $right, Int $frames, :$raw!) returns RawEncode
multi method encode-double(CArray[num64] $frames-in, Int $frames, :$raw!) returns RawEncode
method encode-flush
This returns (flushes) the last encoded data and should always be called after the last PCM data for a particular stream has been encoded. It may return up to 8000 bytes of data.
If the :nogap
adverb is supplied then the padding at the end will
be adjusted such that a subsequent track (or file) will appear to
play seamlessly, typically this will be used with init-bitstream
which should be called after this and before sending further PCM data
to create an (apparently) gapless stream.
If the :raw
adverb is provided then the data will be returned as a
two element array containing a CArray[uint8]
and an Int
with the
number of elements in the array. Otherwise it will return a Raku Array
with the data.
multi method encode-flush() returns Buf
multi method encode-flush(:$nogap!) returns Buf
multi method encode-flush(:$raw!) returns RawEncode
multi method encode-flush(:$nogap!, :$raw!) returns RawEncode
CONFIGURATION ATTRIBUTES
All of those can be supplied to the constructor or can be set as attributes on a constructed object before it is initialised. Some are more useful than others as the library provides sensible defaults.
The lame library provides a wider range of settable parameters that are not exposed as I either don't understand them or they don't seem to be useful.
If of course you need a particular parameter, please feel free to request it to be added - most of the native stubs are there, just not exposed as methods.
The first four are the most likely to be used in most code.
in-samplerate
This should reflect the samplerate of the input PCM data. The default is 44100. If this is not set correctly the speed of the playback of the encoded data will be incorrect.
bitrate
This is the playback bitrate of the encoded data. It should be a value understood by both lame and the target players, values that are fairly universally understood are 64, 128, 192 and 320.
quality
This is an integer value between 0 and 9 that indicates the quality (and hence the speed) of the encoding, where 0 is the best (and slowest) and 9 is the least good and fastest. The default is 5. Most applications will typically use a value between 3 and 7 but your ears and patience might better than mine.
mode
This is a value of the enum
Audio::Encode::LameMP3::MPEG-Mode with the
following items:
Stereo
For lame this setting is probably un-necessary. The stereo channels are
encoded separately and this may result in greater loss of stereo field
information than JointStereo
.
JointStereo
This is the most common setting for most uses. The stereo channel separation is essentially encoded losslessly in lame.
DualChannel
This is not implemented as a separate mode by lame, setting this will have no effect.
Mono
The input source is to be encoded as mono. If interleaved data is presented then it will be read as if it represents a single channel. If separate channels are presented only the left channel will be encoded,
NotSet
This is the default. The library will infact encode as JointStereo
by default.
num-samples
If the number of samples that will be encoded is known in advance (for instance where the PCM data is read from a file.) this can be set. The default is 2^31 samples. If it is set the encoder may be able to make certain small optimisations.
num-channels
This should be either 1 or 2. lame doesn't support a greater number of channels (e.g. surround modes) Setting this is probably completely un-necessary.
scale
This is a scaling factor between 0 and 1 that will be applied to the input data before encoding. The default is 1.
scale-left
scaling between 0 and 1 for the left channel. The default is undefined as scale
will be used.
scale-right
scaling between 0 and 1 for the right channel. The default is undefined as scale
will be used.
out-samplerate
This is the target samplerate of the encoded output (i.e. the samplerate of the resulting PCM if the output were decoded.) The default is the same as the input samplerate and it probably isn't necessary to change it unless some target software or hardware requires a particular samplerate. If you want finer control over the samplerate you may consider using another library such as 'libsamplerate'
ID3 Attributes
These will cause ID3 tags to be inserted into the output stream. For some reason there are no getters for these in 'lame' so they all return an undefined Str.
Both ID3 v1 and v2 tags will be created.
These are quite limited, if you are saving to a file and want finer control over the tags you might want to consider Audio::Taglib::Simple which will let you add more tags more flexibly.
These can be either applied to the constructor as parameters or as
attributes on an Audio::Encode::LameMP3 object before the encoder
is initialised. Additionally the may be set as attributes after
encode-flush
has been called and before it is reinitialised.
title
The title tag.
artist
The artist.
album
The album.
year
The year (this is a string that should look like a year e.g. "2015" )
comment
A comment. The id3v2 tag is created with a language of "XXX" for some reason.