The time module
Functionality to compute the time length of musical expressions.
- class Result(node, time)
Bases:
tuple
The result value (if not None) of the
position()
andduration()
methods.- node
The topmost Music expression.
- time
The position or duration time value.
- class Time(scope=None, wait=False)[source]
Bases:
object
Compute the length of musical expressions.
A
Scope
, if given using thescope
parameter, is used to resolve include files. If no scope is given, only searches the current DOM document for variable assignments.If a scope is given, include commands are followed and
wait
determines whether to wait for ongoing transformations of external DOM documents. If wait is False, and a transformation is not yet finished the include is not followed.An example:
>>> import parce, quickly.time >>> d = parce.Document(quickly.find('lilypond'), r''' ... music = { c4 d e f } ... ... { c2 \music g a b8 g f d } ... ''', transformer=True) >>> m = d.get_transform(True) >>> m.dump() <lily.Document (2 children)> ├╴<lily.Assignment music (3 children)> │ ├╴<lily.Identifier (1 child)> │ │ ╰╴<lily.Symbol 'music' [1:6]> │ ├╴<lily.EqualSign [7:8]> │ ╰╴<lily.MusicList (4 children) [9:21]> │ ├╴<lily.Note 'c' (1 child) [11:12]> │ │ ╰╴<lily.Duration Fraction(1, 4) [12:13]> │ ├╴<lily.Note 'd' [14:15]> │ ├╴<lily.Note 'e' [16:17]> │ ╰╴<lily.Note 'f' [18:19]> ╰╴<lily.MusicList (8 children) [23:49]> ├╴<lily.Note 'c' (1 child) [25:26]> │ ╰╴<lily.Duration Fraction(1, 2) [26:27]> ├╴<lily.IdentifierRef 'music' [28:34]> ├╴<lily.Note 'g' [35:36]> ├╴<lily.Note 'a' [37:38]> ├╴<lily.Note 'b' (1 child) [39:40]> │ ╰╴<lily.Duration Fraction(1, 8) [40:41]> ├╴<lily.Note 'g' [42:43]> ├╴<lily.Note 'f' [44:45]> ╰╴<lily.Note 'd' [46:47]> >>> t=quickly.time.Time() >>> t.position(m[1][0]) # first note in second expression Result(node=<lily.MusicList (8 children) [23:49]>, time=0) >>> t.position(m[1][1]) # \music identifier ref Result(node=<lily.MusicList (8 children) [23:49]>, time=Fraction(1, 2)) >>> t.position(m[1][2]) # the g after the \music ref Result(node=<lily.MusicList (8 children) [23:49]>, time=Fraction(3, 2)) >>> t.length(m[0][2]) # the \music expression Fraction(1, 1) >>> t.length(m[1]) # total length of second expression Fraction(3, 1) # referenced \music correctly counted in :) >>> t.duration(m[1][0], m[1][2])# length of "c2 \music g" part (g has duration 2) Result(node=<lily.MusicList (8 children) [23:49]>, time=Fraction(2, 1))
There are convenient methods to get the musical position of a parce
Cursor
:>>> c = parce.Cursor(d, 44, 47) >>> c.text() # two notes 'f d' >>> t.cursor_position(c) # length or music before the cursor Result(node=<lily.MusicList (8 children) [23:49]>, time=Fraction(11, 4)) >>> t.cursor_duration(c) # duration of the selected music Result(node=<lily.MusicList (8 children) [23:49]>, time=Fraction(1, 4))
LilyPond music functions that alter durations are recognized, and are abstracted in simple transformations that alter log, dotcount and/or scaling. An example:
>>> from quickly.dom import read >>> m = read.lily(r"\tuplet 3/2 { c8 d e }") >>> t.length(m) Fraction(1, 4) >>> m[1][1] # a single note in the tuplet <lily.Note 'd'> >>> t.length(m[1][1]) Fraction(1, 12) >>> m = read.lily(r"\shiftDurations #1 #1 { c4 d e f }") >>> t.length(m) # note value halved and dot added, so should be 3/4 Fraction(3, 4) >>> m[2][2] <lily.Note 'e'> >>> t.length(m[2][2]) # autodiscovers the current duration transform Fraction(3, 16)
Note
As a
Time
instance uses some caching for the duration of individual notes, don’t rely on its computations while also modifying durations of music notes, rests etc.- wait
If True, parce transformations are waited for.
- position(node, include=False)[source]
Return a
Result
two-tuple(node, time).The
node
argument must be (a child of) aMusic
instance.The returned
node
is the topmost Music element, and thetime
is the computed length of all preceding music nodes. Ifinclude
is True, the node’s length itself is also added.
- duration(start_node, end_node)[source]
Return a
Result
two-tuple(node, time) or None.The returned
node
is the topmost Music element both nodes must be a descendant of. Both nodes must be (children of)Music
nodes. If they don’t share the same ancestor, None is returned. The returnedtime
value can be negative when the end node precedes the start node.
- cursor_position(cursor)[source]
Return a
Result
two-tuple(node, time) or None.The
node
is the music expression the cursor is in, and thetime
is the time offset from the start of that expression to the cursor’s position.Returns None if the cursor is not in music.
- cursor_duration(cursor)[source]
Return a
Result
two-tuple(node, time) or None.The
node
is the music expression the cursor is in, and thetime
is the length of the selected music fragment.Returns None if there’s no selection or the selection’s start and/or end are not in music, or in different music expressions.
- class TimeContext(time, transform=None, properties=None)[source]
Bases:
object
Encapsulates the transform and properties during time calculations.
The transform (
Transform
) determines the actual length of Durable objects, and the properties (Properties
) are forwarded to child contexts, where inside thetime_length()
of Music nodes values can be read and also modified.- transform
The current Transform.
- properties
The current Properties.
- enter(node, time=None)[source]
Return a new TimeContext.
The returned TimeContext uses the new
Time
(if given, otherwise the same as ours) and adds theTransform
and theProperties
of the specifiednode
to the current ones.
- length(node, end=None)[source]
Return the length of any node.
Follows variable references using the scope (if given to the
Time
instance) and callstime_length()
for Music nodes. Returns 0 for any other, non-musical, node.