-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathchoro2harte.py
More file actions
148 lines (123 loc) · 4.73 KB
/
choro2harte.py
File metadata and controls
148 lines (123 loc) · 4.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import numpy as np
import pandas as pd
import re
def parse_extensions(extensions):
ext = ",".join([
e
.replace("omit", "*")
.strip("(").strip(")")
for e in re.findall(r'\(.*?\)', extensions)
])
return f"({ext})"
def choro2harte(chord, type="root"):
"""Transforms chord symbols in Choro Songbook Corpus format to
Harte et al's chord syntax. See Harte, C. A., Sandler, M.,
Abdallah, S., & Gómez, E. (2005). Symbolic representation of
musical chords: A proposed syntax for text annotations.
Proceedings of the 4th International Conference on Music Information
Retrieval (ISMIR), 56, 66--71.
Parameters
----------
chord : str
Chord symbol as encoded in the _Choro Songbook Corpus_.
Returns
-------
str
Chord symbol conforming to syntax in Harte et al. (2005).
"""
assert type in ["root", "rn"]
harte = ""
if chord.chord == "NC":
harte = "N"
else:
# ROOT
harte += chord.root if type == "root" else chord.sd
# TYPE
if chord.type == "m":
if chord.added == "7":
harte += ":min7"
elif chord.added == "6":
harte += ":min6"
else:
harte += ":min"
elif chord.type == "o":
harte += ":dim"
elif chord.type is np.nan:
if chord.added == "7":
harte += ":7"
elif chord.added == "7M":
harte += ":maj7"
elif chord.added == "6":
harte += ":maj6"
else:
harte += ":maj"
# EXTENSIONS
if chord.extensions is not np.nan:
harte += parse_extensions(chord.extensions)
# SPECIFIC SHORTHANDS
harte = harte \
.replace("min7(b5)", "hdim7") \
.replace("maj(#5)", "aug") \
.replace("maj7(9)", "maj9") \
.replace(":7(9)", ":9") \
.replace("min(7M)", "minmaj7") \
.replace("add9", "9") \
.replace("min7(9)", "min9") \
.replace("(9,7M)", "(7,9)") \
.replace("dim(7M)", "dim(7)") \
.replace("min6(7M)", "min6(7)")
# BASS
if chord.bass_note is not np.nan:
bass_degree = chord.rn_chord.split("/")[1]
degree, accidental = re.match(r"(\d*)([#b]*)",
bass_degree).groups()
# COVER SOME CASES
if chord.type == "m" and degree == "3" and accidental == "":
degree = "b3"
elif chord.type is np.nan and degree == "3" and accidental == "#":
accidental = ""
degree = "3"
elif chord.type == "m" and degree == "7" and accidental == "":
accidental = "b"
elif chord.type is np.nan and degree == "7" and accidental == "":
accidental = "b"
elif chord.type is np.nan and degree == "5" and accidental == "#":
accidental = ""
elif chord.type == "m" and degree == "5" and accidental == "#":
accidental = ""
harte += "/" + accidental + degree
return harte
def test():
# read data
df = pd.read_csv("data/choro.tsv", sep="\t", index_col=0)
# create new column
df["harte"] = df.apply(lambda x: choro2harte(x, type="root"), axis=1)
df["rn_harte"] = df.apply(lambda x: choro2harte(x, type="rn"), axis=1)
# sort columns
# df = df[[
# 'global_key', 'local_key', 'global_meter', 'local_meter',
# 'local_mode', 'global_mode', 'path', 'phrase', 'part', 'bar_no',
# 'duration', 'chord', 'harte', 'root', 'rn_chord', 'rn_harte', 'sd',
# 'type', 'added', 'extensions', 'bass_note', 'songbook', 'title',
# 'composer', 'sub_genre', 'year', 'filename'
# ]]
# filter only with bass notes
df = df[df["bass_note"].notna()]
print(df[['chord', 'harte', 'root', 'rn_chord',
'rn_harte', 'sd', 'bass_note']].sample(15))
if __name__ == "__main__":
# read data
df = pd.read_csv("data/choro.tsv", sep="\t", index_col=0)
# create new column
df["harte"] = df.apply(lambda x: choro2harte(x, type="root"), axis=1)
df["rn_harte"] = df.apply(lambda x: choro2harte(x, type="rn"), axis=1)
# sort columns
df = df[[
'global_key', 'local_key', 'global_meter', 'local_meter',
'local_mode', 'global_mode', 'path', 'phrase', 'part', 'bar_no',
'duration', 'chord', 'harte', 'root', 'rn_chord', 'rn_harte', 'sd',
'type', 'added', 'extensions', 'bass_note', 'songbook', 'title',
'composer', 'sub_genre', 'year', 'filename'
]]
# export to file
df.to_csv("data/choro.tsv", sep="\t", index=False)