Music Box Magic
So how does a music box work?
A music box has notes of a song encoded on a cylinder or strip of paper. Each pin on a cylinder, or hole in a paper strip, triggers a tooth of the comb to chime. This is how music box's make their music. I was inspired by Wintergatan video demonstrating his knowledge of the technology.
Music Box Rule
To simulate a music box in a rules, I decided( with the help of my coworkers ) to store a song as a list of notes. The crank raises events. Crank events are handled by getting a list of notes for the current beat and sending those midi notes to fluidsynth. The rule to do this is below.
rule playSong {
select when testing playSong
foreach getNotes().append(null) setting (n)
pre {
check = ent:event_count == 0
}
if ( check && not n.isnull() ) then
playSound:play(n)
always{
ent:current_beat := ( not check) => ent:current_beat |
((ent:current_beat < ent:songs[ent:playlist[ent:current_song]]{"song"}.length() - 1) => ent:current_beat + 1 | 0) on final;
ent:event_count := (ent:event_count < ent:events_per_beat - 1) => ent:event_count + 1 | 0 on final;
raise explicit event "openDoor"
if (n == "O" && check)
}
}
This rules name is "playSong". playSong selects on "testing playSong" event, which means this rules logic will only be evaluated when a "testing playSong" event is raised to the engine. Foreach is a way to loop a rule on a data set for a single event. This rule gets a list of notes to be played with getNotes function. getNotes function uses current beat variable to return a list of notes. So for every note that needs to be played this rule will fire. I append(null) to every list for the case that a list is empty, which would result in the rule not firing if null was not appended. "event_count" is used to gear down events. Some songs play faster than others, to handle this I discard some events with event_count. event_count is updatable per song. playSound:play(n) is the midi module I created that sends notes to fluidsynth.
Always is the postlude of this rule. I update current_beat and event_count here. With the use of a guard statement I check for a made up midi note "O". O is added to a song to signify when the latch on the door should be triggered open. When the latch should be open an event is raised where a different rule can catch and handle that event.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.