Beat Repeat

I love this name, but I don't think it goes well with this particular page anymore. Thoughts? "Listing the Notes of a Song"? "Simplifying Your Song"? "Programming a Song More Efficiently" "Playing Each Note in a List"? I like "Playing Each Note in a List" best. Thoughts? --MF, 2/12/22 +1 bh

To do for next year. --MF, 3/6/22

I made a really nice FOR EACH animation that is buried in a yellow box on page 8. I should make another one for this page. It should probably go just before the second header (after exercise 3). --MF, 2/27/22
In this activity, you will make it easier to play a song by putting the notes in a list.

Using For Each to Traverse a List

The paragraph below is well-intentioned, but it doesn't belong here. Maybe after your sample song that uses REPEAT?

Where do you mean, exactly? --MF, 3/6/22

Using the repeat block strategically can make your code shorter and easier to read. It's generally a good idea to write shorter code that is easier to read because when something isn't working right, it's easier to find and fix the problem, or when you want to change it later or have someone else read it, that's easier too.

for each (item) in 'list input slot' {
} One way to simplify writing a song is to use a list to store the pitches and then play each pitch in the list. You can use for each to run a command (or group of commands) for each item in a list. For example:
for each (pitch) in (list (60) (60) (67) (67) (69) (69) (67) (0) (65) (65) (64) (64) (62) (62) (60) (0)) {
	play ♪ pitch: (pitch) beats: (0.5)
}

Playing the pitch 0 works like a rest (a pause in the music).

A list is an ordered sequence of items. You've been using lists throughout this course: to store words for a story, to manipulate the letters of a secret message, and even to store lists such as each individual's responses to the question in a survey.

What does "ordered" mean?

It doesn't mean that the items have to appear in alphabetical or numeric order. It just means that these are different lists:
(list a b) (list b a)

  1. Log in to Snap!, and do one of the following:

    This might be a risky move. I was hoping to give the kids a chance to start from scratch if they had a cluttered project, but it does mean that from this page on, some students will have only one project for the lab while others will have two. It also means that I can't refer to their project by name on the subsequent pages, so if they name it awkwardly and forget the name, they won't be able to find it. Thoughts? --MF, 2/23/22

    The further along I get in writing this lab, the more I regret this choice because I have no way of telling them what project I want them to open other than "your last one". I'm now thinking they should start from a new starter XML here without any option. Thoughts? --MF, 2/27/22

    I agree, pick one. I first thought they should start with the example project, but then they don't get the practice in exercise 2. Maybe have them start with the sample (which should be called the starter instead of sample) but still make them make their own FOR EACH block? -bh 3/3/22

    How about they start with starter project and you can remind them they can open up song player in another tab to remember the pitches that they used? -pf 3/3/22

    To resolve next time around. --MF, 3/6/22

    • Open the for each example project and save it to your Snap! account.
    • Open your "Song Player" project if isn't open already.
  2. Create a simple song using for each. If you opened the example project, edit the pitches in the list to create your song. If you opened your own "Song Player" project...
    1. Drag a for each block into the scripting area, and drag a play ♪ block inside it.
      for each (item) in 'list input slot {
	play ♪ pitch: () beats: ()
}
    2. Rename the item variable to pitch by clicking it, typing the new name ("pitch"), and clicking "OK."

      The orange color of item is inaccessible per https://webaim.org/resources/contrastchecker/ It would need to be a significantly darker orange to meet a11y contrast standards. -pf 3/3/22

      Thanks. Let's address this at a meeting. --MF, 3/6/22

      animation showing the user clicking the 'item' variable in a 'for each block', typing 'pitch', and then pressing 'OK.' The 'for each' variable is then named 'pitch' and not 'item'
    3. Drag the pitch variable into the "pitch" input (the first input) of the play ♪ block. Dragging will make a copy of pitch, so you should see pitch in both places.
      animation showing the user clicking the 'pitch' variable and dragging it into the first input slot of the 'play ♪' block
    4. Type a number for the "beats" input (the second input) of the play ♪ block. (For example, if you want half notes, type the number "0.5".)
    5. Drag a list block into the list input slot of the for each block, add some notes, and click the script to test out your song as you build it.
      animation showing the LIST block being dragged into the list input slot of the FOR EACH block. The right triangle button in the LIST block is clicked twice, and each time three additional inputs to the LIST block appear. The numbers 60, 60, 67, 67, 69, 69, 67 are typed into the inputs to the LIST block, and then the FOR EACH block is clicked.
    6. Tips for working with the list block:
      • If you hold down the "shift" key when you press the ◂ or ▸ buttons, it will remove or add three spaces at the end of the list instead of just one.
      • You can press the "tab" key to move the typing cursor to the next input slot without using your mouse.
      • If you want to add or remove a pitch from your list, you don't have to move the other numbers around. To add a new slot, right-click the slot where you want it to appear, and select "insert a slot." To remove a slot, right-click it, and select "delete slot."
  3. Make sure your script plays your song correctly before moving on.
Maybe add a page break here in the future? --MF, 2/28/22

Using For Each to Play Any List of Pitches

You can create a play song block that will apply this script to any input song.
play song (list (60) (60) (67) (67) (69) (69) (67))

How much experience have they had before this of generalizing a script by turning it into a procedure with an input? They should have done that several times by now, no? So that experience should be called out here. "Remember how you generalized your blah blah by making it a procedure with an input? You can do the same thing with this script that plays the notes in a list." --bh 3/3/22

To revisit... --MF, 3/6/22

  1. Create a new command block called play song that takes a list of notes as input and plays each note in the list using for each.
    If we ever remake this animation, the play song block should be pink! --MF, 2/21/22

    Click for a hint.

    1. Create a new block called play song that takes one input called song, which will be a list of pitches. (To add an input, you have the hover over the tiny space to the right of the block name to get the plus sign (+) to show up and then click it.)
    2. Duplicate your for each pitch, play ♪ code by right-clicking the for each block and selecting "duplicate," and then attach the copied code to the play song hat block in the block editor.
    3. Remove the list block containing your previous song, drag the song variable into the for each block where song had been, and click, "OK."

    Click for a video.

    animation showing the steps for creating a new command block that takes a list of notes as input and plays each note in the list: 1) Create a new block called PLAY SONG that takes one input called SONG, which will be a list of pitches; 2) Duplicate your FOR EACH PITCH, PLAY ♪ code by right-clicking the FOR EACH block and selecting 'duplicate,' and then attach the copied code to the PLAY SONG hat block in the block editor; 3) Remove the list block containing your previous song, drag the SONG variable into the FOR EACH block where SONG had been, and click, 'OK.'
  2. Sorry, this is another Snap bug report, but when I ran play-song, the song suddenly sounded horrifying. I even added an explicit set-instrument to 1 but it still sounds really sharp/grating. It did that for the first 3 times I played it. After writing this comment, it seems to be okay. Not sure what triggers it. I still am getting the issue where switching tabs while playing a song prolongs the current note, that seems very repeatable. -pf 3/3/22

    This needs to go on GH not in the curriculum. https://github.com/jmoenig/Snap/issues :) --MF, 3/6/22

  3. Try out your play song block with at least two different lists of pitches, and fix any issues with the block.
  4. Create help text for your play song block by attaching a comment to the hat block. The help text should describe what the block takes as input and what effect the block produces.
    You learned about adding comments to your code in the "Adding Program Documentation" section of Unit 1 Lab 6 Activity 1: Texting Time.
    uppercase block code with a comment attached to the hat block. The comment contains the text 'This block takes a string of text as input and reports the same text but with all of the lowercase letters changed to uppercase.'
  5. Now Is a Good Time to Save

Does my play song block have to play every note for the same length of time?

No. On a later page, you can learn a way to store and play songs with both pitch and beat information about each note.

In this activity, you used for each to play each pitch in a list and created a play song block that will work with any list of pitches.

This is a more general problem, but it looks particularly bad here: When a <code> text embedded in a line includes spaces, the spaces are way too big compared to all the other spaces on the line. Ideally you'd say <code>for</code> <code>each</code> but that's too horrible to contemplate, so somehow it should be fixed in the Javascript. --bh 3/3/22

Go for it! :) --MF, 3/6/22