diff --git a/docs/source/mirdata.rst b/docs/source/mirdata.rst index 65d01f0cc..ba1480813 100644 --- a/docs/source/mirdata.rst +++ b/docs/source/mirdata.rst @@ -52,6 +52,14 @@ billboard :inherited-members: +candombe +^^^^^^^^ + +.. automodule:: mirdata.datasets.candombe + :members: + :inherited-members: + + cante100 ^^^^^^^^ diff --git a/docs/source/table.rst b/docs/source/table.rst index 329af3247..5502c20ae 100644 --- a/docs/source/table.rst +++ b/docs/source/table.rst @@ -53,6 +53,14 @@ - .. image:: https://licensebuttons.net/l/zero/1.0/80x15.png :target: http://creativecommons.org/publicdomain/zero/1.0/ + * - Candombe + - - audio: ✅ + - annotations: ✅ + - - :ref:`beats` + - 35 + - .. image:: https://licensebuttons.net/l/by-nc-sa/4.0/80x15.png + :target: https://creativecommons.org/licenses/by-nc-sa/4.0 + * - cante100 - - audio: 🔑 - annotations: ✅ diff --git a/mirdata/datasets/candombe.py b/mirdata/datasets/candombe.py new file mode 100644 index 000000000..249d1757c --- /dev/null +++ b/mirdata/datasets/candombe.py @@ -0,0 +1,178 @@ +"""Candombe Dataset Loader + +.. admonition:: Dataset Info + :class: dropdown + + This is a dataset of Candombe recordings with annotated beats and downbeats, totaling over 2 hours of audio. + It comprises 35 complete performances by renowned players, in groups of three to five drums. + Recording sessions were conducted in studio, in the context of musicological research over the past two decades. + A total of 26 tambor players took part, belonging to different generations and representing all the important traditional Candombe styles. + The audio files are stereo with a sampling rate of 44.1 kHz and 16-bit precision. + The location of beats and downbeats was annotated by an expert, adding to more than 4700 downbeats. + + The audio is provided as .flac files and the annotations as .csv files. + The values in the first column of the csv file are the time instants of the beats. + The numbers on the second column indicate both the bar number and the beat number within the bar. + For instance, 1.1, 1.2, 1.3 and 1.4 are the four beats of the first bar. Hence, each label ending with .1 indicates a downbeat. + Another set of annotations are provided as .beats files in which the bar numbers are removed. + +""" +import csv +from typing import BinaryIO, Optional, TextIO, Tuple + +import librosa +import numpy as np + +from mirdata import download_utils, jams_utils, core, annotations, io + +BIBTEX = """ +@inproceedings{Nunes2015, + author = {Leonardo Nunes and Martín Rocamora and Luis Jure and Luiz W. P. Biscainho}, + title = {{Beat and Downbeat Tracking Based on Rhythmic Patterns Applied to the Uruguayan Candombe Drumming}}, + booktitle = {Proceedings of the 16th International Society for Music Information Retrieval Conference (ISMIR 2015)}, + month = {Oct.}, + address = {Málaga, Spain}, + pages = {264--270}, + year = {2015} +} +""" + +INDEXES = { + "default": "1.0", + "test": "1.0", + "1.0": core.Index(filename="candombe_index_1.0.json"), +} + + +REMOTES = { + "annotations": download_utils.RemoteFileMetadata( + filename="candombe_annotations.zip", + url="https://zenodo.org/record/6533068/files/candombe_annotations.zip", + checksum="f78aff60aa413cb4960c0c77cc31c243", + destination_dir=None, + ), + "audio": download_utils.RemoteFileMetadata( + filename="candombe_audio.zip", + url="https://zenodo.org/record/6533068/files/candombe_audio.zip", + checksum="ccd7f437024807b1a52c0818aa0b7f06", + destination_dir=None, + ), +} + +LICENSE_INFO = ( + "Creative Commons Attribution 4.0 International" +) + + +class Track(core.Track): + """Candombe Track class + + Args: + track_id (str): track id of the track + + Attributes: + audio_path (str): path to audio file + beats_path (str): path to beats file + + Cached Properties: + beats (BeatData): beat annotations + + """ + + def __init__(self, track_id, data_home, dataset_name, index, metadata): + super().__init__(track_id, data_home, dataset_name, index, metadata) + + self.audio_path = self.get_path("audio") + self.beats_path = self.get_path("beats") + + @core.cached_property + def beats(self) -> Optional[annotations.BeatData]: + """The track's beats + + Returns: + BeatData: loaded beat data + + """ + return load_beats(self.beats_path) + + @property + def audio(self) -> Optional[Tuple[np.ndarray, float]]: + """The track's audio + + Returns: + * np.ndarray - audio signal + * float - sample rate + + """ + return load_audio(self.audio_path) + + def to_jams(self): + """Get the track's data in jams format + + Returns: + jams.JAMS: the track's data in jams format + + """ + return jams_utils.jams_converter( + audio_path=self.audio_path, beat_data=[(self.beats, None)], metadata=None + ) + + +@io.coerce_to_bytes_io +def load_audio(fhandle: BinaryIO) -> Tuple[np.ndarray, float]: + """Load a candombe audio file. + + Args: + fhandle (str or file-like): path or file-like object pointing to an audio file + + Returns: + * np.ndarray - the audio signal + * float - The sample rate of the audio file + + """ + return librosa.load(fhandle, sr=None, mono=True) + + +@io.coerce_to_string_io +def load_beats(fhandle: TextIO) -> annotations.BeatData: + """Load a candombe beats file. + + Args: + fhandle (str or file-like): path or file-like object pointing to an audio file + + Returns: + BeatData: loaded beat data + """ + reader = csv.reader(fhandle, delimiter=",") + times = [] + beats = [] + for line in reader: + times.append(float(line[0])) + beats.append(int(line[1].split(".")[1])) + + beat_data = annotations.BeatData( + times=np.array(times), + time_unit="s", + positions=np.array(beats), + position_unit="bar_index", + ) + return beat_data + + +@core.docstring_inherit(core.Dataset) +class Dataset(core.Dataset): + """ + The candombe dataset + """ + + def __init__(self, data_home=None, version="default"): + super().__init__( + data_home, + version, + name="candombe", + track_class=Track, + bibtex=BIBTEX, + indexes=INDEXES, + remotes=REMOTES, + license_info=LICENSE_INFO, + ) diff --git a/mirdata/datasets/indexes/candombe_index_1.0.json b/mirdata/datasets/indexes/candombe_index_1.0.json new file mode 100644 index 000000000..e3efcf777 --- /dev/null +++ b/mirdata/datasets/indexes/candombe_index_1.0.json @@ -0,0 +1,355 @@ +{ + "version": 1.0, + "tracks": { + "csic.1995_ansina1_01": { + "audio": [ + "candombe_audio/csic.1995_ansina1_01.flac", + "fe9bb8edaa46892e4f094a07583ecfb7" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_ansina1_01.csv", + "3abfa7a3a13225738b39769a5ef0726a" + ] + }, + "csic.1995_ansina1_02": { + "audio": [ + "candombe_audio/csic.1995_ansina1_02.flac", + "d9d952f51ac38ece03ece0be80fe4071" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_ansina1_02.csv", + "cf1f689d524363ecf2a267736c43d5dc" + ] + }, + "csic.1995_ansina1_03": { + "audio": [ + "candombe_audio/csic.1995_ansina1_03.flac", + "fffe0c4677d994cbc16e7009b7cad982" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_ansina1_03.csv", + "3e6afce6de38df768cecc5eb7676f25d" + ] + }, + "csic.1995_ansina1_04": { + "audio": [ + "candombe_audio/csic.1995_ansina1_04.flac", + "6b94f386f6669dfb75b8af42049fdffd" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_ansina1_04.csv", + "f061084486027a874298677ffc1c805a" + ] + }, + "csic.1995_ansina1_05": { + "audio": [ + "candombe_audio/csic.1995_ansina1_05.flac", + "b0c0938d3c04cc70aeb58cc6e98633bd" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_ansina1_05.csv", + "00f4c16ff9127c4904d8985295eb7b75" + ] + }, + "csic.1995_ansina2_01": { + "audio": [ + "candombe_audio/csic.1995_ansina2_01.flac", + "1131da5060d9a55675563fd0d9754bce" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_ansina2_01.csv", + "07d950c2460d4d7e0e2b8d4fe86fd4b5" + ] + }, + "csic.1995_ansina2_02": { + "audio": [ + "candombe_audio/csic.1995_ansina2_02.flac", + "09fb3f9b9a64a162783dfd62798063ea" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_ansina2_02.csv", + "a07ae4015c2f83fd0e1e5154f5adb828" + ] + }, + "csic.1995_ansina2_03": { + "audio": [ + "candombe_audio/csic.1995_ansina2_03.flac", + "1d280f3a996f500620930b011885b857" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_ansina2_03.csv", + "8f51291430b6c0287d7a6471339f0c0d" + ] + }, + "csic.1995_ansina2_04": { + "audio": [ + "candombe_audio/csic.1995_ansina2_04.flac", + "ea6d50a23fe392aa2c0059378e86c5e1" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_ansina2_04.csv", + "3ba5f867009db02eb8fac52ce0ff10a0" + ] + }, + "csic.1995_cuareim_01": { + "audio": [ + "candombe_audio/csic.1995_cuareim_01.flac", + "efe99db48fc385e90b36ff7a49052462" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_cuareim_01.csv", + "7456802573f3839405e11272805d7e17" + ] + }, + "csic.1995_cuareim_02": { + "audio": [ + "candombe_audio/csic.1995_cuareim_02.flac", + "73aa793b6810118dc19e0f50d63ddcbd" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_cuareim_02.csv", + "5eb8d698b1620bc65b7ff40157c883be" + ] + }, + "csic.1995_cuareim_03": { + "audio": [ + "candombe_audio/csic.1995_cuareim_03.flac", + "67d45b125dc7d99c07ac653407ca7b2d" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_cuareim_03.csv", + "a01612011033aea8b67fcfda2622c48d" + ] + }, + "csic.1995_cuareim_04": { + "audio": [ + "candombe_audio/csic.1995_cuareim_04.flac", + "e01ec34a31e5f93bcb22e74ed83faf9c" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_cuareim_04.csv", + "b3dbcd302891a6692885b3c27f827b12" + ] + }, + "csic.1995_cuareim_05": { + "audio": [ + "candombe_audio/csic.1995_cuareim_05.flac", + "fb0c5db4caa5580e72625fcce0062e94" + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_cuareim_05.csv", + "31112a70b78476501cec9e040e27a85f" + ] + }, + "proyecto.1992_gimenez_02": { + "audio": [ + "candombe_audio/proyecto.1992_gimenez_02.flac", + "c02e1c932727ec94c3153f5de9a2d2fb" + ], + "beats": [ + "candombe_annotations/with_bar_number/proyecto.1992_gimenez_02.csv", + "9fd4364a7d9d5d56fb0db6fb5ba61e71" + ] + }, + "proyecto.1992_gimenez_06": { + "audio": [ + "candombe_audio/proyecto.1992_gimenez_06.flac", + "51208f645e90ea2c967297b18455d342" + ], + "beats": [ + "candombe_annotations/with_bar_number/proyecto.1992_gimenez_06.csv", + "23af6b491f0133f8b1b3cd23a375756e" + ] + }, + "proyecto.1992_lobo_01": { + "audio": [ + "candombe_audio/proyecto.1992_lobo_01.flac", + "e017f03844575a1cca1225b96f212095" + ], + "beats": [ + "candombe_annotations/with_bar_number/proyecto.1992_lobo_01.csv", + "62d3cf27e9b60fcf68f4d27bc2a6b7b7" + ] + }, + "proyecto.1992_lobo_06": { + "audio": [ + "candombe_audio/proyecto.1992_lobo_06.flac", + "9cb81decde63aba9978fb901e09dc2de" + ], + "beats": [ + "candombe_annotations/with_bar_number/proyecto.1992_lobo_06.csv", + "c3d47b4828ec527c96b66bd30247567f" + ] + }, + "proyecto.1992_magarinos_02": { + "audio": [ + "candombe_audio/proyecto.1992_magarinos_02.flac", + "2ec7965082a2cf7ac41424755649ec54" + ], + "beats": [ + "candombe_annotations/with_bar_number/proyecto.1992_magarinos_02.csv", + "2ec3f4cdd2ff9ff80846643ad90c61c8" + ] + }, + "proyecto.1992_pelado_01": { + "audio": [ + "candombe_audio/proyecto.1992_pelado_01.flac", + "0f1e38695131186b1716147ba58d9411" + ], + "beats": [ + "candombe_annotations/with_bar_number/proyecto.1992_pelado_01.csv", + "bd92938935414029cbf20b076a5faa7b" + ] + }, + "proyecto.1992_pelado_05": { + "audio": [ + "candombe_audio/proyecto.1992_pelado_05.flac", + "72a87c91a7af67b6630b4e881ca603d8" + ], + "beats": [ + "candombe_annotations/with_bar_number/proyecto.1992_pelado_05.csv", + "6c62df8870223c94f314ff71bf37b8f7" + ] + }, + "zavala.muniz.2014_41": { + "audio": [ + "candombe_audio/zavala.muniz.2014_41.flac", + "a305627f4549d364a9627e5e507b1046" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_41.csv", + "c6218485a208e7770b1a91a5170d8200" + ] + }, + "zavala.muniz.2014_42": { + "audio": [ + "candombe_audio/zavala.muniz.2014_42.flac", + "39e5ed9021b77d1013aacb4d2fc288db" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_42.csv", + "781c2b3963e761323fb49bb213aee6fd" + ] + }, + "zavala.muniz.2014_44": { + "audio": [ + "candombe_audio/zavala.muniz.2014_44.flac", + "388f460e98398ea3b9e8c0e990d81574" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_44.csv", + "6c819abb4b84c373dd7f537e6e9d16dc" + ] + }, + "zavala.muniz.2014_45": { + "audio": [ + "candombe_audio/zavala.muniz.2014_45.flac", + "46108a01d62ba0259ac4edb61c1c26e6" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_45.csv", + "86a426132c30db1b44d512c48788def8" + ] + }, + "zavala.muniz.2014_46": { + "audio": [ + "candombe_audio/zavala.muniz.2014_46.flac", + "eae726e7c5e96591e85b409ba5ece495" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_46.csv", + "9aa57f8217ba636bbde444f8c08a1a5b" + ] + }, + "zavala.muniz.2014_47": { + "audio": [ + "candombe_audio/zavala.muniz.2014_47.flac", + "0bf42e2c6662efb6aca5ff1090118faf" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_47.csv", + "1bcbf496298b73bd7431b38bef44b050" + ] + }, + "zavala.muniz.2014_48": { + "audio": [ + "candombe_audio/zavala.muniz.2014_48.flac", + "2a8df7f9636412e67bb49d961a65f8c6" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_48.csv", + "2a909fb7bb2b2c4d1034309c976e1af1" + ] + }, + "zavala.muniz.2014_49": { + "audio": [ + "candombe_audio/zavala.muniz.2014_49.flac", + "6b5bb491ba4696facff317ace5f9637f" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_49.csv", + "feb35bd136bd0f6ef8e2da78237736d4" + ] + }, + "zavala.muniz.2014_50": { + "audio": [ + "candombe_audio/zavala.muniz.2014_50.flac", + "9541981fc36724c7aa9d4c666a690d8d" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_50.csv", + "ed4cb4e3954753872dd4504815afae16" + ] + }, + "zavala.muniz.2014_51": { + "audio": [ + "candombe_audio/zavala.muniz.2014_51.flac", + "022124d195d5b76fbc42b8eb423bbafb" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_51.csv", + "12940af6adc5de6d5e3ecd2edc94a94a" + ] + }, + "zavala.muniz.2014_52": { + "audio": [ + "candombe_audio/zavala.muniz.2014_52.flac", + "730c172f12455d7b6f5e55e056c8e2b0" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_52.csv", + "795af8482a6b501b481466ea336be54c" + ] + }, + "zavala.muniz.2014_53": { + "audio": [ + "candombe_audio/zavala.muniz.2014_53.flac", + "8c6e134bb8fabb7ada5ba25ef5a856b4" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_53.csv", + "1ee3f567e93fc91d7590982a467d1484" + ] + }, + "zavala.muniz.2014_54": { + "audio": [ + "candombe_audio/zavala.muniz.2014_54.flac", + "83500f50537a4b80fe7a91c3240b6c9d" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_54.csv", + "fbfad83884635b87a6b39bfdfb7f0efd" + ] + }, + "zavala.muniz.2014_55": { + "audio": [ + "candombe_audio/zavala.muniz.2014_55.flac", + "31c7cdbe1de195e8c4667724a040b3d8" + ], + "beats": [ + "candombe_annotations/with_bar_number/zavala.muniz.2014_55.csv", + "c9027a8bb61821db3980fce4d7c3042e" + ] + } + } +} diff --git a/scripts/make_candombe_index.py b/scripts/make_candombe_index.py new file mode 100644 index 000000000..0903657a7 --- /dev/null +++ b/scripts/make_candombe_index.py @@ -0,0 +1,58 @@ +import argparse +import glob +import json +import os +from mirdata.validate import md5 + +DATASET_INDEX_PATH = "../mirdata/datasets/indexes/candombe_index_1.0.json" + + +def make_dataset_index(dataset_data_path): + annotation_files = glob.glob( + os.path.join(dataset_data_path + 'candombe_annotations/with_bar_number', "*.csv") + ) + + track_ids = sorted([".".join(os.path.basename(f).split(".")[:-1]) for f in annotation_files]) + + # top-key level tracks + index_tracks = {} + for track_id in track_ids: + audio_checksum = md5( + os.path.join(dataset_data_path, "candombe_audio/{}.flac".format(track_id)) + ) + annotation_checksum = md5( + os.path.join( + dataset_data_path, + "candombe_annotations/with_bar_number/{}.csv".format(track_id) + ) + ) + + index_tracks[track_id] = { + "audio": ("candombe_audio/{}.flac".format(track_id), audio_checksum), + "beats": ( + "candombe_annotations/with_bar_number/{}.csv".format(track_id), + annotation_checksum + ), + } + + # top-key level version + dataset_index = {"version": 1.0} + + # combine all in dataset index + dataset_index.update({"tracks": index_tracks}) + + with open(DATASET_INDEX_PATH, "w") as fhandle: + json.dump(dataset_index, fhandle, indent=2) + + +def main(args): + make_dataset_index(args.dataset_data_path) + + +if __name__ == "__main__": + PARSER = argparse.ArgumentParser(description="Make dataset index file.") + PARSER.add_argument( + "dataset_data_path", type=str, help="Path to dataset data folder." + ) + + main(PARSER.parse_args()) diff --git a/tests/datasets/test_candombe.py b/tests/datasets/test_candombe.py new file mode 100644 index 000000000..64ca49e01 --- /dev/null +++ b/tests/datasets/test_candombe.py @@ -0,0 +1,100 @@ +"""Tests for Candombe dataset +""" +import numpy as np +from mirdata import annotations +from mirdata.datasets import candombe +from tests.test_utils import run_track_tests + + +def test_track(): + default_trackid = "csic.1995_ansina1_01" + data_home = "tests/resources/mir_datasets/candombe/" + dataset = candombe.Dataset(data_home, version="1.0") + track = dataset.track(default_trackid) + + expected_attributes = { + "track_id": "csic.1995_ansina1_01", + "audio_path": "tests/resources/mir_datasets/candombe/" + "candombe_audio/csic.1995_ansina1_01.flac", + "beats_path": "tests/resources/mir_datasets/candombe/" + "candombe_annotations/with_bar_number/csic.1995_ansina1_01.csv", + } + + expected_property_types = {"beats": annotations.BeatData, "audio": tuple} + + assert track._track_paths == { + "audio": [ + "candombe_audio/csic.1995_ansina1_01.flac", + "fe9bb8edaa46892e4f094a07583ecfb7", + ], + "beats": [ + "candombe_annotations/with_bar_number/csic.1995_ansina1_01.csv", + "3abfa7a3a13225738b39769a5ef0726a", + ], + } + + run_track_tests(track, expected_attributes, expected_property_types) + + # test audio loadversg functions + audio, sr = track.audio + assert sr == 44100 + assert audio.shape == (12288,) + + +def test_to_jams(): + default_trackid = "csic.1995_ansina1_01" + data_home = "tests/resources/mir_datasets/candombe" + dataset = candombe.Dataset(data_home, version="1.0") + track = dataset.track(default_trackid) + jam = track.to_jams() + beats = jam.search(namespace="beat")[0]["data"] + + assert [beat.time for beat in beats] == [ + 0.548571428, + 0.993877551, + 1.461405895, + 1.895328798, + 2.332653061, + 2.809024943, + 3.253650793, + 3.684126984, + 4.115306122, + 4.581587301, + 5.019863945, + 5.473469387, + ] + + +def test_load_beats(): + # load a file which exists + beats_path = ( + "tests/resources/mir_datasets/candombe/candombe_annotations/" + "with_bar_number/csic.1995_ansina1_01.csv" + ) + beats_data = candombe.load_beats(beats_path) + + # check types + assert type(beats_data) == annotations.BeatData + assert type(beats_data.times) is np.ndarray + # ... etc + + # check values + assert np.array_equal( + beats_data.times, + np.array( + [ + 0.548571428, + 0.993877551, + 1.461405895, + 1.895328798, + 2.332653061, + 2.809024943, + 3.253650793, + 3.684126984, + 4.115306122, + 4.581587301, + 5.019863945, + 5.473469387, + ] + ), + ) diff --git a/tests/resources/mir_datasets/candombe/candombe_annotations/with_bar_number/csic.1995_ansina1_01.csv b/tests/resources/mir_datasets/candombe/candombe_annotations/with_bar_number/csic.1995_ansina1_01.csv new file mode 100644 index 000000000..8d135f2fd --- /dev/null +++ b/tests/resources/mir_datasets/candombe/candombe_annotations/with_bar_number/csic.1995_ansina1_01.csv @@ -0,0 +1,12 @@ +0.548571428,1.1 +0.993877551,1.2 +1.461405895,1.3 +1.895328798,1.4 +2.332653061,2.1 +2.809024943,2.2 +3.253650793,2.3 +3.684126984,2.4 +4.115306122,3.1 +4.581587301,3.2 +5.019863945,3.3 +5.473469387,3.4 diff --git a/tests/resources/mir_datasets/candombe/candombe_audio/csic.1995_ansina1_01.flac b/tests/resources/mir_datasets/candombe/candombe_audio/csic.1995_ansina1_01.flac new file mode 100644 index 000000000..e2700ef27 Binary files /dev/null and b/tests/resources/mir_datasets/candombe/candombe_audio/csic.1995_ansina1_01.flac differ