.. _usersGuide_13_music21object2:

.. WARNING: DO NOT EDIT THIS FILE:
   AUTOMATICALLY GENERATED.
   PLEASE EDIT THE .py FILE DIRECTLY.


User's Guide, Chapter 13: More Music21Object Attributes and Properties
======================================================================

At this point you know how to find a ``Music21Object``, how to name them
and group them (with ``.id`` and ``.groups``) and how to position them
in Streams (with ``.offset``, ``.priority``, ``.classSortOrder`` and the
``.activeSite``). This section gets first into some more advanced things
that Music21Objects have, then some more fun things.

Sites and the storing of elements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

All ``Music21Objects`` (i.e., elements) have a ``.sites`` property which
is a :class:`~music21.sites.Sites` object which holds information
about all the places the ``Music21Object`` is stored in. At its
simplest, it's something that can be iterated over:

.. code:: python

    from music21 import *
    
    n = note.Note()
    s1 = stream.Stream(id='s1')
    s2 = stream.Stream(id='s2')
    s1.insert(10, n)
    s2.insert(20, n)
    
    for s in n.sites:
        print(s, s.elementOffset(n))


.. parsed-literal::
   :class: ipython-result

    <music21.stream.Stream s1> 10.0
    <music21.stream.Stream s2> 20.0


Note that the order of the Streams in ``.sites`` is guaranteed to be the
order in which the note was inserted into the site.

There's a lot more that ``.sites`` can do, but primarily for developers.
We will get back to sites later.

Derivations
~~~~~~~~~~~

We will talk about derivations more in a future chapter, butwe alluded
to them in the Example in chapter 10, so let's say a few words about
this advanced feature. A :class:`~music21.derivation.Derivation`
object is a pointer to an object that this object is derived from in
some way. They've gone their separate ways to an extent, but may want to
talk to each other later. A ``Music21Object`` starts out with no useful
Derivation:

.. code:: python

    c = note.Note("C4")
    c.derivation




.. parsed-literal::
   :class: ipython-result

    <Derivation of <music21.note.Note C> from None via "None">



But we can create new notes from it and they're not totally connected,
but show their connection through ``.derivation``:

.. code:: python

    f = c.transpose('P4')
    f




.. parsed-literal::
   :class: ipython-result

    <music21.note.Note F>



.. code:: python

    f.derivation




.. parsed-literal::
   :class: ipython-result

    <Derivation of <music21.note.Note F> from <music21.note.Note C> via "transpose">



Now ``c`` has a life of its own from ``f``. We can add a sharp to C and
the transpose relationship of F to C does not affect it:

.. code:: python

    c.pitch.accidental = pitch.Accidental('sharp')
    (c, f)




.. parsed-literal::
   :class: ipython-result

    (<music21.note.Note C#>, <music21.note.Note F>)



But if ``f`` wants to do something to ``c``, it can by changing itself
and every element of its ``.derivation.chain()``:

.. code:: python

    f.notehead = 'diamond'
    for n in f.derivation.chain():
        n.notehead = 'diamond'
    
    (f.notehead, c.notehead)




.. parsed-literal::
   :class: ipython-result

    ('diamond', 'diamond')



While ``f`` can search upwards in its ``.derivation.chain()`` and find
``c``, ``c`` cannot find ``f`` in its derivation; it is a connection
that is designed to be one-way only.

Setting derivations can be done manually, but it's an advanced enough
topic that we will get to it later.

Context attributes
~~~~~~~~~~~~~~~~~~

Several attributes of ``Music21Objects`` only work after the object has
been placed inside a Stream that has certain features of their own.

An easy one to understand is ``.measureNumber`` which finds the
``.number`` value of the measure that an object is placed in:

.. code:: python

    n = note.Note('C')
    m = stream.Measure()
    m.number = 7
    m.append(n)
    n.measureNumber




.. parsed-literal::
   :class: ipython-result

    7



This works even if a note is inside a voice inside a measure:

.. code:: python

    v = stream.Voice()
    n2 = note.Note('D')
    v.append(n2)
    m.insert(0, v)
    n2.measureNumber




.. parsed-literal::
   :class: ipython-result

    7



Without a context, you'll get None

.. code:: python

    n3 = note.Note()
    n3.measureNumber is None




.. parsed-literal::
   :class: ipython-result

    True



The second context attribute is, appropriately, called ``.seconds``. It
requires a tempo.MetronomeMark() to be placed into the Stream before the
object and will calculate how many seconds the object (note, etc.) lasts
at that tempo:

.. code:: python

    m.insert(0, tempo.MetronomeMark('Allegro', 120))
    print (n.quarterLength, n.seconds)


.. parsed-literal::
   :class: ipython-result

    1.0 0.5


Unlike ``.measureNumber`` and the rest of the attributes we will see
below, you can change ``.seconds`` to reflect exact timing you might
have from audio or MIDI data.

.. code:: python

    n.seconds = 0.6
    n.seconds




.. parsed-literal::
   :class: ipython-result

    0.6



An object with no tempo information in its surrounding context returns
an error for ``.seconds``

.. code:: python

    n3 = note.Note('E')
    n3.seconds


::


    ---------------------------------------------------------------------------

    Music21ObjectException                    Traceback (most recent call last)

    <ipython-input-13-0a7112d868b7> in <module>()
          1 n3 = note.Note('E')
    ----> 2 n3.seconds
    

    /Users/cuthbert/git/music21base/music21/base.py in _getSeconds(self)
       3260         ti = self.getContextByClass('TempoIndication')
       3261         if ti is None:
    -> 3262             raise Music21ObjectException('this object does not have a TempoIndication in Sites')
       3263         mm = ti.getSoundingMetronomeMark()
       3264         # once we have mm, simply pass in this duration


    Music21ObjectException: this object does not have a TempoIndication in Sites


So use ``try...except...`` to catch this:

.. code:: python

    for el in (n, n2, n3):
        seconds = "No information"
        try:
            seconds = el.seconds
        except exceptions21.Music21Exception:
            pass
        print(el.step, seconds)


.. parsed-literal::
   :class: ipython-result

    C 0.6
    D 0.5
    E No information


The last three context attributes, ``.beat``, ``.beatStr`` (beat
string), and ``.beatStrength``, all require
:class:`~music21.meter.TimeSignature` contexts. Since they're the
topic of :ref:`our next chapter<usersGuide_14_timeSignatures>` we'll
put them off until then.

Most ``Music21Objects`` such as ``Notes`` have many additional
attributes, but these are all the ones that are common to every object
that can go in a ``Stream`` (after all, what would ``.step`` mean for a
:class:`~music21.tempo.MetronomeMark`?)

..note::

   You may find other attributes on your base.Music21Object, especially if you are running
   an older version of `music21`. They are all deprecated and most have been removed in
   v.3; programmers are advised to stick to the safe list of attributes described here.

Methods on ``Music21Objects``
-----------------------------

Attributes and properties are aspects of an object that are lightweight
and have no configuration options, so they are accessed without ``()``.
Methods tend to do more work and have more options, so they will always
be called with ``()`` signs.

Unlike attributes, where we have documented all of them, only a subset
of the methods on ``Music21Objects`` are listed below. All of them can
be found in the documentation to :class:`~music21.base.Music21Object`,
but many of them have obscure uses and might be moved later to not
clutter up what is really important! And those are...

.getOffsetBySite and .setOffsetBySite
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

These methods work as the ``.offset`` attribute but can work on any site
where the object is a part of.

.. code:: python

    n = note.Note()
    s1 = stream.Stream(id="s1")
    s1.insert(10, n)
    s2 = stream.Stream(id="s2")
    s2.insert(20, n)
    n.getOffsetBySite(s1)




.. parsed-literal::
   :class: ipython-result

    10.0



.. code:: python

    n.setOffsetBySite(s1, 15.0)
    n.getOffsetBySite(s1)




.. parsed-literal::
   :class: ipython-result

    15.0



There is one extra possible attribute on ``.getOffsetBySite``,
"stringReturns=True" which will say whether or not an element has a
shifting offset. Right barlines have one:

.. code:: python

    s3 = stream.Measure()
    n3 = note.Note(type='whole')
    s3.append(n3)
    rb = bar.Barline()
    s3.rightBarline = rb
    rb.getOffsetBySite(s3)




.. parsed-literal::
   :class: ipython-result

    4.0



.. code:: python

    rb.getOffsetBySite(s3, stringReturns=True)




.. parsed-literal::
   :class: ipython-result

    'highestTime'



And in fact if we change the duration of ``n3`` the position of the
barline will shift along with it:

.. code:: python

    n3.duration.type = 'half'
    rb.getOffsetBySite(s3)




.. parsed-literal::
   :class: ipython-result

    2.0



getContextByClass()
~~~~~~~~~~~~~~~~~~~

This is an extremely powerful tool -- you might not use it often, but be
assured that ``music21`` is using it on your behalf all the time when
sophisticated analysis is involved. It finds the active element matching
a certain class preceeding the element. Let me demonstrate:

.. code:: python

    bach = corpus.parse('bwv66.6')
    lastNote = bach.recurse().getElementsByClass('Note')[-1]
    lastNote




.. parsed-literal::
   :class: ipython-result

    <music21.note.Note F#>



What part is it in?

.. code:: python

    lastNote.getContextByClass('Part')




.. parsed-literal::
   :class: ipython-result

    <music21.stream.Part Bass>



What is the KeySignature at that moment?

.. code:: python

    lastNote.getContextByClass('KeySignature')




.. parsed-literal::
   :class: ipython-result

    <music21.key.KeySignature of 3 sharps, mode minor>



What is the TimeSignature at that moment?

.. code:: python

    lastNote.getContextByClass('TimeSignature')




.. parsed-literal::
   :class: ipython-result

    <music21.meter.TimeSignature 4/4>



Why is this such a sophisticated method? It knows about the differences
in different types of Streams. If the key signature changes in a
different part then it doesn't affect the notes of the current part, but
if it changes in a previous measure in the same part, then that matters.
Furthermore, the caching mechanism via something called ``Timespans`` is
amazingly fast, so that running through an entire score getting the
context for each object doesn't take long at all:

.. code:: python

    gloria = corpus.parse('luca/gloria')
    soprano = gloria.parts[0]
    
    lastTimeSignature = None
    for n in soprano.recurse().getElementsByClass('Note'):
        thisTimeSignature = n.getContextByClass('TimeSignature')
        if thisTimeSignature is not lastTimeSignature:
            lastTimeSignature = thisTimeSignature
            print(thisTimeSignature, n.measureNumber)


.. parsed-literal::
   :class: ipython-result

    <music21.meter.TimeSignature 6/8> 1
    <music21.meter.TimeSignature 2/4> 28
    <music21.meter.TimeSignature 6/8> 80
    <music21.meter.TimeSignature 3/4> 110


As you might expect, the ``.measureNumber`` routine uses
``.getContextByClass('Measure')`` internally. What is also interesting
is that ``.getContextByClass`` is smart enough to search out derivation
chains to find what it is looking for. For instance, this flat stream
has only notes, no time signatures. But it can still find each note's
time signature ane measure number context.

.. code:: python

    sfn = soprano.flat.notes.stream()
    
    lastTimeSignature = None
    for n in sfn:
        thisTimeSignature = n.getContextByClass('TimeSignature')
        if thisTimeSignature is not lastTimeSignature:
            lastTimeSignature = thisTimeSignature
            print(thisTimeSignature, n.measureNumber)


.. parsed-literal::
   :class: ipython-result

    <music21.meter.TimeSignature 6/8> 1
    <music21.meter.TimeSignature 2/4> 28
    <music21.meter.TimeSignature 6/8> 80
    <music21.meter.TimeSignature 3/4> 110


Internally ``.getContextByClass`` uses another ``Music21Object`` method
called ``.contextSites()`` which is a generator that tells the system
where to search next:

.. code:: python

    for cs in lastNote.contextSites():
        print(cs)


.. parsed-literal::
   :class: ipython-result

    (<music21.stream.Measure 9 offset=33.0>, 2.0, 'elementsFirst')
    (<music21.stream.Part Bass>, 35.0, 'flatten')
    (<music21.stream.Score 0x106e34da0>, 35.0, 'elementsOnly')


This says that first the elements of Measure 9 should be searched,
beginning at 2.0 and working backwards to the beginning of the measure,
then if the matching context isn't found, the measure will be flattened
(in case there are other voices in the measure) and anything from before
offset 2.0 of that flattened stream will be searched.

If that fails, then the Bass part as a whole will be searched, with all
elements flattened, beginning at offset 35 and working backwards. That
way if the context is in another measure it will be found.

Then if that fails, it will look at the score as a whole, beginning at
offset 35 and working backwards, but only looking at things that are at
the score level, not looking at elements within other parts. There may
be scores where for instance, expressive markings appear at the Score
level. This will find them.

Related to ``.getContextByClass()`` is ``.getAllContextsByClass()``
which is a generator that returns each preceeding context.

..note::

   Prior to v.3, `.getAllContextsByClass()` had a different purpose, so do not use it for
   for this purpose. It was unreliable.
   
   Two known bugs that we hope to get fixed soon: if there are two or more
   contexts at the same offset, `.getAllContextsByClass()` will skip over 
   all but one of them. Using `Music21Object` as a class list can create infinite loops.

.. code:: python

    lastGloriaNote = sfn[-1]
    
    for ts in lastGloriaNote.getAllContextsByClass('TimeSignature'):
        print(ts, ts.measureNumber)


.. parsed-literal::
   :class: ipython-result

    <music21.meter.TimeSignature 3/4> 110
    <music21.meter.TimeSignature 6/8> 80
    <music21.meter.TimeSignature 2/4> 28
    <music21.meter.TimeSignature 6/8> 1


Similar to ``.getContextByClass()`` are the ``.next(class)`` and
``.previous(class)`` methods which move to the next or previous element
of the same class at the same (or a higher) hierarchical level. They're
designed to be really easy to use, but so far, I've failed at achieving
that. Hopefully in the next few versions I'll be able to demonstrate in
practice how these commands were designed to work. For now, I'd suggest
avoiding them.

Splitting methods
~~~~~~~~~~~~~~~~~

``Music21`` has three methods on ``Music21Object``\ s for splitting
them. Eventually the plan is to unite them into a single ``.split()``
method, but we're not there yet.

The three methods are:

-  ``.splitAtQuarterLength`` -- splits an object into two objects at the
   given quarter length

-  ``.splitByQuarterLengths`` -- splits an object into two or more
   objects according to a list of quarter lengths

-  ``.splitAtDurations`` -- takes an object with a complex duration
   (such as 5.0 quarters) and splits it into notatable units.

These all work rather similarly. Behind their seeming simplicity are a
host of complex musical decisions that are being made. Take this rather
complex note (we're introducing ``expressions`` and ``articulations``
softly here):

.. code:: python

    n = note.Note('C#5')
    n.duration.type = 'whole'
    n.articulations = [articulations.Staccato(), articulations.Accent()]
    n.lyric = 'hi!'
    n.expressions = [expressions.Mordent(), expressions.Trill(), expressions.Fermata()]
    n.show()




.. image:: usersGuide_13_music21object2_57_0.png



Now let's split this note at the 3/4 mark:

.. code:: python

    splitTuple = n.splitAtQuarterLength(3.0)
    s = stream.Stream()
    s.append(splitTuple)
    s.show()




.. image:: usersGuide_13_music21object2_59_0.png



Notice the choices that ``music21`` made -- the two notes are tied, the
lyrics are sung at the beginning, the accent and mordent appear at the
beginning of the note while the staccato and fermata(!) appear on the
second note, while trill mark gets put onto the first note only. This is
part of the "batteries included" ``music21`` approach -- try to do
something musically smart in most cases. In fact, it's even a bit
smarter -- the ``splitTuple`` knows that there's something called a
TrillExtension spanner in it which should be put into the Stream:

.. code:: python

    for thisSpanner in splitTuple.spannerList:
        s.insert(0, thisSpanner)
    s.show()




.. image:: usersGuide_13_music21object2_61_0.png



..note::

   SplitTuples and spannerList is new as of v3, in v2 and earlier, a trill mark is generated
   for each note and the placement of the staccato would be on the first note as well.

Showing and Writing
~~~~~~~~~~~~~~~~~~~

The two last methods are almost certainly the most important:
``.show()`` and ``.write()``. We've been using ``.show()`` throughout
the User's Guide, so it's familiar. It usually takes a single argument
which is the format (default is ``'musicxml'`` except on IPython where
it is ``'musicxml.png'``. ``.write()`` by contrast writes out the file
to disk. The first argument is again the format. The second argument,
optional, is the filename with path. If omitted then a temporary file is
written (and the filename is returned).

We'll see enough about ``.show()`` and ``.write()`` later, so that's
enough for now on this long chapter. Let's return to the ``.beat``
related function in
:ref:`Chapter 14, Time Signatures <usersGuide_14_timeSignatures>`.