Skip to content

Using metadata APIs with the bindings

Melchor Garau Madrigal edited this page Feb 9, 2017 · 6 revisions

First, selecting the API

There's three types of metadata to manipulate metadata on flacs files with the FLAC API:

And then, common to all, the metadata API that manipulates the objects itself, not the files.

What offers the metadata0 API? It's an easy way to only access to the StreamInfo, VorbisComment, CueSheet and Pictures metadata blocks.

What offers the metadata1 API? It's the easy way to read and write all metadata blocks from a file using an Iterator. Is quite efficient and uses less memory than metadata2 but is slow.

What offers the metadata2 API? A complete way to read and write all metadata blocks from a file using an Iterator. Reads all blocks into memory and operates in memory until save. Is faster than level 1 doing operations.

See this link for a more precise information about the three APIs.

Note The bindings tries to bind everything, but there are some functions that cannot be bound because of the arguments they need (are difficult to implement or impossible). Pay attention to the documentation of the bindings (available on this Wiki).

Note 2 The documentation is not really a fully documentation, only tries to show what is bound and the differences between the C API and the node bindings. You will always find links to the original C API documentation that will explain better than me how the API works.

Note 3 See how the C structs and the Javascript objects are mapped, keep it in a separate page to see it while you read this guide.

Metadata0

You can get metadata blocks from the file quickly with that:

const flac = require('flac-bindings');
let streamInfo = flac.bindings.metadata0.get_streaminfo('a file.flac');
let tags = flac.bindings.metadata0.get_tags('a file.flac');
let cuesheet = flac.bindings.metadata0.get_cuesheet('a file.flac');
let picture = flac.bindings.metadata0.get_picture('a file.flac', -1, null, null, -1, -1, -1, -1);

Easy as that. But remember, you must delete the blocks from memory (free them) when you not need them:

flac.bindings.metadata.delete(streamInfo);
flac.bindings.metadata.delete(tags);
flac.bindings.metadata.delete(cuesheet);
flac.bindings.metadata.delete(picture);

Metadata1

With this iterator, things get interesting. First you must create an instance of the iterator:

let it = flac.bindings.metadata1.new();

You should check if it is a valid object (aka: not a null object). After that, you must initialize the iterator with a file and some options:

flac.bindings.metadata1.init(it, 'a file.flac', isReadOnly, shouldPreserveStats)

Note Is a good practice to check whether this functions return true. That means everything is okay. If something goes wrong you can use flac.bindings.metadata1.status() to know what happen.

To see how it works the last two parameters, you shold see the flac documentation.

If everything goes right, you can now iterate over the metadata blocks and manipulate them:

flac.bindings.metadata1.next(it); //Advances its pointer to the next block
flac.bindings.metadata1.prev(it); //Backs its pointer to the previous block
let blockType = flac.bindings.metadata1.get_block_type(it); //Gets the block type of the block to which the iterator is pointing at
let block = flac.bindings.metadata1.get_block(it); //Gets the block to which the iterator is pointing at

You can use flac.bindings.metadata.MetadataTypeString to get a string representation of the type of the metadata block.

The block you get is yours (according to the FLAC API). So you can modify it using the metadata API or modifing the attributes of the block directly. But you must delete it when it is not needed anymore with the method seen in Metadata0.

To store any changes of a metadata block, you must call:

flac.bindings.metadata1.set_block(it, block, true);

The true value is to indicate the flac API to use padding blocks if available to be as efficient as he can.

You can insert blocks created using the metadata API (click the link after read this section, if you want) in two ways:

flac.bindings.metadata1.set_block(it, newBlock, true); //Replaces the current block (at which the iterator points)
flac.bindings.metadata1.insert_block_after(it, newBlock, true); //Inserts the now block after the current one, then the iterator will point to the inserted block

Easy as that. Remember that you must free (delete) the blocks using the metadata API, the bindings nor flac API will do it for you :(

Last thing is how to delete a block:

flac.bindings.metadata1.delete_block(it, true); //Deletes the current block (at which the iterator points). You cannot delete STREAMINFO blocks.

Note You cannot delete the STREAMINFO block.

This replaces the current block into a PADDING block (because of that true at the end). If you pass a false, the block will be deleted and will rewrite all the flac file.

Oh, I nearly forget that, you must delete the iterator too, when you don't need it anymore:

flac.bindings.metadata1.delete(it);
it = null;

And thats all for the Metadata1 API.

Metadata2

Let's get done with metadata2. Before start coding, you must understand that in this level there are two objects to play with: the chain and the iterator. The chain is where you open the file and you write to the file, and also you can consolidate the padding blocks. The iterator is like the level 1 (metadata1) and you already know how to use it. In this API, everything you do is not saved directly to the file, is all in memory, so you must ensure to save the changes and to not modify the flac file by other ways while using this API.

Well, let's start creating the chain and initializing it with a file:

let chain = flac.bindings.metadata2.chain_new();
flac.bindings.metadata2.chain_read(chain, 'a file.flac'); //Opens the file, reads all blocks into the memory and closes the file

Note Is a good practice to check whether this functions return true. That means everything is okay. If something goes wrong you can use flac.bindings.metadata2.chain_status() to know what happen.

If everything goes ok, you can now create the iterator. But optionally you can reorder and merge the padding blocks to optimize them (flac.bindings.metadata2.chain_sort_padding(chain) and flac.bindings.metadata2.chain_merge_padding(chain)). Let's see how to create and initialize the iterator:

let it = flac.bindings.metadata2.iterator_new(); //Creates a new level2 iterator
flac.bindings.metadata2.iterator_init(it, chain); //Initializes it with the chain

To move the iterator fowards and backwards:

flac.bindings.metadata2.iterator_next(it); //Moves the pointer to the next block
flac.bindings.metadata2.iterator_prev(it); //Moves the pointer to the previous block
let blockType = flac.bindings.metadata2.iterator_get_block_type(it); //Gets the block type of the current block
let block = flac.bindings.metadata2.iterator_get_block(it); //Gets the current block

Note In this metadata API the blocks you get are owned by the chain, that means that if you modify them, the changes will be reflected directly to the chain and you don't need to save it back into the iterator, as in metadata1 does. Also, you cannot delete the object using the metadata API. If you do, you can cause some serious problems, leading to a crash.

If you want to add or replace a block, first you must create and modify it with the metadata API or directly modifying the attributes, and then you can use this three methods:

flac.bindings.metadata2.iterator_insert_after(it, block); //Inserts after the current block, the iterator will point into this new block
flac.bindings.metadata2.iterator_insert_before(it, block); //Inserts before the current block, the iterator will point into this new block
flac.bindings.metadata2.iterator_set_block(it, block); //Replaces the current block with a new one

Note The blocks, once added/replaced into the iterator, will be propiety of the chain. That means that you don't need to delete them, and any changes you do on them will be reflected directly in the chain. Note 2 You cannot insert STREAMINFO blocks. You cannot insert before the STREAMINFO block, this one will always be the first. You can only replace a STREAMINFO block with another STREAMINFO block. You cannot delete the STREAMINFO block.

To delete a block:

flac.bindings.metadata2.iterator_delete_block(it, true); //Deletes the block that the iterator points at. The iterator points to the padding block created, or just the previous one

The true value is to indicate the flac API to replace with a padding block. If false is provided, then it will be deleted and the iterator will point to the previous block. Note Any references to the block deleted will be invalid, so make sure that you don't use them anymore, otherwise node could crash or do wierd things.

When you are done with the iterator, you must delete it:

flac.bindings.metadata2.iterator_delete(it); //Deletes the iterator, but not the chain
it = null;

Once done that, you can always reorder and/or merge padding blocks again:

flac.bindings.metadata2.chain_sort_padding(chain);
flac.bindings.metadata2.chain_merge_padding(chain);

Note Calling one or both methods will invalidate any iterator. Ensure that you don't have any iterator created before calling any of these methods.

And finally you can save all changes:

flac.bindings.metadata2.chain_write(chain, usePadding, shouldPreserveStats);

To see how it works the last two parameters, you shold see the flac documentation.

And don't forget to delete the chain when you are done:

flac.bindings.metadata2.chain_delete(chain);
chain = null;

Note All references to blocks that were owned by the chain will become invalid. Ensure to not use them anymore or node could crash.

Metadata

In general, most of the attributes of the C structs can be modified directly without the need of any function. But there's some others that they need to be modified using a function (a C setter). The mapping between C and Javascript tries to limitate the modification of these attributes when is told to not modify directly (I recommend you to see how the objects are mapped).

First, the objects must be created using the API, you cannot simply create a JS Object and pass it to the API, it won't let you go. When creating the object, you must tell the kind of it (see the possible types)

let block = flac.bindings.metadata.new(flac.bindings.format.MetadataType.VORBISCOMMENT); //Creates a new metadata block of type VorbisComment

The objects can be cloned:

let clonedBlock = flac.bindings.metadata.clone(block);

The objects must be deleted when not needed (except when using with the metadata2 API, remember why?):

flac.bindings.metadata.delete(clonedBlock);
clonedBlock = null;

Application metadata objects

According to the API, you cannot modify the data attribute directly, you must use the function:

flac.bindings.metadata.application_set_data(applicationBlock, data); //data must be a buffer

SeekTable metadata objects

To add, delete or modify points in the seek table, you must use the following functions:

Read carefully how they work (on the C documentation) and how to use it (on the Wiki documentation).

VorbisComment metadata objects

A VorbisComment is a list of entries and a vendor entry. You cannot modify any of these attributes directly, but the API provides functions to alter them.

To modify the vendor entry, you must use:

To insert, delete, resize, replace the entries list, here is a list of functions available:

CueSheet metadata objects

In a CueSheet object, you can modify everything except the list of CueSheet tracks. In a CueSheet track, you can modify everything except the indices list.

To add, replace and delete tracks to the list you can use:

To add, replace and delete indices in the indices list of a track, first you must create a CueSheet track, modify what you want (and can) and then store the track in the CueSheet object, and then use:

I didn't mention how to create a CueSheet track to modify it and then adding it to the CueSheet metadata object. Here is how:

At last, you can check if the CueSheet metadata object is valid with:

Picture metadata objects

The picture metadata objects can modify the size, the depth and colors (o colours) attributes directly, but the MIME type, the description and the image data don't. To modify them, you can use:

You can check if the picture object is valid or not with:

Clone this wiki locally