These functions calculate the ammount of time (either in beats, or seconds)
that have unfolded since the beginning of a piece, giving a sense of the timeline in which events unfold.
In music21
this information is described as "offsets"---however,
we prefer to reserve the words "onset" and "offset" to refer
to the beginning (attack) and end (release) of rhythmic events.
If timeline()
is applied to a humdrumR data class
you may use the data's fields as arguments.
If no field names are specified, the first selectedField is used as x
.
If timestamp()
is applied to a humdrumR data class
you may use the data's fields as arguments.
If no field names are specified, the first selectedField is used as x
.
Usage
# S3 method for default
timeline(
x,
start = 0,
pickup = NULL,
...,
Exclusive = NULL,
threadNA = TRUE,
parseArgs = list(),
groupby = list()
)
humData |> select(Token) |> timeline()
humData |> timeline(Token)
timeline(
x,
start = 0,
pickup = NULL,
...,
Exclusive = NULL,
threadNA = TRUE,
parseArgs = list(),
groupby = list()
)
# S3 method for default
timestamp(
x,
BPM = 60,
start = 0,
pickup = NULL,
minutes = TRUE,
...,
Exclusive = NULL,
threadNA = TRUE,
parseArgs = list(),
groupby = list()
)
humData |> select(Token) |> timestamp()
humData |> timestamp(Token)
timestamp(
x,
BPM = 60,
start = 0,
pickup = NULL,
minutes = TRUE,
...,
Exclusive = NULL,
threadNA = TRUE,
parseArgs = list(),
groupby = list()
)
Arguments
- x
Input rhythm information.
Must be
atomic
, orNULL
.- start
Where does timeline begin?
Defaults to
0
.Must be a single number.
- pickup
Where is there a pickup (anacrusis)?
Defaults to
NULL
Must be
logical
of samelength(x)
, OrNULL
. See "Pickups" section below.- threadNA
Should rhythm-less tokens return
NA
?Defaults to
TRUE
.Must be a singleton
logical
value: an on/off switch.- parseArgs
An optional list of arguments passed to the rhythm parser.
Defaults to an empty
list()
.Must be a
list
of named arguments to the rhythm parser.- groupby
A
list
of vectors to groupx
.Defaults to
list()
.Must be a
list
; every element of the list must be lengthlength(x)
.To function as a by-record timeline, the
groupby
list music include a namedPiece
andRecord
fields. Luckily, these are automatically passed by with(in).humdrumR, so you won't need to worry about it!- BPM
The tempo.
Defaults to
60
.Must be a single number or a
character
string in the format"MM120"
(for 120 bpm).By default, with(in).humdrumR passes the
BPM
field, if present.- minutes
Should minutes be counted in output?
Defaults to
TRUE
.Must be a singleton
logical
value: an on/off switch.If
TRUE
, output seconds are converted to a character string encoding minutes, seconds, and milliseconds in the formatMM.SS.ms
.
Details
Music unfolds over time, and humdrum data typically represents this
by placing simultaneous events in the same record, with successive events
in ever higher records---progressing "top down" through the file.
In some humdrum data, only this (implicit) ordering of data over time is present.
The Record
and DataRecord
fields capture this ordering in all data parsed by humdrumR
.
However, many (probably most) humdrum data files contain at least some information about the relative
duration of events, representing more detailed information about timing and rhythm.
timeline()
parses and input vector x
as durations,
computes the cumulative sum of the durations, with the start
argument appended to the beginning.
The result is a numeric
vector representing the total duration since the beginning of the vector (plus the value of start
, which defaults to zero).
The cumulative durations of timeline()
represent musical duration units, where 1
equals a whole note.
timestamp()
converts these durations to seconds, either using the BPM
argument/field to determine the tempo or using the
default tempo of 60 beats per minute.
If minutes == TRUE
, the output is formatted into "minute:seconds.milliseconds"
character strings.
If a groupby
argument is provided, localDuration()
is used to compute the minimum durations in each group before
computing the cumulative sum only with unique values from each Record
in the groupby
.
By default, with(in).humdrumR will automatically pass groupby = list(Piece = Piece, Record = Record)
into calls to timeline()
or timestamp()
.
Thus, a call like within(humData, timeline(Token))
will compute the correct timeline position for all
tokens across all spines/paths/stops---all values in the same record will be the same.
Note that, timeline()
and timestamp()
follow the default behavior of duration()
by treating grace-notes as duration 0
.
This means that their position on the timeline is simply inherited from the previous event on the timeline, as if they occur
at the same time.
If you want to use the specified duration(s) of grace notes, specify grace = TRUE
.
By default, any other tokens without (parsable) rhythm information are returned a NA
.
However, if threadNA = FALSE
, rhythm-less tokens will be treated as if they have a duration of 0
as well, and thus
have a (shared) position on the timeline.
Pickups
Another option is to pass the pickup
argument a logical vector of the same length as the input x
.
Within each piece/group, any block of TRUE
values at the beginning of the pickup
vector
indicate a pickup.
The first index where the pickup
logical is FALSE
is used as the starting point of the timeline/timecount;
All the earlier (pickup == TRUE
) points will be negative numbers, measured backwards from the start index.
In humdrumR
, and datapoints before the first barline record (=
) are labeled Bar == 0
in the Bar
field.
Thus, a common use for the pickup
argument is within(humData, timeline(Token, pickup = Bar < 1)
, which makes the downbeat of
the first complete bar 1
the starting point of the timeline---any notes in pickup bars are negative on the timeline.
See also
The timecount()
and metcount()
functions provide "higher level" musical interpretations of timeline information.
Examples
tokens <- c('4.GG', '8G', '16E', '16F#', '16G', '16D', 'q8D#', '4E')
timeline(tokens)
#> [1] 0.0000 0.3750 0.5000 0.5625 0.6250 0.6875 0.6875 0.7500
timestamp(tokens, BPM = '90')
#> [1] ":0" ":1" ":1.333" ":1.500" ":1.667" ":1.833" ":1.833" ":2"
if (FALSE) {
B075 <- readHumdrum(humdrumRroot, "HumdrumData/BeethovenVariations/B075_00_0._a.krn")
within(B075, timeline(Token))
}