History:Client HOWTO

From MusicBrainz Wiki
Status: This Page is Glorious History!

The content of this page either is bit-rotted, or has lost its reason to exist due to some new features having been implemented in MusicBrainz, or maybe just described something that never made it in (or made it in a different way), or possibly is meant to store information and memories about our Glorious Past. We still keep this page to honor the brave editors who, during the prehistoric times (prehistoric for you, newcomer!), struggled hard to build a better present and dreamed of an even better future. We also keep it for archival purposes because possibly it still contains crazy thoughts and ideas that may be reused someday. If you're not into looking at either the past or the future, you should just disregard entirely this page content and look for an up to date documentation page elsewhere.

MusicBrainz Client Library HOWTO (MM 2.1)

Attention.png This documentation refers to the old RDF web service which has been deprecated. Do not use this library/web service for new development -- see WebService for more details.

Introduction

libmusicbrainz serves as a tool to allow developers to integrate MusicBrainz searches and metadata exchange functionality into their applications.

The client library includes the following features:

The client library source distribution comes with some ClientExamples programs. If you prefer to read code rather than documentation in order to learn this client library, please check out these code samples.

The client library is released under the LGPL, which means that even developers of closed source applications can use the client library, without having to open source their own code.

Function & Query Reference

For details on the individual functions and queries mentioned in this HOWTO, please refer to the following pages:

version 2.1.x:

version 2.0.x:

Overview

MusicBrainz provides a powerful web service API that uses RDF for expressing queries and query responses. RDF is the Resource Description Framework as specified by World Wide Web Consortium, and it can be used for formally expressing metadata using an XML syntax.

RDF is powerful, but also complex, and thus the client library attempts to shield the end user from having to understand RDF. But in order to understand the Query/Select/Get interface that client library has, a brief overview of the data query process is in order.

To query the MusicBrainz server, the user must pass an RDF query to the server. You may decide to create your own queries if you are comfortable with RDF, or you can use the predefined queries in the client library. The predefined queries will require a number of arguments that will get substituted into the query before the query is sent to the server.

The mb_Query (MusicBrainz::Query in C++) function takes a query string and a number of other arguments that get substituted into the query. The queries are defined in queries.h, and you do not need to really know what the actual query strings mean -- all you need to do is to select the right query for your purpose and then provide the query function with the right arguments and the client library will do the rest.

Once the query function returns it will have retrieved the RDF response from the server. The returned RDF will get parsed and then the user can use the Select/Get/Data functions to extract information from the query result.

The RDF response will typically return a whole bunch of information, and you may only be interested in some of that information. In order to make the data extraction process reasonably easy, the user will need to Select a context (think of it as a subset) of the RDF response. You can then extract pieces of data from that context.

For example, if you look up a CD using the client library, you will get back a list of albums. Each MusicBrainz query will return a list of one kind or another, even if it only contains one item. So, you will need to select an album from the list, and in this case it will be the first album in the list. You'll do that with a call to Select. After calling Select, you can call the GetResultData or GetResultInt functions to extract string or integer values from the returned data. A code fragment to do this in C would look like:

    // Check to see how many items were returned from the server
    if (mb_GetResultInt(o, MBE_GetNumAlbums) < 1)
    {
        printf("This CD was not found.\n");
        return 0;
    }

    // Select the first album
    mb_Select1(o, MBS_SelectAlbum, 1);

    // Get the number of tracks
    numTracks = mb_GetResultInt(o, MBE_AlbumGetNumTracks);
    printf(" NumTracks: %d\n", numTracks);

Finally, a couple of other tidbits for the overview: The client library uses standard HTTP GET and POST queries to accomplish the communication with the server. Thus, the client library has support for using proxies to get across firewalls, and no special firewall arrangements have to be made.

The data that is extracted from the RDF response can either be in standard ISO-8859-1 format (the character encoding that Western European and US computers use) or in the UTF-8 format.

The MusicBrainz client library can also be used to create Relatable TRM acoustic fingerprints for audio files. In order to generate a TRM id, you will need to feed the client library the first 30 seconds worth of PCM data from your audio stream. Once you've fed it the 30 seconds of data, the client library will send the acoustic fingerprint information to the Relatable server and the server will assign and return a TRM ID to the given song. You can then use the TRM id to look up metadata for the song, and fill out the ID3 tags (or equivalent) automatically!

Select & Get Documentation

The most non-obvious issues in dealing with the client library is having to extract data from the result that was returned by the server. If you are RDF savvy and would like deal with the result RDF itself, then call the mb_GetResultRDF function. Most people won't be interested in doing that, so here is a detailed explanation for what you need to do.

The server will return an artist list, album list, track list a trmid list or a lyrics list. Let's examine the artist list first, since it ends up as a good example for the rest of the select/get stuff. This piece of ASCII art shows the different objects returned as part of an artist list query:

                                                                Depth:
                                           +-------------+
  [top level]                              | Artist List |        [1]
                                           +-------------+
                                              |       |
  References to the Artists                   |       |           [2]
                                              |       |
                                      +--------+     +--------+
  MBS_SelectArtist 1 ---------------> | Artist |     | Artist |   [3]
                                      +--------+     +--------+
                                       |      |
  References to the Albums             |      |                   [4]
                                       |      |
                                +-------+    +-------+
  MBS_SelectAlbum 1  ---------> | Album |    | Album |            [5]
                                +-------+    +-------+
                                 |     |
  References to the Tracks       |     |                          [6]
                                 |     |
                          +-------+   +-------+
  MBS_SelectTrack 1  ---> | Track |   | Track |                   [7]
                          +-------+   +-------+

If your artistlist query is successful then you can call do the following to find out the number of artists returned by the query:

    numArtists = mb_GetResultInt(o, MBE_GetNumArtists);

Please note that the MBE_GetNumArtists is a MusicBrainzExtract (MBE_) query, which queries the result set, not the MusicBrainz server. All server queries that can be passed to mb_Query are MusicBrainzQueries that start with MBQ_. Then you also have MusicBrainz Select queries (MBS_) which are used to select a subset of a result from a the server.

Any of the mb_GetResult functions work on the current extract query context. Right after you call mb_Query the current context will be set to the top level query context, where you can get the number of items returned (as shown above) or select one of the returned items as a new context.

So, in our example, after you've determined the number of artists that were returned, you can select one of the artists using a the mb_Selection function. To select the first artist returned do this:

    mb_Select1(o, MBS_SelectArtist, 1);

The third argument to the mb_Select1 function is an ordinal argument, that indicates which artist you'd like to select. Ordinals are 1 based, so to select the first artist, use 1, not 0. Select queries that select something out of a list require an ordinal argument, as shown above. Some select queries do not require ordinals, in which case you can call mb_Select (as opposed to mb_Select1).

Select queries can be arbitrarily complex, and sometimes you may need to pass a list of ordinals to make selections out of multiple lists at the same time. In that case call mb_SelectWithArgs and specify a list of ordinal arguments.

Let's go back to the example. After you select the context of the first artist, you can then use the MBE_ArtistXXXXX functions to extract information from the currently selected artist. To get the name of the artist, do this:

    mb_GetResultData(o, MBE_ArtistGetArtistName, data, 256);

Which will extract the artist name and save it into data. The last argument specifies the number of bytes allocated in data. Check the query reference for the queries that you can do on a given artist.

A query that returns an artist list will also return the list of albums for that that given artist. So, from the Artist context you can find out how many albums have been returned for that artist:

    numAlbums = mb_GetResultInt(o, MBE_GetNumAlbums);

To select the first album do this:

    mb_Select1(o, MBS_SelectAlbum, 1);

Now you can use the MBE_AlbumXXXX functions to retrieve information about the selected album. Now, let's assume that you've extracted the needed information from the first album and you want to select the second album. It would make sense to just be able to repeat the above call with 2 as the ordinal. However, that won't work!!! In order to select an album you need to be in the artist context, which contains the list of albums for the given artist. The proper way to select the second album is to do:

    mb_Select(o, MBS_Back);
    mb_Select1(o, MBS_SelectAlbum, 2);

The first select will back up the context to the previous context (which is the artist context) and then the second call selects the second album. You can now query information for the second album. There is one more special query:

    mb_Select(o, MBS_Rewind);

This will rewind the context to the top level context, just as it was right after the mb_Query function. This should give you a good idea on how to extract data from an artist list.

Using the other queries albumlist, tracklist and trmidlist, works much in the same way that the artistlist works. For the other queries an album will still contain a tracklist, and tracks will point to artists. For some more in-depth examples, check out the findartist.c and gettrack.c examples in the examples directory of the MusicBrainz client distribution.

Query Depth

One more thing that needs explaining is the depth of a query. In the graph above, there is a column that shows depth. The depth of the query determines the amount of data returned by the server. If you set the depth to 1, the server will only return the list of IDs to artists, but not the artists themselves. A depth of 2 will return the list, and all of the artists, but not the list of ids to the next albums. A depth of 3 will return all of the above and the albums that may be referenced in the artist. When you write code to access the server you should carefully select the depth of your query to make sure that you only retrieve as much information as you really need.

MusicBrainz IDs and mb_GetIDFromURL function

All of the MBE_GetXXXXId functions will return web URLs that can be used to retrieve the RDF that describes the object in question. In order to extract the ID from the URL, use the mb_GetIDFromURL function.

Writing a metadata tagger that uses MusicBrainz

If you are interested in writing a metadata tagger (an application that edits the metadata in music files using MusicBrainz), you should use the MBQ_TrackInfoFromTRMId and MBQ_FileInfoLookup functions.

Your tagging application should carry out the following steps:

  1. Generate a TRM Id for the file you are looking up. (see below)
  2. Read the metadata from the file (e.g. ID3 or Vorbiscomment)
  3. Use MBQ_TrackInfoFromTRMId to see if that TRM id is known to MusicBrainz. If so, all the relevant metadata will be returned by the server and that metadata can be written to the file in question. Note: This function may return more than one track, and the tagger application must let the user choose which is the correct track.
  4. If the track is not known to MusicBrainz, the tagger must use the MBQ_FileInfoLookup function to attempt to match the file with its appropriate metadata in the server.
  5. Once the tagger has made a match between a TRM id and a track on the server, the tagger should keep a list of TRM Id, Track Id pairs for submission to the server with MBQ_SubmitTrackTRMId. These pairs should be batched for a one-time submission to the server in order keep down the number of requests made to the server.

The MBQ_FileInfoLookup function should be explained in a bit more detail. In order to use this function, you need to provide the server with all the relevant metadata for the given track. This includes TRM Id, artist name, album name, track name, track number, duration (in milliseconds), file name, artist id, album id, and track id.

The idea is to have the server match as much information as possible from the provided artist, album and track names. The server will do its best to match an artist. If more than one matching artist is found, a list of artists is returned. The tagger must then present the list of artists to the user and have the user choose an artist. The artist id for the chosen artist should then be passed to the server in the artist id field. If an artist id is provided, the artist name is no longer used and can be omitted.

The same process applies to an album. However, if an artist was matched and a album name and track name was provided, the server will attempt to find the right track in the database, based on album name, track name, track number and duration. Possible matches will be returned to the tagger. The tagger must then provide these choices to the user and have the user choose the correct track.

That's it! Once the user has chosen the correct track, the tagger should have everything it needs to write the metadata to the file in question.

Note: Before you get starting writing a tagger, take a look at the client library (2.0.0-pre4 and later) tagger.c example. This example does a large chunk of the tagger work for you. You should be able to grab large chunks of that code and use it in your application (provided your app is LGPL/GPL compatible).

Generating TRM Ids

To create a TRM id, you should use the TRM application/library. Why write new code if you can use a library?

And if for some reason you do not want to use the library, go read the code to figure out how to create TRM ids. :-)