Skip to content

Commit dc566e0

Browse files
committed
Add test for midi file with midi offs
Fix: #2
1 parent 519683f commit dc566e0

7 files changed

+78
-39
lines changed

test/clock_tower_short.mid

208 Bytes
Binary file not shown.

test/machine.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
class PWM():
1+
class PWM:
2+
def __init__(self, *args, **kwargs):
3+
pass
4+
25
def duty(self, i):
36
pass
7+
48
def freq(self, f):
59
pass
610

711

8-
class Pin():
12+
class Pin:
913
OUT = "OUT"
10-
def __init__(self, *arg, **kwargs):
14+
15+
def __init__(self, *args, **kwargs):
1116
pass

test/midi.py

+21-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import struct
2-
import sys
32
import logging
43

54
logger = logging.getLogger(__name__)
65

6+
77
class Note(object):
8-
"Represents a single MIDI note"
9-
8+
"""
9+
Represents a single MIDI note
10+
"""
11+
1012
note_names = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#']
1113

1214
def __init__(self, channel, pitch, velocity, start, duration = 0):
@@ -26,10 +28,14 @@ def __str__(self):
2628
def get_end(self):
2729
return self.start + self.duration
2830

31+
2932
class MidiFile(object):
30-
"Represents the notes in a MIDI file"
31-
32-
def read_byte(self, file):
33+
"""
34+
Represents the notes in a MIDI file
35+
"""
36+
37+
@staticmethod
38+
def read_byte(file):
3339
return struct.unpack('B', file.read(1))[0]
3440

3541
def read_variable_length(self, file, counter):
@@ -45,7 +51,7 @@ def read_variable_length(self, file, counter):
4551
if not (c & 0x80):
4652
break
4753

48-
return (num, counter)
54+
return num, counter
4955

5056
def __init__(self, file_name):
5157
self.tempo = 120
@@ -140,7 +146,7 @@ def read_track(self, track_num=1):
140146
note = Note(channel, param1, param2, abs_time)
141147
if nn == track_num:
142148
logger.debug("%s", note)
143-
track.append(str(note).split())
149+
track.append(note)
144150

145151
elif type == 0x8:
146152
for note in reversed(track):
@@ -166,6 +172,7 @@ def getnote(q):
166172
return None
167173

168174
for nn in track:
175+
nn = str(nn).split()
169176
start, stop = float(nn[2]), float(nn[3])
170177

171178
if start != stop: # note ends because of NOTE OFF event
@@ -191,8 +198,12 @@ def getnote(q):
191198
last2 = start
192199

193200
return song
194-
201+
202+
195203
def getdur(a, b):
196-
"Calculate note length for PySynth"
204+
"""
205+
Calculate note length for PySynth"
206+
"""
207+
197208
return 4 / (b - a)
198209

test/rtttl.py

+12-8
Original file line numberDiff line numberDiff line change
@@ -22,33 +22,37 @@
2222
0.0,
2323
]
2424

25-
class RTTTL:
2625

26+
class RTTTL:
2727
def __init__(self, tune):
2828
tune_pieces = tune.split(':')
2929
if len(tune_pieces) != 3:
3030
raise ValueError('tune should contain exactly 2 colons')
3131
self.tune = tune_pieces[2]
3232
self.tune_idx = 0
33+
self.msec_per_whole_note = 0
34+
self.default_octave = 0
35+
self.default_duration = 0
36+
self.bpm = 0
3337
self.parse_defaults(tune_pieces[1])
3438

3539
def parse_defaults(self, defaults):
3640
# Example: d=4,o=5,b=140
3741
val = 0
38-
id = ' '
42+
_id = ' '
3943
for char in defaults:
4044
char = char.lower()
4145
if char.isdigit():
4246
val *= 10
4347
val += ord(char) - ord('0')
44-
if id == 'o':
48+
if _id == 'o':
4549
self.default_octave = val
46-
elif id == 'd':
50+
elif _id == 'd':
4751
self.default_duration = val
48-
elif id == 'b':
52+
elif _id == 'b':
4953
self.bpm = val
5054
elif char.isalpha():
51-
id = char
55+
_id = char
5256
val = 0
5357
# 240000 = 60 sec/min * 4 beats/whole-note * 1000 msec/sec
5458
self.msec_per_whole_note = 240000.0 / self.bpm
@@ -87,7 +91,7 @@ def notes(self):
8791
return
8892

8993
note = char.lower()
90-
if note >= 'a' and note <= 'g':
94+
if 'a' <= note <= 'g':
9195
note_idx = ord(note) - ord('a')
9296
elif note == 'h':
9397
note_idx = 1 # H is equivalent to B
@@ -109,7 +113,7 @@ def notes(self):
109113
char = self.next_char()
110114

111115
# Check for octave
112-
if char >= '4' and char <= '7':
116+
if '4' <= char <= '7':
113117
octave = ord(char) - ord('0')
114118
char = self.next_char()
115119
else:

test/songs.py

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
'MissionImp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2c,a#5,8c,2p,32p,a#5,g5,2f#,32p,a#5,g5,2f,32p,a#5,g5,2e,d#,8d',
3535
]
3636

37+
3738
def find(name):
3839
for song in SONGS:
3940
song_name = song.split(':')[0]

test/test_buzzer.py

+22-15
Original file line numberDiff line numberDiff line change
@@ -14,49 +14,56 @@
1414

1515
for k in range(88):
1616
freq = int(27.5 * 2. ** (k / 12.))
17-
oct = (k + 9) // 12
18-
note = '%s%d' % (keys_s[k % 12], oct)
17+
_oct = (k + 9) // 12
18+
note = '%s%d' % (keys_s[k % 12], _oct)
1919
PITCHHZ[note] = freq
2020

21+
2122
class BuzzerTests(unittest.TestCase):
2223
sample_file = os.path.join(os.path.dirname(__file__), 'Zlilmehuvan.mid')
2324
nokia_file = os.path.join(os.path.dirname(__file__), 'star_wars.nokia')
2425

2526
def test_00(self):
26-
for k, v in PITCHHZ.items():
27-
self.assertAlmostEqual(note_freq(k), v, delta=2)
27+
for key, val in PITCHHZ.items():
28+
self.assertAlmostEqual(note_freq(key), val, delta=2)
2829

29-
def test_01_init_no_params(self):
30+
@staticmethod
31+
def test_01_init_no_params():
3032
b = BuzzerPlayer()
3133

32-
def test_02_init(self):
33-
b = BuzzerPlayer(1,2,4)
34+
@staticmethod
35+
def test_02_init():
36+
b = BuzzerPlayer(1, 2, 4)
3437

35-
def test_03_play_nokia_tone(self):
36-
buzz = BuzzerPlayer(1,2,4)
38+
@staticmethod
39+
def test_03_play_nokia_tone():
40+
buzz = BuzzerPlayer(1, 2, 4)
3741
song = nokia_songs['pink_panther']
3842
buzz.play_nokia_tone(song, name='pink_panther')
3943

40-
def test_03_play_nokia_tone_esp8266(self):
44+
@staticmethod
45+
def test_03_play_nokia_tone_esp8266():
4146
buzz = BuzzerPlayer(12, platform="esp8266")
4247
song = nokia_songs['pink_panther']
4348
buzz.play_nokia_tone(song, name='pink_panther')
4449

45-
def test_03_play_nokia_tone_pyborad(self):
46-
buzz = BuzzerPlayer(1,2,4, platform='pyboard')
50+
@staticmethod
51+
def test_03_play_nokia_tone_pyborad():
52+
buzz = BuzzerPlayer(1, 2, 4, platform='pyboard')
4753
song = nokia_songs['pink_panther']
4854
buzz.play_nokia_tone(song, name='pink_panther')
4955

5056
def test_03_play_nokie_tone_file(self):
51-
buzz = BuzzerPlayer(1,2,4)
57+
buzz = BuzzerPlayer(1, 2, 4)
5258
buzz.play_nokia_tone(buzz.from_file(self.nokia_file), name='star_wars')
5359

5460
def test_04_play_midi(self):
5561
buzz = BuzzerPlayer()
5662
if hasattr(buzz, 'play_midi'):
5763
buzz.play_midi(self.sample_file, track=1)
58-
59-
def test_05_play_rtttl(self):
64+
65+
@staticmethod
66+
def test_05_play_rtttl():
6067
buzz = BuzzerPlayer()
6168
if hasattr(buzz, 'play_rtttl'):
6269
buzz.play_rtttl(songs.find('Entertainer'))

test/test_midi.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
#import logging
77
#logging.basicConfig(level=logging.DEBUG)
88

9+
910
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
1011
return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
1112

13+
1214
class TestMidi(unittest.TestCase):
1315
sample_file = os.path.join(os.path.dirname(__file__), 'Zlilmehuvan.mid')
1416

@@ -17,18 +19,27 @@ def assertSequenceEqual(self, it1, it2):
1719

1820
def test_01_init_no_file(self):
1921
with self.assertRaises(OSError):
20-
m = MidiFile('nonexist')
22+
m = MidiFile('nonexist')
2123

2224
def test_02_init(self):
23-
m = MidiFile(self.sample_file)
25+
m = MidiFile(self.sample_file)
2426

2527
def test_03_read_track(self):
26-
m = MidiFile(self.sample_file)
28+
m = MidiFile(self.sample_file)
2729
notes = m.read_track(1)
2830
for n, expected in zip(notes[:4], (('r', 0.4343891402714933), ('c2', 1.116279069767441), ('r', 48.00000000000171), ('f1', 1.499999999999998))):
2931
self.assertEqual(n[0], expected[0])
3032
self.assertTrue(isclose(n[1], n[1]))
3133

34+
def test_04_midi_offs(self):
35+
midi_file = os.path.join(os.path.dirname(__file__), 'clock_tower_short.mid')
36+
m = MidiFile(midi_file)
37+
notes = m.read_track(1)
38+
for n, expected in zip(notes[:4], (('r', 2.2857142857142856), ('f#5', 4.0), ('r', 8.0), ('d5', 4.0))):
39+
self.assertEqual(n[0], expected[0])
40+
self.assertTrue(isclose(n[1], n[1]))
41+
42+
3243
if __name__ == "__main__":
3344
unittest.main()
3445

0 commit comments

Comments
 (0)