Source code for carat.annotations

# encoding: utf-8
# pylint: disable=C0103
"""
Annotations
===========

Reading and writing annotations
-------------------------------

.. autosummary::
    :toctree: generated/

    load_beats
    load_downbeats

"""

import csv
import numpy as np

__all__ = ['load_beats', 'load_downbeats']

[docs]def load_beats(labels_file, delimiter=',', times_col=0, labels_col=1): """Load annotated beats from text (csv) file. Parameters ---------- labels_file : str name (including path) of the input file delimiter : str string used as delimiter in the input file times_col : int column index of the time data labels_col : int column index of the label data Returns ------- beat_times : np.ndarray time instants of the beats beat_labels : list labels at the beats (e.g. 1.1, 1.2, etc) Examples -------- Load an included example file from the candombe dataset. http://www.eumus.edu.uy/candombe/datasets/ISMIR2015/ >>> annotations_file = carat.util.example_beats_file(num_file=1) >>> beats, beat_labs = annotations.load_beats(annotations_file) >>> beats[0] 0.548571428 >>> beat_labs[0] '1.1' Load an included example file from the samba dataset. http://www.smt.ufrj.br/~starel/datasets/brid.html >>> annotations_file = carat.util.example_beats_file(num_file=2) >>> beats, beat_labs = annotations.load_beats(annotations_file, delimiter=' ') >>> beats array([ 2.088, 2.559, 3.012, 3.48, 3.933, 4.41, 4.867, 5.32, 5.771, 6.229, 6.69, 7.167, 7.633, 8.092, 8.545, 9.01, 9.48, 9.943, 10.404, 10.865, 11.322, 11.79 , 12.251, 12.714, 13.167, 13.624, 14.094, 14.559, 15.014, 15.473, 15.931, 16.4, 16.865, 17.331, 17.788, 18.249, 18.706, 19.167, 19.643, 20.096, 20.557, 21.018, 21.494, 21.945, 22.408, 22.869, 23.31 , 23.773, 24.235, 24.692, 25.151, 25.608, 26.063, 26.52 ]) >>> beat_labs ['1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2', '1', '2'] Notes ----- It is assumed that the beat annotations are provided as a text file (csv). Apart from the time data (mandatory) a label can be given for each beat (optional). The time data is assumed to be given in seconds. The labels may indicate the beat number within the rhythm cycle (e.g. 1.1, 1.2, or 1, 2). """ # read beat time instants beat_times = np.genfromtxt(labels_file, delimiter=delimiter, usecols=(times_col)) # read beat labels with open(labels_file, 'r') as fi: reader = csv.reader(fi, delimiter=delimiter) # number of columns ncol = len(next(reader)) # check if there are no labels if ncol == 1: beat_labels = [] else: fi.seek(0) beat_labels = [row[labels_col] for row in reader] return beat_times, beat_labels
[docs]def load_downbeats(labels_file, delimiter=',', times_col=0, labels_col=1, downbeat_label='.1'): """Load annotated downbeats from text (csv) file. Parameters ---------- labels_file : str name (including path) of the input file delimiter : str string used as delimiter in the input file times_col : int column index of the time data labels_col : int column index of the label data downbeat_label : str string to look for in the label data to select downbeats Returns ------- downbeat_times : np.ndarray time instants of the downbeats downbeat_labels : list abels at the downbeats Examples -------- Load an included example file from the candombe dataset. http://www.eumus.edu.uy/candombe/datasets/ISMIR2015/ >>> annotations_file = carat.util.example_beats_file(num_file=1) >>> downbeats, downbeat_labs = carat.annotations.load_downbeats(annotations_file) >>> downbeats[:3] array([0.54857143, 2.33265306, 4.11530612]) >>> downbeat_labs[:3] ['1.1', '2.1', '3.1'] Load an included example file from the samba dataset. http://www.smt.ufrj.br/~starel/datasets/brid.html >>> annotations_file = carat.util.example_beats_file(num_file=2) >>> downbeats, downbeat_labs = annotations.load_downbeats(annotations_file, delimiter=' ', downbeat_label='1') >>> downbeats array([ 2.088, 3.012, 3.933, 4.867, 5.771, 6.69 , 7.633, 8.545, 9.48 , 10.404, 11.322, 12.251, 13.167, 14.094, 15.014, 15.931, 16.865, 17.788, 18.706, 19.643, 20.557, 21.494, 22.408, 23.31, 24.235, 25.151, 26.063]) >>> downbeat_labs ['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'] Notes ----- It is assumed that the annotations are provided as a text file (csv). Apart from the time data (mandatory) a label can be given for each downbeat (optional). The time data is assumed to be given in seconds. If a single file contains both beats and downbeats then the downbeat_label is used to select downbeats. The downbeats are those beats whose label has the given downbeat_label string. For instance the beat labels can be numbers, e.g. '1', '2'. Then, the downbeat_label is just '1'. This is the case for the BRID samba dataset. In the case of the candombe dataset, the beat labels indicate bar number and beat number. For instance, '1.1', '1.2', '1.3' and '1.4' are the four beats of the first bar. Hence, the string needed to indetify the downbeats is '.1'. """ # read file as beats beat_times, beat_labs = load_beats(labels_file, delimiter=delimiter, times_col=times_col, labels_col=labels_col) # if there are no labels in the file or downbeat_label is None, then all entries are downbeats if not beat_labs or downbeat_label is None: downbeat_times, downbeat_labs = beat_times, beat_labs else: # get downbeat instants and labels by finding the string downbeat_label in the beat labels ind_downbeats = [ind_beat for ind_beat in range(len(beat_labs)) if downbeat_label in beat_labs[ind_beat]] downbeat_times = beat_times[ind_downbeats] downbeat_labs = [beat_labs[ind_downbeat] for ind_downbeat in ind_downbeats] return downbeat_times, downbeat_labs