Sunday, March 13, 2016

20. Midi numbers and frequencies

Similar to mus11.py, the frequencies will be found for midi numbers between 0 and 127.


mus11.py used music21 to find the frequencies. It is more efficient to use mathematical formulas, rather than creating objects of various classes and then using their methods.


For every 12 midi numbers, the frequency increases by a factor of 2. Thus, for each midi number, the frequency increases by 12th power of 2, or 2**(1/12), with ** being the Python exponential operation. The frequency between two nearest midi numbers will be in variable g.


Further, the midi of 69 is 440 Hz, in music21.


The above can be used to create a lambda function.


# mus20.py
# Midi numbers and frequencies

g = 2**(1/12)

f = lambda midi: 440*g**(midi-69)

for midi in range(128):
    freq = f(midi)
    print('midi = {}, freq = {:.1f} Hz'.format(midi,freq))

This will generate this printout:


midi = 0, freq = 8.2 Hz
midi = 1, freq = 8.7 Hz
midi = 2, freq = 9.2 Hz
midi = 3, freq = 9.7 Hz
midi = 4, freq = 10.3 Hz
midi = 5, freq = 10.9 Hz
midi = 6, freq = 11.6 Hz
midi = 7, freq = 12.2 Hz
midi = 8, freq = 13.0 Hz
midi = 9, freq = 13.7 Hz
midi = 10, freq = 14.6 Hz
midi = 11, freq = 15.4 Hz
midi = 12, freq = 16.4 Hz
midi = 13, freq = 17.3 Hz
midi = 14, freq = 18.4 Hz
midi = 15, freq = 19.4 Hz
midi = 16, freq = 20.6 Hz
midi = 17, freq = 21.8 Hz
midi = 18, freq = 23.1 Hz
midi = 19, freq = 24.5 Hz
midi = 20, freq = 26.0 Hz
midi = 21, freq = 27.5 Hz
midi = 22, freq = 29.1 Hz
midi = 23, freq = 30.9 Hz
midi = 24, freq = 32.7 Hz
midi = 25, freq = 34.6 Hz
midi = 26, freq = 36.7 Hz
midi = 27, freq = 38.9 Hz
midi = 28, freq = 41.2 Hz
midi = 29, freq = 43.7 Hz
midi = 30, freq = 46.2 Hz
midi = 31, freq = 49.0 Hz
midi = 32, freq = 51.9 Hz
midi = 33, freq = 55.0 Hz
midi = 34, freq = 58.3 Hz
midi = 35, freq = 61.7 Hz
midi = 36, freq = 65.4 Hz
midi = 37, freq = 69.3 Hz
midi = 38, freq = 73.4 Hz
midi = 39, freq = 77.8 Hz
midi = 40, freq = 82.4 Hz
midi = 41, freq = 87.3 Hz
midi = 42, freq = 92.5 Hz
midi = 43, freq = 98.0 Hz
midi = 44, freq = 103.8 Hz
midi = 45, freq = 110.0 Hz
midi = 46, freq = 116.5 Hz
midi = 47, freq = 123.5 Hz
midi = 48, freq = 130.8 Hz
midi = 49, freq = 138.6 Hz
midi = 50, freq = 146.8 Hz
midi = 51, freq = 155.6 Hz
midi = 52, freq = 164.8 Hz
midi = 53, freq = 174.6 Hz
midi = 54, freq = 185.0 Hz
midi = 55, freq = 196.0 Hz
midi = 56, freq = 207.7 Hz
midi = 57, freq = 220.0 Hz
midi = 58, freq = 233.1 Hz
midi = 59, freq = 246.9 Hz
midi = 60, freq = 261.6 Hz
midi = 61, freq = 277.2 Hz
midi = 62, freq = 293.7 Hz
midi = 63, freq = 311.1 Hz
midi = 64, freq = 329.6 Hz
midi = 65, freq = 349.2 Hz
midi = 66, freq = 370.0 Hz
midi = 67, freq = 392.0 Hz
midi = 68, freq = 415.3 Hz
midi = 69, freq = 440.0 Hz
midi = 70, freq = 466.2 Hz
midi = 71, freq = 493.9 Hz
midi = 72, freq = 523.3 Hz
midi = 73, freq = 554.4 Hz
midi = 74, freq = 587.3 Hz
midi = 75, freq = 622.3 Hz
midi = 76, freq = 659.3 Hz
midi = 77, freq = 698.5 Hz
midi = 78, freq = 740.0 Hz
midi = 79, freq = 784.0 Hz
midi = 80, freq = 830.6 Hz
midi = 81, freq = 880.0 Hz
midi = 82, freq = 932.3 Hz
midi = 83, freq = 987.8 Hz
midi = 84, freq = 1046.5 Hz
midi = 85, freq = 1108.7 Hz
midi = 86, freq = 1174.7 Hz
midi = 87, freq = 1244.5 Hz
midi = 88, freq = 1318.5 Hz
midi = 89, freq = 1396.9 Hz
midi = 90, freq = 1480.0 Hz
midi = 91, freq = 1568.0 Hz
midi = 92, freq = 1661.2 Hz
midi = 93, freq = 1760.0 Hz
midi = 94, freq = 1864.7 Hz
midi = 95, freq = 1975.5 Hz
midi = 96, freq = 2093.0 Hz
midi = 97, freq = 2217.5 Hz
midi = 98, freq = 2349.3 Hz
midi = 99, freq = 2489.0 Hz
midi = 100, freq = 2637.0 Hz
midi = 101, freq = 2793.8 Hz
midi = 102, freq = 2960.0 Hz
midi = 103, freq = 3136.0 Hz
midi = 104, freq = 3322.4 Hz
midi = 105, freq = 3520.0 Hz
midi = 106, freq = 3729.3 Hz
midi = 107, freq = 3951.1 Hz
midi = 108, freq = 4186.0 Hz
midi = 109, freq = 4434.9 Hz
midi = 110, freq = 4698.6 Hz
midi = 111, freq = 4978.0 Hz
midi = 112, freq = 5274.0 Hz
midi = 113, freq = 5587.7 Hz
midi = 114, freq = 5919.9 Hz
midi = 115, freq = 6271.9 Hz
midi = 116, freq = 6644.9 Hz
midi = 117, freq = 7040.0 Hz
midi = 118, freq = 7458.6 Hz
midi = 119, freq = 7902.1 Hz
midi = 120, freq = 8372.0 Hz
midi = 121, freq = 8869.8 Hz
midi = 122, freq = 9397.3 Hz
midi = 123, freq = 9956.1 Hz
midi = 124, freq = 10548.1 Hz
midi = 125, freq = 11175.3 Hz
midi = 126, freq = 11839.8 Hz
midi = 127, freq = 12543.9 Hz

19. Triads of C major scale

The pitches lists holds the notes in C-major scale (octaves 4 and 5).


In the 7-length chord list, we put the root note as one of the first seven, next 2 above, and last, 4 above.


Then, in the for loop, we go over the chord list. n1, n2, n3 will get the midi values for the notes. By n2 - n1, we find semitones from 1st to 2nd note. By n3 - n1, we find semitone interval from 1st to 3rd note.


Using if and elif, we find the name of interval of n2 - n1 and n3 - n1.


The chords, with major 3 interval, for n2 - n1, chord 1 (I, Tonic), chord 4 (IV, Subdominant), chord 5 (V, Dominant).


# mus19.py
# Triads of C major

import music21 as m21
from writeMIDI import writeMIDI

notes = []

pitches = ['C4','D4','E4','F4','G4','A4','B4',
           'C5','D5','E5','F5','G5','A5','B5']

chord = 7*[None]
for i in range(7):
    chord[i] = pitches[i],pitches[i+2],pitches[i+4]

for i,c in enumerate(chord):
    print('\nChord {}: {}'.format(i+1,c))
    n1 = m21.note.Note(c[0]).pitch.midi
    n2 = m21.note.Note(c[1]).pitch.midi
    n3 = m21.note.Note(c[2]).pitch.midi
    print('n2-n1 = ',n2-n1, end = ' ')
    if n2 - n1 == 3: print('\tminor third')
    elif n2 - n1 == 4: print('\tmajor third')
    print('n3-n1 = ',n3-n1, end = '')
    if n3 - n1 == 7: print('\tperfect fifth')
    elif n3 - n1 == 6: print('\tdiminished fifth')
    notes.append((c[0],2*i,1,120))
    notes.append((c[1],2*i,1,120))
    notes.append((c[2],2*i,1,120))
    
writeMIDI('C','piano',120,notes,'mus19')

This is the printout:

Chord 1: ('C4', 'E4', 'G4')
n2-n1 =  4  major third
n3-n1 =  7 perfect fifth

Chord 2: ('D4', 'F4', 'A4')
n2-n1 =  3  minor third
n3-n1 =  7 perfect fifth

Chord 3: ('E4', 'G4', 'B4')
n2-n1 =  3  minor third
n3-n1 =  7 perfect fifth

Chord 4: ('F4', 'A4', 'C5')
n2-n1 =  4  major third
n3-n1 =  7 perfect fifth

Chord 5: ('G4', 'B4', 'D5')
n2-n1 =  4  major third
n3-n1 =  7 perfect fifth

Chord 6: ('A4', 'C5', 'E5')
n2-n1 =  3  minor third
n3-n1 =  7 perfect fifth

Chord 7: ('B4', 'D5', 'F5')
n2-n1 =  3  minor third
n3-n1 =  6 diminished fifth

This will generate this:


Saturday, March 12, 2016

18. Motifs

Here motif1 and motif2 are series of notes, with timing and volume information. The offset time will correspond to first note, which is at time 0. Here they are strings, but they could also be separate text files with minor changes in program.


notes1 and notes2 are lists which will be populated by getNotes().


In addNotes(), we add either notes1 or notes2 to the main list, notes. We have to adjust the offset time. Tuples can not be modified, and thus we create a temporary list, modify it, and then convert it back to a tuple to append to the notes list.


Finally, we call addNotes() 4 times, adding notes1 or notes2 at appropriate times.


It is also possible to randomly changes notes, etc. to add variation.


# mus18.py
# Motifs

from writeMIDI import writeMIDI

motif1 = '''
C#5 0.0 0.375 106
B4 0.5 0.375 67
G#4 1.0 0.375 80
F#4 1.5 0.375 99
E4 2.0 0.375 84
E4 2.5 0.625 91
E4 3.5 0.375 93
E4 4.0 0.375 78
E4 4.5 0.375 74
E4 5.0 0.375 80
E-4 5.5 0.375 80
E-4 6.0 0.375 80
E4 6.5 0.375 70
E4 7.0 0.625 80
'''

motif2 = '''
C#5 0.0 0.375 81
B4 0.5 0.375 97
G#4 1.0 0.375 77
F#4 1.5 0.375 81
E4 2.0 0.375 97
E4 2.5 0.75 84
E4 3.5 0.375 97
E4 4.0 0.375 91
E4 4.5 0.375 84
E4 5.0 0.375 91
C#4 5.5 0.375 84
C#4 6.0 0.375 80
B3 6.5 0.375 87
B3 7.0 0.667 95
'''

notes = []

notes1 = []
notes2 = []

def getNotes(n,s):
    mot = s.split('\n')
    for m in mot:
        if m == '': continue
        t = m.split()
        n.append((t[0],float(t[1]),
                  float(t[2]),int(t[3])))

def addNotes(n,t):
    for note in n:
        tmp = list(note)
        tmp[1] += t
        notes.append(tuple(tmp))
    
getNotes(notes1,motif1)
getNotes(notes2,motif2)

addNotes(notes1,0)
addNotes(notes2,10)
addNotes(notes2,20)
addNotes(notes1,30)
writeMIDI('C','piano',80,notes,'mus18')

This will generate this:


Thursday, March 3, 2016

17. Modes

A Python dictionary is unordered. It is possible to use an OrderedDict from the standard collections module.


For the 7 modes (given in the order), with roots of C through B, we only get white keys. For 'C' root, we have major (Ionian), and for 'A' we have minor (Dorian).


In the printouts, we can see that the scale is shifted left, for the next mode, and a value an octave above is the new value, replacing the rightmost note (a left rotate operation for the semitone intervals).


The MIDI has 7 scales, with each scale taking 2 measures, with a total length of 14 measures or 14 bars.


# mus17.py
# Modes

import music21 as m21
from writeMIDI import writeMIDI
from collections import OrderedDict

SCALE = OrderedDict()
SCALE['Ionian'] = [2,2,1,2,2,2,1] # major
SCALE['Dorian'] = [2,1,2,2,2,1,2]
SCALE['Phrygian'] = [1,2,2,2,1,2,2]
SCALE['Lydian'] = [2,2,2,1,2,2,1]
SCALE['Mixolydian'] = [2,2,1,2,2,1,2]
SCALE['Aeolian'] = [2,1,2,2,1,2,2] # minor
SCALE['Locrian'] = [1,2,2,1,2,2,2]

start = 0
notes = []

def scale(root, n, kind):
    global start
    start += 8
    print('\nroot = {} \tkind = {}'.format(root,kind))
    p = m21.pitch.Pitch(root)
    midi = p.midi
    for i in range(8):
        if i<7: print('{},'.format(midi),end=' ')
        else: print('{}'.format(midi))
        n.append((midi,start+i,1,120))
        midi += SCALE[kind][i%7]
        
keys = 'CDEFGAB'
lett = 0

for kind in SCALE:
    scale(keys[lett],notes,kind)
    lett += 1

writeMIDI('C','piano',130,notes,'mus17')

This is the printout:

root = C  kind = Ionian
60, 62, 64, 65, 67, 69, 71, 72

root = D  kind = Dorian
62, 64, 65, 67, 69, 71, 72, 74

root = E  kind = Phrygian
64, 65, 67, 69, 71, 72, 74, 76

root = F  kind = Lydian
65, 67, 69, 71, 72, 74, 76, 77

root = G  kind = Mixolydian
67, 69, 71, 72, 74, 76, 77, 79

root = A  kind = Aeolian
69, 71, 72, 74, 76, 77, 79, 81

root = B  kind = Locrian
71, 72, 74, 76, 77, 79, 81, 83

This will generate this MIDI:


Wednesday, March 2, 2016

16. MIDI of Major and Minor Scales

The midi of a scale in a random root note is generated. We use the scales of major and different minors, which are stored in the SCALE dictionary.


All notes are quarter notes, no each takes 2 measures or 8 quarter lengths, assuming time signature of 4/4.


The total duration is 8 measures for the 4 scales.


Also we print a new line only if i is 7. The default end, for a print statement, is new line, unless we override it.


# mus16.py
# scales

import music21 as m21
from writeMIDI import writeMIDI
from random import choice

SCALE = {}
SCALE['major'] = [2,2,1,2,2,2,1]
SCALE['natural minor'] = [2,1,2,2,1,2,2]
SCALE['melodic minor'] = [2,1,2,2,2,2,1]
SCALE['harmonic minor'] = [2,1,2,2,1,3,1]

start = 0
notes = []

def scale(root, n, kind):
    global start
    start += 8
    print('\nroot = {} \tkind = {}'.format(root,kind))
    p = m21.pitch.Pitch(root)
    midi = p.midi
    for i in range(8):
        if i<7: print('{},'.format(midi),end=' ')
        else: print('{}'.format(midi))
        n.append((midi,start+i,1,120))
        midi += SCALE[kind][i%7]
        
keys = ['C','C#','D','D#',
        'E','F','F#','G',
        'G#','A','A#','B']

for kind in SCALE:
    scale(choice(keys),notes,kind)

writeMIDI('C','piano',130,notes,'mus16')

This is one possible output:


root = A  kind = harmonic minor
69, 71, 72, 74, 76, 77, 80, 81

root = D#  kind = major
63, 65, 67, 68, 70, 72, 74, 75

root = G  kind = melodic minor
67, 69, 70, 72, 74, 76, 78, 79

root = A  kind = natural minor
69, 71, 72, 74, 76, 77, 79, 81

The output is:

15. Melodic minor scales

The 12 notes within each octave is represented in the Python list called keys, as in the last example.


We list the semitone intervals of a minor scale, inside the minor list. We copy it to melodic_minor list and then change two of the values.


Inside the main loop, iterated over all keys, we use i%7 (i modulo 7) as index into melodic_minor so we only access indexes 0 through 6.


Also we print a new line only if i is 7. The default end, for a print statement, is new line, unless we override it.


# mus15.py
# melodic minor scales

import music21 as m21

minor = [2,1,2,2,1,2,2]
melodic_minor = minor[:]
melodic_minor[-3] += 1
melodic_minor[-1] -= 1
print('melodic minor = ',melodic_minor)

keys = ['C','C#','D','D#',
        'E','F','F#','G',
        'G#','A','A#','B']

print('The 12 melodic minor scales:')
for key in keys:
    n = m21.note.Note(key)
    midi = n.pitch.midi
    for i in range(8):
        n = m21.note.Note(midi = midi)
        if i<7: print(n.name, end= ' - ')
        else: print(n.name)
        midi = n.pitch.midi
        midi += melodic_minor[i%7]

This will generate this output:


melodic minor =  [2, 1, 2, 2, 2, 2, 1]
The 12 melodic minor scales:
C - D - E- - F - G - A - B - C
C# - E- - E - F# - G# - B- - C - C#
D - E - F - G - A - B - C# - D
E- - F - F# - G# - B- - C - D - E-
E - F# - G - A - B - C# - E- - E
F - G - G# - B- - C - D - E - F
F# - G# - A - B - C# - E- - F - F#
G - A - B- - C - D - E - F# - G
G# - B- - B - C# - E- - F - G - G#
A - B - C - D - E - F# - G# - A
B- - C - C# - E- - F - G - A - B-
B - C# - D - E - F# - G# - B- - B

Sunday, February 28, 2016

14. Harmonic minor scales

The 12 notes within each octave is represented in the Python list called keys, as in the last example.


We list the semitone intervals of a minor scale, inside the minor list. We copy it to harmonic_minor list and then set the last two values, either raise or decrease by a semitone.


Inside the main loop, iterated over all keys, we use i%7 (i modulo 7) as index into harmonic_minor so we only access indexes 0 through 6.


Also we print a new line only if i is 7. The default end, for a print statement, is new line, unless we override it.


# mus14.py
# harmonic minor scales

import music21 as m21

minor = [2,1,2,2,1,2,2]
harmonic_minor = minor[:]
harmonic_minor[-2] += 1
harmonic_minor[-1] -= 1
print('harmonic minor = ',harmonic_minor)

keys = ['C','C#','D','D#',
        'E','F','F#','G',
        'G#','A','A#','B']

print('The 12 harmonic minor scales:')
for key in keys:
    n = m21.note.Note(key)
    midi = n.pitch.midi
    for i in range(8):
        n = m21.note.Note(midi = midi)
        if i<7: print(n.name, end= ' - ')
        else: print(n.name)
        midi = n.pitch.midi
        midi += harmonic_minor[i%7]

This will generate this output:


harmonic minor =  [2, 1, 2, 2, 1, 3, 1]
The 12 harmonic minor scales:
C - D - E- - F - G - G# - B - C
C# - E- - E - F# - G# - A - C - C#
D - E - F - G - A - B- - C# - D
E- - F - F# - G# - B- - B - D - E-
E - F# - G - A - B - C - E- - E
F - G - G# - B- - C - C# - E - F
F# - G# - A - B - C# - D - F - F#
G - A - B- - C - D - E- - F# - G
G# - B- - B - C# - E- - E - G - G#
A - B - C - D - E - F - G# - A
B- - C - C# - E- - F - F# - A - B-
B - C# - D - E - F# - G - B- - B

13. Minor Scales

The 12 notes within each octave is represented in the Python list called keys.


We use the semitone intervals of a minor scale, inside the minor list. The minor list contains the last two elements of major plus the first five elements. In Python we can use negative numbers to indicate index from last element.


Inside the main loop, iterated over all keys, we use i%7 (i modulo 7) as index into minor so we only access indexes 0 through 6.


Also we print a new line only if i is 7. The default end, for a print statement, is new line, unless we override it.


We can see A (natural) minor scale has same notes as C major (its relative). The only difference is the root is A or C in the two cases.


# mus13.py
# minor scales

import music21 as m21

major = [2,2,1,2,2,2,1]
# minor = last 2 + first 5 (of major)
minor = major[-2:]+major[:5]
print('minor = ',minor)

keys = ['C','C#','D','D#',
        'E','F','F#','G',
        'G#','A','A#','B']

print('The 12 minor scales:')
for key in keys:
    n = m21.note.Note(key)
    midi = n.pitch.midi
    for i in range(8):
        n = m21.note.Note(midi = midi)
        if i<7: print(n.name, end= ' - ')
        else: print(n.name)
        midi = n.pitch.midi
        midi += minor[i%7]

This will generate this output:


minor =  [2, 1, 2, 2, 1, 2, 2]
The 12 minor scales:
C - D - E- - F - G - G# - B- - C
C# - E- - E - F# - G# - A - B - C#
D - E - F - G - A - B- - C - D
E- - F - F# - G# - B- - B - C# - E-
E - F# - G - A - B - C - D - E
F - G - G# - B- - C - C# - E- - F
F# - G# - A - B - C# - D - E - F#
G - A - B- - C - D - E- - F - G
G# - B- - B - C# - E- - E - F# - G#
A - B - C - D - E - F - G - A
B- - C - C# - E- - F - F# - G# - B-
B - C# - D - E - F# - G - A - B

Saturday, February 27, 2016

12. Major Scales

There are 12 notes in each octave. They are in the Python list called keys. It can be written also all on one long line. However, here, it is broken into 3 lines.


We use the semitone intervals of a major scale, inside the major list.


Inside the main loop, iterated over all keys, we use i%7 (i modulo 7) as index into major so we only access indexes 0 through 6.


Also we print a new line only if i is 7. The default end, for a print statement, is new line, unless we override it.


# mus12.py
# major scales

import music21 as m21

major = [2,2,1,2,2,2,1]

keys = ['C','C#','D','D#',
        'E','F','F#','G',
        'G#','A','A#','B']

print('The 12 major scales:')
for key in keys:
    n = m21.note.Note(key)
    midi = n.pitch.midi
    for i in range(8):
        n = m21.note.Note(midi = midi)
        if i<7: print(n.name, end= ' - ')
        else: print(n.name)
        midi = n.pitch.midi
        midi += major[i%7]

This will generate this output:


The 12 major scales:
C - D - E - F - G - A - B - C
C# - E- - F - F# - G# - B- - C - C#
D - E - F# - G - A - B - C# - D
E- - F - G - G# - B- - C - D - E-
E - F# - G# - A - B - C# - E- - E
F - G - A - B- - C - D - E - F
F# - G# - B- - B - C# - E- - F - F#
G - A - B - C - D - E - F# - G
G# - B- - C - C# - E- - F - G - G#
A - B - C# - D - E - F# - G# - A
B- - C - D - E- - F - G - A - B-
B - C# - E- - E - F# - G# - B- - B

11. Names and Frequencies of notes

Note objects may be created by passing in a midi number in the range from 0 to 127. Since we start at 0, we have a total of 128 numbers.


For the Note object, we can find the name, the octave, as well as the nameWithOctave.


We also find the frequency of the associated Pitch object.


# mus11.py
# Names and Frequencies of notes

import music21 as m21

for midi in range(128):
    n = m21.note.Note(midi=midi)
    print_string = 'midi = {} \t{} \t{:.1f} Hz'
    print(print_string.format(midi,
                              n.nameWithOctave,
                              n.pitch.frequency))

This will generate output:


midi = 0  C-1  8.2 Hz
midi = 1  C#-1  8.7 Hz
midi = 2  D-1  9.2 Hz
midi = 3  E--1  9.7 Hz
midi = 4  E-1  10.3 Hz
midi = 5  F-1  10.9 Hz
midi = 6  F#-1  11.6 Hz
midi = 7  G-1  12.2 Hz
midi = 8  G#-1  13.0 Hz
midi = 9  A-1  13.7 Hz
midi = 10  B--1  14.6 Hz
midi = 11  B-1  15.4 Hz
midi = 12  C0  16.4 Hz
midi = 13  C#0  17.3 Hz
midi = 14  D0  18.4 Hz
midi = 15  E-0  19.4 Hz
midi = 16  E0  20.6 Hz
midi = 17  F0  21.8 Hz
midi = 18  F#0  23.1 Hz
midi = 19  G0  24.5 Hz
midi = 20  G#0  26.0 Hz
midi = 21  A0  27.5 Hz
midi = 22  B-0  29.1 Hz
midi = 23  B0  30.9 Hz
midi = 24  C1  32.7 Hz
midi = 25  C#1  34.6 Hz
midi = 26  D1  36.7 Hz
midi = 27  E-1  38.9 Hz
midi = 28  E1  41.2 Hz
midi = 29  F1  43.7 Hz
midi = 30  F#1  46.2 Hz
midi = 31  G1  49.0 Hz
midi = 32  G#1  51.9 Hz
midi = 33  A1  55.0 Hz
midi = 34  B-1  58.3 Hz
midi = 35  B1  61.7 Hz
midi = 36  C2  65.4 Hz
midi = 37  C#2  69.3 Hz
midi = 38  D2  73.4 Hz
midi = 39  E-2  77.8 Hz
midi = 40  E2  82.4 Hz
midi = 41  F2  87.3 Hz
midi = 42  F#2  92.5 Hz
midi = 43  G2  98.0 Hz
midi = 44  G#2  103.8 Hz
midi = 45  A2  110.0 Hz
midi = 46  B-2  116.5 Hz
midi = 47  B2  123.5 Hz
midi = 48  C3  130.8 Hz
midi = 49  C#3  138.6 Hz
midi = 50  D3  146.8 Hz
midi = 51  E-3  155.6 Hz
midi = 52  E3  164.8 Hz
midi = 53  F3  174.6 Hz
midi = 54  F#3  185.0 Hz
midi = 55  G3  196.0 Hz
midi = 56  G#3  207.7 Hz
midi = 57  A3  220.0 Hz
midi = 58  B-3  233.1 Hz
midi = 59  B3  246.9 Hz
midi = 60  C4  261.6 Hz
midi = 61  C#4  277.2 Hz
midi = 62  D4  293.7 Hz
midi = 63  E-4  311.1 Hz
midi = 64  E4  329.6 Hz
midi = 65  F4  349.2 Hz
midi = 66  F#4  370.0 Hz
midi = 67  G4  392.0 Hz
midi = 68  G#4  415.3 Hz
midi = 69  A4  440.0 Hz
midi = 70  B-4  466.2 Hz
midi = 71  B4  493.9 Hz
midi = 72  C5  523.3 Hz
midi = 73  C#5  554.4 Hz
midi = 74  D5  587.3 Hz
midi = 75  E-5  622.3 Hz
midi = 76  E5  659.3 Hz
midi = 77  F5  698.5 Hz
midi = 78  F#5  740.0 Hz
midi = 79  G5  784.0 Hz
midi = 80  G#5  830.6 Hz
midi = 81  A5  880.0 Hz
midi = 82  B-5  932.3 Hz
midi = 83  B5  987.8 Hz
midi = 84  C6  1046.5 Hz
midi = 85  C#6  1108.7 Hz
midi = 86  D6  1174.7 Hz
midi = 87  E-6  1244.5 Hz
midi = 88  E6  1318.5 Hz
midi = 89  F6  1396.9 Hz
midi = 90  F#6  1480.0 Hz
midi = 91  G6  1568.0 Hz
midi = 92  G#6  1661.2 Hz
midi = 93  A6  1760.0 Hz
midi = 94  B-6  1864.7 Hz
midi = 95  B6  1975.5 Hz
midi = 96  C7  2093.0 Hz
midi = 97  C#7  2217.5 Hz
midi = 98  D7  2349.3 Hz
midi = 99  E-7  2489.0 Hz
midi = 100  E7  2637.0 Hz
midi = 101  F7  2793.8 Hz
midi = 102  F#7  2960.0 Hz
midi = 103  G7  3136.0 Hz
midi = 104  G#7  3322.4 Hz
midi = 105  A7  3520.0 Hz
midi = 106  B-7  3729.3 Hz
midi = 107  B7  3951.1 Hz
midi = 108  C8  4186.0 Hz
midi = 109  C#8  4434.9 Hz
midi = 110  D8  4698.6 Hz
midi = 111  E-8  4978.0 Hz
midi = 112  E8  5274.0 Hz
midi = 113  F8  5587.7 Hz
midi = 114  F#8  5919.9 Hz
midi = 115  G8  6271.9 Hz
midi = 116  G#8  6644.9 Hz
midi = 117  A8  7040.0 Hz
midi = 118  B-8  7458.6 Hz
midi = 119  B8  7902.1 Hz
midi = 120  C9  8372.0 Hz
midi = 121  C#9  8869.8 Hz
midi = 122  D9  9397.3 Hz
midi = 123  E-9  9956.1 Hz
midi = 124  E9  10548.1 Hz
midi = 125  F9  11175.3 Hz
midi = 126  F#9  11839.8 Hz
midi = 127  G9  12543.9 Hz

Wednesday, February 24, 2016

10. Primary Triads in C

The three lists correspond to chords I, IV, and V, for key of 'C4'.


The purpose of addChord is to add a chord I, IV, or V, randomly, with the condition that that we have a change in chord.


The function randint from the standard random module, will generate a random integer within the given limits, and including those limits, that is, randint(0,2) can result in 0, 1 or 2.


The global variable num contains the last value indicating which chord was added. That is, num = 0 (chord I), num = 1, (chord IV), or num = 2 (chord V).


After each time, addChord() function is called it will calculate a new_num which is the value of randint(0,2). If it happens to be the same as last value (num), new_num is calculated again. This loop continues until the new_num is different from num. Then new_num replaces the value of num.


From now on, I will use a key of 'C' for the writeMIDI function. In the piano roll, the key does not matter, only on the score so it can put the appropriate sharps and flats.


# mus10.py
# Primary Triads in key of C

from writeMIDI import writeMIDI
from random import randint

# beats per minute
bpm = 130

tonic = ['C4','E4','G4']
subdominant = ['F4','A4','C5']
dominant = ['G4','B4','D5']

notes = []

start = -1
num = randint(0,2)

def addChord(n):
    global num
    global start
    start += 1
    print('num = {}'.format(num))
    if num == 0:
        for ch in tonic:
            n.append((ch,start,1,115))
    if num == 1:
        for ch in subdominant:
            n.append((ch,start,1,120))
    if num == 2:
        for ch in dominant:
            n.append((ch,start,1,125))
    new_num = randint(0,2)
    while new_num == num:
        new_num = randint(0,2)
    num = new_num
            
for i in range(20):
    addChord(notes)

writeMIDI('C','piano',bpm,notes,'mus10')

A possible output might be:

num = 0
num = 1
num = 2
num = 0
num = 2
num = 1
num = 2
num = 0
num = 1
num = 0
num = 2
num = 1
num = 2
num = 1
num = 2
num = 0
num = 2
num = 0
num = 2
num = 0

This will generate this:


9. Natural Minor Scale

The Python list, minor, contains the semitone intervals for the natural minor scale.


Each time, the scale function is called, it will increase the global variable start by 8, or two measures. If we did not indicate it is global inside function definition, it will try to look for a local variable and complain.


Now the scale function can be called with kind equal to 'major' or 'minor'.


The scale function is called twice with the two different kinds of scale. If we did not have a start which changes, it will write to same 2 measures.


# mus9.py
# D natural minor scale
# D major scale

import music21 as m21
from writeMIDI import writeMIDI

# beats per minute
bpm = 130

major = [2,2,1,2,2,2,1]
minor = [2,1,2,2,1,2,2] 

notes = []

start = 0

def scale(key, n, kind):
    global start
    start += 8
    print('\nkey = {}'.format(key))
    p = m21.pitch.Pitch(key)
    midi = p.midi
    for i in range(8):
        print('midi of {} added'.format(midi))
        n.append((midi,start+i,1,120))
        if kind == 'major': midi += major[i%7]
        elif kind == 'minor': midi += minor[i%7]

scale('D',notes,'minor')
scale('D',notes,'major')
writeMIDI('C',"piano",bpm,notes,'mus9')

The output is:

key = D
midi of 62 added
midi of 64 added
midi of 65 added
midi of 67 added
midi of 69 added
midi of 70 added
midi of 72 added
midi of 74 added

key = D
midi of 62 added
midi of 64 added
midi of 66 added
midi of 67 added
midi of 69 added
midi of 71 added
midi of 73 added
midi of 74 added

This will generate this:


Tuesday, February 23, 2016

8. Consonant to Dissonant Intervals

There is a list, interval, of 13 elements. While it is possible to write it all on one line, sometimes it is better to write on multiple lines.


The function, base, adds 13 'C4' quarter notes at beat 0, 2, 4, and so on. The 'C4' is midi number 60.


The function, consonant_to_dissonant, will add intervals such that midi number is 60 + appropriate interval. Again in this function, we use commas to separate lines.


# mus8.py
# consonant to dissonant intervals

from writeMIDI import writeMIDI

# beats per minute
bpm = 130

notes = []
midi = 60

# consonant to dissonant (semitones)
interval = [0, # Unison/prime
            12, # Octave
            7, # Perfect fifth
            5, # Perfect fourth
            4, # Major third
            8, # Minor sixth
            3, # Minor third
            9, # Major sixth
            2, # Major second
            10, # Minor seventh
            1, # Minor second
            11, # Major seventh
            6] # Augmented fourth/diminished fifth

def base(n):
    "Add 13 C4 quarter notes"
    for i in range(13):
        n.append((midi,2*i,1,120))
        
def consonant_to_dissonant(n):
    "Intervals from consonant to dissonant"
    for i in range(13):
        n.append((midi+interval[i], # Note midi number
                  2*i,              # Start in quarter lengths
                  1,                # Duration is 1 quarter note
                  120))             # Volume is 120

base(notes)
consonant_to_dissonant(notes)
writeMIDI('C','piano',bpm,notes,'mus8')

This will generate this:


Sunday, February 21, 2016

7. Drone bass

A C major scale has 8 notes. If all are quarter notes, one C major scale takes 2 measures, assuming no rests.


Here we have two C major scales over 4 measures, which is done by the function scale().


A drone consisting of note C3, two whole notes for first 2 measures, and four half notes for the next 2 measures, which is done by the function drone().


We can always include a documentation string as the first line of a function.


The first 2 and last 2 measures will sound different due to the increasing number of notes in the last 2 measures.


# mus7.py
# drone bass

from writeMIDI import writeMIDI

# beats per minute
bpm = 130

major = [2,2,1,2,2,2,1]

notes = []

def scale(n):
    "Add two C major scales (4 measures)"
    for j in range(2):
        midi = 60
        for i in range(8):
            n.append((midi,8*j+i,1,120))
            midi += major[i%7]

def drone(n):
    "Add drone C3 over 4 measures"
    n.append((48,0,4,115)) # whole note, measure 1
    n.append((48,4,4,115)) # whole note, measure 2
    n.append((48,8,2,115)) # half note, measure 3 - first half
    n.append((48,10,2,115)) # half note, measure 3 - second half
    n.append((48,12,2,115)) # half note, measure 4 - first half
    n.append((48,14,2,115)) # half note, measure 4 - second half
             
scale(notes)
drone(notes)
writeMIDI('C','piano',bpm,notes,'mus7')

This will generate this:


6. Soundfonts

For a MIDI file to play, it needs to load a soundfont file.


The midi file will sound different based on the particular soundfont.


Clicking on a midi file should play it according to the default soundfont.


More control is possible using a digital audio workstation (DAW). Here I use free and open source LMMS to illustrate use of soundfonts.


From the Project menu, you can select Import and then select an midi file. It will be automatically loaded with the soundfont player (sf2) as shown below.



By double clicking on the sf2 player, you can get the patch it is playing and change the instrument.


To set a particular soundfont you have to set them in the Edit menu and Settings submenu. Some soundfonts can be found at this site.

5. Intervals

Note "C3", midi 60, is the base note.


13 intervals, from 0 semitones to 12 semitones are created. A difference of 12 semitones is an octave, and a difference of 7 semitones yields the perfect fifth.


The interval function creates the different spaced notes. Note they have identical start time, duration time, and volume. We could randomize it slightly to humanize the notes.


The printouts will show which semitone is being created. The perfect fifth should give the most consonant note.


# mus5.py
# Intervals

from writeMIDI import writeMIDI

# beats per minute
bpm = 130

notes = []

def interval(start,val):
    notes.append((60,start,1,112))
    notes.append((60+val,start,1,112))

for i in range(13):
    print("Creating interval of {} semitones".format(i))
    diff = 2**(i/12)
    print("Frequency ratio difference of {:.2f}".format(diff))
    print()
    interval(2*i,i)

key = 'C'
writeMIDI(key,"piano",bpm,notes,'mus5')

PrintOut:


Creating interval of 0 semitones
Frequency ratio difference of 1.00

Creating interval of 1 semitones
Frequency ratio difference of 1.06

Creating interval of 2 semitones
Frequency ratio difference of 1.12

Creating interval of 3 semitones
Frequency ratio difference of 1.19

Creating interval of 4 semitones
Frequency ratio difference of 1.26

Creating interval of 5 semitones
Frequency ratio difference of 1.33

Creating interval of 6 semitones
Frequency ratio difference of 1.41

Creating interval of 7 semitones
Frequency ratio difference of 1.50

Creating interval of 8 semitones
Frequency ratio difference of 1.59

Creating interval of 9 semitones
Frequency ratio difference of 1.68

Creating interval of 10 semitones
Frequency ratio difference of 1.78

Creating interval of 11 semitones
Frequency ratio difference of 1.89

Creating interval of 12 semitones
Frequency ratio difference of 2.00

This will generate this for piano roll for mus5.mid:


Saturday, February 20, 2016

4. Chords

Chords are composed of multiple notes harmonizing at same time.


Here lists are built up so chords will contain more intervals.


For example, for the dyad, the interval is 7 semitones.


The printouts will show the six created lists.


In the measure function, we iterate over all notes in a list and add a note for 3 of the 4 beats at the 6 different measures.


# mus4.py
# Chords

import music21 as m21
from writeMIDI import writeMIDI

# beats per minute
bpm = 130

notes = []

# dyad
m1 = ['C3','G3']
# triad
m2 = m1 + ['E4']
# tetrad
m3 = m2 + ['B3']
# pentad
m4 = m3 + ['F#4']
# hexad
m5 = m4 + ['A4']
# heptad
m6 = m5 + ['D5']

# lists
print('m1 =',m1)
print('m2 =',m2)
print('m3 =',m3)
print('m4 =',m4)
print('m5 =',m5)
print('m6 =',m6)

def measure(meas,m):
    for n in m:
        notes.append((n,4*meas,3,115))
        
measure(0,m1)
measure(1,m2)
measure(2,m3)
measure(3,m4)
measure(4,m5)
measure(5,m6)

key = 'C'
writeMIDI(key,"piano",bpm,notes,'mus4')

PrintOut:


m1 = ['C3', 'G3']
m2 = ['C3', 'G3', 'E4']
m3 = ['C3', 'G3', 'E4', 'B3']
m4 = ['C3', 'G3', 'E4', 'B3', 'F#4']
m5 = ['C3', 'G3', 'E4', 'B3', 'F#4', 'A4']
m6 = ['C3', 'G3', 'E4', 'B3', 'F#4', 'A4', 'D5']

This will generate this for mus4.mid:



Or piano roll: (The only view given from now on):


3. C# and D major scales

Version 2 of writeMIDI.py, included in the right side link, has as one of the arguments, the key signature.


We are using the lists notes1 and notes2 to populate the notes of the two scales. In Python, lists are passed as reference, thus in the first call the local n points to note1 and then in second call, n is the same as note2.


Since we are only changing lists, the function scale does not return anything.


The printouts will show which notes are being added.


# mus3.py
# C# major scale
# D major scale

import music21 as m21
from writeMIDI import writeMIDI

# beats per minute
bpm = 130

major = [2,2,1,2,2,2,1]

notes1 = []
notes2 = []

def scale(key, n):
    print('\nkey = {}'.format(key))
    p = m21.pitch.Pitch(key)
    midi = p.midi
    for i in range(8):
        print('midi of {} added'.format(midi))
        n.append((midi,i,1,120))
        midi += major[i%7]

key = 'C#'
scale(key,notes1)
writeMIDI(key,"piano",bpm,notes1,'mus3a')
key = 'D'
scale(key,notes2)
writeMIDI(key,"flute",bpm,notes2,'mus3b')


PrintOut:


key = C#
midi of 61 added
midi of 63 added
midi of 65 added
midi of 66 added
midi of 68 added
midi of 70 added
midi of 72 added
midi of 73 added

key = D
midi of 62 added
midi of 64 added
midi of 66 added
midi of 67 added
midi of 69 added
midi of 71 added
midi of 73 added
midi of 74 added

This will generate this for mus3a.mid:



This will generate this for mus3b.mid:


Friday, February 19, 2016

2. Midi Numbers

Each note is composed of 4 values which were listed last time.


The first could be a string corresponding to note number, such as 'C4'.


However, it could also be a midi number, such as 60 for 'C4'. (60 is 'C4', 61 is 'C#4', ... 72 is 'C5', ...)


Here we use midi numbers to generate same output as first program. It should be noted that we have to know the whole step, half step sequence in the Major Scale.


# mus2.py
# C major scale

from writeMIDI import writeMIDI

# beats per minute
bpm = 130

major = [2,2,1,2,2,2,1]

notes = []

midi = 60
for i in range(8):
    notes.append((midi,i,1,120))
    midi += major[i%7]

writeMIDI("piano",bpm,notes,'mus2')

This will generate this:


1. C major scale

The module writeMIDI.py requires music21 music module.


Each note is a tuple with 4 different values. The first is a string corresponding to note number, such as 'C4'.


Next is the start time in quarter lengths. A note starting in the second measure will have start of 4.


The third number is the length in quarter notes. A whole note would correspond to 4. Here we only have quarter notes (duration is 1).


The last number is volume and is between 0 and 127, 0 no sound and 127 is max sound.


# mus1.py
# C major scale

from writeMIDI import writeMIDI

# beats per minute
bpm = 130

notes = []
# C4, quarter note at time 0, at volume 120
notes.append(('C4',0,1,120))
# D4, quarter note at time 1, at volume 120
notes.append(('D4',1,1,120))
# E4, quarter note at time 2, at volume 120
notes.append(('E4',2,1,120))
# F4, quarter note at time 3, at volume 120
notes.append(('F4',3,1,120))
# G4, quarter note at time 4, at volume 120
notes.append(('G4',4,1,120))
# A4, quarter note at time 5, at volume 120
notes.append(('A4',5,1,120))
# B4, quarter note at time 6, at volume 120
notes.append(('B4',6,1,120))
# C5, eighth note at time 7, at volume 120
notes.append(('C5',7,1,120))

writeMIDI("piano",bpm,notes,'mus1')

This will generate this: