/
instruments.py
206 lines (166 loc) · 6.27 KB
/
instruments.py
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
import os
import subprocess
import abjad as abj
from abjad import scoretools as st
from abjad import topleveltools as tlt
from abjad.tools import pitchtools as pt
from abjad.tools import schemetools as scht
from abjad.tools.topleveltools import set_
from abjad.tools import lilypondfiletools as lyft
from random import choice
from copy import deepcopy
from contextlib import contextmanager
def lookup_by_name(comp_val, coll):
for x in coll:
if x['name'] == comp_val:
return x
return None
def range_tuple(start_str, stop_str):
return tuple([n.written_pitch.pitch_number
for n in st.make_notes([start_str, stop_str], (1, 4))])
def get_instrument_dicts(*instrument_names):
inst_list = [
{
'name': 'Clarinet',
'range': range_tuple("e", "c'''"),
'voice': st.Voice(),
'transpose': pt.Transposition(2),
'clef': 'treble'
},
{
'name': 'Viola',
'range': range_tuple("c", "c'''"),
'voice': st.Voice(),
'transpose': None,
'clef': 'alto'
},
{
'name': 'Guitar',
'range': range_tuple("e,", "e''"),
'voice': st.Voice(),
'transpose': None, # pt.Transposition(12),
'clef': 'treble_8'
},
{
'name': 'Bass',
'range': range_tuple("e,,", "g'"),
'voice': st.Voice(),
'transpose': None,
'clef': 'bass'
}
]
return [deepcopy(inst)
for inst in [lookup_by_name(name, inst_list)
for name in instrument_names]
if inst is not None]
@contextmanager
def transposition(inst, n):
if inst['transpose'] is not None:
n.written_pitch = inst['transpose'](n.written_pitch)
yield n
@contextmanager
def inst_range(inst, n):
lo, hi = inst['range']
if n.written_pitch.pitch_number in range(lo, hi):
yield n
else:
yield abj.Rest(n.written_duration)
def add_note_to_inst(inst, n):
with transposition(inst, n) as n:
with inst_range(inst, n) as n_or_r:
inst['voice'].append(n_or_r)
def all_rests(tup):
for n in list(tup):
if type(n) != abj.Rest:
return False
return True
def add_tup_to_inst(inst, tup):
new_tup = abj.Tuplet(tup.multiplier, [])
for note in list(tup): # for some reason tups don't iterate well??
with transposition(inst, note) as note:
with inst_range(inst, note) as note:
new_tup.append(note)
if all_rests(new_tup):
inst['voice'].append(abj.Rest(new_tup.multiplied_duration))
else:
inst['voice'].append(new_tup)
def add_note_or_tup_to_inst(inst, n_or_t):
if type(n_or_t) == abj.Note:
add_note_to_inst(inst, n_or_t)
else:
add_tup_to_inst(inst, n_or_t)
def pack_instruments(notes, instrument_dicts):
insts = deepcopy(instrument_dicts)
for note in deepcopy(notes):
for inst in insts:
n = deepcopy(note)
add_note_or_tup_to_inst(inst, n)
return insts
def prep_instruments(instrument_dicts):
insts = deepcopy(instrument_dicts)
for inst in insts:
abj.attach(abj.Clef(inst['clef']), inst['voice'])
inst['voice'].remove_commands.append('Note_heads_engraver')
inst['voice'].consists_commands.append('Completion_heads_engraver')
inst['voice'].remove_commands.append('Rest_engraver')
inst['voice'].consists_commands.append('Completion_rest_engraver')
set_(inst['voice']).beam_exceptions = scht.SchemeVector()
set_(inst['voice']).base_moment = scht.SchemeMoment(1, 4)
set_(inst['voice']).beat_structure = scht.SchemeVector(1, 1)
set_(inst['voice']).completion_unit = scht.SchemeMoment(1, 4)
return insts
def merge_rests(time_signature, staff):
for shard in abj.mutate(staff[:]).split([time_signature], cyclic=True):
abj.mutate(shard).rewrite_meter(time_signature)
def apply_techniques(instrument_dict):
pass
def make_main_staff(take_amt, ts_tuple, rewrite_tuple, instrument_dict):
tmp = st.Staff([instrument_dict['voice']])
merge_rests(abj.TimeSignature(rewrite_tuple), tmp)
staff = abj.Staff()
for x in tmp[:take_amt]:
staff.append(deepcopy(x))
print(instrument_dict['name'])
print(len(staff))
abj.attach(abj.TimeSignature(ts_tuple), staff)
abj.attach(abj.Clef(instrument_dict['clef']), staff)
return staff
def make_drone_staff(anchor_tones, instrument_dict):
staff = abj.Staff()
for tone in anchor_tones:
m = abj.Measure((1, 1), [abj.Note(tone % 12, abj.Duration(1, 1))])
tlt.override(staff).time_signature.stencil = False
staff.append(m)
staff.append(m)
return staff
def make_page(direc, main_staff, drone_staff, inst):
mfn = inst['name'] + '_main.ly'
dfn = inst['name'] + '_drone.ly'
main_group = st.StaffGroup([main_staff])
drone_group = st.StaffGroup([drone_staff])
for group in [main_group, drone_group]:
tlt.override(group).system_start_bracket.collapse_height = 2000
score1 = st.Score([main_group])
score2 = st.Score([drone_group])
for score in [score1, score2]:
tlt.override(score).staff_grouper.staffgroup_staff_spacing = \
scht.SchemeAssociativeList(('basic-distance', 30), ('padding', 1))
tlt.override(score).bar_line.allow_span_bar = False
tlt.override(score).system_start_bar.collapse_height = 2000
mf = lyft.make_basic_lilypond_file(score1)
df = lyft.make_basic_lilypond_file(score2)
for fn, lf in zip([mfn, dfn], [mf, df]):
lf.header_block.composer = "Danny Clarke"
lf.header_block.instrument = scht.Scheme(inst['name'], quoting="'")
with open(direc + '/' + fn, 'w+') as f:
f.write(format(lf))
return mfn, dfn
def gen_ly(direc, take_amt, ts_tuple, rewrite_tuple, anchor_tones, inst):
if not os.path.isdir(direc):
os.makedirs(direc)
main_staff = make_main_staff(take_amt, ts_tuple, rewrite_tuple, inst)
drone_staff = make_drone_staff(anchor_tones, inst)
mfn, dfn = make_page(direc, main_staff, drone_staff, inst)
os.chdir(direc)
subprocess.call(['lilypond', mfn, dfn])
print('done with', inst['name'], mfn, dfn)