Hi.
I'm Zachary Kanfer, and this is waving
at repetitive repetitive repetitive
music. Over quarantine, I've been bored,
and I found this Android app that has a
bunch of mini-games,
one of which lets you compose music.
And it works, but I
want a little bit more functionality
than it offers, it's not very flexible.
So, I thought what if I made this,
and what programs could I make this
in that are really flexible, are really
customizable.
Emacs. So, I looked into it, and
Emacs can play sounds, right? If you hit
control g a couple of times, you'll hear
like an error tone,
and it turns out that, that is actually
playing a WAVE file,
but what's a WAVE file?
Well, it turns out that WAVE is a musical
file format,
or really an annoying file format.
So, data in it can be an unsigned integer
or a signed integer, it's not consistent,
and it's little-endian by default which
is not the way I like to think about it.
Now, you can
set a WAVE file to be big-endian,
but if you do that,
Emacs can't play it.
So, little-endian it is.
There's also duplicate data fields.
Here are some fields that are fine, but
then there's a fourth field that's
calculated based on multiplying two of
the other ones together,
and then there's another data field
that's… you multiply those three ones
together. So, it's just repetitive and
unnecessary, but you have to do it, or
it's not a valid WAVE file.
Also, the last part of the file is
described as data
or as one website I found said,
the actual sound data. Now,
I don't know about you but when I see
that, I think,
what is data? It turns out
that sound is just a wave, and
the data is just a bunch of measurements
of the height of that wave forming each
sample.
So, this wave starts at 8 goes 9, 11, 13,
14, 15, and then back down. If you just
take those measurements, those numbers,
put them in a file,
that's all your data is.
All right. Let's go to a demo of my
program.
So, this is what zmusic looks like. The
blue highlighted row is a single beat,
there's 16 of them in this zmusic file,
and each dash in the row
is a single note increasing…, starting
really low all the way on the left and
going up
as we go to the right. So, if we started
playing,
we won't hear anything, but we'll see the
highlighted beat is the currently
playing one,
and we see that it loops.
So, we can stop it,
and now we can click to add some notes.
[Music]
Even more than one note at the same time
works.
[Music]
And we can even add notes
while it's playing.
[Music]
Okay, here are some other features that I
didn't have time to demo.
So, you can save the music to a file, and
this is interesting because normally
if there's no note in a beat, we just
don't play that beat,
but if you're writing to a file you have
to put something in,
so when it's playing it knows to not
make a sound there.
We can also use different scales.
We're using the minor pentatonic
in the demo, but you can use the major
scale the minor scale
or anything else.
And there's also keyboard support,
but it sounds really bad,
and I'll explain why later.
Here are some things I learned while
writing zmusic.
Emacs has buttons which are great as
long
as you don't put two of them right next
to each other. So, if you do that,
mousing over one of them highlights both
of them.
Now, that's because a button is really
just a series of characters with a text
property to highlight them.
So, the fix is, you put another character
between the two buttons,
then mousing over one of them only
highlights the one you want,
but even this doesn't work really great
for zmusic,
because zmusic has a lot of very
small buttons in a row.
So, it's really easy to accidentally put
your cursor over the space
and click on that instead of the button.
So, I looked into unicode, and I found
this character called
a zero-width space. So, we should be able
to put that between buttons and not be
able to accidentally click on it.
Unfortunately, a zero-width space isn't
actually zero width.
If we put a hundred of them between two
other characters, you can see there's
space there,
and I think what's happening is, the
space is zero width
but then Emacs `put` uses one pixel between
each pair of characters
for the cursor, so it's almost zero width.
Some ways to play sound that don't quite
work! `play-sound` plays music,
but it blocks, you can't do things like,
set other notes or even pause the music.
And if you throw it into async.el, it's
silent, and I don't know why.
So, the solution I went with is taking
that WAVE file,
ran into the file system, and then
shelling out to a native executable to
play the sound.
And that works fine as long as you only
do it once,
because if you do it a couple of times at
the same time like if you have a chord,
and you want to play three notes
simultaneously,
you get this weird interference, and
that's actually why the keyboard from
before didn't work.
Also, side effects have this unexpected
impact,
when you saw the demo it was running
pretty smoothly,
but if I just add one message statement
every beat for
debugging purposes, I was getting lag and
jitter.
Here's the one thing I learned about
music theory, music theory
is not easy to program.
I was looking around to see what
concepts we can use to code the scales,
to code the notes,
the first thing that I saw is
scale degrees,
and this when I looked into it, you don't
want to program in scale degrees.
So, you see we have the first, second,
third, fourth, fifth, sixth, seventh but
then it wraps around. That octave up
is also a first, and that's because both
of those notes are C,
so that didn't work, and also you
couldn't really easily
specify a flat or sharp. You could say
a sharp third or
you know, a flat seventh or whatever, but
then you kind of have these two pieces
of data that indicate the note, and I
didn't love that.
So, I looked again, and I
found intervals,
and then I thought about it, and you
don't really want to program in
intervals either.
It fixes some of the problems with scale
degrees, you see,
all the way on the right you have an
octave, so you wrap to 8, and you
go 9, 10 and that works. But you solve the
same problem, you see you have a major
third but below we also have a minor
third, so you saw that problem of having
two pieces of information.
So, I thought about it. Music is really
frequencies. Like an A is 440 hertz.
So, at a low level that's what we're
going to do, we're just going to use
frequencies.
And then at the one level above that,
that's a little bit easier for humans to
think about,
we're going to use semitones up from the
root, which is kind of like scale degrees,
but instead of just counting each note
as one more, we're going to say how many
semitones up it is.
So, if there's a sharp between two notes,
that's going to be two steps up instead
of just one.
And then we translate those two
frequencies, so your A is 440 hertz,
another note might be
613.5,
or whatever, and that's we use the low
level to play.
Some future work I have, I want to add
some drums.
I want to make that keyboard actually
work,
and computers and synthesizers are
the only place you hear a pure sine wave
like the one we have here,
so I want to add overtones or other
octaves above it just to make it
sound a little bit more realistic.
I've put notes references and the source
code up
at zck.org/emacsconf2020 [updated].
I'm one of the organizers of EmacsNYC
check that out. And if you take a look
or have any thoughts, I'd love to hear
them, and
thanks so much for coming to my talk.