Skip to content

Commit 803870a

Browse files
committed
Eliminate redundancy between Note 'dynamics' and 'channel & velocity'
Keep 'dynamics' as a read-only property, for compatibility.
1 parent 4d82cbd commit 803870a

3 files changed

Lines changed: 60 additions & 38 deletions

File tree

mingus/containers/note.py

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@
2323
from math import log
2424
import six
2525

26+
_DEFAULT_NAME = "C"
27+
_DEFAULT_OCTAVE = 4
28+
_DEFAULT_CHANNEL = 1
29+
_DEFAULT_VELOCITY = 64
30+
2631

2732
class Note(object):
2833

@@ -41,11 +46,10 @@ class Note(object):
4146
and chords.
4247
"""
4348

44-
name = "C"
45-
octave = 4
46-
dynamics = {}
47-
channel = 1
48-
velocity = 64
49+
name = _DEFAULT_NAME
50+
octave = _DEFAULT_OCTAVE
51+
channel = _DEFAULT_CHANNEL
52+
velocity = _DEFAULT_VELOCITY
4953

5054
def __init__(self, name="C", octave=4, dynamics=None):
5155
if dynamics is None:
@@ -55,21 +59,28 @@ def __init__(self, name="C", octave=4, dynamics=None):
5559
elif hasattr(name, "name"):
5660
# Hardcopy Note object
5761
self.set_note(name.name, name.octave, name.dynamics)
58-
if hasattr(name, "channel"):
59-
self.channel = name.channel
60-
if hasattr(name, "velocity"):
61-
self.velocity = name.velocity
6262
elif isinstance(name, int):
6363
self.from_int(name)
6464
else:
6565
raise NoteFormatError(
6666
"Don't know what to do with name object: " "'%s'" % name
6767
)
6868

69+
@property
70+
def dynamics(self):
71+
return {
72+
"channel": self.channel,
73+
"velocity": self.velocity,
74+
}
75+
6976
def set_channel(self, channel):
77+
if not 0 <= channel < 16:
78+
raise ValueError("MIDI channel must be 0-15")
7079
self.channel = channel
7180

7281
def set_velocity(self, velocity):
82+
if not 0 <= velocity < 128:
83+
raise ValueError("MIDI velocity must be 0-127")
7384
self.velocity = velocity
7485

7586
def set_note(self, name="C", octave=4, dynamics=None):
@@ -80,23 +91,27 @@ def set_note(self, name="C", octave=4, dynamics=None):
8091
"""
8192
if dynamics is None:
8293
dynamics = {}
94+
if "channel" in dynamics:
95+
self.set_channel(dynamics["channel"])
96+
if "velocity" in dynamics:
97+
self.set_velocity(dynamics["velocity"])
98+
8399
dash_index = name.split("-")
84100
if len(dash_index) == 1:
85101
if notes.is_valid_note(name):
86102
self.name = name
87103
self.octave = octave
88-
self.dynamics = dynamics
89104
return self
90105
else:
91106
raise NoteFormatError(
92107
"The string '%s' is not a valid "
93108
"representation of a note in mingus" % name
94109
)
95110
elif len(dash_index) == 2:
96-
if notes.is_valid_note(dash_index[0]):
97-
self.name = dash_index[0]
98-
self.octave = int(dash_index[1])
99-
self.dynamics = dynamics
111+
note, octave = dash_index
112+
if notes.is_valid_note(note):
113+
self.name = note
114+
self.octave = int(octave)
100115
return self
101116
else:
102117
raise NoteFormatError(
@@ -107,9 +122,12 @@ def set_note(self, name="C", octave=4, dynamics=None):
107122

108123
def empty(self):
109124
"""Remove the data in the instance."""
125+
# TODO: Review these two. This seems to leave the object in an invalid state
110126
self.name = ""
111-
octave = 0
112-
dynamics = {}
127+
self.octave = 0
128+
129+
self.channel = _DEFAULT_CHANNEL
130+
self.velocity = _DEFAULT_VELOCITY
113131

114132
def augment(self):
115133
"""Call notes.augment with this note as argument."""

mingus/midi/midi_track.py

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,8 @@ def play_Note(self, note):
6161
To set the channel on which to play this note, set Note.channel, the
6262
same goes for Note.velocity.
6363
"""
64-
velocity = 64
65-
channel = 1
66-
if hasattr(note, "dynamics"):
67-
if "velocity" in note.dynamics:
68-
velocity = note.dynamics["velocity"]
69-
if "channel" in note.dynamics:
70-
channel = note.dynamics["channel"]
71-
if hasattr(note, "channel"):
72-
channel = note.channel
73-
if hasattr(note, "velocity"):
74-
velocity = note.velocity
64+
channel = note.channel
65+
velocity = note.velocity
7566
if self.change_instrument:
7667
self.set_instrument(channel, self.instrument)
7768
self.change_instrument = False
@@ -130,17 +121,8 @@ def play_Track(self, track):
130121

131122
def stop_Note(self, note):
132123
"""Add a note_off event for note to event_track."""
133-
velocity = 64
134-
channel = 1
135-
if hasattr(note, "dynamics"):
136-
if "velocity" in note.dynamics:
137-
velocity = note.dynamics["velocity"]
138-
if "channel" in note.dynamics:
139-
channel = note.dynamics["channel"]
140-
if hasattr(note, "channel"):
141-
channel = note.channel
142-
if hasattr(note, "velocity"):
143-
velocity = note.velocity
124+
channel = note.channel
125+
velocity = note.velocity
144126
self.track_data += self.note_off(channel, int(note) + 12, velocity)
145127

146128
def stop_NoteContainer(self, notecontainer):

tests/unit/containers/test_note.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,25 @@ def test_from_shorthand(self):
112112
self.assertTrue(Note().from_shorthand("c") == Note("C-3"))
113113
self.assertTrue(Note().from_shorthand("c'") == Note("C-4"))
114114
self.assertTrue(Note().from_shorthand("c''''''") == Note("C-9"))
115+
116+
def test_velocity(self):
117+
self.assertEqual(42, Note("A", 4, {"velocity": 42}).velocity)
118+
self.assertEqual(64, Note("A", 4, {"channel": 2}).velocity) # default velocity
119+
self.assertEqual(42, Note(Note("A", 4, {"velocity": 42})).velocity)
120+
121+
def test_channel(self):
122+
self.assertEqual(1, Note("A", 4, {"velocity": 100}).channel) # default channel
123+
self.assertEqual(4, Note("A", 4, {"channel": 4}).channel)
124+
self.assertEqual(4, Note(Note("A", 4, {"channel": 4})).channel)
125+
126+
def test_invalid_channel(self):
127+
with self.assertRaises(ValueError):
128+
Note("A", 4, {"channel": 100})
129+
with self.assertRaises(ValueError):
130+
Note("A", 4, {"channel": -1})
131+
132+
def test_invalid_velocity(self):
133+
with self.assertRaises(ValueError):
134+
Note("A", 4, {"velocity": 200})
135+
with self.assertRaises(ValueError):
136+
Note("A", 4, {"velocity": -1})

0 commit comments

Comments
 (0)