You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Apr 29, 2020. It is now read-only.
I have a feeling that the Maybe may not be necessary for anything but implementing rest. Indeed, most Score instances seem to be juggling around it. On the other hand, a score without rests does not really seem like a musical score to me.
Note that we can remove all rests from a score and still get an unaffectd score as far as notes are concerned, however without them a note-less score can note does not have duration or offset, so we can not do
c |> d |> rest^*2
Onset, offset, duration
This is related to the onset/offset/duration mixup. I am unsure what onset/offset/duration should mean for the different types.
The duration laws is a starting point:
duration a = offset a - onset a
duration a >=0
accordingly
offset a >= onset a
Intutuion says that a |> b should place the onset of b at the offset of a, i.e.
a |> b = a <|> startAt (offset a) b
= a <|> delay (offset a - onset b) b
In the original library, onset was always zero, so we could simply do
a |> b = a <|> delay (duration a) b
= a <|> delay (offset a - onset a) -- as per the duration law= a <|> delay (offset a -0)
= a <|> delay (offset a - onset b)
Instancces
Track and Score has more or less identical onset and offset instances:
instanceHasOnset (Tracka) where
onset x =minimum (map on x) where on (t,x) = t
offset x =maximum (map off x) where off (t,x) = t
instanceHasOnset (Scorea) where
onset x =minimum (map on x) where on (t,d,x) = t
offset x =maximum (map off x) where off (t,d,x) = t + d
This also give us duration instances for Track and Score per the duration laws.
instanceHasOnseta=>HasDurationawhere
duration x = offset x - onset x
Note that in a track/score with onset zero (let us call that a normalized track/score), we still have duration = offset.
Part is different: duration is sum and there is no onset/offset.
instanceHasDuration (Parta) where
duration x =sum (map duration x)
Note that while both tracks, scores and parts have scale, only tracks and scores have delay. Put it differently, parts are completely relative in time (like vectors), while scores and tracks are absolute (like points). Maybe we should rename parts to reflect this?
If a score is notes with possibly empty space around them, and onset, offset and duration is determined by the note occurences, then a score without values can not have a duration. Or well, it is error "empty list". Disambiguate as follows:
duration mempty=0
onset mempty=0
offset mempty=0
We want to have a function rest :: Score a, analogous to note :: a -> Score a. The purpose of a rest is simply to allow sequential catenation (juxtaposition) without values (similar to strut in diagrams). We can do rests either by wrapping score elements in Maybe, or by maintaining a separate duration valid if there are no elements. I choose the maybe option as it is more clear.
In the original library, I used an implementation like delay t x = rest^*t |> x. This does not make sense now, as rests are themselves elements (i.e. this implementation of delay would affect duration but not onset instead of the other way around.
Summary
Think of it like this:
Rests (Nothing) is not a way to encode empty space (as it is in a classical score).
Rather, each score (or note, track etc) has a nominal onset and offset. There may be sound outside these values (see pre-onset etc below), they are defined as logical start (attack action) and stop (damp action) time.
Redifine sequential and parallel composition to align so that onset a == onset b, or offset a == onset b respectively. For instaneous things, sequential composition is (of course) not defined.
Rests are simply empty scores for padding purposes. We remove them with removeRests.
Side notes
Diagrams
Compare this to (===) and (|||) in diagrams. Normally, all diagrams have an intuitive bounding box. However, we can also use functions like strut allow us to create empty diagrams with bounding boxes for juxtaposition purposes. I feel want something similar, and not just for Score (Maybe a), but the real thing.
Prepared notes
Think of something like an ADSR envelope. Logically, the onset of the note is the start of the attack phase. However, under parallel catenation we want the maximum level (in-between A and D) to be the concurring point. It makes sense to think of an ADSR as having five interesting events: pre-onset <= onset <= post-onset <= offset <= post-offset. Given onset and offset (or onset and duration), the pre and post events are determined by the qualities of the instrument: how long does it take to to excite, stabilize and tranquilize. We can thus amend our duration laws:
excite a = onset a - preOnset a
stabilize a = postOnset a - onset a
tranquilize a = postOffset a - offset a
excite, stabilize, tranquilize >0
The text was updated successfully, but these errors were encountered:
We now have the following semantics:
I have a feeling that the Maybe may not be necessary for anything but implementing
rest
. Indeed, mostScore
instances seem to be juggling around it. On the other hand, a score without rests does not really seem like a musical score to me.Note that we can remove all rests from a score and still get an unaffectd score as far as notes are concerned, however without them a note-less score can note does not have duration or offset, so we can not do
Onset, offset, duration
This is related to the onset/offset/duration mixup. I am unsure what onset/offset/duration should mean for the different types.
The duration laws is a starting point:
accordingly
offset a >= onset a
Intutuion says that
a |> b
should place the onset ofb
at the offset ofa
, i.e.In the original library, onset was always zero, so we could simply do
Instancces
Track and Score has more or less identical onset and offset instances:
This also give us duration instances for Track and Score per the duration laws.
Note that in a track/score with onset zero (let us call that a normalized track/score), we still have
duration = offset
.Part is different: duration is sum and there is no onset/offset.
Note that while both tracks, scores and parts have
scale
, only tracks and scores havedelay
. Put it differently, parts are completely relative in time (like vectors), while scores and tracks are absolute (like points). Maybe we should rename parts to reflect this?If a score is notes with possibly empty space around them, and onset, offset and duration is determined by the note occurences, then a score without values can not have a duration. Or well, it is
error "empty list"
. Disambiguate as follows:We want to have a function
rest :: Score a
, analogous tonote :: a -> Score a
. The purpose of a rest is simply to allow sequential catenation (juxtaposition) without values (similar tostrut
in diagrams). We can do rests either by wrapping score elements inMaybe
, or by maintaining a separate duration valid if there are no elements. I choose the maybe option as it is more clear.In the original library, I used an implementation like
delay t x = rest^*t |> x
. This does not make sense now, as rests are themselves elements (i.e. this implementation of delay would affect duration but not onset instead of the other way around.Summary
Think of it like this:
Nothing
) is not a way to encode empty space (as it is in a classical score).onset
andoffset
. There may be sound outside these values (see pre-onset etc below), they are defined as logical start (attack action) and stop (damp action) time.onset a == onset b
, oroffset a == onset b
respectively. For instaneous things, sequential composition is (of course) not defined.removeRests
.Side notes
Diagrams
Compare this to
(===)
and(|||)
in diagrams. Normally, all diagrams have an intuitive bounding box. However, we can also use functions likestrut
allow us to create empty diagrams with bounding boxes for juxtaposition purposes. I feel want something similar, and not just forScore (Maybe a)
, but the real thing.Prepared notes
Think of something like an ADSR envelope. Logically, the onset of the note is the start of the attack phase. However, under parallel catenation we want the maximum level (in-between A and D) to be the concurring point. It makes sense to think of an ADSR as having five interesting events: pre-onset <= onset <= post-onset <= offset <= post-offset. Given onset and offset (or onset and duration), the pre and post events are determined by the qualities of the instrument: how long does it take to to excite, stabilize and tranquilize. We can thus amend our duration laws:
The text was updated successfully, but these errors were encountered: