-
Notifications
You must be signed in to change notification settings - Fork 0
/
README
314 lines (223 loc) · 8.36 KB
/
README
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
===============================================================================
Python Music Generator
===============================================================================
Simple library to generate midi patterns from numbers.
This library can be used to build generative music tools.
Download from http://code.google.com/p/python-music-gen/
Midi examples
http://www.black-aura.com/resources/python-music-gen/arptest.mid
http://www.black-aura.com/resources/python-music-gen/bassline.mid
http://www.black-aura.com/resources/python-music-gen/chords.mid
http://www.black-aura.com/resources/python-music-gen/chords2.mid
MP3 examples (imported MIDI in Ableton Live and added instruments)
http://www.black-aura.com/resources/python-music-gen/arps.mp3
Code Examples
View the examples under /music to start creating your own music!
Documentation
Creating a MIDI file
===============================================================================
from midiutil.MidiGenerator import MidiGenerator
midiGenerator = MidiGenerator(tempo=105)
midiGenerator.write()
This code will write an empty midi file.
The midi file name will be the python_file_name.mid.
A simple loop
===============================================================================
The following code will generate a loop with notes 60,62 and 64 playing in
sequence. The length and distance between notes will be 1/2 a beat. The
velocities will loop as follows: 100, 90, 100, 90, etc.
from midiutil.MidiGenerator import MidiGenerator
from midiutil.TrackGen import LoopingArray
midiGenerator = MidiGenerator(tempo=105)
# Create a looping array of notes 60, 62 and 64 (C, D, E)
notes = LoopingArray([[60],[62],[64]])
# Create a looping array of beats (note duration, note length)
beats = LoopingArray([(0.5,0.5)])
# Create a looping array of velocities
velocities = LoopingArray([100,90])
midiGenerator.add_track(0, 0,
beat=beats,
notes=notes,
velocities=velocities,
length=16)
midiGenerator.write()
A slightly more complex loop
===============================================================================
The following loop will play multiple notes with a varying beat.
from midiutil.MidiGenerator import MidiGenerator
from midiutil.TrackGen import LoopingArray
midiGenerator = MidiGenerator(tempo=105)
# Create a looping array of chord C, note C, and notes 64+67
notes = LoopingArray([[60,64,67],[60],[64,67]])
# Create a looping array of beats (note duration, note length)
beats = LoopingArray([(0.5,0.5), (0.25,0.125)])
# Create a looping array of velocities
velocities = LoopingArray([100,90])
midiGenerator.add_track(0, 0,
beat=beats,
notes=notes,
velocities=velocities,
length=16)
midiGenerator.write()
Introducing functioniterator
===============================================================================
The LoopingArray class can take as a parameter a number of generator classes
which modify the way notes are read from the array. For example the following
code will read notes from the array by skipping a value.
from midiutil.MidiGenerator import MidiGenerator
from midiutil.TrackGen import LoopingArray, StaticIterator
midiGenerator = MidiGenerator(tempo=105)
notes = LoopingArray(
[[x] for x in range(60,80)],
functioniterator=[('add',StaticIterator(value=2))]
)
beats = LoopingArray([(0.5,0.5)])
velocities = LoopingArray([100,90])
midiGenerator.add_track(0, 0,
beat=beats,
notes=notes,
velocities=velocities,
length=16)
midiGenerator.write()
functioniterator is a list of tuples in the form (function, generator)
function can be: add, dec, mult, div
For example:
notes = LoopingArray(
[[x] for x in range(60,80)],
functioniterator=[
('add',StaticIterator(value=2)),
('dec',StaticIterator(value=1)),
]
)
Will first add 2 to the index and reduce it by 1. Note that when using
StaticIterator, this does not make alot of sense. However when using complex
generators such as LoopingArray, then very complex patterns can be achieved.
Complex functioniterator
===============================================================================
As already mentioned, one can add a LoopingArray as a functioniterator.
In the following example, the note array index is first incremented by 1,
then by 2, 1 again, etc...
from midiutil.MidiGenerator import MidiGenerator
from midiutil.TrackGen import LoopingArray, StaticIterator
midiGenerator = MidiGenerator(tempo=105)
notes = LoopingArray(
[[x] for x in range(60,80)],
functioniterator=[('add',LoopingArray([1,2]))]
)
beats = LoopingArray([(0.5,0.5)])
velocities = LoopingArray([100,90])
midiGenerator.add_track(0, 0,
beat=beats,
notes=notes,
velocities=velocities,
length=16)
midiGenerator.write()
One can build complex patterns such as:
import sys
sys.path.append("../")
from midiutil.TrackGen import LoopingArray
if __name__ == '__main__':
arr = LoopingArray(
[x for x in range(128)],
functioniterator=[
('add', LoopingArray([1, 2, 3], functioniterator=[
('add', LoopingArray([1, 2, 3], functioniterator=[
('add', LoopingArray([1,2,3], id='array4', debug=True))
],
id='array3', debug=True)
)
],
id='array2', debug=True)
)
],
id='array1', debug=True
)
for _ in range(20):
arr.next()
LoopingIndexedArray
===============================================================================
A LoopingIndexedArray returns items from an array.
values = [value1, value2, value3, value4, value5]
indexes = [index1, index2, index3, index4, index5]
^
loopindex
returns values[indexes[loopindex]]
on next(), the loopindex is moved. By default the value is incremented by 1,
however this can be modified by adding values to the list functioniterator
(see below).
Example:
x = LoopingIndexedArray([1,2,3,4,5],[0,1,0,2,0,3])
x.next()
> 1
x.next()
> 2
x.next()
> 1
x.next()
3
x.next()
> 1
LoopingIncrementalIndexedArray
===============================================================================
A LoopingIncrementalIndexedArray returns items from an array.
values = [value1, value2, value3, value4, value5]
indexes = [index1, index2, index3, index4, index5]
^
loopindex
noteindex=noteindex+indexes[loopindex]
returns values[noteindex]
on next(), the loopindex is moved. By default the value is incremented by 1,
however this can be modified by adding values to the list functioniterator
(see below).
Example:
x = LoopingIncrementalIndexedArray([1,2,3,4,5],[0,1,-1,2,0,3])
x.next()
> 1
x.next()
> 1
x.next()
> 2
x.next()
> 1
x.next()
> 3
x.next()
> 3
x.next()
> 1
Note: negative values will move the loopindex to the right
Arpeggiator
===============================================================================
So far we have seen adding note loops as tracks. You can also add
arpeggios by using the add_arpeggio method.
from midiutil.MidiGenerator import MidiGenerator
from midiutil.Scales import MINOR, buildScale
from midiutil.TrackGen import LoopingIncrementalIndexedArray, LoopingArray
midiGenerator = MidiGenerator(tempo=105)
sc = MINOR
mscale = buildScale(sc, 48, 80)
notes = LoopingArray([
[mscale[x] for x in [0, 2, 4, 6]], # chord 1
[mscale[x] for x in [3, 5, 7, 9]], # chord 2
[mscale[x] for x in [5, 7, 11]] # chord 3
], functioniterator=[('add', LoopingArray([1, 1, 2]))])
chord_beats = LoopingArray([(4, 4), (2, 2)])
notes_beats = LoopingArray([(0.25, 0.25)])
velocities = LoopingArray([120, 120])
note_skip = LoopingArray(
[0, 1, 2, 3, 1],
functioniterator=[('add', LoopingArray([1, 2]))]
)
midiGenerator.add_arpeggio(0, 0,
chords_beat=chord_beats,
notes_beat=notes_beats,
chords=notes,
velocities=velocities,
note_skip=note_skip,
length=32)
midiGenerator.write()
In this example, the chords inside the LoopingArray notes, are played note
by note. The length of the chorded arpeggio is determined by chords_beat. The
duration of the notes inside the arpeggio is determined by notes_beat. So in
this example, the arpeggio chords are held for 4 beat and then 2 beats. The
notes inside the arpeggio are 1/4 in length.