Duration
The Duration module defines basic structures for describing a symbolic representation of time by hierarchical subdivision. The building blocks of the Duration module are the Duration, Rhythm, Tempo, and Meter structures.
Duration
The Duration structure is a Rational type, defined by its numerator (Beats) over its power-of-two denominator (Subdivision). A Duration can be instantiated with a Beats and Subdivision.
let dur = Duration(5,32)
Warning: The denominator must be a power-of-two, otherwise your program will crash.
let notDur = Duration(4,17) // boom
A Duration can be created with a shorthand via the /> operator.
let dur = 17/>64
Rhythm
ProportionTree
A ProportionTree is a typealias for Tree<Int,Int>, from the dn-m/Structure/DataStructures module, which provides a hierarchical model of relative durational values without a specificed Duration container size. A ProportionTree can be as simple as a pair of eighth notes,
let eighthPair: ProportionTree = .branch(1, [1,1])
or as complicated as a deeply nested tuplet.
let nested: ProportionTree = .branch(1, [
.branch(2, [
.branch(2, [
.leaf(1),
.leaf(1)
]),
.leaf(3)
]),
.branch(4, [
.leaf(3),
.leaf(4),
.branch(6, [
.leaf(1),
.leaf(1)
]),
.leaf(2),
.branch(2, [
.leaf(3),
.leaf(5)
])
]),
.branch(3, [
.leaf(2),
.leaf(4),
.branch(1, [
.leaf(16),
.leaf(17)
])
])
])
Note: This type is useful for composing up arbitrarily simple or complex rhythms without having to commit to an overall
Duration, or having to normalize the subdivision relationships between all of the nodes.
DurationTree
A DurationTree is a typealias for Tree<Duration,Duration>, from the dn-m/Structure/DataStructures module.
A DurationTree is often not needed to be created by user, but is often the composition of a Duration container size and a ProportionTree.
let proportions: ProportionTree = .branch(1, [1,2,4])
let duration = 13/>64
let durationTree = DurationTree(duration, proportions)
The beat and subdivision values of each node of the resulting DurationTree will be normalized automatically
durationTree // => .branch(13/>64, [
.leaf(2/>64),
.leaf(4/>64),
.leaf(8/>64)
])
for a resulting tuplet ratio of 14:13.
Rhythm.Leaf
A Rhythm.Leaf models the metrical identity of a given rhythmic leaf item. It is a typealias for ContinuationOrInstance<AbsenceOrEvent<Element>>.
.continuation(i.e., a leaf istied
over from the previous event).instance(.rest)(i.e., a leaf is arest
, a measured silence).instance(.event(Element))(i.e., a leaf is a measured non-silence)
ContinuationOrInstance
ContinuationOrInstance is a two-case generic enum similar to the Optional enum of the Standard Library, which describes whether a rhythmic item is:
- a
.continuation(i.e.,tied-over
from its preceeding item), or - an
.instance(Element)(i.e., an action occuring).
AbsenceOrEvent
AbsenceOrEvent is a two-case generic enum similar to the Optional enum of the Standard Library, which describes whether a rhythmic item is:
- an
.absence(i.e., arest
), or - an
.event(Element)(i.e., anote
).
Rhythm
A Rhythm is the composition of a DurationTree and an array of Rhythm.Leaf values (with a length equivalent to the leaves of the durationTree). The Rhythm.Leaf values can store any value generically.
We can decorate the durationTree above like so:
let rhythm = Rhythm<String>(durationTree, [
.instance(.absence), // rest
.instance(.event("BANG")), // start event
.continuation // tied from previous event
])
Meter
Like a Duration, a Meter is a Rational type, used for defining the metrical context of measure.
You can create a common time
meter,
let meter = Meter(4,4)
or maybe something a little more fun.
let meter = Meter(31,128)
Tempo
A Tempo is the definition of a pulse occurring at a given frequency (beatsPerMinute) at a given Subdivision level (e.g., quarter, sixteenth, etc.).
let stayinAlive = Tempo(100, subdivision: 4) // remember this for CPR
Tempo.Interpolation.Easing
A Tempo.Interpolation.Easing specifies the curve of a Tempo.Interpolation.
linearpowerInpowerInOutexponentialInsineInOut
Tempo.Interpolation
A Tempo.Interpolation defines a transition between two Tempo values, over a given length, with a specified easing.
let startTempo = Tempo(24, subdivision: 4)
let endTempo = Tempo(192, subdivision: 8)
let interpolation = Tempo.Interpolation(
start: startTempo,
end: endTempo,
length: Fraction(37,4),
easing: .sineInOut
)
Note: Subdivision values needn’t be the same.
Tempo.Interpolation.Fragment
A Tempo.Interpolation.Fragment is a portion of a Tempo.Interpolation within a given range.
let startTempo = Tempo(24)
let endTempo = Tempo(72)
let interpolation = Tempo.Interpolation(
start: startTempo,
end: endTempo,
length: Fraction(13,4)
)
let fragment = Tempo.Interpolation.Fragment(
interpolation,
in: Fraction(5,4) ..< Fraction(11,4)
)
Note: The default
subdivisionvalue is4and the defaulteasingvalue is.linear.
Tempo.Interpolation.Collection
A Tempo.Interpolation.Collection defines a contiguous collection of Tempo.Interpolation.Fragment values, which are indexed by the offset Fraction value.
Tempo.Interpolation.Collection.Builder
A helper class Tempo.Interpolation.Collection.Builder is provided to encapsulate the stateful construction process of a Tempo.Interpolation.Collection.
You can start with an empty Builder,
let builder = Tempo.Interpolation.Collection.Builder()
create a few interpolations (e.g., accelerando, ritardando, static),
let a = Tempo.Interpolation(
start: Tempo(60),
end: Tempo(120),
length: Fraction(4,4)
)
let b = Tempo.Interpolation(
start: Tempo(120),
end: Tempo(60),
length: Fraction(4,4)
)
let c = Tempo.Interpolation(
start: Tempo(60),
end: Tempo(60),
length: Fraction(4,4)
)
then add them with the Builder.
for interpolation in [a,b,c] {
builder.add(interpoation)
}
Now we are ready for the Builder to give us a finished product.
let collection = builder.build()
If it makes more sense, we can also create a Tempo.Interpolation.Collection directly.
let collection = Tempo.Interpolation.Collection([a,b,c])
In the case that we need to retrieve a subsection of your collection, we can provide a subscript with a Range<Fraction> to get it out.
let fragment = collection[Fraction(3,32)..<Fraction(19,8)]
This will produce a Tempo.Interpolation.Collection with three Tempo.Interpolation.Fragments representing the three subsections of the interpolations we created above.
View on GitHub
Install in Dash
Duration Reference