Files
alda-mirror/client/model/repeat.go
Dave Yarwood e0d11b1ec2 include source context EVERYWHERE
This provides filename/line/column context for any error I could possibly find.
To achieve this, I made it so that all ScoreUpdates have source context, so when
updating the score results in an error, we can print out the line and column
number corresponding to the error.

It's a bit more complicated than that, because score updates are nestable (e.g.
event sequences can contain cram expressions can contain chords, etc.), which
essentially gives us a stacktrace whenever a score update results in an error. I
punted on giving the user the full stacktrace, in favor of doing something
simpler and just showing the bottom-most error, because that's probably going to
be the line and column number that's the most helpful.
2020-11-14 20:34:04 -05:00

75 lines
1.8 KiB
Go

package model
import (
"alda.io/client/json"
"github.com/mohae/deepcopy"
)
// A Repeat expression repeats an event a number of times.
type Repeat struct {
SourceContext AldaSourceContext
Event ScoreUpdate
Times int32
}
// GetSourceContext implements HasSourceContext.GetSourceContext.
func (repeat Repeat) GetSourceContext() AldaSourceContext {
return repeat.SourceContext
}
// JSON implements RepresentableAsJSON.JSON.
func (repeat Repeat) JSON() *json.Container {
return json.Object(
"type", "repeat",
"value", json.Object(
"event", repeat.Event.JSON(),
"times", repeat.Times,
),
)
}
// UpdateScore implements ScoreUpdate.UpdateScore by repeatedly updating the
// score with an event a specified number of times.
func (repeat Repeat) UpdateScore(score *Score) error {
for repetition := int32(1); repetition <= repeat.Times; repetition++ {
for _, part := range score.CurrentParts {
part.currentRepetition = repetition
}
if err := score.Update(repeat.Event); err != nil {
return err
}
}
return nil
}
// DurationMs implements ScoreUpdate.DurationMs by returning the total duration
// of the event being repeated the specified number of times.
func (repeat Repeat) DurationMs(part *Part) float64 {
durationMs := 0.0
for repetition := int32(1); repetition <= repeat.Times; repetition++ {
part.currentRepetition = repetition
durationMs += repeat.Event.DurationMs(part)
}
return durationMs
}
// VariableValue implements ScoreUpdate.VariableValue by returning a version of
// the repeat where the value of the event to be repeated is captured.
func (repeat Repeat) VariableValue(score *Score) (ScoreUpdate, error) {
result := deepcopy.Copy(repeat).(Repeat)
eventValue, err := repeat.Event.VariableValue(score)
if err != nil {
return nil, err
}
result.Event = eventValue
return result, nil
}