1# -*- coding: utf-8 -*-
2# ------------------------------------------------------------------------------
3# Name:         note.py
4# Purpose:      music21 classes for representing notes
5#
6# Authors:      Michael Scott Cuthbert
7#               Christopher Ariza
8#
9# Copyright:    Copyright © 2006-2019 Michael Scott Cuthbert and the music21 Project
10# License:      BSD, see license.txt
11# ------------------------------------------------------------------------------
12'''
13Classes and functions for creating Notes, Rests, and Lyrics.
14
15The :class:`~music21.pitch.Pitch` object is stored within,
16and used to configure, :class:`~music21.note.Note` objects.
17'''
18
19import copy
20import unittest
21
22from typing import Optional, List, Union, Tuple, Iterable
23
24from music21 import base
25from music21 import beam
26from music21 import common
27from music21 import duration
28from music21 import exceptions21
29from music21 import expressions
30from music21 import interval
31from music21 import pitch
32from music21 import prebase
33from music21 import style
34from music21 import tie
35from music21 import volume
36
37from music21 import environment
38environLocal = environment.Environment('note')
39
40noteheadTypeNames = (
41    'arrow down',
42    'arrow up',
43    'back slashed',
44    'circle dot',
45    'circle-x',
46    'circled',
47    'cluster',
48    'cross',
49    'diamond',
50    'do',
51    'fa',
52    'inverted triangle',
53    'la',
54    'left triangle',
55    'mi',
56    'none',
57    'normal',
58    'other',
59    're',
60    'rectangle',
61    'slash',
62    'slashed',
63    'so',
64    'square',
65    'ti',
66    'triangle',
67    'x',
68)
69
70stemDirectionNames = (
71    'double',
72    'down',
73    'noStem',
74    'none',
75    'unspecified',
76    'up',
77)
78
79def __dir__():
80    out = [n for n in globals() if not n.startswith('__') and not n.startswith('Test')]
81    for n in ('Optional', 'List', 'Union', 'Tuple', 'Iterable'):
82        out.remove(n)
83    out.remove('unittest')
84    out.remove('copy')
85    out.remove('_DOC_ORDER')
86    return out
87
88# -----------------------------------------------------------------------------
89class LyricException(exceptions21.Music21Exception):
90    pass
91
92
93class NoteException(exceptions21.Music21Exception):
94    pass
95
96
97class NotRestException(exceptions21.Music21Exception):
98    pass
99
100
101# ------------------------------------------------------------------------------
102SYLLABIC_CHOICES: List[Optional[str]] = [
103    None, 'begin', 'single', 'end', 'middle', 'composite',
104]
105
106
107class Lyric(prebase.ProtoM21Object, style.StyleMixin):
108    '''
109    An object representing a single Lyric as part of a note's .lyrics property.
110
111    The note.lyric property is a simple way of specifying a single lyric, but
112    Lyric objects are needed for working with multiple lyrics.
113
114    >>> l = note.Lyric(text='hello')
115    >>> l
116    <music21.note.Lyric number=1 syllabic=single text='hello'>
117
118    Music21 processes leading and following hyphens intelligently...
119
120    >>> l2 = note.Lyric(text='hel-')
121    >>> l2
122    <music21.note.Lyric number=1 syllabic=begin text='hel'>
123
124    ...unless applyRaw is set to True
125
126    >>> l3 = note.Lyric(number=3, text='hel-', applyRaw=True)
127    >>> l3
128    <music21.note.Lyric number=3 syllabic=single text='hel-'>
129
130    Lyrics have four properties: text, number, identifier, syllabic (single,
131    begin, middle, end, or (not in musicxml) composite)
132
133    >>> l3.text
134    'hel-'
135
136    >>> l3.number
137    3
138
139    >>> l3.syllabic
140    'single'
141
142    Note musicXML only supports one 'identifier' attribute which is called
143    'number' but which can be a number or a descriptive identifier like
144    'part2verse1.' To preserve lyric ordering, music21 stores a number and a
145    descriptive identifier separately. The descriptive identifier is by default
146    the same as the number, but in cases where a string identifier is present,
147    it will be different.
148
149    Both music21 and musicxml support multiple `Lyric` objects in the same stanza,
150    for instance, if there is an elision on a note then multiple lyrics with
151    different syllabics can appear on a single note.  In music21 these are supported
152    by setting .components into a list of `Lyric` object.  For instance in
153    the madrigal "Il bianco e dolce cigno", the "co" and "e" of "bianco e"
154    are elided into a single lyric:
155
156    >>> bianco = note.Lyric()
157    >>> co = note.Lyric('co', syllabic='end')
158    >>> e = note.Lyric('e', syllabic='single')
159    >>> bianco.components = [co, e]
160    >>> bianco.isComposite
161    True
162    >>> bianco.text
163    'co e'
164    >>> bianco.syllabic
165    'composite'
166    >>> e.elisionBefore = '_'
167    >>> bianco.text
168    'co_e'
169
170    >>> [component.syllabic for component in bianco.components]
171    ['end', 'single']
172
173    Custom elision elements for composite components will be supported later.
174
175    New in v6.7 -- composite components, elisionBefore
176    '''
177    _styleClass = style.TextStylePlacement
178    # CLASS VARIABLES #
179
180    __slots__ = (
181        '_identifier',
182        '_number',
183        '_syllabic',
184        '_text',
185        'components',
186        'elisionBefore',
187    )
188
189    # INITIALIZER #
190
191    def __init__(self, text=None, number=1, **kwargs):
192        super().__init__()
193        self._identifier: Optional[str] = None
194        self._number: Optional[int] = None
195        self._text: Optional[str] = None
196        self._syllabic = None
197        self.components: Optional[List['music21.note.Lyric']] = None
198        self.elisionBefore = ' '
199
200        applyRaw = kwargs.get('applyRaw', False)
201
202        # these are set by setTextAndSyllabic
203        if text is not None:
204            self.setTextAndSyllabic(text, applyRaw)
205
206        # given as begin, middle, end, or single
207        if 'syllabic' in kwargs:
208            self.syllabic = kwargs['syllabic']
209
210        self.number = number
211        self.identifier = kwargs.get('identifier', None)
212
213    # PRIVATE METHODS #
214
215    def _reprInternal(self):
216        out = ''
217        if self.number is not None:
218            out += f'number={self.number} '
219        if self._identifier is not None:
220            out += f'identifier={self.identifier!r} '
221        if self.syllabic is not None:
222            out += f'syllabic={self.syllabic} '
223        if self.text is not None:
224            out += f'text={self.text!r} '
225        return out
226
227    # PUBLIC PROPERTIES #
228    @property
229    def isComposite(self) -> bool:
230        '''
231        Returns True if this Lyric has composite elements,
232        for instance, is multiple lyrics placed together.
233        '''
234        return bool(self.components)
235
236    @property
237    def text(self) -> Optional[str]:
238        '''
239        Gets or sets the text of the lyric.  For composite lyrics, set
240        the text of individual components instead of setting the text here.
241
242        Setting the text of a composite lyric wipes out the components
243        '''
244        if not self.isComposite:
245            return self._text
246        else:
247            text_out = self.components[0].text
248            if text_out is None:
249                text_out = ''
250            for component in self.components[1:]:
251                componentText = component.text if component.text is not None else ''
252                text_out += component.elisionBefore + componentText
253            return text_out
254
255    @text.setter
256    def text(self, newText: Optional[str]):
257        if self.isComposite:
258            self.components = None
259        self._text = newText
260
261    @property
262    def syllabic(self) -> Optional[str]:
263        '''
264        Returns or sets the syllabic property of a lyric.
265
266        >>> fragment = note.Lyric('frag', syllabic='begin')
267        >>> fragment.syllabic
268        'begin'
269        >>> fragment.rawText
270        'frag-'
271        >>> fragment.syllabic = 'end'
272        >>> fragment.rawText
273        '-frag'
274
275        Illegal values raise a LyricException
276
277        >>> fragment.syllabic = 'slide'
278        Traceback (most recent call last):
279        music21.note.LyricException: Syllabic value 'slide' is not in
280            note.SYLLABIC_CHOICES, namely:
281            [None, 'begin', 'single', 'end', 'middle', 'composite']
282        '''
283        if self.isComposite:
284            return 'composite'
285        else:
286            return self._syllabic
287
288
289    @syllabic.setter
290    def syllabic(self, newSyllabic):
291        if newSyllabic not in SYLLABIC_CHOICES:
292            raise LyricException(
293                f'Syllabic value {newSyllabic!r} is not in '
294                + f'note.SYLLABIC_CHOICES, namely: {SYLLABIC_CHOICES}'
295            )
296        self._syllabic = newSyllabic
297
298    @property
299    def identifier(self) -> str:
300        '''
301        By default, this is the same as self.number. However, if there is a
302        descriptive identifier like 'part2verse1', it is stored here and
303        will be different from self.number. When converting to musicXML,
304        this property will be stored in the lyric 'number' attribute which
305        can store a number or a descriptive identifier but not both.
306
307        >>> l = note.Lyric()
308        >>> l.number = 12
309        >>> l.identifier
310        12
311
312        >>> l.identifier = 'Rainbow'
313        >>> l.identifier
314        'Rainbow'
315        '''
316        if self._identifier is None:
317            return self._number
318        else:
319            return self._identifier
320
321    @identifier.setter
322    def identifier(self, value: str):
323        self._identifier = value
324
325    @property
326    def rawText(self) -> str:
327        '''
328        returns the text of the syllable with '-' etc.
329
330        >>> l = note.Lyric('hel-')
331        >>> l.text
332        'hel'
333        >>> l.rawText
334        'hel-'
335
336        >>> l = note.Lyric('lo', syllabic='end')
337        >>> l.rawText
338        '-lo'
339
340        >>> l = note.Lyric('-ti-')
341        >>> l.rawText
342        '-ti-'
343
344        >>> l = note.Lyric('bye')
345        >>> l.rawText
346        'bye'
347
348        Composite lyrics take their endings from the first and last components:
349
350        >>> composite = note.Lyric()
351        >>> co = note.Lyric('co', syllabic='end')
352        >>> e = note.Lyric('e', syllabic='single')
353        >>> e.elisionBefore = '_'
354        >>> composite.components = [co, e]
355        >>> composite.rawText
356        '-co_e'
357        >>> e.syllabic = 'middle'
358        >>> composite.rawText
359        '-co_e-'
360        '''
361        text = self.text
362        if not self.isComposite:
363            syllabic = self.syllabic
364            if syllabic == 'begin':
365                return text + '-'
366            elif syllabic == 'middle':
367                return '-' + text + '-'
368            elif syllabic == 'end':
369                return '-' + text
370            else:
371                return text
372        else:
373            firstSyllabic = self.components[0].syllabic
374            lastSyllabic = self.components[-1].syllabic
375            if firstSyllabic in ['middle', 'end']:
376                text = '-' + text
377            if lastSyllabic in ['begin', 'middle']:
378                text += '-'
379            return text
380
381
382    @rawText.setter
383    def rawText(self, t):
384        self.setTextAndSyllabic(t, applyRaw=True)
385
386    @property
387    def number(self) -> int:
388        '''
389        This stores the number of the lyric (which determines the order
390        lyrics appear in the score if there are multiple lyrics). Unlike
391        the musicXML lyric number attribute, this value must always be a
392        number; lyric order is always stored in this form. Descriptive
393        identifiers like 'part2verse1' which can be found in the musicXML
394        lyric number attribute should be stored in self.identifier.
395
396        >>> l = note.Lyric('Hi')
397        >>> l.number = 5
398        >>> l.number
399        5
400        >>> l.number = None
401        Traceback (most recent call last):
402        music21.note.LyricException: Number best be number
403        '''
404        return self._number
405
406    @number.setter
407    def number(self, value: int) -> None:
408        if not common.isNum(value):
409            raise LyricException('Number best be number')
410        self._number = value
411
412    # PUBLIC METHODS #
413    def setTextAndSyllabic(self, rawText: str, applyRaw: bool = False) -> None:
414        '''
415        Given a setting for rawText and applyRaw,
416        sets the syllabic type for a lyric based on the rawText.  Useful for
417        parsing raw text from, say, an OMR score.  Or just to quickly set text
418        and syllabic.
419
420        >>> l = note.Lyric()
421        >>> l.setTextAndSyllabic('hel-')
422        >>> l.text
423        'hel'
424        >>> l.syllabic
425        'begin'
426        >>> l.setTextAndSyllabic('-lo')
427        >>> l.text
428        'lo'
429        >>> l.syllabic
430        'end'
431        >>> l.setTextAndSyllabic('the')
432        >>> l.text
433        'the'
434        >>> l.syllabic
435        'single'
436
437        If applyRaw is True then this will assume you actually want hyphens
438        in the text, and if syllabic is None, sets it to 'single'
439
440        >>> l = note.Lyric()
441        >>> l.setTextAndSyllabic('hel-', applyRaw=True)
442        >>> l.text
443        'hel-'
444        >>> l.syllabic
445        'single'
446
447        If applyRaw is True, other syllabic settings except None are retained
448
449        >>> l.syllabic = 'begin'
450        >>> l.setTextAndSyllabic('-lo', applyRaw=True)
451        >>> l.text
452        '-lo'
453        >>> l.syllabic
454        'begin'
455
456        This method wipes out components.
457        '''
458        # do not want to do this unless we are sure this is not a string
459        # possible might alter unicode or other string-like representations
460        if not isinstance(rawText, str):
461            rawText = str(rawText)
462
463        # check for hyphens
464        if applyRaw is False and rawText.startswith('-') and not rawText.endswith('-'):
465            self.text = rawText[1:]
466            self.syllabic = 'end'
467        elif applyRaw is False and not rawText.startswith('-') and rawText.endswith('-'):
468            self.text = rawText[:-1]
469            self.syllabic = 'begin'
470        elif applyRaw is False and rawText.startswith('-') and rawText.endswith('-'):
471            self.text = rawText[1:-1]
472            self.syllabic = 'middle'
473        else:  # assume single
474            self.text = rawText
475            if self.syllabic is None or not applyRaw:
476                self.syllabic = 'single'
477
478
479# ------------------------------------------------------------------------------
480
481
482class GeneralNote(base.Music21Object):
483    '''
484    A GeneralNote object is the base class object
485    for the :class:`~music21.note.Note`,
486    :class:`~music21.note.Rest`, :class:`~music21.chord.Chord`,
487    and related objects.
488
489    Keywords can be passed to
490    a GeneralNote which are then passed to the
491    underlying :class:`~music21.duration.Duration`.
492    These keywords might be listed like
493    type='16th', dots=2 etc. to create a
494    double-dotted sixteenth note.
495
496    In almost every circumstance, you should
497    create note.Note() or note.Rest() or chord.Chord()
498    objects directly, and not use this underlying
499    structure.
500
501
502    >>> gn = note.GeneralNote(type='16th', dots=2)
503    >>> gn.quarterLength
504    0.4375
505    '''
506    isNote = False
507    isRest = False
508    isChord = False
509    _styleClass = style.NoteStyle
510
511    # define order to present names in documentation; use strings
512    _DOC_ORDER = ['duration', 'quarterLength']
513    # documentation for all attributes (not properties or methods)
514    _DOC_ATTR = {
515        'isChord': 'Boolean read-only value describing if this object is a Chord.',
516        'lyrics': 'A list of :class:`~music21.note.Lyric` objects.',
517        'tie': 'either None or a :class:`~music21.note.Tie` object.',
518        'expressions': '''a list of expressions (such
519            as :class:`~music21.expressions.Fermata`, etc.)
520            that are stored on this Note.''',
521        'articulations': '''a list of articulations such
522            as :class:`~music21.articulations.Staccato`, etc.) that are stored on this Note.'''
523    }
524
525    def __init__(self, *arguments, **keywords):
526        if 'duration' not in keywords:
527            # ensure music21base not automatically create a duration.
528            if not keywords:
529                tempDuration = duration.Duration(1.0)
530            else:
531                tempDuration = duration.Duration(**keywords)
532                # only apply default if components are empty
533                # looking at currentComponents so as not to trigger
534                # _updateComponents
535                if (tempDuration.quarterLength == 0
536                        and not tempDuration.currentComponents()):
537                    tempDuration.quarterLength = 1.0
538        else:
539            tempDuration = keywords['duration']
540        # this sets the stored duration defined in Music21Object
541        super().__init__(duration=tempDuration)
542
543        self.lyrics: List[Lyric] = []  # a list of lyric objects
544        self.expressions = []
545        self.articulations = []
546
547        if 'lyric' in keywords and keywords['lyric'] is not None:
548            self.addLyric(keywords['lyric'])
549
550        # note: Chords handle ties differently
551        self.tie = None  # store a Tie object
552
553    def __eq__(self, other):
554        '''
555        General Note objects are equal if their durations are equal and
556        they have the same articulation and expression classes (in any order)
557        and their ties are equal.
558        '''
559
560        if other is None or not isinstance(other, GeneralNote):
561            return NotImplemented
562        # checks type, dots, tuplets, quarterLength, uses Pitch.__eq__
563        if self.duration != other.duration:
564            return False
565        # articulations are a list of Articulation objects
566        # converting to sets produces ordered cols that remove duplicate
567        # however, must then convert to list to match based on class ==
568        # not on class id()
569        if (sorted({x.classes[0] for x in self.articulations})
570                != sorted({x.classes[0] for x in other.articulations})):
571            return False
572        if (sorted({x.classes[0] for x in self.expressions})
573                != sorted({x.classes[0] for x in other.expressions})):
574            return False
575
576        # Tie objects if present compare only type
577        if self.tie != other.tie:
578            return False
579        return True
580
581    # --------------------------------------------------------------------------
582    def _getLyric(self) -> Optional[str]:
583        if not self.lyrics:
584            return None
585
586        allText = [ly.text for ly in self.lyrics]
587        return '\n'.join([t for t in allText if t is not None])
588
589    def _setLyric(self, value: Union[str, Lyric, None]) -> None:
590        self.lyrics = []
591        if value is None:
592            return
593
594        if isinstance(value, Lyric):
595            self.lyrics.append(value)
596            return
597
598        if not isinstance(value, str):
599            value = str(value)
600
601        values = value.split('\n')
602        for i, v in enumerate(values):
603            self.lyrics.append(Lyric(v, number=i + 1))
604
605    lyric = property(_getLyric,
606                     _setLyric,
607                     doc=r'''
608        The lyric property can
609        be used to get and set a lyric for this
610        Note, Chord, or Rest. This is a simplified version of the more general
611        :meth:`~music21.note.GeneralNote.addLyric` method.
612
613        >>> a = note.Note('A4')
614        >>> a.lyrics
615        []
616        >>> a.lyric = 'hel-'
617        >>> a.lyric
618        'hel'
619        >>> a.lyrics
620        [<music21.note.Lyric number=1 syllabic=begin text='hel'>]
621
622        Eliminate Lyrics by setting a.lyric to None
623
624        >>> a.lyric = None
625        >>> a.lyric
626        >>> a.lyrics
627        []
628
629        Set multiple lyrics with \n separated text:
630
631        >>> a.lyric = '1. Hi\n2. Bye'
632        >>> a.lyric
633        '1. Hi\n2. Bye'
634        >>> a.lyrics
635        [<music21.note.Lyric number=1 syllabic=single text='1. Hi'>,
636         <music21.note.Lyric number=2 syllabic=single text='2. Bye'>]
637
638
639        You can also set a lyric with a lyric object directly:
640
641        >>> b = note.Note('B5')
642        >>> ly = note.Lyric('bon-')
643        >>> b.lyric = ly
644        >>> b.lyrics
645        [<music21.note.Lyric number=1 syllabic=begin text='bon'>]
646        >>> b.lyric
647        'bon'
648
649        Changed in v6.7 -- added setting to a Lyric object.  Removed undocumented
650        setting to False instead of setting to None
651        ''')
652
653    def addLyric(self,
654                 text,
655                 lyricNumber=None,
656                 *,
657                 applyRaw=False,
658                 lyricIdentifier=None) -> None:
659        '''
660        Adds a lyric, or an additional lyric, to a Note, Chord, or Rest's lyric list.
661        If `lyricNumber` is not None, a specific line of lyric text can be set.
662        The lyricIdentifier can also be set.
663
664        >>> n1 = note.Note()
665        >>> n1.addLyric('hello')
666        >>> n1.lyrics[0].text
667        'hello'
668        >>> n1.lyrics[0].number
669        1
670
671        An added option gives the lyric number, not the list position
672
673        >>> n1.addLyric('bye', 3)
674        >>> n1.lyrics[1].text
675        'bye'
676        >>> n1.lyrics[1].number
677        3
678        >>> for lyr in n1.lyrics:
679        ...     print(lyr.text)
680        hello
681        bye
682
683        Replace an existing lyric by specifying the same number:
684
685        >>> n1.addLyric('ciao', 3)
686        >>> n1.lyrics[1].text
687        'ciao'
688        >>> n1.lyrics[1].number
689        3
690
691        Giving a lyric with a hyphen at either end will set whether it
692        is part of a multisyllable word:
693
694        >>> n1.addLyric('good-')
695        >>> n1.lyrics[2].text
696        'good'
697        >>> n1.lyrics[2].syllabic
698        'begin'
699
700        This feature can be overridden by specifying the keyword only argument "applyRaw=True":
701
702        >>> n1.addLyric('-5', applyRaw=True)
703        >>> n1.lyrics[3].text
704        '-5'
705        >>> n1.lyrics[3].syllabic
706        'single'
707        '''
708        if not isinstance(text, str):
709            text = str(text)
710        if lyricNumber is None:
711            maxLyrics = len(self.lyrics) + 1
712            self.lyrics.append(Lyric(text, maxLyrics,
713                                     applyRaw=applyRaw, identifier=lyricIdentifier))
714        else:
715            foundLyric = False
716            for thisLyric in self.lyrics:
717                if thisLyric.number == lyricNumber:
718                    thisLyric.text = text
719                    foundLyric = True
720                    break
721            if foundLyric is False:
722                self.lyrics.append(Lyric(text, lyricNumber,
723                                         applyRaw=applyRaw, identifier=lyricIdentifier))
724
725    def insertLyric(self, text, index=0, *, applyRaw=False, identifier=None):
726        '''
727        Inserts a lyric into the Note, Chord, or Rest's lyric list in front of
728        the index specified (0 by default), using index + 1 as the inserted lyric's
729        line number. shifts line numbers of all following lyrics in list
730
731        >>> n1 = note.Note()
732        >>> n1.addLyric('second')
733        >>> n1.lyrics
734        [<music21.note.Lyric number=1 syllabic=single text='second'>]
735        >>> n1.insertLyric('first', 0)
736        >>> n1.lyrics
737        [<music21.note.Lyric number=1 syllabic=single text='first'>,
738         <music21.note.Lyric number=2 syllabic=single text='second'>]
739
740        OMIT_FROM_DOCS
741
742        test inserting in the middle.
743
744        >>> n1.insertLyric('newSecond', 1)
745        >>> n1.lyrics
746        [<music21.note.Lyric number=1 syllabic=single text='first'>,
747         <music21.note.Lyric number=2 syllabic=single text='newSecond'>,
748         <music21.note.Lyric number=3 syllabic=single text='second'>]
749
750        Test number as lyric...
751
752        >>> n1.insertLyric(0, 3)
753        >>> n1.lyrics
754        [<music21.note.Lyric number=1 syllabic=single text='first'>,
755         <music21.note.Lyric number=2 syllabic=single text='newSecond'>,
756         <music21.note.Lyric number=3 syllabic=single text='second'>,
757         <music21.note.Lyric number=4 syllabic=single text='0'>]
758        '''
759        if not isinstance(text, str):
760            text = str(text)
761        for lyric in self.lyrics[index:]:
762            lyric.number += 1
763        self.lyrics.insert(index, Lyric(text, (index + 1),
764                                        applyRaw=applyRaw, identifier=identifier))
765
766    # --------------------------------------------------------------------------
767    # properties common to Notes, Rests,
768
769    # --------------------------------------------------------------------------
770    def augmentOrDiminish(self, scalar, *, inPlace=False):
771        '''
772        Given a scalar greater than zero, return a Note with a scaled Duration.
773        If `inPlace` is True, this is done in-place and the method returns None.
774        If `inPlace` is False [default], this returns a modified deepcopy.
775
776        Changed -- inPlace is now False as of version 5.
777
778        >>> n = note.Note('g#')
779        >>> n.quarterLength = 3
780        >>> n.augmentOrDiminish(2, inPlace=True)
781        >>> n.quarterLength
782        6.0
783
784        >>> c = chord.Chord(['g#', 'a#', 'd'])
785        >>> c.quarterLength = 2
786        >>> c.augmentOrDiminish(0.25, inPlace=True)
787        >>> c.quarterLength
788        0.5
789
790        >>> n = note.Note('g#')
791        >>> n.augmentOrDiminish(-1)
792        Traceback (most recent call last):
793        music21.note.NoteException: scalar must be greater than zero
794
795        >>> n = note.Note()
796        >>> n.quarterLength = 3
797        >>> n2 = n.augmentOrDiminish(1/3, inPlace=False)
798        >>> n2.quarterLength
799        1.0
800        >>> n.quarterLength
801        3.0
802        '''
803        if not scalar > 0:
804            raise NoteException('scalar must be greater than zero')
805
806        if inPlace:
807            post = self
808        else:  # slight speedup could happen by setting duration to Zero before copying.
809            post = copy.deepcopy(self)
810
811        # this is never True.
812        post.duration = post.duration.augmentOrDiminish(scalar)
813
814        if not inPlace:
815            return post
816        else:
817            return None
818
819    # --------------------------------------------------------------------------
820    def getGrace(self, *, appoggiatura=False, inPlace=False):
821        '''
822        Return a grace version of this GeneralNote
823
824        >>> n = note.Note('G4', quarterLength=2)
825        >>> n.duration.quarterLength
826        2.0
827        >>> n.duration.isGrace
828        False
829        >>> n.duration
830        <music21.duration.Duration 2.0>
831        >>> n.duration.type
832        'half'
833        >>> n.duration.components
834        (DurationTuple(type='half', dots=0, quarterLength=2.0),)
835
836        >>> ng = n.getGrace()
837        >>> ng.duration.quarterLength
838        0.0
839        >>> ng.duration.isGrace
840        True
841        >>> ng.duration
842        <music21.duration.GraceDuration unlinked type:half quarterLength:0.0>
843        >>> ng.duration.type
844        'half'
845        >>> ng.duration.components
846        (DurationTuple(type='half', dots=0, quarterLength=0.0),)
847
848        Appoggiaturas are still a work in progress...
849        Changed in v.6 -- corrected spelling of `appoggiatura` keyword.
850
851        >>> ng2 = n.getGrace(appoggiatura=True)
852        >>> ng2.duration
853        <music21.duration.AppoggiaturaDuration unlinked type:half quarterLength:0.0>
854        >>> ng2.duration.slash
855        False
856
857        Set inPlace to True to change the duration element on the Note.  This can have
858        negative consequences if the Note is in a stream.
859
860        >>> r = note.Rest(quarterLength=0.5)
861        >>> r.getGrace(inPlace=True)
862        >>> r.duration
863        <music21.duration.GraceDuration unlinked type:eighth quarterLength:0.0>
864        '''
865        if inPlace is False:
866            e = copy.deepcopy(self)
867        else:
868            e = self
869
870        e.duration = e.duration.getGraceDuration(appoggiatura=appoggiatura)
871
872        if inPlace is False:
873            return e
874
875
876# ------------------------------------------------------------------------------
877class NotRest(GeneralNote):
878    '''
879    Parent class for Note-like objects that are not rests; that is to say
880    they have a stem, can be tied, and volume is important.
881    Basically, that's a :class:`Note` or :class:`~music21.chord.Chord`
882    (or their subclasses such as :class:`~music21.harmony.ChordSymbol`), or
883    :class:`Unpitched` object.
884    '''
885    # unspecified means that there may be a stem, but its orientation
886    # has not been declared.
887
888    _DOC_ATTR = {
889        'beams': '''
890            A :class:`~music21.beam.Beams` object that contains
891            information about the beaming of this note.''',
892    }
893
894    def __init__(self, *arguments, **keywords):
895        super().__init__(**keywords)
896        self._notehead = 'normal'
897        self._noteheadFill = None
898        self._noteheadParenthesis = False
899        self._stemDirection = 'unspecified'
900        self._volume = None  # created on demand
901        # replace
902        self.linkage = 'tie'
903        if 'beams' in keywords:
904            self.beams = keywords['beams']
905        else:
906            self.beams = beam.Beams()
907        self._storedInstrument: Optional['music21.instrument.Instrument'] = None
908
909    # ==============================================================================================
910    # Special functions
911    # ==============================================================================================
912    def __eq__(self, other):
913        if super().__eq__(other) is NotImplemented:
914            return NotImplemented
915        if not super().__eq__(other):
916            return False
917        if not isinstance(other, NotRest):
918            return False
919
920        if self.notehead != other.notehead:
921            return False
922        if self.noteheadFill != other.noteheadFill:
923            return False
924        if self.noteheadParenthesis != other.noteheadParenthesis:
925            return False
926        # Q: should volume need to be equal?
927        if self.beams != other.beams:
928            return False
929        return True
930
931    def __deepcopy__(self, memo=None):
932        '''
933        As NotRest objects have a Volume, objects, and Volume objects
934        store weak refs to the to client object, need to specialize deep copy handling
935
936        >>> import copy
937        >>> n = note.NotRest()
938        >>> n.volume = volume.Volume(50)
939        >>> m = copy.deepcopy(n)
940        >>> m.volume.client is m
941        True
942        '''
943        # environLocal.printDebug(['calling NotRest.__deepcopy__', self])
944        new = super().__deepcopy__(memo=memo)
945        # after copying, if a Volume exists, it is linked to the old object
946        # look at _volume so as not to create object if not already there
947        if self._volume is not None:
948            new.volume.client = new  # update with new instance
949        return new
950
951    def __getstate__(self):
952        state = super().__getstate__()
953        if '_volume' in state and state['_volume'] is not None:
954            state['_volume'].client = None
955        return state
956
957    def __setstate__(self, state):
958        super().__setstate__(state)
959        if self._volume is not None:
960            self._volume.client = self
961    ####
962
963    def _getStemDirection(self) -> str:
964        return self._stemDirection
965
966    def _setStemDirection(self, direction):
967        if direction is None:
968            direction = 'unspecified'  # allow setting to None meaning
969        elif direction == 'none':
970            direction = 'noStem'  # allow setting to none or None
971        elif direction not in stemDirectionNames:
972            raise NotRestException(f'not a valid stem direction name: {direction}')
973        self._stemDirection = direction
974
975    stemDirection = property(_getStemDirection,
976                             _setStemDirection,
977                             doc='''
978        Get or set the stem direction of this NotRest object.
979        Valid stem direction names are found in note.stemDirectionNames (see below).
980
981        >>> note.stemDirectionNames
982        ('double', 'down', 'noStem', 'none', 'unspecified', 'up')
983        >>> n = note.Note()
984
985        By default a Note's stemDirection is 'unspecified'
986        meaning that it is unknown:
987
988        >>> n.stemDirection
989        'unspecified'
990
991        >>> n.stemDirection = 'noStem'
992        >>> n.stemDirection
993        'noStem'
994
995        The alias 'none' (the string) is the same as 'noStem'
996
997        >>> n.stemDirection = 'none'
998        >>> n.stemDirection
999        'noStem'
1000
1001        >>> n.stemDirection = 'junk'
1002        Traceback (most recent call last):
1003        music21.note.NotRestException: not a valid stem direction name: junk
1004
1005        Stem direction can be set explicitly to None to remove
1006        any prior stem information, same as 'unspecified':
1007
1008        >>> n.stemDirection = None
1009        >>> n.stemDirection
1010        'unspecified'
1011        ''')
1012
1013    @property
1014    def notehead(self) -> str:
1015        '''
1016        Get or set the notehead type of this NotRest object.
1017        Valid notehead type names are found in note.noteheadTypeNames (see below):
1018
1019
1020        >>> note.noteheadTypeNames
1021        ('arrow down', 'arrow up', 'back slashed', 'circle dot', 'circle-x', 'circled', 'cluster',
1022         'cross', 'diamond', 'do', 'fa', 'inverted triangle', 'la', 'left triangle',
1023         'mi', 'none', 'normal', 'other', 're', 'rectangle', 'slash', 'slashed', 'so',
1024         'square', 'ti', 'triangle', 'x')
1025        >>> n = note.Note()
1026        >>> n.notehead = 'diamond'
1027        >>> n.notehead
1028        'diamond'
1029
1030        >>> n.notehead = 'junk'
1031        Traceback (most recent call last):
1032        music21.note.NotRestException: not a valid notehead type name: 'junk'
1033        '''
1034        return self._notehead
1035
1036    @notehead.setter
1037    def notehead(self, value):
1038        if value in ('none', None, ''):
1039            value = None  # allow setting to none or None
1040        elif value not in noteheadTypeNames:
1041            raise NotRestException(f'not a valid notehead type name: {value!r}')
1042        self._notehead = value
1043
1044    @property
1045    def noteheadFill(self) -> str:
1046        '''
1047        Get or set the note head fill status of this NotRest. Valid note head fill values are
1048        True, False, or None (meaning default).  "yes" and "no" are converted to True
1049        and False.
1050
1051        >>> n = note.Note()
1052        >>> n.noteheadFill = 'no'
1053        >>> n.noteheadFill
1054        False
1055        >>> n.noteheadFill = 'filled'
1056        >>> n.noteheadFill
1057        True
1058
1059        >>> n.noteheadFill = 'jelly'
1060        Traceback (most recent call last):
1061        music21.note.NotRestException: not a valid notehead fill value: jelly
1062        '''
1063        return self._noteheadFill
1064
1065    @noteheadFill.setter
1066    def noteheadFill(self, value):
1067        if value in ('none', None, 'default'):
1068            value = None  # allow setting to none or None
1069        if value in ('filled', 'yes'):
1070            value = True
1071        elif value in ('notfilled', 'no'):
1072            value = False
1073        if value not in (True, False, None):
1074            raise NotRestException(f'not a valid notehead fill value: {value}')
1075        self._noteheadFill = value
1076
1077    @property
1078    def noteheadParenthesis(self) -> bool:
1079        '''
1080        Get or set the note head parentheses for this Note/Unpitched/Chord object.
1081
1082        >>> n = note.Note()
1083        >>> n.noteheadParenthesis
1084        False
1085        >>> n.noteheadParenthesis = True
1086        >>> n.noteheadParenthesis
1087        True
1088
1089        'yes' or 1 equate to True; 'no' or 0 to False
1090
1091        >>> n.noteheadParenthesis = 'no'
1092        >>> n.noteheadParenthesis
1093        False
1094
1095        Anything else raises an exception:
1096
1097        >>> n.noteheadParenthesis = 'blah'
1098        Traceback (most recent call last):
1099        music21.note.NotRestException: notehead parentheses must be True or False, not 'blah'
1100        '''
1101        return self._noteheadParenthesis
1102
1103    @noteheadParenthesis.setter
1104    def noteheadParenthesis(self, value):
1105        if value in (True, 'yes', 1):
1106            value = True
1107        elif value in (False, 'no', 0):
1108            value = False
1109        else:
1110            raise NotRestException(f'notehead parentheses must be True or False, not {value!r}')
1111        self._noteheadParenthesis = value
1112
1113    # --------------------------------------------------------------------------
1114    def hasVolumeInformation(self) -> bool:
1115        '''
1116        Returns bool whether volume was set -- saving some time for advanced
1117        users (such as MusicXML exporters) that only want to look at the volume
1118        if it is already there.
1119
1120        >>> n = note.Note()
1121        >>> n.hasVolumeInformation()
1122        False
1123        >>> n.volume
1124         <music21.volume.Volume realized=0.71>
1125        >>> n.hasVolumeInformation()
1126        True
1127        '''
1128        if self._volume is None:
1129            return False
1130        else:
1131            return True
1132
1133    @property
1134    def pitches(self) -> Tuple[pitch.Pitch]:
1135        '''
1136        Returns an empty tuple.  (Useful for iterating over NotRests since they
1137        include Notes and Chords.)
1138        '''
1139        return ()
1140
1141    @pitches.setter
1142    def pitches(self, _value: Iterable[pitch.Pitch]):
1143        pass
1144
1145
1146    def _getVolume(self, forceClient: Optional[base.Music21Object] = None) -> volume.Volume:
1147        # DO NOT CHANGE TO @property because of optional attributes
1148        # lazy volume creation
1149        if self._volume is None:
1150            if forceClient is None:
1151                # when creating the volume object, set the client as self
1152                self._volume = volume.Volume(client=self)
1153            else:
1154                self._volume = volume.Volume(client=forceClient)
1155        return self._volume
1156
1157    def _setVolume(self, value, setClient=True):
1158        # DO NOT CHANGE TO @property because of optional attributes
1159        # setParent is only False when Chords bundling Notes
1160        # test by looking for method
1161        if value is None:
1162            self._volume = None
1163        elif hasattr(value, 'getDynamicContext'):
1164            if setClient:
1165                if value.client is not None:
1166                    value = copy.deepcopy(value)
1167                value.client = self  # set to self
1168            self._volume = value
1169        elif common.isNum(value) and setClient:
1170            # if we can define the client, we can set from numbers
1171            # call local getVolume will set client appropriately
1172            vol = self._getVolume()
1173            if value < 1:  # assume a scalar
1174                vol.velocityScalar = value
1175            else:  # assume velocity
1176                vol.velocity = value
1177
1178        else:
1179            raise Exception(f'this must be a Volume object, not {value}')
1180
1181    volume = property(_getVolume,
1182                      _setVolume,
1183                      doc='''
1184        Get and set the :class:`~music21.volume.Volume` object of this object.
1185        Volume objects are created on demand.
1186
1187        >>> n1 = note.Note()
1188        >>> n1.volume.velocity = 120
1189        >>> n2 = note.Note()
1190        >>> n2.volume = 80  # can directly set a velocity value
1191        >>> s = stream.Stream()
1192        >>> s.append([n1, n2])
1193        >>> [n.volume.velocity for n in s.notes]
1194        [120, 80]
1195        ''')
1196
1197    def _getStoredInstrument(self):
1198        return self._storedInstrument
1199
1200    def _setStoredInstrument(self, newValue):
1201        if not (hasattr(newValue, 'instrumentId') or newValue is None):
1202            raise TypeError(f'Expected Instrument; got {type(newValue)}')
1203        self._storedInstrument = newValue
1204
1205    storedInstrument = property(_getStoredInstrument,
1206                                _setStoredInstrument,
1207                                doc='''
1208        Get and set the :class:`~music21.instrument.Instrument` that
1209        should be used to play this note, overriding whatever
1210        Instrument object may be active in the Stream. (See
1211        :meth:`getInstrument` for a means of retrieving `storedInstrument`
1212        if available before falling back to a context search to find
1213        the active instrument.)
1214        ''')
1215
1216    def getInstrument(self,
1217                      *,
1218                      returnDefault: bool = True
1219                      ) -> Optional['music21.instrument.Instrument']:
1220        '''
1221        Retrieves the `.storedInstrument` on this `NotRest` instance, if any.
1222        If one is not found, executes a context search (without following
1223        derivations) to find the closest (i.e., active) instrument in the
1224        stream hierarchy.
1225
1226        Returns a default instrument if no instrument is found in the context
1227        and `returnDefault` is True (default).
1228
1229        >>> n = note.Note()
1230        >>> m = stream.Measure([n])
1231        >>> n.getInstrument(returnDefault=False) is None
1232        True
1233        >>> dulc = instrument.Dulcimer()
1234        >>> m.insert(0, dulc)
1235        >>> n.getInstrument() is dulc
1236        True
1237
1238        Overridden `.storedInstrument` is privileged:
1239
1240        >>> picc = instrument.Piccolo()
1241        >>> n.storedInstrument = picc
1242        >>> n.getInstrument() is picc
1243        True
1244
1245        Instruments in containing streams ARE found:
1246
1247        >>> n.storedInstrument = None
1248        >>> m.remove(dulc)
1249        >>> p = stream.Part([m])
1250        >>> p.insert(0, dulc)
1251        >>> n.getInstrument() is dulc
1252        True
1253
1254        But not if the instrument is only found in a derived stream:
1255
1256        >>> derived = p.stripTies()
1257        >>> p.remove(dulc)
1258        >>> derived.getInstruments().first()
1259        <music21.instrument.Dulcimer 'Dulcimer'>
1260        >>> n.getInstrument(returnDefault=False) is None
1261        True
1262
1263        Electing to return a default generic `Instrument`:
1264
1265        >>> n.getInstrument(returnDefault=True)
1266        <music21.instrument.Instrument ''>
1267        '''
1268        from music21 import instrument
1269        if self.storedInstrument is not None:
1270            return self.storedInstrument
1271        instrument_or_none = self.getContextByClass(
1272            instrument.Instrument, followDerivation=False)
1273        if returnDefault and instrument_or_none is None:
1274            return instrument.Instrument()
1275        return instrument_or_none
1276
1277
1278# ------------------------------------------------------------------------------
1279class Note(NotRest):
1280    '''
1281    One of the most important music21 classes, a Note
1282    stores a single note (that is, not a rest or an unpitched element)
1283    that can be represented by one or more notational units -- so
1284    for instance a C quarter-note and a D# eighth-tied-to-32nd are both
1285    a single Note object.
1286
1287
1288    A Note knows both its total duration and how to express itself as a set of
1289    tied notes of different lengths. For instance, a note of 2.5 quarters in
1290    length could be half tied to eighth or dotted quarter tied to quarter.
1291
1292
1293    The first argument to the Note is the pitch name (with or without
1294    octave, see the introduction to :class:`music21.pitch.Pitch`).
1295    Further arguments can be specified as keywords (such as type, dots, etc.)
1296    and are passed to the underlying :class:`music21.duration.Duration` element.
1297
1298    >>> n = note.Note()
1299    >>> n
1300    <music21.note.Note C>
1301    >>> n.pitch
1302    <music21.pitch.Pitch C4>
1303
1304    >>> n = note.Note('B-')
1305    >>> n.name
1306    'B-'
1307    >>> n.octave is None
1308    True
1309    >>> n.pitch.implicitOctave
1310    4
1311
1312    >>> n = note.Note(name='D#')
1313    >>> n.name
1314    'D#'
1315    >>> n = note.Note(nameWithOctave='D#5')
1316    >>> n.nameWithOctave
1317    'D#5'
1318
1319    Other ways of instantiating a Pitch object, such as by MIDI number or pitch class
1320    are also possible:
1321
1322    >>> note.Note(64).nameWithOctave
1323    'E4'
1324
1325    Two notes are considered equal if their most important attributes
1326    (such as pitch, duration,
1327    articulations, and ornaments) are equal.  Attributes
1328    that might change based on the wider context
1329    of a note (such as offset)
1330    are not compared. This test does not look at lyrics in
1331    establishing equality.  (It may in the future.)
1332
1333    >>> note.Note('C4') == note.Note('C4')
1334    True
1335    '''
1336    isNote = True
1337
1338    # define order to present names in documentation; use strings
1339    _DOC_ORDER = ['duration', 'quarterLength', 'nameWithOctave']
1340    # documentation for all attributes (not properties or methods)
1341    _DOC_ATTR = {
1342        'isNote': 'Boolean read-only value describing if this Note is a Note (True).',
1343        'isRest': 'Boolean read-only value describing if this Note is a Rest (False).',
1344        'pitch': '''A :class:`~music21.pitch.Pitch` object containing all the
1345                information about the note's pitch.  Many `.pitch` properties and
1346                methods are also made `Note` properties also''',
1347    }
1348
1349    # Accepts an argument for pitch
1350    def __init__(self, pitchName=None, **keywords):
1351        super().__init__(**keywords)
1352        self._chordAttached: Optional['music21.chord.Chord'] = None
1353
1354        if 'pitch' in keywords and pitchName is None:
1355            pitchName = keywords['pitch']
1356            del keywords['pitch']
1357
1358        if pitchName is not None:
1359            if isinstance(pitchName, pitch.Pitch):
1360                self.pitch = pitchName
1361            else:  # assume first argument is pitch
1362                self.pitch = pitch.Pitch(pitchName, **keywords)
1363        else:  # supply a default pitch
1364            name = 'C4'
1365            if 'name' in keywords:
1366                name = keywords['name']
1367                del keywords['name']
1368            elif 'nameWithOctave' in keywords:
1369                name = keywords['nameWithOctave']
1370                del keywords['nameWithOctave']
1371            self.pitch = pitch.Pitch(name, **keywords)
1372
1373        # noinspection PyProtectedMember
1374        self.pitch._client = self
1375
1376    # --------------------------------------------------------------------------
1377    # operators, representations, and transformations
1378
1379    def _reprInternal(self):
1380        return self.name
1381
1382    def __eq__(self, other):
1383        '''
1384        Tests Equality. See docs under Note above
1385        (since __eq__'s docs don't display)
1386
1387        >>> n1 = note.Note()
1388        >>> n1.pitch.name = 'G#'
1389        >>> n2 = note.Note()
1390        >>> n2.pitch.name = 'A-'
1391        >>> n3 = note.Note()
1392        >>> n3.pitch.name = 'G#'
1393        >>> n1 == n2
1394        False
1395        >>> n1 == n3
1396        True
1397        >>> n3.duration.quarterLength = 3
1398        >>> n1 == n3
1399        False
1400
1401        >>> n1 == 5
1402        False
1403        '''
1404        if other is None or not isinstance(other, Note):
1405            return NotImplemented
1406
1407        # checks pitch.octave, pitch.accidental, uses Pitch.__eq__
1408        if self.pitch != other.pitch:
1409            return False
1410
1411        return super().__eq__(other)
1412
1413    def __lt__(self, other):
1414        '''
1415        __lt__, __gt__, __le__, __ge__ all use a pitch comparison.
1416
1417        >>> highE = note.Note('E5')
1418        >>> lowF = note.Note('F2')
1419        >>> otherHighE = note.Note('E5')
1420
1421        >>> highE > lowF
1422        True
1423        >>> highE < lowF
1424        False
1425        >>> highE >= otherHighE
1426        True
1427        >>> highE <= otherHighE
1428        True
1429
1430        Notice you cannot compare Notes w/ ints or anything not pitched.
1431
1432        >>> highE < 50
1433        Traceback (most recent call last):
1434        TypeError: '<' not supported between instances of 'Note' and 'int'
1435
1436        Note also that two objects can be >= and <= without being equal, because
1437        only pitch-height is being compared in <, <=, >, >= but duration and other
1438        elements are compared in equality.
1439
1440        >>> otherHighE.duration.type = 'whole'
1441        >>> highE >= otherHighE
1442        True
1443        >>> highE <= otherHighE
1444        True
1445        >>> highE == otherHighE
1446        False
1447        '''
1448        try:
1449            return self.pitch < other.pitch
1450        except AttributeError:
1451            return NotImplemented
1452
1453    # do not factor out into @total_ordering because of the difference between __eq__ and
1454    # the equal part of __le__ and __ge__
1455    def __gt__(self, other):
1456        try:
1457            return self.pitch > other.pitch
1458        except AttributeError:
1459            return NotImplemented
1460
1461    def __le__(self, other):
1462        try:
1463            return self.pitch <= other.pitch
1464        except AttributeError:
1465            return NotImplemented
1466
1467    def __ge__(self, other):
1468        try:
1469            return self.pitch >= other.pitch
1470        except AttributeError:
1471            return NotImplemented
1472
1473    # --------------------------------------------------------------------------
1474    # property access
1475
1476    def _getName(self) -> str:
1477        return self.pitch.name
1478
1479    def _setName(self, value: str):
1480        self.pitch.name = value
1481
1482    name = property(_getName,
1483                    _setName,
1484                    doc='''
1485        Return or set the pitch name from the :class:`~music21.pitch.Pitch` object.
1486        See `Pitch`'s attribute :attr:`~music21.pitch.Pitch.name`.
1487        ''')
1488
1489    def _getNameWithOctave(self) -> str:
1490        return self.pitch.nameWithOctave
1491
1492    def _setNameWithOctave(self, value: str):
1493        self.pitch.nameWithOctave = value
1494
1495    nameWithOctave = property(_getNameWithOctave,
1496                              _setNameWithOctave,
1497                              doc='''
1498        Return or set the pitch name with octave from the :class:`~music21.pitch.Pitch` object.
1499        See `Pitch`'s attribute :attr:`~music21.pitch.Pitch.nameWithOctave`.
1500        ''')
1501
1502    def _getStep(self) -> str:
1503        return self.pitch.step
1504
1505    def _setStep(self, value: str):
1506        self.pitch.step = value
1507
1508    step = property(_getStep,
1509                    _setStep,
1510                    doc='''
1511        Return or set the pitch step from the :class:`~music21.pitch.Pitch` object.
1512        See :attr:`~music21.pitch.Pitch.step`.
1513        ''')
1514
1515    def _getOctave(self) -> int:
1516        return self.pitch.octave
1517
1518    def _setOctave(self, value: int):
1519        self.pitch.octave = value
1520
1521    octave = property(_getOctave,
1522                      _setOctave,
1523                      doc='''
1524        Return or set the octave value from the :class:`~music21.pitch.Pitch` object.
1525        See :attr:`~music21.pitch.Pitch.octave`.
1526        ''')
1527
1528    @property
1529    def pitches(self) -> Tuple[pitch.Pitch]:
1530        '''
1531        Return the single :class:`~music21.pitch.Pitch` object in a tuple.
1532        This property is designed to provide an interface analogous to
1533        that found on :class:`~music21.chord.Chord` so that `[c.pitches for c in s.notes]`
1534        provides a consistent interface for all objects.
1535
1536        >>> n = note.Note('g#')
1537        >>> n.nameWithOctave
1538        'G#'
1539        >>> n.pitches
1540        (<music21.pitch.Pitch G#>,)
1541
1542        Since this is a Note, not a chord, from the list or tuple,
1543        only the first one will be used:
1544
1545        >>> n.pitches = [pitch.Pitch('c2'), pitch.Pitch('g2')]
1546        >>> n.nameWithOctave
1547        'C2'
1548        >>> n.pitches
1549        (<music21.pitch.Pitch C2>,)
1550
1551        The value for setting must be a list or tuple:
1552
1553        >>> n.pitches = pitch.Pitch('C4')
1554        Traceback (most recent call last):
1555        music21.note.NoteException: cannot set pitches with provided object: C4
1556
1557        For setting a single one, use `n.pitch` instead.
1558
1559        Don't use strings, or you will get a string back!
1560
1561        >>> n.pitches = ('C4', 'D4')
1562        >>> n.pitch
1563        'C4'
1564        >>> n.pitch.diatonicNoteNum
1565        Traceback (most recent call last):
1566        AttributeError: 'str' object has no attribute 'diatonicNoteNum'
1567        '''
1568        return (self.pitch,)
1569
1570    @pitches.setter
1571    def pitches(self, value: Iterable[pitch.Pitch]):
1572        if common.isListLike(value) and value:
1573            self.pitch = value[0]
1574        else:
1575            raise NoteException(f'cannot set pitches with provided object: {value}')
1576
1577    def transpose(self, value, *, inPlace=False):
1578        '''
1579        Transpose the Note by the user-provided
1580        value. If the value is an integer, the transposition is treated in half steps.
1581
1582        If the value is a string, any Interval string specification can be provided.
1583
1584        >>> a = note.Note('g4')
1585        >>> b = a.transpose('m3')
1586        >>> b
1587        <music21.note.Note B->
1588        >>> aInterval = interval.Interval(-6)
1589        >>> b = a.transpose(aInterval)
1590        >>> b
1591        <music21.note.Note C#>
1592
1593        >>> c = b.transpose(interval.GenericInterval(2))
1594        >>> c
1595        <music21.note.Note D#>
1596
1597        >>> a.transpose(aInterval, inPlace=True)
1598        >>> a
1599        <music21.note.Note C#>
1600
1601
1602        If the transposition value is an integer, take the KeySignature or Key context
1603        into account...
1604
1605        >>> s = stream.Stream()
1606        >>> s.append(key.Key('D'))
1607        >>> s.append(note.Note('F'))
1608        >>> s.append(key.Key('b-', 'minor'))
1609        >>> s.append(note.Note('F'))
1610        >>> s.show('text')
1611        {0.0} <music21.key.Key of D major>
1612        {0.0} <music21.note.Note F>
1613        {1.0} <music21.key.Key of b- minor>
1614        {1.0} <music21.note.Note F>
1615        >>> for n in s.notes:
1616        ...     n.transpose(1, inPlace=True)
1617        >>> s.show('text')
1618        {0.0} <music21.key.Key of D major>
1619        {0.0} <music21.note.Note F#>
1620        {1.0} <music21.key.Key of b- minor>
1621        {1.0} <music21.note.Note G->
1622
1623        '''
1624        if isinstance(value, interval.IntervalBase):
1625            intervalObj = value
1626        else:  # try to process
1627            intervalObj = interval.Interval(value)
1628
1629        if not inPlace:
1630            post = copy.deepcopy(self)
1631        else:
1632            post = self
1633
1634        # use inPlace, b/c if we are inPlace, we operate on self;
1635        # if we are not inPlace, post is a copy
1636        post.pitch.transpose(intervalObj, inPlace=True)
1637        if (post.pitch.accidental is not None
1638                and isinstance(value, (int, interval.ChromaticInterval))):
1639            ksContext = self.getContextByClass('KeySignature')
1640            if ksContext is not None:
1641                for alteredPitch in ksContext.alteredPitches:
1642                    if (post.pitch.pitchClass == alteredPitch.pitchClass
1643                            and post.pitch.accidental.alter != alteredPitch.accidental.alter):
1644                        post.pitch.getEnharmonic(inPlace=True)
1645
1646        if not inPlace:
1647            post.derivation.method = 'transpose'
1648            return post
1649        else:
1650            return None
1651
1652    @property
1653    def fullName(self) -> str:
1654        '''
1655        Return the most complete representation of this Note,
1656        providing duration and pitch information.
1657
1658
1659        >>> n = note.Note('A-', quarterLength=1.5)
1660        >>> n.fullName
1661        'A-flat Dotted Quarter Note'
1662
1663        >>> n = note.Note('E~3', quarterLength=2)
1664        >>> n.fullName
1665        'E-half-sharp in octave 3 Half Note'
1666
1667        >>> n = note.Note('D', quarterLength=0.25)
1668        >>> n.pitch.microtone = 25
1669        >>> n.fullName
1670        'D (+25c) 16th Note'
1671        '''
1672        msg = []
1673        msg.append(self.pitch.fullName + ' ')
1674        msg.append(self.duration.fullName)
1675        msg.append(' Note')
1676        return ''.join(msg)
1677
1678    def pitchChanged(self):
1679        '''
1680        Called by the underlying pitch if something changed there.
1681        '''
1682        self._cache = {}
1683        if self._chordAttached is not None:
1684            self._chordAttached.clearCache()
1685
1686# ------------------------------------------------------------------------------
1687# convenience classes
1688
1689
1690# ------------------------------------------------------------------------------
1691class Unpitched(NotRest):
1692    '''
1693    A General class of unpitched objects which appear at different places
1694    on the staff.  Examples: percussion notation.
1695
1696    >>> unp = note.Unpitched()
1697
1698    Unpitched elements have :attr:`displayStep` and :attr:`displayOctave`,
1699    which shows where they should be displayed as if the staff were a
1700    5-line staff in treble clef, but they do not have pitch
1701    objects:
1702
1703    >>> unp.displayStep
1704    'B'
1705    >>> unp.displayOctave
1706    4
1707    >>> unp.displayStep = 'G'
1708    >>> unp.pitch
1709    Traceback (most recent call last):
1710    AttributeError: 'Unpitched' object has no attribute 'pitch'
1711    '''
1712
1713    def __init__(self, displayName=None, **keywords):
1714        super().__init__(**keywords)
1715
1716        self.displayStep: str = 'B'
1717        self.displayOctave: int = 4
1718        if displayName:
1719            display_pitch = pitch.Pitch(displayName)
1720            self.displayStep = display_pitch.step
1721            self.displayOctave = display_pitch.octave
1722
1723    def __eq__(self, other):
1724        if super().__eq__(other) is NotImplemented:
1725            return NotImplemented
1726        if not super().__eq__(other):
1727            return False
1728        if not isinstance(other, Unpitched):
1729            return False
1730        if self.displayStep != other.displayStep:
1731            return False
1732        if self.displayOctave != other.displayOctave:
1733            return False
1734        return True
1735
1736    def _getStoredInstrument(self):
1737        return self._storedInstrument
1738
1739    def _setStoredInstrument(self, newValue):
1740        self._storedInstrument = newValue
1741
1742    storedInstrument = property(_getStoredInstrument, _setStoredInstrument)
1743
1744    def displayPitch(self) -> pitch.Pitch:
1745        '''
1746        returns a pitch object that is the same as the displayStep and displayOctave.
1747        it will never have an accidental.
1748
1749        >>> unp = note.Unpitched()
1750        >>> unp.displayStep = 'E'
1751        >>> unp.displayOctave = 4
1752        >>> unp.displayPitch()
1753        <music21.pitch.Pitch E4>
1754        '''
1755        p = pitch.Pitch()
1756        p.step = self.displayStep
1757        p.octave = self.displayOctave
1758        return p
1759
1760    @property
1761    def displayName(self) -> str:
1762        '''
1763        Returns the `nameWithOctave` of the :meth:`displayPitch`.
1764
1765        >>> unp = note.Unpitched('B2')
1766        >>> unp.displayName
1767        'B2'
1768        '''
1769        display_pitch = self.displayPitch()
1770        return display_pitch.nameWithOctave
1771
1772
1773# ------------------------------------------------------------------------------
1774class Rest(GeneralNote):
1775    '''
1776    Rests are represented in music21 as GeneralNote objects that do not have
1777    a pitch object attached to them.  By default they have length 1.0 (Quarter Rest)
1778
1779    Calling :attr:`~music21.stream.Stream.notes` on a Stream does not get rests.
1780    However, the property :attr:`~music21.stream.Stream.notesAndRests` of Streams
1781    gets rests as well.
1782
1783
1784    >>> r = note.Rest()
1785    >>> r.isRest
1786    True
1787    >>> r.isNote
1788    False
1789    >>> r.duration.quarterLength = 2.0
1790    >>> r.duration.type
1791    'half'
1792
1793    All Rests have the name property 'rest':
1794
1795    >>> r.name
1796    'rest'
1797    '''
1798    isRest = True
1799    name = 'rest'
1800
1801    _DOC_ATTR = {
1802        'isNote': 'Boolean read-only value describing if this Rest is a Note (False).',
1803        'isRest': 'Boolean read-only value describing if this Rest is a Rest (True, obviously).',
1804        'name': '''returns "rest" always.  It is here so that you can get
1805               `x.name` on all `.notesAndRests` objects''',
1806        'stepShift': 'number of lines/spaces to shift the note upwards or downwards for display.',
1807        'fullMeasure': '''does this rest last a full measure (thus display as whole, center, etc.)
1808                Options are False, True, "always", "auto" (default)
1809
1810                False means do not set as full measure, no matter what.
1811
1812                True keeps the set duration, but will always display as a full measure rest.
1813
1814                "always" means the duration will (EVENTUALLY, not yet!)
1815                update automatically to match the time signature context; and is True.
1816                Does not work yet -- functions as True.
1817
1818                # TODO: get it to work.
1819
1820                "auto" is the default, where if the rest value happens to match the current
1821                time signature context, then display it as a whole rest, centered, etc.
1822                otherwise will display normally.
1823
1824                See examples in :meth:`music21.musicxml.m21ToXml.MeasureExporter.restToXml`
1825                ''',
1826    }
1827
1828    def __init__(self, *arguments, **keywords):
1829        super().__init__(**keywords)
1830        self.stepShift = 0  # display line
1831        self.fullMeasure = 'auto'  # see docs; True, False, 'always',
1832
1833    def _reprInternal(self):
1834        duration_name = self.duration.fullName.lower()
1835        if len(duration_name) < 15:  # dotted quarter = 14
1836            return duration_name.replace(' ', '-')
1837        else:
1838            ql = self.duration.quarterLength
1839            if ql == int(ql):
1840                ql = int(ql)
1841            ql_string = str(ql)
1842            return f'{ql_string}ql'
1843
1844    def __eq__(self, other):
1845        '''
1846        A Music21 rest is equal to another object if that object is also a rest which
1847        has the same duration.
1848
1849
1850        >>> r1 = note.Rest()
1851        >>> r2 = note.Rest()
1852        >>> r1 == r2
1853        True
1854        >>> r1 != r2
1855        False
1856
1857        >>> r2.duration.quarterLength = 4.0/3
1858        >>> r1 == r2
1859        False
1860        >>> r1 == note.Note()
1861        False
1862        '''
1863        if not isinstance(other, Rest):
1864            return NotImplemented
1865
1866        return super().__eq__(other)
1867
1868    @property
1869    def fullName(self) -> str:
1870        '''
1871        Return the most complete representation of this Rest,
1872        providing duration information.
1873
1874        >>> r = note.Rest(quarterLength=1.5)
1875        >>> r.fullName
1876        'Dotted Quarter Rest'
1877
1878        >>> note.Rest(type='whole').fullName
1879        'Whole Rest'
1880        '''
1881        return self.duration.fullName + ' Rest'
1882
1883
1884# ------------------------------------------------------------------------------
1885# test methods and classes
1886
1887class TestExternal(unittest.TestCase):
1888    '''
1889    These are tests that open windows and rely on external software
1890    '''
1891    show = True
1892
1893    def testSingle(self):
1894        '''Need to test direct meter creation w/o stream
1895        '''
1896        a = Note('d-3')
1897        a.quarterLength = 2.25
1898        if self.show:
1899            a.show()
1900
1901    def testBasic(self):
1902        from music21 import stream
1903        a = stream.Stream()
1904
1905        for pitchName, qLen in [('d-3', 2.5), ('c#6', 3.25), ('a--5', 0.5),
1906                                ('f', 1.75), ('g3', 1.5), ('d##4', 1.25),
1907                                ('d-3', 2.5), ('c#6', 3.25), ('a--5', 0.5),
1908                                ('f#2', 1.75), ('g-3', (4 / 3)), ('d#6', (2 / 3))
1909                                ]:
1910            b = Note()
1911            b.quarterLength = qLen
1912            b.name = pitchName
1913            b.style.color = '#FF00FF'
1914            a.append(b)
1915
1916        if self.show:
1917            a.show()
1918
1919
1920# ------------------------------------------------------------------------------
1921class Test(unittest.TestCase):
1922
1923    def testCopyAndDeepcopy(self):
1924        '''
1925        Test copying all objects defined in this module
1926        '''
1927        import sys
1928        import types
1929        for part in sys.modules[self.__module__].__dict__:
1930            match = False
1931            for skip in ['_', '__', 'Test', 'Exception']:
1932                if part.startswith(skip) or part.endswith(skip):
1933                    match = True
1934            if match:
1935                continue
1936            name = getattr(sys.modules[self.__module__], part)
1937            # noinspection PyTypeChecker
1938            if callable(name) and not isinstance(name, types.FunctionType):
1939                try:  # see if obj can be made w/ args
1940                    obj = name()
1941                except TypeError:  # pragma: no cover
1942                    continue
1943                a = copy.copy(obj)
1944                b = copy.deepcopy(obj)
1945                self.assertNotEqual(id(a), id(b))
1946
1947    def testLyricRepr(self):
1948        from music21 import note
1949        ly = note.Lyric()
1950        self.assertEqual(repr(ly), '<music21.note.Lyric number=1>')
1951        ly.text = 'hi'
1952        self.assertEqual(repr(ly), "<music21.note.Lyric number=1 text='hi'>")
1953        ly.identifier = 'verse'
1954        self.assertEqual(repr(ly), "<music21.note.Lyric number=1 identifier='verse' text='hi'>")
1955        ly.text = None
1956        self.assertEqual(repr(ly), "<music21.note.Lyric number=1 identifier='verse'>")
1957
1958    def testComplex(self):
1959        from music21 import note
1960        note1 = note.Note()
1961        note1.duration.clear()
1962        d1 = duration.DurationTuple('whole', 0, 4.0)
1963        d2 = duration.DurationTuple('quarter', 0, 1.0)
1964        note1.duration.addDurationTuple(d1)
1965        note1.duration.addDurationTuple(d2)
1966        self.assertEqual(note1.duration.quarterLength, 5.0)
1967        self.assertEqual(note1.duration.componentIndexAtQtrPosition(2), 0)
1968        self.assertEqual(note1.duration.componentIndexAtQtrPosition(4), 1)
1969        self.assertEqual(note1.duration.componentIndexAtQtrPosition(4.5), 1)
1970        note1.duration.sliceComponentAtPosition(1.0)
1971
1972        matchStr = "c'4~\nc'2.~\nc'4"
1973        from music21.lily.translate import LilypondConverter
1974        conv = LilypondConverter()
1975        conv.appendM21ObjectToContext(note1)
1976        outStr = str(conv.context).replace(' ', '').strip()
1977        # print(outStr)
1978        self.assertEqual(matchStr, outStr)
1979        i = 0
1980        for thisNote in note1.splitAtDurations():
1981            matchSub = matchStr.split('\n')[i]  # pylint: disable=use-maxsplit-arg
1982            conv = LilypondConverter()
1983            conv.appendM21ObjectToContext(thisNote)
1984            outStr = str(conv.context).replace(' ', '').strip()
1985            self.assertEqual(matchSub, outStr)
1986            i += 1
1987
1988    def testNote(self):
1989        note2 = Rest()
1990        self.assertTrue(note2.isRest)
1991        note3 = Note()
1992        note3.pitch.name = 'B-'
1993        # not sure how to test not None
1994        # self.assertFalse (note3.pitch.accidental, None)
1995        self.assertEqual(note3.pitch.accidental.name, 'flat')
1996        self.assertEqual(note3.pitch.pitchClass, 10)
1997
1998        a5 = Note()
1999        a5.name = 'A'
2000        a5.octave = 5
2001        self.assertAlmostEqual(a5.pitch.frequency, 880.0)
2002        self.assertEqual(a5.pitch.pitchClass, 9)
2003
2004    def testCopyNote(self):
2005        a = Note()
2006        a.quarterLength = 3.5
2007        a.name = 'D'
2008        b = copy.deepcopy(a)
2009        self.assertEqual(b.name, a.name)
2010
2011    def testMusicXMLFermata(self):
2012        from music21 import corpus
2013        a = corpus.parse('bach/bwv5.7')
2014        found = []
2015        for n in a.flatten().notesAndRests:
2016            for obj in n.expressions:
2017                if isinstance(obj, expressions.Fermata):
2018                    found.append(obj)
2019        self.assertEqual(len(found), 24)
2020
2021    def testNoteBeatProperty(self):
2022        from music21 import stream
2023        from music21 import meter
2024
2025        data = [
2026            ['3/4', 0.5, 6, [1.0, 1.5, 2.0, 2.5, 3.0, 3.5],
2027             [1.0] * 6, ],
2028            ['3/4', 0.25, 8, [1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75],
2029             [1.0] * 8],
2030            ['3/2', 0.5, 8, [1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75],
2031             [2.0] * 8],
2032
2033            ['6/8', 0.5, 6, [1.0, 1.3333, 1.66666, 2.0, 2.3333, 2.666666],
2034             [1.5] * 6],
2035            ['9/8', 0.5, 6, [1.0, 1.3333, 1.66666, 2.0, 2.3333, 2.666666],
2036             [1.5] * 6],
2037            ['12/8', 0.5, 6, [1.0, 1.3333, 1.66666, 2.0, 2.3333, 2.666666],
2038             [1.5] * 6],
2039
2040            ['6/16', 0.25, 6, [1.0, 1.3333, 1.66666, 2.0, 2.3333, 2.666666],
2041             [0.75] * 6],
2042
2043            ['5/4', 1, 5, [1.0, 2.0, 3.0, 4.0, 5.0],
2044             [1.] * 5],
2045
2046            ['2/8+3/8+2/8', 0.5, 6, [1.0, 1.5, 2.0, 2.33333, 2.66666, 3.0],
2047             [1., 1., 1.5, 1.5, 1.5, 1.]],
2048
2049        ]
2050
2051        # one measure case
2052        for tsStr, nQL, nCount, matchBeat, matchBeatDur in data:
2053            n = Note()  # need fully qualified name
2054            n.quarterLength = nQL
2055            m = stream.Measure()
2056            m.timeSignature = meter.TimeSignature(tsStr)
2057            m.repeatAppend(n, nCount)
2058
2059            self.assertEqual(len(m), nCount + 1)
2060
2061            # test matching beat proportion value
2062            post = [m.notesAndRests[i].beat for i in range(nCount)]
2063            for i in range(len(matchBeat)):
2064                self.assertAlmostEqual(post[i], matchBeat[i], 4)
2065
2066            # test getting beat duration
2067            post = [m.notesAndRests[i].beatDuration.quarterLength for i in range(nCount)]
2068
2069            for i in range(len(matchBeat)):
2070                self.assertAlmostEqual(post[i], matchBeatDur[i], 4)
2071
2072        # two measure case
2073        for tsStr, nQL, nCount, matchBeat, matchBeatDur in data:
2074            p = stream.Part()
2075            n = Note()
2076            n.quarterLength = nQL
2077
2078            # m1 has time signature
2079            m1 = stream.Measure()
2080            m1.timeSignature = meter.TimeSignature(tsStr)
2081            p.append(m1)
2082
2083            # m2 does not have time signature
2084            m2 = stream.Measure()
2085            m2.repeatAppend(n, nCount)
2086            self.assertEqual(len(m2), nCount)
2087            self.assertEqual(len(m2.notesAndRests), nCount)
2088
2089            p.append(m2)
2090
2091            # test matching beat proportion value
2092            post = [m2.notesAndRests[i].beat for i in range(nCount)]
2093            for i in range(len(matchBeat)):
2094                self.assertAlmostEqual(post[i], matchBeat[i], 4)
2095            # test getting beat duration
2096            post = [m2.notesAndRests[i].beatDuration.quarterLength for i in range(nCount)]
2097            for i in range(len(matchBeat)):
2098                self.assertAlmostEqual(post[i], matchBeatDur[i], 4)
2099
2100    def testNoteBeatPropertyCorpus(self):
2101        data = [['bach/bwv255', [4.0, 1.0, 2.5, 3.0, 4.0, 4.5, 1.0, 1.5]],
2102                ['bach/bwv153.9', [1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 3.0, 1.0]]
2103                ]
2104
2105        for work, match in data:
2106            from music21 import corpus
2107            s = corpus.parse(work)
2108            # always use tenor line
2109            found = []
2110            for n in s.parts[2].flatten().notesAndRests:
2111                n.lyric = n.beatStr
2112                found.append(n.beat)
2113
2114            for i in range(len(match)):
2115                self.assertEqual(match[i], found[i])
2116
2117            # s.show()
2118
2119    def testNoteEquality(self):
2120        from music21 import articulations
2121
2122        n1 = Note('a#')
2123        n2 = Note('g')
2124        n3 = Note('a-')
2125        n4 = Note('a#')
2126
2127        self.assertNotEqual(n1, n2)
2128        self.assertNotEqual(n1, n3)
2129        self.assertEqual(n1, n4)
2130
2131        # test durations with the same pitch
2132        for x, y, match in [
2133            (1, 1, True),
2134            (1, 0.5, False),
2135            (1, 2, False),
2136            (1, 1.5, False)
2137        ]:
2138            n1.quarterLength = x
2139            n4.quarterLength = y
2140            self.assertEqual(n1 == n4, match)  # sub1
2141
2142        # test durations with different pitch
2143        for x, y, match in [(1, 1, False), (1, 0.5, False),
2144                            (1, 2, False), (1, 1.5, False)]:
2145            n1.quarterLength = x
2146            n2.quarterLength = y
2147            self.assertEqual(n1 == n2, match)  # sub2
2148
2149        # same pitches different octaves
2150        n1.quarterLength = 1.0
2151        n4.quarterLength = 1.0
2152        for x, y, match in [(4, 4, True), (3, 4, False), (2, 4, False)]:
2153            n1.pitch.octave = x
2154            n4.pitch.octave = y
2155            self.assertEqual(n1 == n4, match)  # sub4
2156
2157        # with and without ties
2158        n1.pitch.octave = 4
2159        n4.pitch.octave = 4
2160        t1 = tie.Tie()
2161        t2 = tie.Tie()
2162        for x, y, match in [(t1, None, False), (t1, t2, True)]:
2163            n1.tie = x
2164            n4.tie = y
2165            self.assertEqual(n1 == n4, match)  # sub4
2166
2167        # with ties but different pitches
2168        for n in [n1, n2, n3, n4]:
2169            n.quarterLength = 1.0
2170        t1 = tie.Tie()
2171        t2 = tie.Tie()
2172        for a, b, match in [(n1, n2, False), (n1, n3, False),
2173                            (n2, n3, False), (n1, n4, True)]:
2174            a.tie = t1
2175            b.tie = t2
2176            self.assertEqual(a == b, match)  # sub5
2177
2178        # articulation groups
2179        a1 = [articulations.Accent()]
2180        a2 = [articulations.Accent(), articulations.StrongAccent()]
2181        a3 = [articulations.StrongAccent(), articulations.Accent()]
2182        a4 = [articulations.StrongAccent(), articulations.Accent(),
2183              articulations.Tenuto()]
2184        a5 = [articulations.Accent(), articulations.Tenuto(),
2185              articulations.StrongAccent()]
2186
2187        for a, b, c, d, match in [(n1, n4, a1, a1, True),
2188                                      (n1, n2, a1, a1, False), (n1, n3, a1, a1, False),
2189                                  # same pitch different orderings
2190                                  (n1, n4, a2, a3, True), (n1, n4, a4, a5, True),
2191                                  # different pitch same orderings
2192                                  (n1, n2, a2, a3, False), (n1, n3, a4, a5, False),
2193                                  ]:
2194            a.articulations = c
2195            b.articulations = d
2196            self.assertEqual(a == b, match)  # sub6
2197
2198    def testMetricalAccent(self):
2199        from music21 import meter
2200        from music21 import stream
2201        data = [
2202            ('4/4', 8, 0.5, [1.0, 0.125, 0.25, 0.125, 0.5, 0.125, 0.25, 0.125]),
2203            ('3/4', 6, 0.5, [1.0, 0.25, 0.5, 0.25, 0.5, 0.25]),
2204            ('6/8', 6, 0.5, [1.0, 0.25, 0.25, 0.5, 0.25, 0.25]),
2205
2206            ('12/32', 12, 0.125, [1.0, 0.125, 0.125, 0.25, 0.125, 0.125,
2207                                  0.5, 0.125, 0.125, 0.25, 0.125, 0.125]),
2208
2209            ('5/8', 10, 0.25, [1.0, 0.25, 0.5, 0.25, 0.5, 0.25, 0.5, 0.25, 0.5, 0.25]),
2210
2211            # test notes that do not have defined accents
2212            ('4/4', 16, 0.25, [1.0, 0.0625, 0.125, 0.0625, 0.25, 0.0625, 0.125, 0.0625,
2213                               0.5, 0.0625, 0.125, 0.0625, 0.25, 0.0625, 0.125, 0.0625]),
2214            ('4/4', 32, 0.125, [1.0, 0.0625, 0.0625, 0.0625, 0.125, 0.0625, 0.0625, 0.0625,
2215                                0.25, 0.0625, 0.0625, 0.0625, 0.125, 0.0625, 0.0625, 0.0625,
2216                                0.5, 0.0625, 0.0625, 0.0625, 0.125, 0.0625, 0.0625, 0.0625,
2217                                0.25, 0.0625, 0.0625, 0.0625, 0.125, 0.0625, 0.0625, 0.0625]),
2218        ]
2219
2220        for tsStr, nCount, dur, match in data:
2221
2222            m = stream.Measure()
2223            m.timeSignature = meter.TimeSignature(tsStr)
2224            n = Note()
2225            n.quarterLength = dur
2226            m.repeatAppend(n, nCount)
2227
2228            self.assertEqual([n.beatStrength for n in m.notesAndRests], match)
2229
2230    def testTieContinue(self):
2231        from music21 import stream
2232
2233        n1 = Note()
2234        n1.tie = tie.Tie()
2235        n1.tie.type = 'start'
2236
2237        n2 = Note()
2238        n2.tie = tie.Tie()
2239        n2.tie.type = 'continue'
2240
2241        n3 = Note()
2242        n3.tie = tie.Tie()
2243        n3.tie.type = 'stop'
2244
2245        s = stream.Stream()
2246        s.append([n1, n2, n3])
2247
2248        # need to test that this gets us a continue tie, but hard to test
2249        # post musicxml processing
2250        # s.show()
2251
2252    def testVolumeA(self):
2253        from music21 import note
2254        v1 = volume.Volume()
2255
2256        n1 = note.Note()
2257        n2 = note.Note()
2258
2259        n1.volume = v1  # can set as v1 has no client
2260        self.assertEqual(n1.volume, v1)
2261        self.assertEqual(n1.volume.client, n1)
2262
2263        # object is created on demand
2264        self.assertIsNot(n2.volume, v1)
2265        self.assertIsNotNone(n2.volume)
2266
2267    def testVolumeB(self):
2268        from music21 import note
2269        # manage deepcopying properly
2270        n1 = note.Note()
2271
2272        n1.volume.velocity = 100
2273        self.assertEqual(n1.volume.velocity, 100)
2274        self.assertEqual(n1.volume.client, n1)
2275
2276        n1Copy = copy.deepcopy(n1)
2277        self.assertEqual(n1Copy.volume.velocity, 100)
2278        self.assertEqual(n1Copy.volume.client, n1Copy)
2279
2280
2281# ------------------------------------------------------------------------------
2282# define presented order in documentation
2283_DOC_ORDER = [Note, Rest, Unpitched, NotRest, GeneralNote, Lyric]
2284
2285if __name__ == '__main__':
2286    # sys.arg test options will be used in mainTest()
2287    import music21
2288    music21.mainTest(Test)
2289
2290