Repository: cuthbertLab/music21 (python)

Issue:
makeTies in makeNotation failing with end split
<!-- Version of music21:  print(music21.__version__) -->
**music21 version**

`8.0alpha master`   <!-- replace with actual version -->


**Problem summary**
<!-- Briefly: what undesired thing happens when what action is taken? -->

makeTies is supposed to be able to create new measures to deal w/ long notes extending beyond the final measure, and works fine when called separately but fails when called in makeNotation

**Steps to reproduce**

```
p = stream.Part()
m = stream.Measure(number=1)
m.append(meter.TimeSignature('4/4'))
m.append(note.Note(type='breve'))
p.append(m)
p.makeNotation().show('text', addEndTimes=True)
p.makeTies().show('text', addEndTimes=True)
```

**Expected vs. actual behavior**
<!-- Consider annotating the output produced by a function -->
*Expected*: both show 'text' will have two measures.

*Actual*:
```
>>> p.makeNotation().show('text', addEndTimes=True)
{0.0 - 4.0} <music21.stream.Measure 1 offset=0.0>
    {0.0 - 0.0} <music21.meter.TimeSignature 4/4>
    {0.0 - 4.0} <music21.note.Note C>

>>> p.makeTies().show('text', addEndTimes=True)
{0.0 - 4.0} <music21.stream.Measure 1 offset=0.0>
    {0.0 - 0.0} <music21.meter.TimeSignature 4/4>
    {0.0 - 4.0} <music21.note.Note C>
{4.0 - 8.0} <music21.stream.Measure 2 offset=4.0>
    {0.0 - 4.0} <music21.note.Note C>
``` 


**More information**
<!-- If relevant: OS, suggested fix, attempted workarounds -->
OS: macOS

<!-- Note: only Mac and Windows are directly supported by music21 staff.  
     Bug reports that are specific to other OSes w/o a PR will be closed
     unless the reporter is willing to contribute a fix.
 -->


Pull request description:
makeTies within makeNotation; getTimeSignatures recurse
Fixes #1345 

One more bug (duplicate measure being put into stream) emerging but seems to be only partly related.  Might try to fix within this PR or open a new one.

See also new comment on #866 

Patch:
diff --git a/music21/musicxml/m21ToXml.py b/music21/musicxml/m21ToXml.py
index 00553fe8c..02b703cf6 100644
--- a/music21/musicxml/m21ToXml.py
+++ b/music21/musicxml/m21ToXml.py
@@ -746,7 +746,10 @@ class GeneralObjectExporter:
         if 0 < n.quarterLength <= 6.0:
             new_part.insert(0, meter.bestTimeSignature(new_part))
         stream.makeNotation.makeMeasures(
-            new_part, inPlace=True, refStreamOrTimeRange=[0, nCopy.quarterLength])
+            new_part,
+            inPlace=True,
+            refStreamOrTimeRange=[0, nCopy.quarterLength]
+        )
         stream.makeNotation.makeTupletBrackets(new_part, inPlace=True)
         return self.fromPart(new_part)
 
@@ -1624,18 +1627,9 @@ class ScoreExporter(XMLExporterBase, PartStaffExporterMixin):
         <music21.meter.TimeSignature 4/4>
         '''
         s = self.stream
-        # search context probably should always be True here
-        # to search container first, we need a non-flat version
-        # searching a flattened version, we will get contained and non-container
-        # this meter  stream is passed to makeNotation()
         meterStream = s.getTimeSignatures(searchContext=False,
-                                          sortByCreationTime=False, returnDefault=False)
-        # environLocal.printDebug(['setMeterStream: post meterStream search',
-        #                meterStream, meterStream[0]])
-        if not meterStream:
-            # note: this will return a default if no meters are found
-            meterStream = s.flatten().getTimeSignatures(searchContext=False,
-                                                        sortByCreationTime=True, returnDefault=True)
+                                          sortByCreationTime=False,
+                                          returnDefault=True)
         self.meterStream = meterStream
 
     def setScoreLayouts(self):
diff --git a/music21/stream/base.py b/music21/stream/base.py
index 39ad6929b..e0dcc1ba5 100644
--- a/music21/stream/base.py
+++ b/music21/stream/base.py
@@ -5257,29 +5257,123 @@ class Stream(core.StreamCore, t.Generic[M21ObjType]):
     def getTimeSignatures(self, *,
                           searchContext=True,
                           returnDefault=True,
+                          recurse=True,
                           sortByCreationTime=True):
         '''
         Collect all :class:`~music21.meter.TimeSignature` objects in this stream.
         If no TimeSignature objects are defined, get a default (4/4 or whatever
         is defined in the defaults.py file).
 
-        >>> a = stream.Stream()
-        >>> b = meter.TimeSignature('3/4')
-        >>> a.insert(b)
-        >>> a.repeatInsert(note.Note('C#'), list(range(10)))
-        >>> c = a.getTimeSignatures()
-        >>> len(c) == 1
+        >>> s = stream.Part(id='changingMeter')
+        >>> s.repeatInsert(note.Note('C#'), list(range(11)))
+
+        >>> threeFour = meter.TimeSignature('3/4')
+        >>> s.insert(0.0, threeFour)
+        >>> twoTwo = meter.TimeSignature('2/2')
+        >>> s.insert(3.0, twoTwo)
+        >>> tsStream = s.getTimeSignatures()
+        >>> tsStream.derivation.method
+        'getTimeSignatures'
+
+        >>> tsStream
+        <music21.stream.Part changingMeter>
+        >>> tsStream.show('text')
+        {0.0} <music21.meter.TimeSignature 3/4>
+        {3.0} <music21.meter.TimeSignature 2/2>
+
+        The contents of the time signature stream are the original, not copies
+        of the original:
+
+        >>> tsStream[0] is threeFour
         True
+
+        Many time signatures are found within measures, so this method will find
+        them also and place them at the appropriate point within the overall Stream.
+
+        N.B. if there are different time signatures for different parts, this method
+        will not distinguish which parts use which time signatures.
+
+        >>> sm = s.makeMeasures()
+        >>> sm.show('text')
+        {0.0} <music21.stream.Measure 1 offset=0.0>
+            {0.0} <music21.clef.TrebleClef>
+            {0.0} <music21.meter.TimeSignature 3/4>
+            {0.0} <music21.note.Note C#>
+            {1.0} <music21.note.Note C#>
+            {2.0} <music21.note.Note C#>
+        {3.0} <music21.stream.Measure 2 offset=3.0>
+            {0.0} <music21.meter.TimeSignature 2/2>
+            {0.0} <music21.note.Note C#>
+            {1.0} <music21.note.Note C#>
+            {2.0} <music21.note.Note C#>
+            {3.0} <music21.note.Note C#>
+        {7.0} <music21.stream.Measure 3 offset=7.0>
+            {0.0} <music21.note.Note C#>
+            {1.0} <music21.note.Note C#>
+            {2.0} <music21.note.Note C#>
+            {3.0} <music21.note.Note C#>
+            {4.0} <music21.bar.Barline type=final>
+
+        >>> tsStream2 = sm.getTimeSignatures()
+        >>> tsStream2.show('text')
+        {0.0} <music21.meter.TimeSignature 3/4>
+        {3.0} <music21.meter.TimeSignature 2/2>
+
+        If you do not want this recursion, set recurse=False
+
+        >>> len(sm.getTimeSignatures(recurse=False, returnDefault=False))
+        0
+
+        We set returnDefault=False here, because otherwise a default time signature
+        of 4/4 is returned:
+
+        >>> sm.getTimeSignatures(recurse=False)[0]
+        <music21.meter.TimeSignature 4/4>
+
+        Note that a measure without any time signature can still find a context TimeSignature
+        with this method so long as searchContext is True (as by default):
+
+        >>> m3 = sm.measure(3)
+        >>> m3.show('text')
+        {0.0} <music21.note.Note C#>
+        {1.0} <music21.note.Note C#>
+        {2.0} <music21.note.Note C#>
+        {3.0} <music21.note.Note C#>
+        {4.0} <music21.bar.Barline type=final>
+
+        >>> m3.getTimeSignatures()[0]
+        <music21.meter.TimeSignature 2/2>
+
+        The oldest context for the measure will be used unless sortByCreationTime is False, in which
+        case the typical order of context searching will be used.
+
+        >>> p2 = stream.Part()
+        >>> p2.insert(0, meter.TimeSignature('1/1'))
+        >>> p2.append(m3)
+        >>> m3.getTimeSignatures()[0]
+        <music21.meter.TimeSignature 2/2>
+
+        If searchContext is False then the default will be returned (which is somewhat
+        acceptable here, since there are 4 quarter notes in the measure) but not generally correct:
+
+        >>> m3.getTimeSignatures(searchContext=False)[0]
+        <music21.meter.TimeSignature 4/4>
+
+
+        Changed in v.8: time signatures within recursed streams are found by default.
+            Added recurse. Removed option for recurse=False and still getting the
+            first time signature in the first measure.  This was wholly inconsistent.
         '''
         # even if this is a Measure, the TimeSignature in the Stream will be
         # found
-        post = self.getElementsByClass(meter.TimeSignature).stream()
+        if recurse:
+            post = self[meter.TimeSignature].stream()
+        else:
+            post = self.getElementsByClass(meter.TimeSignature).stream()
+        post.derivation.method = 'getTimeSignatures'
 
         # search activeSite Streams through contexts
         if not post and searchContext:
-            # returns a single value
-            post = self.cloneEmpty(derivationMethod='getTimeSignatures')
-
             # sort by time to search the most recent objects
             obj = self.getContextByClass('TimeSignature', sortByCreationTime=sortByCreationTime)
             # obj = self.previous(meter.TimeSignature)
@@ -5287,14 +5381,6 @@ class Stream(core.StreamCore, t.Generic[M21ObjType]):
             if obj is not None:
                 post.append(obj)
 
-        # if there is no timeSignature, we will look at any stream at offset 0:
-        if not post:
-            streamsAtStart = self.getElementsByOffset(0.0).getElementsByClass('Stream')
-            for s in streamsAtStart:
-                tss = s.getElementsByOffset(0.0).getElementsByClass(meter.TimeSignature)
-                for ts in tss:
-                    post.append(ts)
-
         # get a default and/or place default at zero if nothing at zero
         if returnDefault:
             if not post or post[0].offset > 0.0:
@@ -5308,11 +5394,28 @@ class Stream(core.StreamCore, t.Generic[M21ObjType]):
                        *,
                        searchActiveSite=True,
                        returnDefault=True,
-                       recurse=False) -> Stream[instrument.Instrument]:
+                       recurse=True) -> Stream[instrument.Instrument]:
         '''
-        Search this stream or activeSite streams for
+        Search this stream (and, by default, its subStreams) or activeSite streams for
         :class:`~music21.instrument.Instrument` objects, and return a new stream
-        containing them. Otherwise, return a Stream containing a single default `Instrument`.
+        containing them.
+
+        >>> m1 = stream.Measure([meter.TimeSignature('4/4'),
+        ...                      instrument.Clarinet(),
+        ...                      note.Note('C5', type='whole')])
+        >>> m2 = stream.Measure([instrument.BassClarinet(),
+        ...                      note.Note('C3', type='whole')])
+        >>> p = stream.Part([m1, m2])
+        >>> instruments = p.getInstruments()
+        >>> instruments
+        <music21.stream.Part 0x112ac26e0>
+
+        >>> instruments.show('text')
+        {0.0} <music21.instrument.Clarinet 'Clarinet'>
+        {4.0} <music21.instrument.BassClarinet 'Bass clarinet'>
+
+        If there are no instruments, returns a Stream containing a single default `Instrument`,
+        unless returnDefault is False.
 
         >>> p = stream.Part()
         >>> m = stream.Measure([note.Note()])
@@ -5322,18 +5425,22 @@ class Stream(core.StreamCore, t.Generic[M21ObjType]):
         >>> defaultInst
         <music21.instrument.Instrument ': '>
 
-        Insert the default instrument into the part:
+        Insert an instrument into the Part (not the Measure):
 
-        >>> p.insert(0, defaultInst)
+        >>> p.insert(0, instrument.Koto())
 
-        Searching the measure will find it only if the measure's active site is searched:
+        Searching the measure will find this instrument only if the measure's activeSite is
+        searched, as it is by default:
 
-        >>> search1 = p.measure(1).getInstruments(searchActiveSite=False, returnDefault=False)
-        >>> search1.first() is None
-        True
-        >>> search2 = p.measure(1).getInstruments(searchActiveSite=True, returnDefault=False)
-        >>> search2.first() is defaultInst
-        True
+        >>> searchActiveSite = p.measure(1).getInstruments()
+        >>> searchActiveSite.first()
+        <music21.instrument.Koto 'Koto'>
+
+        >>> searchNaive = p.measure(1).getInstruments(searchActiveSite=False, returnDefault=False)
+        >>> len(searchNaive)
+        0
+
+        Changed in v.8: recurse is True by default.
         '''
         instObj = None
 
@@ -5487,7 +5594,7 @@ class Stream(core.StreamCore, t.Generic[M21ObjType]):
             quickSearch = False
 
         inversionDNN = inversionNote.pitch.diatonicNoteNum
-        for n in returnStream.recurse().getElementsByClass(note.NotRest):
+        for n in returnStream[note.NotRest]:
             n.pitch.diatonicNoteNum = (2 * inversionDNN) - n.pitch.diatonicNoteNum
             if quickSearch:  # use previously found
                 n.pitch.accidental = ourKey.accidentalByStep(n.pitch.step)
@@ -6580,7 +6687,7 @@ class Stream(core.StreamCore, t.Generic[M21ObjType]):
             # definitely do NOT put a constrainingSpannerBundle constraint
         )
         # only use inPlace arg on first usage
-        if not self.hasMeasures():
+        if not returnStream.hasMeasures():
             # only try to make voices if no Measures are defined
             returnStream.makeVoices(inPlace=True, fillGaps=True)
             # if this is not inPlace, it will return a newStream; if
@@ -6592,20 +6699,17 @@ class Stream(core.StreamCore, t.Generic[M21ObjType]):
                 inPlace=True,
                 bestClef=bestClef)
 
-        measureStream: Stream[Measure] = returnStream.getElementsByClass(Measure).stream()
-        # environLocal.printDebug(['Stream.makeNotation(): post makeMeasures,
-        #   length', len(returnStream)])
-        if not measureStream:
-            raise StreamException(
-                f'no measures found in stream with {len(self)} elements')
+            if not returnStream.hasMeasures():
+                raise StreamException(
+                    f'no measures found in stream with {len(self)} elements')
 
         # for now, calling makeAccidentals once per measures
         # pitches from last measure are passed
         # this needs to be called before makeTies
         # note that this functionality is also placed in Part
-        if not measureStream.streamStatus.accidentals:
+        if not returnStream.streamStatus.accidentals:
             makeNotation.makeAccidentalsInMeasureStream(
-                measureStream,
+                returnStream,
                 pitchPast=pitchPast,
                 pitchPastMeasure=pitchPastMeasure,
                 useKeySignature=useKeySignature,
@@ -6616,12 +6720,12 @@ class Stream(core.StreamCore, t.Generic[M21ObjType]):
                 cautionaryNotImmediateRepeat=cautionaryNotImmediateRepeat,
                 tiePitchSet=tiePitchSet)
 
-        measureStream.makeTies(meterStream, inPlace=True)
+        makeNotation.makeTies(returnStream, meterStream=meterStream, inPlace=True)
 
         # measureStream.makeBeams(inPlace=True)
-        if not measureStream.streamStatus.beams:
+        if not returnStream.streamStatus.beams:
             try:
-                measureStream.makeBeams(inPlace=True)
+                makeNotation.makeBeams(returnStream, inPlace=True)
             except meter.MeterException as me:
                 environLocal.warn(['skipping makeBeams exception', me])
 
@@ -6629,7 +6733,7 @@ class Stream(core.StreamCore, t.Generic[M21ObjType]):
         # makeBeams was causing the duration's tuplet to lose its type setting
         # check for tuplet brackets one measure at a time
         # this means that they will never extend beyond one measure
-        for m in measureStream:
+        for m in returnStream.getElementsByClass(Measure):
             if not m.streamStatus.tuplets:
                 makeNotation.makeTupletBrackets(m, inPlace=True)
 
@@ -9374,23 +9478,29 @@ class Stream(core.StreamCore, t.Generic[M21ObjType]):
         '''
         Return a boolean value showing if this Stream contains Measures.
 
-
-        >>> s = stream.Stream()
-        >>> s.repeatAppend(note.Note(), 8)
-        >>> s.hasMeasures()
+        >>> p = stream.Part()
+        >>> p.repeatAppend(note.Note(), 8)
+        >>> p.hasMeasures()
         False
-        >>> s.makeMeasures(inPlace=True)
-        >>> len(s.getElementsByClass(stream.Measure))
+        >>> p.makeMeasures(inPlace=True)
+        >>> len(p.getElementsByClass(stream.Measure))
         2
-        >>> s.hasMeasures()
+        >>> p.hasMeasures()
         True
+
+        Only returns True if the immediate Stream has measures, not if there are nested measures:
+
+        >>> sc = stream.Score()
+        >>> sc.append(p)
+        >>> sc.hasMeasures()
+        False
         '''
         if 'hasMeasures' not in self._cache or self._cache['hasMeasures'] is None:
             post = False
             # do not need to look in endElements
             for obj in self._elements:
                 # if obj is a Part, we have multi-parts
-                if getattr(obj, 'isMeasure', False):
+                if isinstance(obj, Measure):
                     post = True
                     break  # only need one
             self._cache['hasMeasures'] = post
diff --git a/music21/stream/makeNotation.py b/music21/stream/makeNotation.py
index 05969b841..0e507292a 100644
--- a/music21/stream/makeNotation.py
+++ b/music21/stream/makeNotation.py
@@ -449,7 +449,7 @@ def makeMeasures(
     # may need to look in activeSite if no time signatures are found
     if meterStream is None:
         # get from this Stream, or search the contexts
-        meterStream = srcObj.flatten().getTimeSignatures(
+        meterStream = srcObj.getTimeSignatures(
             returnDefault=True,
             searchContext=False,
             sortByCreationTime=False
@@ -994,8 +994,7 @@ def makeTies(
 
     Note that this method assumes that there is appropriate space in the
     next Measure: this will not shift Note objects, but instead allocate
-    them evenly over barlines. Generally, makeMeasures is called prior to
-    calling this method.
+    them evenly over barlines.
 
     If `inPlace` is True, this is done in-place;
     if `inPlace` is False, this returns a modified deep copy.
@@ -1194,59 +1193,39 @@ def makeTies(
         classFilterList = [classFilterList]
 
     # get measures from this stream
-    measureStream = returnObj.getElementsByClass(stream.Measure)
-    if not measureStream:
-        raise stream.StreamException(
-            'cannot process a stream without measures')
-
-    # environLocal.printDebug([
-    #    'makeTies() processing measureStream, length', measureStream,
-    #    len(measureStream)])
+    if not returnObj.hasMeasures():
+        raise stream.StreamException('cannot process a stream without measures')
 
     # may need to look in activeSite if no time signatures are found
     # presently searchContext is False to save time
     if meterStream is None:
         meterStream = returnObj.getTimeSignatures(sortByCreationTime=True,
                                                   searchContext=False)
+    elif not meterStream:
+        # an empty stream
+        ts = meter.TimeSignature(
+            f'{defaults.meterNumerator}/{defaults.meterDenominatorBeatType}'
+        )
+        meterStream.insert(0, ts)
 
     mCount = 0
-    lastTimeSignature = None
+    measureList = list(returnObj.getElementsByClass(stream.Measure))
 
-    while True:  # pylint: disable=too-many-nested-blocks
-        # TODO: find a way to avoid 'while True'
-        # update measureIterator on each iteration,
-        # as new measure may have been added to the returnObj stream
-        measureIterator = returnObj.getElementsByClass(stream.Measure)
-        if mCount >= len(measureIterator):
-            break  # reached the end of all measures available or added
+    while mCount < len(measureList):  # pylint: disable=too-many-nested-blocks
         # get the current measure to look for notes that need ties
-        m = measureIterator[mCount]
-        if m.timeSignature is not None:
-            lastTimeSignature = m.timeSignature
+        m = measureList[mCount]
+        activeTS = meterStream.getElementAtOrBefore(m.offset)
 
         # get next measure; we may not need it, but have it ready
-        if mCount + 1 < len(measureIterator):
-            mNext = measureIterator[mCount + 1]
+        if mCount + 1 < len(measureList):
+            mNext = measureList[mCount + 1]
             mNextAdd = False  # already present; do not append
         else:  # create a new measure
             mNext = stream.Measure()
             # set offset to last offset plus total length
             mOffset = m.offset
-            if lastTimeSignature is not None:
-                mNext.offset = (mOffset
-                                + lastTimeSignature.barDuration.quarterLength)
-            else:
-                mNext.offset = mOffset
-            if not meterStream:  # in case no meters are defined
-                ts = meter.TimeSignature(
-                    f'{defaults.meterNumerator}/{defaults.meterDenominatorBeatType}'
-                )
-            else:  # get the last encountered meter
-                ts = meterStream.getElementAtOrBefore(mNext.offset)
-            # only copy and assign if not the same as the last
-            if (lastTimeSignature is not None
-                    and not lastTimeSignature.ratioEqual(ts)):
-                mNext.timeSignature = copy.deepcopy(ts)
+            mNext.offset = (mOffset
+                            + activeTS.barDuration.quarterLength)
             # increment measure number
             mNext.number = m.number + 1
             mNextAdd = True  # new measure, needs to be appended
@@ -1261,18 +1240,10 @@ def makeTies(
         # for each measure, go through each element and see if its
         # duration fits in the bar that contains it
 
+        mEnd = activeTS.barDuration.quarterLength
         # if there are voices, we must look at voice id values to only
         # connect ties to components in the same voice, assuming there
         # are voices in the next measure
-        if lastTimeSignature is not None:
-            mEnd = lastTimeSignature.barDuration.quarterLength
-        else:
-            possible_ts = m.getContextByClass(meter.TimeSignature)
-            if possible_ts is not None:
-                lastTimeSignature = possible_ts
-                mEnd = lastTimeSignature.barDuration.quarterLength
-            else:
-                mEnd = 4.0  # Default
         if m.hasVoices():
             bundle = m.voices
             mHasVoices = True
@@ -1297,14 +1268,15 @@ def makeTies(
                 if overshot <= 0:
                     continue
                 if eOffset >= mEnd:
-                    continue  # skip elements that extend past measure boundary.
+                    continue  # skip elements that begin past measure boundary.
+                    # TODO: put them entirely in the next measure.
                     # raise stream.StreamException(
                     #     'element (%s) has offset %s within a measure '
                     #     'that ends at offset %s' % (e, eOffset, mEnd))
 
-                qLenBegin = mEnd - eOffset
+                qLenWithinMeasure = mEnd - eOffset
                 e, eRemain = e.splitAtQuarterLength(
-                    qLenBegin,
+                    qLenWithinMeasure,
                     retainOrigin=True,
                     displayTiedAccidentals=displayTiedAccidentals
                 )
@@ -1345,6 +1317,8 @@ def makeTies(
                     #    'makeTies() inserting mNext into returnObj',
                     #    mNext])
                     returnObj.insert(mNext.offset, mNext)
+                    # need to make sure that the new measure is processed.
+                    measureList.append(mNext)
         mCount += 1
 
     for measure in returnObj.getElementsByClass(stream.Measure):
@@ -1647,7 +1621,7 @@ def makeAccidentalsInMeasureStream(
     tiePitchSet: t.Optional[t.Set[str]] = None
 ) -> None:
     '''
-    Makes accidentals in place on a stream consisting of only Measures.
+    Makes accidentals in place on a stream that contains Measures.
     Helper for Stream.makeNotation and Part.makeAccidentals.
 
     The function walks measures in order to update the values for the following keyword
@@ -1662,38 +1636,40 @@ def makeAccidentalsInMeasureStream(
         tiePitchSet
 
     Operates on the measures in place; make a copy first if this is not desired.
-    '''
-    if s.getElementsNotOfClass('Measure'):
-        raise ValueError(f'{s} must contain only Measures')
 
+    Changed in v8: the Stream may have other elements besides measures and the method
+        will still work.
+    '''
+    from music21.stream import Measure, Stream
     # bool values for useKeySignature are not helpful here
     # because we are definitely searching key signature contexts
     # only key.KeySignature values are interesting
     # but method arg is typed this way for backwards compatibility
+    ksLast: t.Union[bool, key.KeySignature] = False
+    ksLastDiatonic: t.List[str] = []
+
     if isinstance(useKeySignature, key.KeySignature):
         ksLast = useKeySignature
-    else:
-        ksLast = None
+        ksLastDiatonic = [p.name for p in ksLast.getScale().pitches]
 
-    for i, m in enumerate(s):
+    measuresOnly: t.List[Measure] = list(s.getElementsByClass(Measure))
+    for i, m in enumerate(measuresOnly):
         # if beyond the first measure, use the pitches from the last
         # measure for context (cautionary accidentals)
         # unless this measure has a key signature object
         if i > 0:
-            pitchPastMeasure = None
             if m.keySignature is None:
-                pitchPastMeasure = s[i - 1].pitches
+                pitchPastMeasure = measuresOnly[i - 1].pitches
             elif ksLast:
                 # If there is any key signature object to the left,
                 # just get the chromatic pitches from previous measure
                 # G-naturals in C major following G-flats in F major need cautionary
                 # G-naturals in C major following G-flats in Db major don't
-                ksLastDiatonic = [p.name for p in ksLast.getScale().pitches]
-                pitchPastMeasure = [p for p in s[i - 1].pitches
-                    if p.name not in ksLastDiatonic]
+                pitchPastMeasure = [p for p in measuresOnly[i - 1].pitches
+                                    if p.name not in ksLastDiatonic]
             # Get tiePitchSet from previous measure
             try:
-                previousNoteOrChord = s[i - 1][note.NotRest][-1]
+                previousNoteOrChord = measuresOnly[i - 1][note.NotRest][-1]
                 tiePitchSet = getTiePitchSet(previousNoteOrChord)
                 if tiePitchSet is not None and m.keySignature is not None:
                     # Get the diatonic pitches in this (new) key
@@ -1706,6 +1682,7 @@ def makeAccidentalsInMeasureStream(
 
         if m.keySignature is not None:
             ksLast = m.keySignature
+            ksLastDiatonic = [p.name for p in ksLast.getScale().pitches]
 
         m.makeAccidentals(
             pitchPast=pitchPast,
@@ -1720,6 +1697,8 @@ def makeAccidentalsInMeasureStream(
             cautionaryNotImmediateRepeat=cautionaryNotImmediateRepeat,
             tiePitchSet=tiePitchSet,
         )
+    if isinstance(s, Stream):
+        s.streamStatus.accidentals = True
 
 def iterateBeamGroups(
     s: StreamType,
@@ -1811,8 +1790,8 @@ def setStemDirectionForBeamGroups(
     if `setANewStems` is True (as by default), then even notes with stemDirection
     of 'unspecified' get a stemDirection.
 
-    Currently assumes that the clef does not change within a beam group.  This
-    assumption may change in the future.
+    The method currently assumes that the clef does not change within a beam group.  This
+    assumption may change in the future without notice.
 
     Operates in place.  Run `copy.deepcopy(s)` beforehand for a non-inPlace version.
 
@@ -2036,12 +2015,29 @@ class Test(unittest.TestCase):
         self.assertEqual(str(cm.exception),
             'meterStream is neither a Stream nor a TimeSignature!')
 
-    def testMakeAccidentalsInMeasureStreamException(self):
-        from music21 import converter
-        p = converter.parse(self.allaBreveBeamTest)
-        with self.assertRaises(ValueError) as cm:
-            makeAccidentalsInMeasureStream(p.measure(1))
-        self.assertIn('must contain only Measures', str(cm.exception))
+    def testMakeTiesChangingTimeSignatures(self):
+        '''
+        From a real-world failure.  Should not be
+        making ties in an example that starts with a short TS
+        but moves to a longer one and all is valid.
+        '''
+        from music21 import stream
+        p = stream.Part()
+        m1 = stream.Measure(number=1)
+        m1.insert(0, meter.TimeSignature('3/4'))
+        m1.insert(0, note.Note('C4', quarterLength=3.0))
+        m2 = stream.Measure(number=2)
+        m2.insert(0, meter.TimeSignature('6/1'))
+        m2.insert(0, note.Note('D4', quarterLength=24.0))
+        m3 = stream.Measure(number=3)
+        m3.insert(0, note.Note('E4', quarterLength=24.0))
+        p.append([m1, m2, m3])
+        pp = p.makeTies()
+        self.assertEqual(len(pp[stream.Measure]), 3)
+        self.assertEqual(pp[stream.Measure].first().notes.first().duration.quarterLength, 3.0)
+        self.assertEqual(pp[stream.Measure][1].notes.first().duration.quarterLength, 24.0)
+        self.assertEqual(len(pp[stream.Measure][2].notes), 1)
+        self.assertEqual(pp[stream.Measure][2].notes.first().duration.quarterLength, 24.0)
 
 
 # -----------------------------------------------------------------------------


Test patch:
diff --git a/music21/stream/tests.py b/music21/stream/tests.py
index 7e980b236..8971d2e09 100644
--- a/music21/stream/tests.py
+++ b/music21/stream/tests.py
@@ -4462,8 +4462,6 @@ class Test(unittest.TestCase):
         self.assertEqual(m1.keySignature.sharps, sharpsInKey)
 
     def testMakeTies(self):
-
-
         def collectAccidentalDisplayStatus(s_inner):
             post = []
             for e in s_inner.flatten().notesAndRests:
@@ -4533,6 +4531,30 @@ class Test(unittest.TestCase):
                           ('C#', None), ('C#', None)]
                          )
 
+    def testMakeTiesAddNewMeasure(self):
+        '''
+        Test that makeTies adds a new measure when the last note is too long,
+        both when called directly and when called from makeNotation
+        '''
+        p = Part()
+        m = Measure(number=1)
+        m.append(meter.TimeSignature('4/4'))
+        m.append(note.Note(type='breve'))
+        p.append(m)
+        p_makeTies = p.makeTies()
+        self.assertEqual(len(p_makeTies[Measure]), 2)
+        n1 = p_makeTies[Measure].first().notes.first()
+        n2 = p_makeTies[Measure].last().notes.first()
+        self.assertEqual(n1.duration.quarterLength, 4.0)
+        self.assertEqual(n1.duration.quarterLength, 4.0)
+        self.assertIsNotNone(n1.tie)
+        self.assertIsNotNone(n2.tie)
+        self.assertEqual(n1.tie.type, 'start')
+        self.assertEqual(n2.tie.type, 'stop')
+
+        p_makeNotation = p.makeNotation()
+        self.assertEqual(len(p_makeNotation[Measure]), 2)
+
     def testMeasuresAndMakeMeasures(self):
         s = converter.parse('tinynotation: 2/8 g8 e f g e f g a')
         sSub = s.measures(3, 3)
@@ -6567,6 +6589,7 @@ class Test(unittest.TestCase):
         s.insert(key.Key('Gb'))
         s.insert(0, note.Note('D-5'))
         s.insert(0, note.Note('D-4'))
+        self.assertFalse(s.haveAccidentalsBeenMade())
         post = s.makeNotation()  # makes voices, makes measures, makes accidentals
         self.assertEqual(len(post.recurse().getElementsByClass(Voice)), 2)
         self.assertTrue(post.haveAccidentalsBeenMade())