Skip to content

The Nendo Library¤

The nendo library is at the center of Nendo Core. It provides all functionalities required to handle a large catalog of audio assets, manage their metadata and group them logically into collections. Most library features can be accessed via shortcut functions, as explained in the NendoTrack and NendoCollection user guides. In the following, we therefore focus on explaining the high-level ideas and providing some useful introductory examples.

For a list of all nendo library functions, refer to the API reference

Configuring the Library Plugin¤

If left untouched, the default configuration of Nendo Core will use the default nendo library plugin, which is a DuckDB implementation of the nendo library.

Using a different library plugin

You can change the library plugin to be used by nendo via the nendo.config.library_plugin configuration variable. For example, to use the postgres implementation of the nendo library plugin, set nendo.config.library_plugin = nendo_plugin_library_postgres.

The default implementation of the nendo library uses a local directory for storing its binary assets. You can control where the assets (such as audio files, blobs, etc.) should be stored via the nendo.config.library_path variable.

The default library path is ./nendo_library

Furthermore, there are a number of other configuration variables that adjust how the nendo library behaves. Specifically, the variables copy_to_library, skip_duplicate, auto_convert, auto_resample, and default_sr are revelant, whose documentation can be found in the configuration guide.

Using the Library Plugin¤

The following paragraphs introduce the most essential functions to use when interacting with the nendo library.

Preparations

The following examples assume that you have already created a nendo instance, e.g. with the default configuration:

nendo = Nendo()

The nendo library is available via the field Nendo.library. To

Library access shortcuts

To make your code simpler, nendo allows to call any library function directly on the main instance, such that, for example, nendo.library.add_track("file.mp3") can also be written as `nendo.add_track("file.mp3").

Adding audio files¤

The first step in most AI audio workflows is to import existing assets for analysis, generation and model training. The nendo library provides a set of functions that help adding individual files, as well as adding entire folders

Simple import

>>> new_track = nendo.library.add_track("/path/to/my/file.mp3")
>>> type(new_track)
<class 'nendo.schema.core.NendoTrack'>

Duplicate import

To add the same track (of type "voice") twice to the library:

>>> new_track = nendo.library.add_track("/path/to/my/file.mp3")
>>> duplicate_track = nendo.library.add_track(
... file_path = "/path/to/my/file.mp3",
... track_type = "voice",
... skip_duplicate = False,
... )
>>> new_track == duplicate_track
False

Adding without import

>>> new_track = nendo.library.add_track(
... file_path = "/path/to/my/file.mp3",
... copy_to_library = False,
... )
>>> print(new_track.resource.src)
/path/to/my/file.mp3

The following example adds all files in the target directory to nendo. The result is a NendoCollection containing all files as NendoTracks.

Example

>>> new_collection = nendo.library.add_tracks("/path/to/my/files/")
>>> type(new_collection)
<class 'nendo.schema.core.NendoCollection'>
>>> len(new_collection)
32

Creating an empty collection

>>> new_collection = nendo.library.add_collection(
... name = "Empty collection",
... description = "My first nendo collection",
... collection_type = "playlist",
... visibilty = "private",
... )
>>> type(new_collection)
<class 'nendo.schema.core.NendoCollection'>
>>> len(new_collection)
0

Creating an collection from existing tracks

>>> # new_track = ...
>>> new_collection = nendo.library.add_collection(
... name = "New collection",
... track_ids = [new_track.id]
... )
>>> len(new_collection)
1

Tip

The behavior of the above functions is influenced by the copy_to_library and skip_duplicate configuration variables. Passing parameters with the same names to the functions as demonstrated will overwrite the configured behavior for the single function call.

Retrieving tracks and collections¤

Obtaining individual tracks and collections as well as all items in the library is

Streaming mode

The nendo.config.stream_mode configuration variable can be used to change the behavior / return type of all library functions that retrieve multiple items. If stream_mode is set to False, the functions will return lists, whereas setting stream_mode to True will make them return Iterators.

Example

>>> track = nendo.library.get_track("c48d0436-6fa0-4cf6-9ab2-c6b00fbe3f91")
>>> collection = nendo.library.get_collection("c01e9559-ac1b-4a2a-a30d-f038933ef5c0")

Retrieve multiple items as list

>>> tracks = nendo.library.get_tracks(
... order_by = "created_at",
... limit = 10,
... offset = 0,
... )
>>> len(tracks)
10

Retrieve all items as iterator

>>> nendo.config.stream_mode = True
>>> collections = nendo.library.get_collections()
>>> type(collections)
<class 'generator'>
>>> for c in collections:
...     print(c.id)
"a11909ae-575e-40e6-9b80-c722c7ec85d4"
"49efed34-3584-451d-83a8-b7bb8093a4ca"
# ...

Finding and filtering¤

Managing a large collection of audio files can be tedious. Nendo core allows to search through tracks, filter for specific keywords or plugin data values and to return the results as ordered lists. With stream_mode even large numbers of tracks can be efficiently iterated over. By using a combination of advanced nendo plugins, handling even very large audio libraries becomes easy.

To find a track by searching over text representations of it's meta and resource fields, use the Nendo.library.find_tracks() method.

Example

found_tracks = nendo.library.find_tracks(value = "bounce")

Note, that like all functions in the nendo library that retrieve multiple items at once, the find_tracks() function accepts the additional parameters user_id, order_by, order, limit and offset, which can be useful for developers using nendo inside their (paginated) web applications.

Performance of the default implementation

Unfortunately, due to the simplistic implementation of this function in the default nendo library, it will not be very efficient for very large databases. If you are running into performance issues, consider switching to a more advanced implementation of the nendo library like the postgres library plugin or using the Nendo.library.filter_tracks() function which leverages the resource field's structure to make the matching more efficient.

To find a collection by searching over it's name and decription fields, use the Nendo.library.find_collections() method.

Example

found_collections = nendo.library.find_collections(value = "greatest hits")

Note, that like all functions in the nendo library that retrieve multiple items at once, the find_collections() function accepts the additional parameters user_id, order_by, order, limit and offset, which can be useful for developers using nendo inside their (paginated) web applications.

Filtering tracks with regard to specific fields is one of the most complex operations supported by the nendo library. The filter_tracks() method comes with a number of parameters that can be used in isolation or in conjunction to refine the search. The following examples provides a simple introduction, followed by a comprehensive list of supported paramters and their filtering effects.

Filtering by track_type

The following call will filter all tracks whose track_type field has the value "voice":

voice_tracks = nendo.library.filter_tracks(track_type = "voice")

Filtering by collection

The following call will filter all tracks whose track_type field has the value "voice" and who are contained in the collection with the ID ba57d368-94a5-4ded-8b1c-478026e24a66:

collection_tracks = nendo.library.filter_tracks(
    track_type = "voice",
    collection_id = "ba57d368-94a5-4ded-8b1c-478026e24a66",
)

Filtering by search value

The following call will filter all tracks wehre both words "Michael" and "Jackson" occur anywhere in their track.meta or track.resource.meta fields:

mj_tracks = nendo.library.filter_tracks(
    search_meta = ["Michael", "Jackson"],
)

Filtering by plugin data range

The following call will filter all tracks whose plugin_data have an entry created by the nendo_plugin_classify_core plugin where the bpm value is between 100 and 120:

bpm_filtered_tracks = nendo.library.filter_tracks(
    filters = {"bpm": (100, 120)},
    plugin_names = ["nendo_plugin_classify_core"],
)

The following table provides an overview over the parameters and how they affect the search.

Parameter Type Description
filters dict Filters to apply to the plugin_data field of the track. The dictionary can contain multiple filters, where the key is matched against the key of the NendoPluginData entry and the value can be either of the following:
  • tuple - Check, whether the plugin data's value is in the range specified by the tuple.
  • list - Check, whether the plugin data's value matches any of the items in the list.
  • str - Do a fuzzy match comparison between plugin data's value and the value passed in the filters dictionary.
search_meta dict Dictionary containing the keywords to search for over the track.resource.meta field. The dictionary's values should contain singular search tokens and the keys have no effect in the default implementation of the nendo library.
track_type str Match the NendoTrack.track_type field against this value.
user_id uuid Filter for tracks with the given user_id.
collection_id uuid Filter for tracks who have a relationship to the collection with the given ID.
plugin_names list[str] Filter to apply in addition to the fields above, when filtering with respect to plugin_data entries.

Library integrity functions¤

The nendo library also comes with a few functions that can be used to verify and restore it's integrity, in cases where files have been (re)moved from their original locations without updating the corresponding tracks in the nendo library.

To reset the nendo library, deleteing all data and corresponding files, simply call nendo.library.reset(). Calling this function will prompt the user to confirm the operation, unless the function parameter force = True is passed.

Resetting the library

Resetting the library will purge all items from the database and delete the corresponding files from their location in the library_path. Files residing outside the nendo library, who were added to the library with the configuration parameter config_to_library = False, will not be deleted.

To verify every track in the nendo library with respect to the existence of it's associated resource on disk, call nendo.library.verify(). For every inconsistency thus detected, the user will be prompted how to act, allowing to type the letter "i" to ignore the specific inconsistency or the letter "r" to resolve the inconsistency, by

  • removing the physical file if no corresponding database entry exists, or
  • removing the database entry if no corresponding file exists.

Working with binary data (blobs)¤

Pieces of binary data are called blobs in nendo. They can be stored, loaded and removed from the nendo library by using the corresponding library functions introduced below.

To store a binary file into the nendo library, use nendo.library.store_blob(file_path).

Likewise, to store a bytes object from memory by pickling it onto disk and storing a corresponding object in the nendo library, use nendo.library.store_blob_from_bytes(data).

Example

>>> # to store a blob from a binary file:
>>> file_blob = nendo.library.store_blob(file_path = "/path/to/blob")
>>> # to store a blob from a bytes object:
>>> bytes_obj = os.urandom(16) # get a random bytes object
>>> bytes_blob = nendo.library.store_blob_from_bytes(data = bytes_obj)

To obtain a blob from the nendo library and load the corresponding binary file into memory, use nendo.library.load_blob().

Example

# blob_id = ...
blob = nendo.library.load_blob(blob_id)

To remove a blob from the nendo library, use nendo.library.remove_blob().

Example

# blob_id = ...
blob = nendo.library.remove_blob(blob_id)

Writing a Library Plugin¤

Please refer to the library plugin development pages.


Success

That's all you need to know about the nendo library. Next up, dive deeper into the concept of plugins in nendo.