prefix function below. Did you know the A section and the B section simply swap the roots of these three iterations? The A section’s three iterations start at G#, G#, and B. The B section’s three iterations start at B, B, and G#.
Hit the Play button to hear. The editor is a little cramped in this blog; I suggest you scroll down and click Expand to open it in a new tab or window.
Computer science education has had a good run of late. It’s been endorsed by presidents, athletes, musicians, and household names in technology. A number of states allow computer science to count toward math, science, or even foreign language requirements, and some require that it be offered in all high schools. There are many organizations aiming to provide access to computer science learning to underrepresented groups. A lot of funding is available for educators who can find effective ways to teach computer science.
Blikstein identifies four rationales behind the push to expand computer science education:
Each of these rationales has merit, but the first three are focused on secondary rewards like jobs, status, and transfer. The rationale that is dearest to my heart as an educator is computational literacy. Computational literacy is not about breeding a new generation of software developers. Advocates of this rationale view computer science as a medium for learning in all disciplines—just as literacy considers the written word to be a medium for all kinds of learning. By writing programs and reading them, we learn.
There’s one particular kind of learning for which I think computer science is well-suited: the learning of music theory.
Programming is one of the primary activities of computer science. But learning to program is generally time-consuming and full of heartache. For programming not to distract from the learning process of another discipline, we need small languages tailored to the discipline. Sometimes these are called domain-specific languages or DSLs. I have been working on a DSL for music called Deltaphone. I will give a demonstration of its features as they relate to the learning of musical theory.
Deltaphone supports sequencing, putting one note after another across time. Let’s write a program to render and play a scale. We’ll start with the chromatic scale. Instead of thinking of notes as absolute positions on the staff, learners can describe notes as changes or deltas from the previous note. In the chromatic scale, for example, each note is one halfstep or semitone higher than the previous note.
We can change the root of this scale, and the rest of the scale moves accordingly. In the Logo programming language, Seymour Papert called this turtle geometry. Instead of treating space as an absolute coordinate system, Logo programmers move around space by turning and moving relative to their current position and heading. You could say that Deltaphone supports turtle music.
The major scale follows a different offset pattern: +2 +2 +1 +2 +2 +2 +1.
The minor scale follows a rotated version of this offset pattern: +2 +1 +2 +2 +1 +2 +2.
Musical actions can be repeated. Musicians acknowledge repetition with various repeat structures, but there is also considerable implicit repetition. Deltaphone supports both explicit repeat structures and more general purpose loops called ditto and for. Let’s walk up the staff in perfect fifths with ditto and do it again with repeat:
One particularly important cognitive activity that programming contributes to learning is abstraction, the generalization of specifics into patterns. In algebra, for instance, we think about operations in terms of variables instead of specific numbers. In Deltaphone, we can abstract data too. Consider this program that plays four quarter notes:
If I decide I want these to be half notes instead, I must make four changes. However, if I do little higher-order thinking, I can instead create a variable storing the duration. In this program I can make a single change to affect all four notes:
Variables make connections between separate instructions clear and make experimenting less costly.
In addition to abstracting data, we can also abstract procedures. If there’s a chunk of code that represents a high-level action, we can give that chunk an appropriate name. For example, in this program, we can create procedures for chords of the major scale:
My dream for Deltaphone is not to use it to teach kids how to program. Rather, I want to collaborate with music educators and develop a curriculum for learning music theory through programming. The learners will start with a just a handful of Deltaphone’s primitive commands and build up a whole library of musical structures, like repeats, chords, inversions, and so on. They will be computationally literate in music theory.
]]>The major scale is defined to be a list of notes that starts at some root note, jumps up 2 halfsteps, jumps up 2 more, jumps up 1, jumps up 2, jumps up 2, jumps up 2, and jumps up 1. All told, we travel 12 halfsteps up from the root, landing one octave above.
In this program, we generate the C major scale using these offsets, starting at C in the fourth octave and landing on C in the fifth octave:
The notes we visit are C, D, E, F, G, A, B, and C.
Now, consider this simple rule for finding notes in this scale that sound pleasing together:
That set of three notes is called a triad. Let’s write a function that formalizes the algorithm:
That sounds pleasing, right? The best part is that the algorithm is versatile. It can be applied at any of the notes in the major scale. Let’s walk up the scale and apply it at each note:
All those triads should sound pleasing to your ears. But the code is awfully repetitive. Let’s walk up the whole scale with a loop instead:
Our algorithm for picking notes works across the whole scale!
There’s still one improvement we can make. Musicians give names to each of the triads using Roman numerals. When we pick the scale’s root as the triad’s root, we have a I chord. When we pick the second note of the scale as the triad’s root, we have a ii chord. When we pick the third note, a iii chord. The fourth note, a IV chord. The fifth note, a V chord. The sixth note, a vi chord. And the seventh note, a vii chord.
Let’s write some helper functions that abstract away the I, IV, V, and vi chords:
Now we have a language for compactly describing chords, and we can create chord progressions like I, V, vi, IV:
This progression and other orderings of the same four chords are quite common in popular music.
There’s one last trick we can apply to our triads, but let’s save inversions for next time.
]]>Yesterday I set about adding support to Deltaphone for generating this kind of interactive game so that I too could acquire this superpower. But Deltaphone wasn’t exactly designed with interaction in mind. Previously, I interpreted the program completely before processing and rendering the score. But in a game, the interpreter might need to render the score more frequently to prompt the player or give feedback. Furthermore, the interpreter must occasionally wait for user input before proceeding. How would I stop the interpreter?
I feared I would need to rewrite the interpreter from scratch to support some form of continuations. But then I discovered Javascript’s async and await commands. Tagging a function with async makes it run asynchronously. An async function immediately returns a promise to its caller, at which point the caller normally continues on its merry way. To cause execution to block, however, one can await the resolution of a promise. Using these two commands, one can effectively suspend a function’s return without a busy loop.
Suppose I want to pause the interpreter until the user clicks a button. I added this wait-for-click statement, which only resolves its promise on the button’s click event:
class StatementWaitForClick() {
async evaluate(env) {
await new Promise(resolve => {
button.onclick = () => resolve();
});
}
}
Very few of my structures need an explicit promise—only wait-for-click and multiple-choice-quiz. But I had to tag all my evaluate functions across my abstract syntax tree with async because I never know if a substructure might pause during its evaluation. This means that even those operations without an explicit promise must still await the asynchronous evaluation of their substructures, as we do in this add operation:
class ExpressionAdd(a, b) {
constructor(a, b) {
this.a = a;
this.b = b;
}
async evaluate(env) {
let valueA = await a.evaluate(env);
let valueB = await b.evaluate(env);
return valueA + valueB;
}
}
With a pausable interpreter, Deltaphone programmers can now build interactive games. Like this one for recognizing intervals:
Just now I got 4 out of 5!
]]>A few weeks ago, my wife asked me if I thought our sons would study computer science. I told her that I hoped to teach them enough of it at home that they’d be freed up to study something else.
I really do like my discipline, but I love more the things that my children, my students, and I can make with it. The past few years, I have been searching for ways to make computer science less virtual and more physical, more integrated in the world around us. Our agenda for today is to demonstrate three projects that support my mission of making computer science less virtual.
Schools left and right, politically and geographically, are establishing makerspaces, buying up 3D printers and laser cutters, and getting their students designing and building real things. The students are making. This sounds great. However, if you talk to the teachers and librarians who are staffing these makerspaces, you will hear about the many kids who are just downloading other people’s 3D models and design files from Thingiverse and fabricating those.
This happens for a couple of reasons. First, its part of the maker ethos to share what one has made. Second, learning to model in 2D and 3D is time-consuming and doesn’t really fit well into an already crowded school curricula. I think computer science can fix this. Instead of just plain making, we need computational making.
We hear a lot these days about computational thinking. There’s little agreement about what skills and concepts make up computational thinking, and it has come to be used as a way to invoke the idea of computer science but subtract out or downplay programming. I needed a term to invoke the idea of creating but with programming added in. That is computational making, which I define as a creative process
Let’s now look at some tools I’ve been building to facilitate computational making.
The first tool is Madeup, a programming language for making things up—literally. It is very much modeled after the drawing mechanics of Seymour Papert’s Logo from the 1980s, but extended to three dimensions. Madeup, like Logo, is meant to make learning geometry an interactive experience. Instead of imposing a grand coordinate system over all space, the programmer uses a coordinate system relative to the avatar on the screen. Logo’s avatar was a turtle, and Papert called this way of thinking about space turtle geometry. Let’s see it at work in an example. We’ll code a rupee from the Legend of Zelda games.
For those of you who have been spending your time elsewhere, rupees look like this:
We will program the cross section of one of these. Imagine that we cut one right down the middle. What shape would we see? An elongated hexagon. Let’s write Madeup code to trace out the top half of the hexagon, like so:
Next we revolve that cross section around the x-axis, sampling the surface or revolution just six times to produce the hexagonal structure:
And finally we stretch it a bit vertically:
What if want to make a sharper bevel? We must change the angle we turn. Instead of 45, let’s try 30:
Whoops. We’ll need to change the peak angle too. But to what? Some experimentation leads us to 120:
But we can do better than experiment. Why is it 120? Because all told, we are turning back the direction we came, which is 180 degrees. We burn 30 of those up on the first yaw and 30 on the third yaw. That leaves 120 left for the middle yaw. Now we can generalize this and turn the angle into a parameter:
Madeup is a fully-featured programming language. It supports conditionals, loops, variables, functions, and arrays. There are many ways to turn a path into a solid. We’ve seen revolve, but there’s also dowel. Let’s make a chain link:
Let’s see a few more examples.
This perimeter of this gear is extruded and a hole is subtracted from its center:
The Madeup editor also supports a blocks programming interface, and one can (mostly) switch back and forth between text and blocks.
How does Madeup make computer science less virtual? The model can be printed on a 3D printer or embedded in a game engine.
I spent the last year
The second project I’d like to share you has one less than dimension than Madeup. Twoville’s purpose is to help programmers build 2D scalable vector graphics (SVG) files that can be fed into a laser or vinyl cutter.
Let’s make another jewel, a diamond. Since we’re in 2D, we’ll just create the profile of a diamond. We start with a square, but rotate it a bit:
Twoville tends to be a very declarative language, as we’re often just setting properties. To ease the syntactic burden of setting a sequence of properties, I added in the scoping function with:
We want to chop off the top, so we overlay another rectangle across it:
To remove the red rectangle, we create a cutout object that serves as a mask:
A similar approach can be used to make a phone:
Like Madeup, Twoville supports conditionals, loops, functions, and arrays. I used functions to abstract out the droplet shapes of this logo that I walked by everyday in Brisbane, Australia, during the first half of my sabbatical:
If you’ve done anything with 3D printing in schools, you will have encountered the slowness of the technology. Models take a long time to print, and the machines need minding. 3D printing doesn’t scale well to large groups of students. Vinyl and laser cutters are much faster, and I think Twoville will better accommodate the time-limited summer camps and workshops I’ve been putting on back home.
The last project I’d like to share has a less touchable output. It also has one less dimension than Twoville. I’m losing dimensions as I get older. It must be a case of “dimentia.” Deltaphone is my exploration of applying the idea of turtle geometry to music. Instead of thinking about music as a sequence of absolute positions on the staff, we think of a song in Deltaphone as a sequence of changes or deltas between one note and the next.
Let’s compose a little song to see how it works.
Deltaphone supports variables, conditionals, loops, and functions. The output of Deltaphone is a score.
This project is only a few months old, and I don’t know if it has a future or not. I need to find a music teacher who doesn’t feel threatened by technology and who can help me shape it into a tool to explore music theory and composition.
These are three projects that I have been developing to make computer science less virtual, to fit it into the everyday worlds of objects and music.
Educational psychologists argue about whether its better to learn a subject in a contextualized or decontextualized manner. Contextualized learning situates concepts in a themed narrative, like robotics or game development. Decontextualized learning happens when there is no overarching narrative.
Neither approach is perfect. We often rely on the context to engage students. The danger of contextualized learning is that learners may not see that concepts transfer to other contexts. For example, someone who has written an algorithm to determine the winner from a collection of players may not see that a very similar algorithm can be used to find the largest file in a directory. The danger of decontextualized learning is that that learners may not see that concepts transfer anywhere.
While this debate is important for educators to consider, I’d like turn it around a bit. What if we embedded computer science in a context not to improve the learning of computer science, but to improve the learning of the context? If the folks using these tools become better makers, mathematicians, and musicians, then my goal will be met.
]]>Ultimately, we want our instruments to sound pleasing to our ears. Octaves are the prime way to achieve this consonance. The doublings in our instruments’ wires and passageways always sound good together. But we want other combinations to sound good together too.
What does it mean for two notes to sound good together? Physically, it means that the notes’ pressure waves oscillate in such a way that they coincide at regular intervals. In a doubling, for example, two oscillations of the faster wave coincide with one oscillation of the slower wave. The ratio of the frequencies is 2:1.
Of all the possible partitioning schemes, a 12-partition produces the largest proportion of simple ratios. See how nicely the waves for notes 0 and 7 coincide?
In the time that it takes note 0 in red to oscillate twice, note 7 in blue oscillates three times. Our ears will like that!
Meanwhile, as note 0 in red oscillates three times, note 5 in blue oscillates four times:
A whopping six of the intermediate tones can be expressed with simple ratios:
| Note | Ratio to Root | Approximate Ratio |
|---|---|---|
| 0 | $2^\frac{0}{12}$ | $1$ |
| 1 | $2^\frac{1}{12}$ | $-$ |
| 2 | $2^\frac{2}{12}$ | $-$ |
| 3 | $2^\frac{3}{12}$ | $\frac{6}{5}$ |
| 4 | $2^\frac{4}{12}$ | $\frac{5}{4}$ |
| 5 | $2^\frac{5}{12}$ | $\frac{4}{3}$ |
| 6 | $2^\frac{6}{12}$ | $-$ |
| 7 | $2^\frac{7}{12}$ | $\frac{3}{2}$ |
| 8 | $2^\frac{8}{12}$ | $\frac{8}{5}$ |
| 9 | $2^\frac{9}{12}$ | $\frac{5}{3}$ |
| 10 | $2^\frac{10}{12}$ | $-$ |
| 11 | $2^\frac{11}{12}$ | $-$ |
| 12 | $2^\frac{12}{12}$ | $2$ |
The ratios are not exact, it should be noted. For example, note 7 is $2^\frac{7}{12} \approx 1.498307 \neq \frac{3}{2}$. Our ears probably won’t notice this slight deviation.
Given its high probability of producing consonant notes, the 12-partition came to dominate our musical systems. The sequence of all 12 steps is called the chromatic scale, which can be programmed in Deltaphone:
It’s rare that we find all twelve notes in a piece of music. Instead we restrict ourselves to subsets of these notes to achieve an even greater likelihood of consonance.
]]>Music theory is a daunting subject, built out of centuries of mathematical analysis and aristocratic pride. Sometimes I think I’d be better off reinventing it than trying to learn it at this late stage of its maturity. Here’s how I might get started.
One day I’d be absently fooling around with a bit of wire, which I’d stretch between two nails. I’d absently pluck the wire and hear it make an intriguing sound. I’d pluck it over and over again until I grew tired, and then I’d move on to something else.
Later on I’d recreate the experiment using another bit of wire, and I’d notice that the sound was similar to but different from my original wire. I’d observe that my second wire was of a different length than my first. Intrigued by this difference, I’d start to experiment. Soon I’d have a series of wires of different lengths that I could pluck. I’d pluck them individually in succession, but I’d also pluck them simultaneously. Some multi-plucks would bring discomfort to my ears, but others would please me.
I don’t have such an instrument to play for you, but I can simulate one. This one has ten wires, with the shortest having length 1 and the longest having length 2:
Much to my surprise, I would discover that a wire of a certain length would “cooperate” with a wire twice its length. I’d find the same to be true of a wire four times as long and half as long. All of them would fit together nicely, as shown in this simulation:
I’d name the region between cooperating wire lengths a doubling. I’d make a device out of several doublings that I would use to entertain friends and pass the time. I wouldn’t be able to have very many doublings, though, before the device became unwieldy and the sound too shrill. I’d want more qualities of sounds. The only way to do this, I’d reason, is to add back in wires with lengths in between each doubling. But I’d need to be careful to only play wires that sounded pleasing together.
Suppose I inserted just one extra wire. What length would I make this new wire? Probably I’m make it the average of the base wire and its double. All told, the wire lengths would be 1, 1.5, and 2. If I named the shortest wire wire 0 and the longest wire 2, I’d document my instrument using the following table of wire numbers and lengths:
| Wire | Length |
|---|---|
| 0 | 1 |
| 1 | 1.5 |
| 2 | 2 |
I’d name this arrangement a 2-partition.
To create a 3-partition, I’d insert another wire, but redistribute the wires evenly, resulting in these lengths:
| Wire | Length |
|---|---|
| 0 | 1 |
| 1 | 1.3 |
| 2 | 1.6 |
| 3 | 2 |
In a 4-partition, I’d have these lengths:
| Wire | Length |
|---|---|
| 0 | 1 |
| 1 | 1.25 |
| 2 | 1.5 |
| 3 | 1.75 |
| 4 | 2 |
And so on and so forth. In general, if I placed n wires in each doubling to make an n-partition, I’d measure each wire according to this formula:
Suppose I settled on a making 12-partition instrument. Visually, a plot of my wire lengths would look like this, with the wires on the x-axis and their lengths on the y-axis:
Eventually, I would try adding more wires after the double: wire 13, wire 14, and so on. Following my length formula, my wires would have these lengths:
| Wire | Length |
|---|---|
| 0 | 1 |
| 1 | 1.083 |
| 2 | 1.16 |
| 3 | 1.25 |
| 4 | 1.3 |
| 5 | 1.416 |
| 6 | 1.5 |
| 7 | 1.583 |
| 8 | 1.6 |
| 9 | 1.75 |
| 10 | 1.83 |
| 11 | 1.916 |
| 12 | 2 |
| 13 | 2.083 |
| 14 | 2.16 |
| 15 | 2.25 |
| 16 | 2.3 |
| 17 | 2.416 |
| 18 | 2.5 |
| 19 | 2.583 |
| 20 | 2.6 |
| 21 | 2.75 |
| 22 | 2.83 |
| 23 | 2.916 |
| 24 | 3 |
In scanning this table, I would eventually find a pernicious flaw in my design. I’d find that going from wire 0 of length 1 to wire 12 of length 2 would produce the doubling that I liked so much. But going up another 12 wires to wire 24 would produce a 3. “That’s not a doubling,” I’d say to myself. Nor is going another 12-partition from wire 1 to wire 13. In fact, there would only be the one doubling in my entire instrument. Given the pleasure I found in doublings and my instrument’s failure to provide them, I would throw my instrument down, smashing it into tiny pieces.
After taking some time cool off, I would vent about my failure with some trusted friends, and they would think through the problem with me. In particular, one might suggest trying a different partitioning scheme. Perhaps instead of dividing the doubling into equally-sized chunks, in which each neighboring pair of wires has the same additive difference, the friend would wonder what would happen if I made each pair of wires have the same multiplicative ratio.
I’d wonder what ratio I should use. A ratio of 1 would make every string have the same length. A ratio of 2 would make every string a doubling. I’d conclude that I needed a ratio x somewhere between 1 and 2. It would take me a while to figure out exactly what ratio to use. But in my notebook I’d mark down the following observations about the wire lengths and their relationships if their ratio was held constant. Each wire would be some fixed proportion x of the previous wire:
| Wire | Length |
|---|---|
| 0 | 1 |
| 1 | $\textrm{length}_0 \cdot x$ |
| 2 | $\textrm{length}_1 \cdot x$ |
| 3 | $\textrm{length}_2 \cdot x$ |
| 4 | $\textrm{length}_3 \cdot x$ |
| … | … |
| i | $\textrm{length}_{i – 1} \cdot x$ |
After considering this table, I’d find that I could simplify the lengths by substituting in the previous wires’ lengths:
| Wire | Length | Simplified Length |
|---|---|---|
| 0 | 1 | 1 |
| 1 | $\textrm{length}_0 \cdot x$ | $1 \cdot x = x$ |
| 2 | $\textrm{length}_1 \cdot x$ | $x \cdot x = x^2$ |
| 3 | $\textrm{length}_2 \cdot x$ | $x^2 \cdot x = x^3$ |
| 4 | $\textrm{length}_3 \cdot x$ | $x^3 \cdot x = x^4$ |
| … | … | … |
| i | $\textrm{length}_{i – 1} \cdot x$ | $x^{i – 1} \cdot x = x^i$ |
From this table, I would know that wire 12 would have length $x^{12}$. But I would also excitedly recall that I wanted wire 12 to have length 2. With two measures of the same string, I would figure out what x should be:
Plugging this magic value of x into my table, I’d find the following exact lengths of the wires:
| Wire | Length |
|---|---|
| 0 | $x^0 = (2^\frac{1}{12})^0 = 1$ |
| 1 | $x^1 = (2^\frac{1}{12})^1 = 1.059463$ |
| 2 | $x^2 = (2^\frac{1}{12})^2 = 1.122462$ |
| 3 | $x^3 = (2^\frac{1}{12})^3 = 1.189207$ |
| 4 | $x^4 = (2^\frac{1}{12})^4 = 1.259921$ |
| … | … |
| i | $x^i = (2^\frac{1}{12})^i = 2^\frac{i}{12}$ |
| … | … |
| 12 | $x^{12} = (2^\frac{1}{12})^{12} = 2$ |
| 13 | $x^{13} = (2^\frac{1}{12})^{13} = 2.118926$ |
| … | … |
| 24 | $x^{24} = (2^\frac{1}{12})^{24} = 4$ |
| … | … |
To my delight, I would find doublings all over—in fact, every 12-wire jump would yield a doubling!
Visually, a plot of my wire lengths for a ratio-based 12-partition would look like the blue line, with the old scheme plotted in green:
This table and plot show the lengths for a 12-partition. For a more general n-partition under this new ratio-based partitioning scheme, I’d measure each wire i according to this formula:
I would then rebuild my instrument to span several doublings, with each wire being $2^\frac{1}{12}$ times the length of the preceding wire:
I would still find combinations of wires that didn’t sound pleasing, but I’d also find a number of combinations that did sound pleasing. Furthermore, the combinations that sounded good together in one doubling would sound just as good if I shifted them to a different doubling. And I’d find doublings between each pair of 12 notes.
Thus would I become the father of music theory. But really, I’d just think of myself as a musician trying to please my own ears.
]]>The past year or so I’ve been taking piano lessons from a guy I met on the internet. The lessons expose me to ideas about music theory that I want to understand, but I’ve gotten to the point in life where I don’t feel like I understand anything unless I program it. So, I started working on Deltaphone not as a tool to teach computer science, but as a tool to teach myself music. I will be slowly writing up the things I learn about music by coding it.
Today our subject is intervals. Pick any two notes. The gap between their frequencies is their interval. Play the notes at the same time or in succession. If they sound pleasing together, we say that the interval is consonant, which derives from the Latin word for “to sound together.” If they don’t sound pleasing, they are dissonant.
On a rainy day it might be interesting to play all possible intervals and decide which ones we think are consonant. But there are so many possible intervals. We’d probably need a rainy week! However, we may not need a week for three reasons:
The standard intervals that our Western musical ancestors defined for us are as follows:
Let’s make this idea concrete by writing a Deltaphone program to play all of these intervals, and we can decide for ourselves about their consonance. We start by dragging out the play block that supports chords, and we combine C4 and the note 0 steps above it in the current key:
The other intervals can be formed in similar fashion. We need only change the delta:
While this works, it’s very repetitive. After the first intervals, the ideas stop being new. Let’s generalize this into a function. We’ll have the parameter be the interval’s number.
You may have noticed in the previous video that the second used a delta of +1. This is confusing. For our function, we’ll make it so that if the caller passes a 2, we’ll play the second. If the caller passes a 3, we’ll play the third. And so on. We’ll need to subtract 1 from the parameter to get the delta:
This feels pretty good, but let’s generalize interval so that it can play from any root note, and let’s also use a for loop to walk through our numbers:
That’s enough about intervals for now. In the next installment, we’ll see how these intervals change when the underlying scale changes.
]]>play block came in two forms. There was a form for an absolutely-specified note, like “play C natural in the fourth octave.” And there was a form for a relatively-specified note, like “play the note 2 halfsteps up from where I’m currently at on the staff.” They looked like this:
How do I add chords to this? My first attempt was to add a new chord statement that accepted a stack of play statements. Something like this:
But this structure has two problems. First, a chord generally should have all of its notes be of the same duration. (The MusicXML docs agree.) Each play block has its duration specified separately and is therefore vulnerable to getting out of sync with its siblings. Second, other statements can be nested inside the chord, like repeat blocks, which is nonsense.
I decided instead to generalize the play to a single block that could play absolute notes, relative notes, or chords. Polymorphism fixes everything, right? The new block looked like this in its different contexts:
But after using this new play block to compose some simple songs, it felt too heavyweight. I want to be able to take Deltaphone into an elementary school classroom, and I expected that the polymorphic solution would require too much explanation. But I still needed a way to play chords. So, I decided to keep all three forms of the play block.
See them at work as I program the stepping-up-and-stepping-down exercise:
The exercise ends with three chords: a I chord, a V7 chord, and a I chord. With chords, only the root note has any long-term effect on the “cursor” that marks our current position on the staff.
]]>The koalas slept precariously in their perches, and we looked at them. It was great—until a loud boom came from within the center. A large spinning wheel that was part of a display had come loose from its mount and had fallen on a child. It’s not just the kangaroos.
One thing we have seen (and heard) plenty of are Australian birds. Like the noisy miner, magpie, and the kookaburra. There’s a famous Australian song about a kookaburra sitting in an old gum tree, and I was inspired to program its first two lines in Deltaphone:
This song was a helpful exercise. In programming it, I discovered that the second line is not an exact transposition of the first. If I maintain the exact halfstep differences between notes, I end up landing on notes not in the key of C major. See:
This led me to add a unit specifier to the delta blocks. One can jump either in halfsteps or in keysteps. Keystep jumps move a number of positions within the scale of the current key signature. This version sounds much better:
]]>