Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions parsers/data/rwcmelodypop/metadata.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
Piece No.,Cat. Suffix,Tr. No.,Title,Artist (Vocal),Singer Information,Length,Tempo,Live Instruments Used,Drum Information
No. 1,M01,Tr. 01,Eien no replica,Kazuo Nishi,Male,3:29,135,Gt,Drum sequences
No. 2,M01,Tr. 02,Magic in your eyes,Hiromi Yoshii,Female,3:42,100,Gt & Bs,Drum sequences
No. 3,M01,Tr. 03,HORO,MIT,Vocal group (1 male + 1 female),3:15,111,,Drum sequences
No. 4,M01,Tr. 04,Spice of Life,Hisayoshi Kazato,Male,4:02,86,Gt,Drum sequences
No. 5,M01,Tr. 05,Koino Ver.2.4,Eves,Vocal group (4 female),3:48,135,Gt,Drum sequences
No. 6,M01,Tr. 06,Funky Life,Oriken,Male,3:26,120,Gt,Drum sequences
No. 7,M01,Tr. 07,PROLOGUE,Tomomi Ogata,Female,4:58,122,Gt,Drum sequences
No. 8,M01,Tr. 08,Jinsei konnamono,fevers,Vocal group (2 female),3:12,127,Gt & Bs,Drum sequences
No. 9,M01,Tr. 09,Doukoku,Kazuo Nishi,Male,4:37,70,Gt & Bs & Dr,Live drums
No. 10,M01,Tr. 10,Getting Over,Brakes,Vocal group (3 female),3:35,125,Gt,Drum sequences
No. 11,M01,Tr. 11,Ienai,Hisayoshi Kazato,Male,4:27,90,Gt,Drum sequences
No. 12,M01,Tr. 12,KAGE-ROU,Kazuo Nishi,Male,3:24,120,Gt & Bs,Drum sequences
No. 13,M01,Tr. 13,Catch ball,Konbu,Female,3:39,103,Gt,Drum sequences
No. 14,M01,Tr. 14,Karehairo no Twilight,Rin,Female,3:54,88,Gt & Bs,Drum sequences
No. 15,M01,Tr. 15,old fashioned,Katsuyuki Ozawa,Male,2:42,132,Gt,Drum sequences
No. 16,M01,Tr. 16,Game of Love,Hiromi Yoshii,Female,4:22,122,Gt & Bs,Drum loops
No. 17,M02,Tr. 01,Anata to aete,Hiromi Yoshii,Female,4:01,97,Gt,Drum sequences
No. 18,M02,Tr. 02,True Heart,Tomomi Ogata,Female,4:14,112,Gt,Drum sequences
No. 19,M02,Tr. 03,COOL Motion,Hisayoshi Kazato,Male,4:49,130,Gt,Drum sequences
No. 20,M02,Tr. 04,Tokimeki no syunkan,Eri Ichikawa,Female,4:10,134,,Drum sequences
No. 21,M02,Tr. 05,Feeling In My Heart,Rin,Female,4:28,98,Gt,Drum sequences
No. 22,M02,Tr. 06,Koi ni ochiru jikan ni kansuru kousatsu,Kazuo Nishi,Male,3:29,135,Gt,Drum sequences
No. 23,M02,Tr. 07,SHAKE,MAPS,Vocal group (2 male),3:21,132,Gt,Drum sequences
No. 24,M02,Tr. 08,it's all right,Hisayoshi Kazato,Male,4:00,130,,Drum sequences
No. 25,M02,Tr. 09,tell me,Tomomi Ogata,Female,4:16,103,Gt,Drum sequences
No. 26,M02,Tr. 10,aozora sanpo michi,Tomoko Nitta,Female,3:27,158,Gt & Bs,Drum sequences
No. 27,M02,Tr. 11,stay,Shingo Katsuta,Male,5:18,124,Gt,Drum sequences
No. 28,M02,Tr. 12,Fly away,Tomomi Ogata,Female,4:10,109,Gt,Drum sequences
No. 29,M02,Tr. 13,One Two STEP,Kazuo Nishi,Male,3:35,103,Gt,Drum sequences
No. 30,M02,Tr. 14,syounen no omoi,Mitsuru Tanimoto,Male,3:16,104,,Drum sequences
No. 31,M02,Tr. 15,Moving Round and Round,Yuuichi Nagayama,Male,4:10,129,,Drum loops
No. 32,M02,Tr. 16,what could I do for you,Masaki Kuehara,Male,4:12,125,Gt,Drum sequences
No. 33,M03,Tr. 01,DREAM MAGIC,Hiromi Yoshii,Female,4:47,108,Gt & Bs,Drum sequences
No. 34,M03,Tr. 02,Hitoyo no yume,Hiromi Yoshii,Female,3:27,93,Gt & Bs & Dr,Live drums
No. 35,M03,Tr. 03,Midarana kami no moushigo,Hiromi Yoshii,Female,3:13,170,Gt & Bs & Dr,Live drums
No. 36,M03,Tr. 04,over and over,Kazuo Nishi,Male,5:16,135,Gt & Bs & Dr,Live drums
No. 37,M03,Tr. 05,Replica,Yoshinori Hatae,Male,3:59,184,Gt & Bs & Dr,Live drums
No. 38,M03,Tr. 06,1999,Kousuke Morimoto,Male,4:35,125,Gt & Bs & Dr,Live drums
No. 39,M03,Tr. 07,SPUL,Kousuke Morimoto,Male,4:48,73,Gt & Bs & HH,Drum sequences
No. 40,M03,Tr. 08,promise,Kazuo Nishi,Male,3:46,122,Gt & Bs,Drum sequences
No. 41,M03,Tr. 09,Non Stop Driving,Katsuyuki Ozawa,Male,2:50,200,Gt,Drum sequences
No. 42,M03,Tr. 10,Fly to the moon,Kousuke Morimoto,Male,4:08,125,Gt & Bs,Drum sequences
No. 43,M03,Tr. 11,Centimeter no kodoku,Kazuo Nishi,Male,3:24,163,Gt,Drum sequences
No. 44,M03,Tr. 12,REAL na 5 hun,Kousuke Morimoto,Male,4:06,124,Gt & Bs,Drum sequences
No. 45,M03,Tr. 13,Hajimari,Kousuke Morimoto,Male,3:42,77,Gt & Bs & Dr,Live drums
No. 46,M03,Tr. 14,Senro wa tsuzukuyo,Kousuke Morimoto,Male,3:19,168,Gt,Drum sequences
No. 47,M03,Tr. 15,Deaetakara,Satoshi Kumasaka,Male,3:30,94,Gt × 2 & Bs & Dr & Pf,Live drums
No. 48,M03,Tr. 16,Syodoubutsu,Hiroshi Sekiya,Male,4:29,86,Gt,Drum sequences
No. 49,M04,Tr. 01,Sekai no mikata,Hiroshi Sekiya,Male,4:35,100,Gt,Drum sequences
No. 50,M04,Tr. 02,Mrs. Maril,Rin,Female,3:15,114,Gt & Bs,Drum sequences
No. 51,M04,Tr. 03,Modoranai natsu,Hiroshi Sekiya,Male,6:07,104,Gt × 2 & Bs & Dr & Pf,Live drums
No. 52,M04,Tr. 04,Haru ga kurukara,Tomomi Ogata,Female,3:45,140,Gt,Drum sequences
No. 53,M04,Tr. 05,Ashita wa,Rin,Female,3:39,132,Gt & Bs,Drum sequences
No. 54,M04,Tr. 06,Harukana omoi,Rin,Female,3:42,125,Gt & Bs,Drum sequences
No. 55,M04,Tr. 07,First Love,Akiko Kaburagi,Female,4:09,74,Gt × 2 & Bs & Dr,Live drums
No. 56,M04,Tr. 08,I've got a mail,Masashi Hashimoto,Male,5:22,74,Gt & Bs,Drum loops
No. 57,M04,Tr. 09,Stay with me,Masashi Hashimoto,Male,4:27,70,,Drum sequences
No. 58,M04,Tr. 10,Silver shoes,Rin,Female,3:45,118,,Drum loops
No. 59,M04,Tr. 11,Tenshi no utatane,Rin,Female,3:25,98,Gt & Tp,Drum loops
No. 60,M04,Tr. 12,Kumorizora,Yuzu Iijima,Female,4:03,148,Gt × 2 & Bs,Drum loops
No. 61,M04,Tr. 13,FOR YOU,Kazuo Nishi,Male,4:43,121,Gt,Drum sequences
No. 62,M04,Tr. 14,Be with me Now,Rin,Female,3:11,81,Gt,Drum sequences
No. 63,M04,Tr. 15,Power of mind,Reiko Sato,Female,4:11,126,Gt & Bs & Dr,Live drums
No. 64,M04,Tr. 16,So Long,Kousuke Morimoto,Male,4:52,100,Gt & Bs,Drum sequences
No. 65,M05,Tr. 01,Tanabata,Makiko Hattori,Female,3:52,76,Gt & Bs & Dr,Live drums
No. 66,M05,Tr. 02,Mousugu natsu ga kuru,M & Y,Vocal group (2 female),5:20,76,Gt & HH & Pf,Drum sequences
No. 67,M05,Tr. 03,Tokei no hayasa wa,Makiko Hattori,Female,4:10,88,Gt & Bs & Dr,Live drums
No. 68,M05,Tr. 04,Nichiyoubi,Makiko Hattori,Female,4:54,92,Gt & Bs & Dr,Live drums
No. 69,M05,Tr. 05,Gin no sora,Hiromi Yoshii,Female,6:00,62,Gt,Drum sequences
No. 70,M05,Tr. 06,Miageta sora wa,Tamako Matsuzaka,Female,4:06,104,Gt & Bs & Dr & Pf,Live drums
No. 71,M05,Tr. 07,Tsuki no youni,Hiromi Yoshii,Female,4:46,70,Gt & Pf,Without drums
No. 72,M05,Tr. 08,Heart to Hurt,Kousuke Morimoto,Male,3:21,76,Pf & Vc,Without drums
No. 73,M05,Tr. 09,Miss Maria,Kazuo Nishi,Male,3:16,144,Pf & Vc,Without drums
No. 74,M05,Tr. 10,Kimi no iro,Kousuke Morimoto,Male,3:14,94,Gt,Without drums
No. 75,M05,Tr. 11,Toui machi e,Hiromi Yoshii,Female,3:21,108,Pf,Without drums
No. 76,M05,Tr. 12,Chikai,Kousuke Morimoto,Male,3:50,70,Gt,Without drums
No. 77,M05,Tr. 13,Aishiteru,Makiko Hattori,Female,3:56,120,Gt & Pf,Without drums
No. 78,M05,Tr. 14,Kumo,Masaki Kuehara,Male,4:21,75,Gt,Without drums
No. 79,M05,Tr. 15,Together,Tomomi Ogata,Female,4:28,92,,Without drums
No. 80,M05,Tr. 16,Sagashimono,Tomomi Ogata,Female,3:39,80,,Without drums
No. 81,M06,Tr. 01,How Deep Is Your Love?,Donna Burke,Female [English],3:50,90,Gt,Drum sequences
No. 82,M06,Tr. 02,Once in a life time,Shinya Iguchi,Male [English],5:37,88,Gt & Dr,Live drums
No. 83,M06,Tr. 03,Doing That Thing,Jeff Manning,Male [English],3:37,140,Gt,Drum sequences
No. 84,M06,Tr. 04,Someday,Shinya Iguchi,Male [English],4:40,138,Gt & Dr,Live drums
No. 85,M06,Tr. 05,Waiting for the moment,Jeff Manning,Male [English],3:30,98,Gt,Drum sequences
No. 86,M06,Tr. 06,Angel Baby,Betty,Female [English],4:17,80,Gt,Drum sequences
No. 87,M06,Tr. 07,I think of you,Jeff Manning,Male [English],4:51,90,Gt,Drum sequences
No. 88,M06,Tr. 08,Woman Like You,Shinya Iguchi,Male [English],4:09,120,Gt & Dr,Live drums
No. 89,M06,Tr. 09,Life Is What You Make It To Be,Donna Burke,Female [English],3:43,134,Gt,Drum sequences
No. 90,M06,Tr. 10,Don't Say Good bye,Shinya Iguchi,Male [English],4:37,127,Gt & Dr,Live drums
No. 91,M07,Tr. 01,Change Of Heart,Donna Burke,Female [English],3:43,124,Gt,Drum sequences
No. 92,M07,Tr. 02,I'll be there for you,Betty,Female [English],3:40,134,,Drum sequences
No. 93,M07,Tr. 03,Sweet Dreams,Donna Burke,Female [English],4:18,90,Gt,Drum sequences
No. 94,M07,Tr. 04,Life,Betty,Female [English],3:43,78,Gt,Drum sequences
No. 95,M07,Tr. 05,Feel,Jeff Manning,Male [English],3:52,161,Gt & Bs & Dr,Live drums
No. 96,M07,Tr. 06,Weekend,Betty,Female [English],4:40,130,,Drum loops
No. 97,M07,Tr. 07,Don't Lie To Me,Donna Burke,Female [English],4:03,91,Gt,Drum sequences
No. 98,M07,Tr. 08,31 BLUES,Jeff Manning,Male [English],3:31,107,Gt & Bs & Dr,Live drums
No. 99,M07,Tr. 09,Once and For All,Shinya Iguchi,Male [English],5:17,73,Gt,Without drums
No. 100,M07,Tr. 10,No Regrets,Shinya Iguchi,Male [English],4:53,80,Gt,Drum loops
132 changes: 132 additions & 0 deletions parsers/midi_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#!/usr/bin/env python
"""
Translates any folder of MIDI files to a set of JAMS files.

To parse the MIDI files, you just need to provide the path to the folder
containing the files.

Example:
./midi_parser.py ~/midi_files -o ~/midi_jams/

NOTE: pitch bend information is ignored, so notes with pitch bends will be
converted to notes with a fixed pitch value.

"""

__author__ = "J. Salamon"
__copyright__ = "Copyright 2016, Music and Audio Research Lab (MARL)"
__license__ = "GPL"
__version__ = "1.0"
__email__ = "[email protected]"

import argparse
import logging
import os
import time
import midi
import pretty_midi
import pandas as pd

import jams


def fill_file_metadata(jam, midi_file, duration):
"""Fills the global metada into the JAMS jam."""
jam.file_metadata.title = os.path.basename(midi_file)[:-4]
jam.file_metadata.duration = duration


def fill_annotation_metadata(annot):
"""Fills the annotation metadata."""
annot.annotation_metadata.corpus = ""
annot.annotation_metadata.version = ""
annot.annotation_metadata.annotation_tools = ""
annot.annotation_metadata.annotation_rules = ""
annot.annotation_metadata.validation = ""
annot.annotation_metadata.data_source = ""
annot.annotation_metadata.curator = jams.Curator(name="",
email="")
annot.annotation_metadata.annotator = {}


def create_jams(midi_file, out_file):
"""
Creates a JAMS file from a MIDI file
"""

# Create jam
jam = jams.JAMS()

# Create annotation
midi_ann = jams.Annotation('pitch_midi')

# Load midi file
pm = pretty_midi.PrettyMIDI(midi_file)

notes = []

for inst in pm.instruments:
for note in inst.notes:
midi_ann.append(time=note.start, duration=(note.end-note.start),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should all tracks be combined like this? Is it possible to keep each instrument separately within a jam file? Or at least output one jam file per midi track.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

midi files are generally messy, it's non-trivial to group tracks into instruments (as @craffel can attest), and the mapping between tracks<--> instruments is not 1-1. So this is the simplest solution, which I'd keep as the default behavior. That said, I don't see why we couldn't provide an optional parameter that would allow you to ask for each instrument to go in a separate annotation (where instruments are defined using the grouping used in pretty_midi), and if you really think it'd be useful we could consider creating an annotation per-track too (messier).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it's trivial to separate MIDI notes by track+program number (this is what pretty_midi, and basically any MIDI parser does) but there is not a 1-1 mapping between program number and instruments in a given song.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, even though there's no standardized way of how to use the tracks in MIDI and for what instruments, etc., it still seems like useful information is lost when everything is merged, no?

provide an optional parameter that would allow you to ask for each instrument to go in a separate annotation (where instruments are defined using the grouping used in pretty_midi)

This. 👍

value=note.pitch, confidence=1.)

# Fill annotation metadata
fill_annotation_metadata(midi_ann)

# Add annotation to jam
jam.annotations.append(midi_ann)

# Fill file metadata
duration = pm.get_end_time()
fill_file_metadata(jam, midi_file, duration)

# Save JAMS
jam.save(out_file)


def process_folder(midi_dir, out_dir):
"""Converts the original SMF annotations into the JAMS format (keeping only
the notes of the melody track), and saves them in the out_dir folder."""

# Collect all MIDI annotations.
midi_files = jams.util.find_with_extension(midi_dir, '.mid', depth=1)
midi_files.extend(jams.util.find_with_extension(midi_dir, '.MID', depth=1))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of two lines, shouldn't this really be a case insensitive search (e.g. song.MiD is actually a valid extension on some OS:es)? Also .midi is a very common extension (even Windows doesn't rely on FAT anymore).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be more elegant, yes, it was just the simplest way to use find_with_extension without modification. In the short-term iterating over a list of accepted file extensions (mid, MID, midi, MIDI) would do the trick, though perhaps building case insensitivity into find_with_extension would be a nice thing to have @bmcfee ?

print(len(midi_files))

for mf in midi_files:

jams_file = (
os.path.join(out_dir, os.path.basename(mf)[:-3] + "jams"))
jams.util.smkdirs(os.path.split(jams_file)[0])
# Create a JAMS file for this track
print(mf)
create_jams(mf, jams_file)


def main():
"""Main function to convert the dataset into JAMS."""
parser = argparse.ArgumentParser(
description="Converts a dataset of MIDI files to the JAMS format",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("midi_dir",
action="store",
help="Folder of MIDI files")
parser.add_argument("-o",
action="store",
dest="out_dir",
default="midi_jams",
help="Output JAMS folder")
args = parser.parse_args()
start_time = time.time()

# Setup the logger
logging.basicConfig(format='%(asctime)s: %(message)s', level=logging.INFO)

# Run the parser
process_folder(args.midi_dir, args.out_dir)

# Done!
logging.info("Done! Took %.2f seconds.", time.time() - start_time)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have a logger if it's only used for profiling elapsed time? Seems better to just remove it entirely and let external profilers measure main() if needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logging is intended for end users who are not necessarily python coders and just need to use the script to convert a dataset. It's the same in all converters pretty much.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consistency, fair point! 👍


if __name__ == '__main__':
main()
Loading