Xylophone: What You'll Build
Xylophone: What You'll Build
Xylophone: What You'll Build
Xylophone
Getting Started
Connect to the App Inventor website and start a new project. Name it Xylophone,
and also set the screens title to Xylophone. Open the Blocks Editor and connect to
your phone or emulator.
Palette group
What youll
name it
Purpose
Button
Basic
Button1
Button
Basic
Button2
Play D key.
Button
Basic
Button3
Play E key.
Button
Basic
Button4
Play F key.
Button
Basic
Button5
Play G key.
Button
Basic
Button6
Play A key.
Button
Basic
Button7
Play B key.
Button
Basic
Button8
Sound
Media
Sound1
Button
Basic
PlayButton
Button
Basic
ResetButton
Horizontal
Arrangement
Screen Arrangement
Horizontal
Arrangement1
Clock
Basic
Clock1
The display on your phone should look similar, although there will not be any empty
space between the two colored buttons.
We could do the same for Button2, as shown in Figure 9-4 (just changing the text
value), but the code would be awfully repetitive.
Repeated code is a good sign that you should create a procedure, which youve
already done in Chapter 3s MoleMash game and Chapter 5s Ladybug Chase game.
Specifically, well create a procedure that takes a number as an argument, sets
Sound1s Source to the appropriate file, and plays the sound. This is another example
of refactoringimproving a programs implementation without changing its behavior,
a concept introduced in the MoleMash tutorial. We can use the Text drawers join block
(an alternate version of make text) to combine the number (e.g., 1) and the text
.wav to create the proper filename (e.g., 1.wav). Here are the steps for creating the
procedure we need:
1. Under the Built-In tab, go to the Definition drawer and drag out the to procedure block.
2. Go back to the Definition drawer and drag a name block into the arg socket of
to procedure.
3. Click the rightmost name and set the name to number.
4. Click procedure and set the name to PlayNote.
5. Drag the Sound1.Source block from Button1.Click into PlayNote to the right
of the word do. The Sound1.Play block will move with it.
6. Drag the 1.wav block into the trash can.
7. From the Text drawer, drag the join block into Sound1.Sources socket.
8. Type number and move it to the left socket of the join block (if it is not already
there).
9. From the Text drawer, drag the text block into the right socket of the join block.
10. Change the text value to .wav. (Remember not to type the quotation marks.)
11. Under the My Blocks tab, go to the My Definitions drawer and drag a call PlayNote
block into the empty body of Button1.Click.
12. Type 1 and put it in the number socket.
Now, when Button1 is clicked, the procedure PlayNote will be called, with its number argument having the value 1. It should set Sound1.Source to 1.wav and play
the sound.
Create a similar Button2.Click block with a call to PlayNote with an argument of 2.
(You can copy the existing PlayNote block and move it into the body of Button2.
Click, making sure to change the argument.) Your program should look like Figure 9-5.
Test your app. Now if you restart the app by clicking on Connect to
Device... in the Blocks Editor, the notes should play without delay. (If
you dont hear anything, make sure that the media volume on your
phone is not set to mute.)
You may also want to change Button8s TextColor property to White, as shown in
Figure 9-7, so it is more legible.
Figure 9-7. Putting the remaining buttons and sounds in the Component Designer
Back in the Blocks Editor, create Click blocks for each of the new buttons with appropriate calls to PlayNote. Similarly, add each new sound file to Screen.Initialize,
as shown in Figure 9-8.
With your program getting so large, you might find it helpful to click the white minus
signs near the bottom of the container blocks, such as PlayNote, to minimize them
and conserve screen space.
Test your app. You should now have all the buttons, and each one
will play a different note when you click it.
Figure 9-8. Programming the button click events to correspond to all the keyboard keys
We can get the timing information from a Clock component, which we will also use
to properly time the notes for playback.
Figure 9-9. Adding components for recording and playing back sounds
For example, if you play Row, Row, Row Your Boat [C C C D E], your lists would end
up having five entries, which might be:
notes: 1.wav, 1.wav, 1.wav, 2.wav, 3.wav
times [dates omitted]: 12:00:01, 12:00:02, 12:00:03, 12:00:03.5, 12:00:04
When the user presses the Reset button, we want the two lists to go back to their
original, empty states. Since the user wont see any change, its nice to add a small
Sound1.Vibrate block so he knows that the key click was registered. Figure 9-12
shows the blocks for this behavior.
Figure 9-12. Providing feedback when the user resets the app
Variations 145
Variations
Here are some alternative scenarios to explore:
Currently, theres nothing to stop a user from clicking ResetButton during playback, which will cause the program to crash. (Can you figure out why?) Modify
PlayButton.Click so it disables ResetButton. To reenable it when the song is
complete, change the if block in PlayButton.Click into an ifelse block, and
reenable ResetButton in the else portion.
Similarly, the user can currently click PlayButton while a song is already playing. (Can you figure out what will happen if she does so?) Make it so PlayButton
.Click disables PlayButton and changes its text to Playing You can reenable
it and reset the text in an ifelse block, as described in the previous bullet.
Add a button with the name of a song, such as Fr Elise. If the user clicks it,
populate the notes and times lists with the corresponding values, set count to
1, and call PlayBackNote. To set the appropriate times, youll find the Clock1
.MakeInstantFromMillis block useful.
If the user presses a note, goes away and does something else, and comes back
hours later and presses an additional note, the notes will be part of the same
song, which is probably not what the user intended. Improve the program by (1)
stopping recording after some reasonable interval of time, such as a minute; or
(2) putting a limit on the amount of time used for Clock1.TimerInterval using
the max block from the Math drawer.
Visually indicate which note is playing by changing the appearance of the button
for example, by changing its Text, BackgroundColor, or ForegroundColor.
Summary
Here are some of the ideas weve covered in this tutorial:
You can play different audio files from a single Sound component by changing its
Source property. This enabled us to have one Sound component instead of eight.
Just be sure to load the sounds at initialization to prevent delays (Figure 9-6).
Lists can provide a program with memory, with a record of user actions stored in
the list and later retrieved and reprocessed. We used this functionality to record
and play back a song.
The Clock component can be used to determine the current time. Subtracting
two time values gives us the amount of time between two events.
The Clocks TimerInterval property can be set within the program, such as
how we set it to the duration of time between the starts of two notes.
It is not only possible but sometimes desirable for a procedure to make a call to
itself. This is a powerful technique called recursion. When writing a recursive procedure, make sure that there is a base case in which the procedure ends, rather
than calling itself, or the program will loop infinitely.