Skip to content

Commit

Permalink
eliminate pitch.defaultOctave
Browse files Browse the repository at this point in the history
  • Loading branch information
mscuthbert committed Oct 14, 2022
1 parent 57d0af6 commit e0983db
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 38 deletions.
1 change: 0 additions & 1 deletion music21/analysis/transposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from music21 import chord
from music21 import common
from music21 import environment
from music21 import exceptions21
from music21 import pitch

environLocal = environment.Environment('analysis.transposition')
Expand Down
12 changes: 7 additions & 5 deletions music21/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,9 @@ def _deepcopySubclassable(self: _M21T,
Changed in v9: removeFromIgnore removed; never used and this is performance
critical.
'''
defaultIgnoreSet = {'_derivation', '_activeSite', '_cache'}
defaultIgnoreSet = {'_derivation', '_activeSite', '_sites', '_cache'}
if not self.groups:
defaultIgnoreSet.add('groups')
# duration is smart enough to do itself.
# sites is smart enough to do itself

Expand All @@ -482,6 +484,9 @@ def _deepcopySubclassable(self: _M21T,

new = common.defaultDeepcopy(self, memo, ignoreAttributes=ignoreAttributes)
setattr(new, '_cache', {})
setattr(new, '_sites', Sites())
if 'groups' in defaultIgnoreSet:
new.groups = Groups()

# was: keep the old ancestor but need to update the client
# 2.1 : NO, add a derivation of __deepcopy__ to the client
Expand Down Expand Up @@ -535,10 +540,7 @@ def __deepcopy__(self: _M21T, memo: dict[int, t.Any] | None = None) -> _M21T:
>>> ('flute' in n.groups, 'flute' in b.groups)
(False, True)
'''
# environLocal.printDebug(['calling Music21Object.__deepcopy__', self])
new = self._deepcopySubclassable(memo)
# environLocal.printDebug([self, 'end deepcopy', 'self._activeSite', self._activeSite])
return new
return self._deepcopySubclassable(memo)

def __getstate__(self) -> dict[str, t.Any]:
state = self.__dict__.copy()
Expand Down
25 changes: 10 additions & 15 deletions music21/duration.py
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,6 @@ def durationTupleFromQuarterLength(ql=1.0) -> DurationTuple:
return DurationTuple('inexpressible', 0, ql)


@lru_cache(1024)
def durationTupleFromTypeDots(durType='quarter', dots=0):
'''
Returns a DurationTuple (which knows its quarterLength) for
Expand Down Expand Up @@ -1669,7 +1668,7 @@ def __init__(self,
/,
*,
type: str | None = None, # pylint: disable=redefined-builtin
dots: int | None = None,
dots: int | None = 0,
quarterLength: OffsetQLIn | None = None,
durationTuple: DurationTuple | None = None,
components: Iterable[DurationTuple] | None = None,
Expand Down Expand Up @@ -1715,18 +1714,13 @@ def __init__(self,
if durationTuple is not None:
self.addDurationTuple(durationTuple, _skipInform=True)

if dots is not None:
storeDots = dots
else:
storeDots = 0

if components is not None:
self.components = t.cast(tuple[DurationTuple, ...], components)
# this is set in _setComponents
# self._quarterLengthNeedsUpdating = True

if type is not None:
nt = durationTupleFromTypeDots(type, storeDots)
nt = durationTupleFromTypeDots(type, dots)
self.addDurationTuple(nt, _skipInform=True)
# permit as keyword so can be passed from notes
elif quarterLength is not None:
Expand Down Expand Up @@ -1812,15 +1806,16 @@ def __deepcopy__(self, memo):
'''
Don't copy client when creating
'''
if (self._componentsNeedUpdating is False
and len(self._components) == 1
and self._dotGroups == (0,)
and self._linked is True
and not self._tuplets): # 99% of notes...
if self._componentsNeedUpdating:
self._updateComponents()

if (len(self._components) == 1
and self._dotGroups == (0,)
and self._linked is True
and not self._tuplets): # 99% of notes...
# ignore all but components
return self.__class__(durationTuple=self._components[0])
elif (self._componentsNeedUpdating is False
and not self._components
elif (not self._components
and self._dotGroups == (0,)
and not self._tuplets
and self._linked is True):
Expand Down
27 changes: 13 additions & 14 deletions music21/pitch.py
Original file line number Diff line number Diff line change
Expand Up @@ -1585,7 +1585,8 @@ class Pitch(prebase.ProtoM21Object):
Sometimes we need an octave for a `Pitch` even if it's not
specified. For instance, we can't play an octave-less `Pitch`
in MIDI or display it on a staff. So there is an `.implicitOctave`
tag to deal with these situations; by default it's always 4.
tag to deal with these situations; by default it's always 4 (unless
defaults.pitchOctave is changed)
>>> anyGSharp.implicitOctave
4
Expand All @@ -1596,7 +1597,6 @@ class Pitch(prebase.ProtoM21Object):
>>> highEflat.implicitOctave
6
If an integer or float >= 12 is passed to the constructor then it is
used as the `.ps` attribute, which is for most common piano notes, the
same as a MIDI number:
Expand Down Expand Up @@ -1830,11 +1830,12 @@ def __init__(self,
# 5% of pitch creation time; it'll be created in a sec anyhow
self._microtone: Microtone | None = None

# CA, Q: should this remain an attribute or only refer to value in defaults?
# MSC A: no, it's a useful attribute for cases such as scales where if there are
# no octaves we give a defaultOctave higher than the previous
# (MSC 12 years later: maybe Chris was right...)
self.defaultOctave: int = defaults.pitchOctave
# # CA, Q: should this remain an attribute or only refer to value in defaults?
# # MSC A: no, it's a useful attribute for cases such as scales where if there are
# # no octaves we give a defaultOctave higher than the previous
# # MSC 12 years later: maybe Chris was right...
# self.defaultOctave: int = defaults.pitchOctave
# # MSC: even later: Chris Ariza was right
self._octave: int | None = None

# if True, accidental is not known; is determined algorithmically
Expand Down Expand Up @@ -1919,7 +1920,6 @@ def __eq__(self, other):
>>> d = pitch.Pitch('d-4')
>>> b == d
False
'''
if other is None:
return False
Expand All @@ -1946,11 +1946,13 @@ def __deepcopy__(self, memo):
new = Pitch.__new__(Pitch)
for k in self.__dict__:
v = getattr(self, k, None)
if k in ('_step', '_overridden_freq440', 'defaultOctave',
if k in ('_step', '_overridden_freq440',
'_octave', 'spellingIsInferred'):
setattr(new, k, v)
elif k == '_client':
setattr(new, k, None)
elif v is None: # common -- save time over deepcopy.
setattr(new, k, None)
else:
setattr(new, k, copy.deepcopy(v, memo))
return new
Expand Down Expand Up @@ -2465,7 +2467,7 @@ def ps(self):
>>> d.ps
63.0
>>> d.defaultOctave = 5
>>> d.octave = 5
>>> d.ps
75.0
Expand All @@ -2489,9 +2491,6 @@ def ps(self):
The property is called when self.step, self.octave
or self.accidental are changed.
Should be called when .defaultOctave is changed if octave is None,
but isn't yet.
'''
step = self._step
ps = float(((self.implicitOctave + 1) * 12) + STEPREF[step])
Expand Down Expand Up @@ -3078,7 +3077,7 @@ def implicitOctave(self) -> int:
Cannot be set. Instead, just change the `.octave` of the pitch
'''
if self.octave is None:
return self.defaultOctave
return defaults.pitchOctave
else:
return self.octave

Expand Down
4 changes: 2 additions & 2 deletions music21/scale/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,10 @@ def fixDefaultOctaveForPitchList(pitchList):
for p in pitchList:
if p.octave is None:
if lastPs > p.ps:
p.defaultOctave = lastOctave
p.octave = lastOctave
while lastPs > p.ps:
lastOctave += 1
p.defaultOctave = lastOctave
p.octave = lastOctave

lastPs = p.ps
lastOctave = p.implicitOctave
Expand Down
2 changes: 1 addition & 1 deletion music21/voiceLeading.py
Original file line number Diff line number Diff line change
Expand Up @@ -2029,7 +2029,7 @@ class ThreeNoteLinearSegment(NNoteLinearSegment):
>>> ex2 = voiceLeading.ThreeNoteLinearSegment('a', 'b', 'c')
>>> ex2.n1
<music21.note.Note A>
>>> ex2.n1.pitch.defaultOctave
>>> defaults.pitchOctave
4
'''
Expand Down

0 comments on commit e0983db

Please sign in to comment.