-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding loader for BRID Dataset (#633)
* Adding BRID loader * Updated doc for brid * black fixes * Fixes in doc and test * Brid updated index * uploaded index to zenodo * Rename annotations to annotations_temp * Rename annotations_temp to Annotations * Fixes in spell * update in index --------- Co-authored-by: Tanmay Khandelwal <[email protected]> Co-authored-by: Guillem Cortès-Sebastià <[email protected]> Co-authored-by: tanmayy24 <tk3309nyu.edu>
- Loading branch information
1 parent
62385ef
commit be63396
Showing
10 changed files
with
462 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
"""BRID Dataset Loader | ||
.. admonition:: Dataset Info | ||
:class: dropdown | ||
The Brazilian Rhythmic Instruments Dataset (BRID) [1] is a valuable resource assembled for research in Music Information Retrieval (MIR). This dataset is designed to facilitate research in computational rhythm analysis, beat tracking, and rhythmic pattern recognition, particularly in the context of Brazilian music. BRID offers a comprehensive collection of solo and multiple-instrument recordings, featuring 10 different instrument classes playing in 5 main rhythm classes from Brazilian music, including samba, partido alto, samba-enredo, capoeira, and marcha. | ||
**Dataset Overview:** | ||
BRID comprises a total of 367 tracks, averaging about 30 seconds each, amounting to approximately 2 hours and 57 minutes of music. These tracks include recordings of various Brazilian instruments, played in different Brazilian rhythmic styles. | ||
**Instruments and Rhythms:** | ||
The recorded instruments in BRID represent the most significant instruments in Brazilian music, particularly samba. Ten different instrument classes were chosen, including agogoˆ, caixa (snare drum), cu ́ıca, pandeiro (frame drum), reco-reco, repique, shaker, surdo, tamborim, and tanta ̃. To ensure diversity in sound, these instruments vary in terms of shape, size, material, pitch/tuning, and the way they are struck, resulting in 32 variations. | ||
**Rhythms in BRID:** | ||
BRID features various Brazilian rhythmic styles, with a focus on samba and its sub-genres, samba-enredo and partido alto. Additionally, the dataset includes rhythms such as marcha, capoeira, and a few tracks of baia ̃o and maxixe styles. The dataset provides a faithful representation of each rhythm, all of which are in duple meter. | ||
**Dataset Recording:** | ||
All recordings in BRID were made in a professional recording studio in Manaus, Brazil, between October and November. | ||
**Applications:** | ||
The Brazilian Rhythmic Instruments Dataset (BRID) serves as a crucial resource for researchers in the field of Music Information Retrieval (MIR) and rhythm analysis. It showcases the richness of Brazilian rhythmic content and highlights the challenges that non-Western music presents to traditional computational musicology research. Researchers can use BRID to develop more robust MIR tools tailored to Brazilian music. | ||
**Acknowledgments:** | ||
We extend our gratitude to the creators of BRID for providing this valuable dataset for research purposes in the field of MIR. Additionally, we acknowledge the authors of the following research paper for their contributions to the dataset and experiments: | ||
[1] Lucas Maia, Pedro D. de Tomaz Júnior, Magdalena Fuentes, Martín Rocamora, Luiz W. P. Biscainho, Maurício V. M. Costa, and Sara Cohen. "A Novel Dataset of Brazilian Rhythmic Instruments and Some Experiments in Computational Rhythm Analysis." In Proceedings of the {CONGRESO LATINOAMERICANO DE LA AES}, 2018. [Link](https://api.semanticscholar.org/CorpusID:204762166) | ||
For more details on the dataset and its applications, please refer to the associated research papers and documentation. | ||
""" | ||
|
||
import os | ||
import csv | ||
import logging | ||
import librosa | ||
import numpy as np | ||
from typing import BinaryIO, Optional, TextIO, Tuple | ||
|
||
from mirdata import annotations, core, download_utils, io, jams_utils | ||
|
||
|
||
BIBTEX = """ | ||
@inproceedings{Maia2018AND, | ||
title={A Novel Dataset of Brazilian Rhythmic Instruments and Some Experiments in Computational Rhythm Analysis}, | ||
author={Lucas Maia and Pedro D. de Tomaz J{\'u}nior and Magdalena Fuentes and Mart{\'i}n Rocamora and Luiz W. P. Biscainho and Maur{\'i}cio V. M. Costa and Sara Cohen}, | ||
year={2018}, | ||
url={https://api.semanticscholar.org/CorpusID:204762166} | ||
} | ||
""" | ||
|
||
INDEXES = { | ||
"default": "1.0", | ||
"test": "sample", | ||
"1.0": core.Index( | ||
filename="brid_full_index_1.0.json", | ||
url="https://zenodo.org/records/14052434/files/brid_full_index_1.0.json?download=1", | ||
checksum="6292a6d36d6ae267534107f4e5f6bcca", | ||
), | ||
"sample": core.Index(filename="brid_full_index_1.0_sample.json"), | ||
} | ||
|
||
|
||
REMOTES = { | ||
"annotations": download_utils.RemoteFileMetadata( | ||
filename="annotations.zip", | ||
url="https://zenodo.org/records/14051323/files/annotations.zip?download=1", | ||
checksum="678b2fa99c8d220cddd9f5e20d55d0c1", | ||
destination_dir="BRID_1.0", | ||
), | ||
"audio": download_utils.RemoteFileMetadata( | ||
filename="audio.zip", | ||
url="https://zenodo.org/records/14051323/files/audio.zip?download=1", | ||
checksum="3514b53d66515181f95619adb71a59b4", | ||
destination_dir="BRID_1.0", | ||
), | ||
} | ||
|
||
|
||
LICENSE_INFO = ( | ||
"Creative Commons Attribution Non Commercial Share Alike 4.0 International." | ||
) | ||
|
||
|
||
class Track(core.Track): | ||
"""BRID Rhythm class | ||
Args: | ||
track_id (str): track id of the track | ||
data_home (str): Local path where the dataset is stored. default=None | ||
If `None`, looks for the data in the default directory, `~/mir_datasets` | ||
Attributes: | ||
audio_path (str): path to audio file | ||
beats_path (str): path to beats file | ||
tempo_path (str): path to tempo file | ||
""" | ||
|
||
def __init__( | ||
self, | ||
track_id, | ||
data_home, | ||
dataset_name, | ||
index, | ||
metadata, | ||
): | ||
super().__init__( | ||
track_id, | ||
data_home, | ||
dataset_name, | ||
index, | ||
metadata, | ||
) | ||
|
||
# Audio path | ||
self.audio_path = self.get_path("audio") | ||
|
||
# Annotations paths | ||
self.beats_path = self.get_path("beats") | ||
self.tempo_path = self.get_path("tempo") | ||
|
||
@core.cached_property | ||
def beats(self) -> Optional[annotations.BeatData]: | ||
return load_beats(self.beats_path) | ||
|
||
@core.cached_property | ||
def tempo(self) -> Optional[float]: | ||
return load_tempo(self.tempo_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, "beats")], | ||
tempo_data=[(self.tempo, "tempo")], | ||
metadata=None, | ||
) | ||
|
||
|
||
def load_audio(audio_path): | ||
"""Load an audio file. | ||
Args: | ||
audio_path (str): path to audio file | ||
Returns: | ||
* np.ndarray - the mono audio signal | ||
* float - The sample rate of the audio file | ||
""" | ||
if audio_path is None: | ||
return None | ||
return librosa.load(audio_path, sr=44100, mono=False) | ||
|
||
|
||
@io.coerce_to_string_io | ||
def load_beats(fhandle: TextIO): | ||
"""Load beats | ||
Args: | ||
fhandle (str or file-like): Local path where the beats annotation is stored. | ||
Returns: | ||
BeatData: beat annotations | ||
""" | ||
beat_times = [] | ||
beat_positions = [] | ||
|
||
reader = csv.reader(fhandle, delimiter=" ") | ||
for line in reader: | ||
beat_times.append(float(line[0])) | ||
beat_positions.append(int(line[1])) | ||
|
||
if not beat_times or beat_times[0] == -1.0: | ||
return None | ||
|
||
return annotations.BeatData( | ||
np.array(beat_times), "s", np.array(beat_positions), "bar_index" | ||
) | ||
|
||
|
||
@io.coerce_to_string_io | ||
def load_tempo(fhandle: TextIO) -> float: | ||
"""Load tempo | ||
Args: | ||
fhandle (str or file-like): Local path where the tempo annotation is stored. | ||
Returns: | ||
float: tempo annotation | ||
""" | ||
reader = csv.reader(fhandle, delimiter=",") | ||
return float(next(reader)[0]) | ||
|
||
|
||
@core.docstring_inherit(core.Dataset) | ||
class Dataset(core.Dataset): | ||
""" | ||
The BRID dataset | ||
""" | ||
|
||
def __init__(self, data_home=None, version="default"): | ||
super().__init__( | ||
data_home, | ||
version, | ||
name="brid", | ||
track_class=Track, | ||
bibtex=BIBTEX, | ||
indexes=INDEXES, | ||
remotes=REMOTES, | ||
license_info=LICENSE_INFO, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import argparse | ||
import hashlib | ||
import json | ||
import os | ||
from mirdata.validate import md5 | ||
|
||
BRID_RHYTHM_INDEX_PATH = "../mirdata/datasets/indexes/brid_full_index_1.0.json" | ||
|
||
def make_brid_rhythm_index(dataset_data_path): | ||
cmr_index = { | ||
"version": "1.0", | ||
"tracks": {}, | ||
} | ||
|
||
dataset_folder_name = "BRID_1.0" # Adjust as needed for your dataset's root directory in mirdata | ||
|
||
# Define paths for beats and tempo annotations | ||
beats_path = os.path.join(dataset_data_path, "Annotations", "beats") | ||
tempo_path = os.path.join(dataset_data_path, "Annotations", "tempo") | ||
|
||
for root, dirs, files in os.walk(dataset_data_path): | ||
for filename in files: | ||
if filename.endswith(".wav"): | ||
# Extract relevant path details | ||
idx = filename.split(".")[0] | ||
relative_audio_path = os.path.relpath(os.path.join(root, filename), dataset_data_path) | ||
|
||
# Construct paths for annotations | ||
beat_file = f"{idx}.beats" | ||
tempo_file = f"{idx}.bpm" | ||
|
||
# Set relative paths to None if files do not exist | ||
relative_beat_path = os.path.join("Annotations", "beats", beat_file) if os.path.exists(os.path.join(beats_path, beat_file)) else None | ||
relative_tempo_path = os.path.join("Annotations", "tempo", tempo_file) if os.path.exists(os.path.join(tempo_path, tempo_file)) else None | ||
|
||
|
||
# Check if annotation files exist | ||
beat_file_path = os.path.join(beats_path, beat_file) if relative_beat_path else None | ||
tempo_file_path = os.path.join(tempo_path, tempo_file) if relative_tempo_path else None | ||
|
||
# Add track information to index | ||
cmr_index["tracks"][idx] = { | ||
"audio": ( | ||
os.path.join(dataset_folder_name, relative_audio_path), | ||
md5(os.path.join(root, filename)), | ||
), | ||
"beats": ( | ||
os.path.join(dataset_folder_name, relative_beat_path) if relative_beat_path else None, | ||
md5(beat_file_path) if beat_file_path else None, | ||
), | ||
"tempo": ( | ||
os.path.join(dataset_folder_name, relative_tempo_path) if relative_tempo_path else None, | ||
md5(tempo_file_path) if tempo_file_path else None, | ||
) | ||
} | ||
|
||
# Write to index file | ||
with open(BRID_RHYTHM_INDEX_PATH, "w") as fhandle: | ||
json.dump(cmr_index, fhandle, indent=2) | ||
|
||
def main(args): | ||
print("Creating index...") | ||
make_brid_rhythm_index(args.dataset_data_path) | ||
print("Index creation done!") | ||
|
||
if __name__ == "__main__": | ||
PARSER = argparse.ArgumentParser(description="Make BRID Rhythm index file.") | ||
PARSER.add_argument( | ||
"dataset_data_path", type=str, help="Path to the BRID Rhythm data folder." | ||
) | ||
main(PARSER.parse_args()) |
Oops, something went wrong.