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.

Audio::Encode::LameMP3 v0.0.14

Encode PCM Audio data to MP3 in Raku using a binding to liblame

Authors

  • Jonathan Stowe

License

Artistic-2.0

Dependencies

Test Dependencies

Provides

  • Audio::Encode::LameMP3

Documentation

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.