Shallow Thoughts : tags : music
Akkana's Musings on Open Source Computing and Technology, Science, and Nature.
Sat, 23 Mar 2024
I mentioned before that I'm taking beginner guitar lessons.
Justin recommends using a
metronome for some of the practicing, and that makes sense:
I notice that sometimes when I practice I try to go too fast,
which might or might not be good for learning the chord changes
but it also leads to more mistakes and worse chord quality.
There are probably lots of phone metronome apps,
but I'm usually practicing near my computer (where I watch
the lessons and where I keep all my notes on chords and rhythms for
particular songs), so I thought it would be nice to have a metronome
on Linux.
Read more ...
Tags: guitar, music, cmdline, linux
[
18:37 Mar 23, 2024
More linux |
permalink to this entry |
]
Tue, 27 Feb 2024
I've been learning guitar. I've tried several times in the past
without much success, concluding that although I love music, making it is
just not where my talents lie. But this time I'm following a course
(Justin Guitar),
doing things more or less in the recommended order rather than
jumping around randomly. It's fun, and I'm practicing regularly
and feel like I'm making progress.
So far I know about five chords, and surprisingly, there are a lot of good
songs you can play with only three to five chords. But if you want to
play along with a record, some songs need a capo
(one of those little dinguses you can clamp around the guitar's neck)
to map the chords to ones that are easy for beginners to play.
I don't have a capo.
Justin Guitar has a phone app that supposedly can transpose songs,
but I wouldn't know about that, because it doesn't work on my phone,
just spins forever any time I try to load a song.
But I do have a computer; can't I just take a recording and transpose it?
Yes! It's easy in Audacity.
Read more ...
Tags: music, guitar, audacity
[
14:06 Feb 27, 2024
More misc |
permalink to this entry |
]
Wed, 05 Oct 2016
Reading
Stephen
Wolfram's latest discussion of teaching computational thinking
(which, though I mostly agree with it, is more an extended ad for
Wolfram Programming Lab than a discussion of what computational
thinking is and why we should teach it) I found myself musing over
ideas for future computer classes for
Los Alamos Makers.
Students, and especially kids, like to see something other than words
on a screen. Graphics and games good, or robotics when possible ...
but another fun project a novice programmer can appreciate is music.
I found myself curious what you could do with Python, since
I hadn't played much with Python sound generation libraries.
I did discover a while ago that
Python
is rather bad at playing audio files,
though I did eventually manage to write
a music
player script that works quite well.
What about generating tones and chords?
A web search revealed that this is another thing Python is bad at. I
found lots of people asking about chord generation, and a handful of
half-baked ideas that relied on long obsolete packages or external
program. But none of it actually worked, at least without requiring
Windows or relying on larger packages like fluidsynth (which looked
worth exploring some day when I have more time).
Play an arbitrary waveform with Pygame and NumPy
But I did find one example based on a long-obsolete Python package
called Numeric which, when rewritten to use NumPy, actually played a sound.
You can take a NumPy array and play it using a pygame.sndarray object
this way:
import pygame, pygame.sndarray
def play_for(sample_wave, ms):
"""Play the given NumPy array, as a sound, for ms milliseconds."""
sound = pygame.sndarray.make_sound(sample_wave)
sound.play(-1)
pygame.time.delay(ms)
sound.stop()
Then you just need to calculate the waveform you want to play. NumPy
can generate sine waves on its own, while scipy.signal can generate
square and sawtooth waves. Like this:
import numpy
import scipy.signal
sample_rate = 44100
def sine_wave(hz, peak, n_samples=sample_rate):
"""Compute N samples of a sine wave with given frequency and peak amplitude.
Defaults to one second.
"""
length = sample_rate / float(hz)
omega = numpy.pi * 2 / length
xvalues = numpy.arange(int(length)) * omega
onecycle = peak * numpy.sin(xvalues)
return numpy.resize(onecycle, (n_samples,)).astype(numpy.int16)
def square_wave(hz, peak, duty_cycle=.5, n_samples=sample_rate):
"""Compute N samples of a sine wave with given frequency and peak amplitude.
Defaults to one second.
"""
t = numpy.linspace(0, 1, 500 * 440/hz, endpoint=False)
wave = scipy.signal.square(2 * numpy.pi * 5 * t, duty=duty_cycle)
wave = numpy.resize(wave, (n_samples,))
return (peak / 2 * wave.astype(numpy.int16))
# Play A (440Hz) for 1 second as a sine wave:
play_for(sine_wave(440, 4096), 1000)
# Play A-440 for 1 second as a square wave:
play_for(square_wave(440, 4096), 1000)
Playing chords
That's all very well, but it's still a single tone, not a chord.
To generate a chord of two notes, you can add the waveforms for the
two notes. For instance, 440Hz is concert A, and the A one octave above
it is double the frequence, or 880 Hz. If you wanted to play a chord
consisting of those two As, you could do it like this:
play_for(sum([sine_wave(440, 4096), sine_wave(880, 4096)]), 1000)
Simple octaves aren't very interesting to listen to.
What you want is chords like major and minor triads and so forth.
If you google for chord ratios
Google helpfully gives
you a few of them right off, then links to a page with
a table of
ratios for some common chords.
For instance, the major triad ratios are listed as 4:5:6
.
What does that mean? It means that for a C-E-G triad (the first C
chord you learn in piano), the E's frequency is 5/4 of the C's
frequency, and the G is 6/4 of the C.
You can pass that list, [4, 5, 5] to a function that will calculate
the right ratios to produce the set of waveforms you need to add
to get your chord:
def make_chord(hz, ratios):
"""Make a chord based on a list of frequency ratios."""
sampling = 4096
chord = waveform(hz, sampling)
for r in ratios[1:]:
chord = sum([chord, sine_wave(hz * r / ratios[0], sampling)])
return chord
def major_triad(hz):
return make_chord(hz, [4, 5, 6])
play_for(major_triad(440), length)
Even better, you can pass in the waveform you want to use
when you're adding instruments together:
def make_chord(hz, ratios, waveform=None):
"""Make a chord based on a list of frequency ratios
using a given waveform (defaults to a sine wave).
"""
sampling = 4096
if not waveform:
waveform = sine_wave
chord = waveform(hz, sampling)
for r in ratios[1:]:
chord = sum([chord, waveform(hz * r / ratios[0], sampling)])
return chord
def major_triad(hz, waveform=None):
return make_chord(hz, [4, 5, 6], waveform)
play_for(major_triad(440, square_wave), length)
There are still some problems. For instance, sawtooth_wave() works
fine individually or for pairs of notes, but triads of sawtooths don't
play correctly. I'm guessing something about the sampling rate is
making their overtones cancel out part of the sawtooth wave. Triangle
waves (in scipy.signal, that's a sawtooth wave with rising ramp width
of 0.5) don't seem to work right even for single tones. I'm sure these
are solvable, perhaps by fiddling with the sampling rate. I'll
probably need to add graphics so I can look at the waveform for
debugging purposes.
In any case, it was a fun morning hack. Most chords work pretty well,
and it's nice to know how to to play any waveform I can generate.
The full script is here:
play_chord.py
on GitHub.
Tags: python, programming, music
[
11:29 Oct 05, 2016
More programming |
permalink to this entry |
]
Sun, 17 Feb 2013
I've done a few experiments with
playing
music on an Arduino over the years -- the Arduino library has a
tone()
call that gives you a nice tinny monophonic
"chiptunes" style noise. But for playing anything more complex,
you need more processing power.
I had a silly little project in mind. I like some pink noise when I'm
sleeping (in summer, I usually have a fan running). You can buy
electronic devices called "sleep soothers" that have tracks of the
ocean, rain, trains etc. but they often have annoying misfeatures
(like foghorns or train whistles in the middle of a track). Wouldn't
it be more fun to make my own, with sound samples of my choice?
Pink noise samples
Of course, I needed some sound samples, and
I found a great resource: Laptop.org's list of
Free sound samples.
I downloaded a few sample collections that looked like they might have
some nice ambient pink-noise sounds -- rain, ocean and so forth.
Some of the samples were usable right away.
But others are only available at 44.1k, and the
Adafruit Wave Shield, the hardware I was targeting first, will only play
WAV audio at 16k. So they needed to be converted.
A simple shell loop did that:
for fil in *.wav ; do
avconv -i $fil -ar 16000 ../samples16/$fil
echo $fil
done
Arduino hardware
There are several Arduino shields for playing sound files.
The simplest (and probably cheapest) is the
Adafruit Wave Shield,
and that's what I started with. It comes as a kit that you solder
together (an easy soldering project) and it has its own volume control
and SD card reader. On the down side, it can only play .WAV files, not
other formats like .MP3 or .OGG. But for my sleep soother project that
was okay.
Getting basic sounds playing was easy, following Adafruit's tutorial
and sample code. But for my project, I also needed some external
buttons, to allow for jumping from one track to the next. I was a
little confused about which pins are used by the shield, and I ended
up wiring my button to one of the pins that the shield uses for
talking to the SD card reader. Things didn't work at all. And then
while I was fumbling with plugging/unplugging things, at some point
I installed the shield onto the Arduino wrong, with the pins off by one.
I'm not sure whether it was the miswired button or the off-by-one shield,
but something got fried in the wave shield and it was never able to
read an SD card again after that (yes, even after plugging it in properly).
I thought about ordering another Wave Shield. But I was leery -- if
it's so delicate that a stray 5v signal in the wrong place can fry it
permanently, how long did I expect a second one to last? Besides, I was
tired of soldering things, and I happened to be putting in an Amazon
order for some other things. So I ran a search and found that there was
an MP3 player shield available through them, made by Seeed Studio.
It even had buttons built in, so I wouldn't need any extra hardware.
It was a little more expensive than the Wave shield, but it claimed to
play MP3 and OGG as well as WAV, and it comes pre-assembled, no
soldering needed.
The hardware arrived and looked nice. Two simple buttons plus a
"multifunction" button you can press or rock left or right. I grabbed
a micro SD card, put some MP3s on it, and went to
Seeed's page
on the Music Shield.
Hacking the Seeed library
I was a little worried when I discovered that they have three
different demos there -- each of which comes with a different library,
and you have to remove one set of libraries before you can try a
different demo. Not a good sign.
And indeed, it wasn't. None of the demos worked at all. When I added
some debug Serial.println
s, I found that it wasn't opening
the SD card.
Much web searching found a couple of people saying they'd discovered that
the Seeed shield only works with 2G or smaller microSD cards. Good luck
finding one of those! The next day, I drove all over town looking for
one, without success, and was on the verge of giving up when Dave remembered a
little cheapie camera he'd bought a few years ago for taking airplane
movies. It came with a microSD card. Success! It was a 2G card.
Back to trying the various demos and their incompatible libraries again.
And this time, one of the demos, the first one (the one that comes with
the Music v1 14.zip library), worked. I could play tracks,
sequentially as they were loaded on the SD card.
Unfortunately, that wasn't what I wanted to do -- I wanted to play the
same track over and over, jumping to the next track when the user
presses a button. I tried the other demos. None of them worked at all.
Long story short, after struggling for the better part of a week and
reverse-engineering a fair amount of the Music v1 14 library, I finally
got my sketch working.
Sharing the changes
I come from the open-source world. I keep my
Arduino sketches on GitHub
(at least once they work well enough to be useful to anybody).
So of course I wanted to share the work I'd put into fixing this
library.
I had it all laid out and ready to commit, and was working on
some documentation on how to use it, when I noticed the readme.txt
in the library directory. It begins:
Copyright (c) 2010 Seedstudio. All right reserved.
Pffft! So after finally getting things working, I can't share my working
version of the library! What are they thinking? What on earth is the
point of distributing a library for your hardware, one that you know
doesn't work very well (or you wouldn't be distributing four different
incompatible versions of it), and then not letting anyone fix it for you?
I posted a query in one of the many
threads
discussing problems with the Music Shield, asking if Seeed would
consider releasing the library under a license that allowed redistribution.
It's been a few weeks now, and no answer yet.
Incidentally, even posting the query wasn't easy. Seeed doesn't let
you post in their forums unless you register -- and the registration
process requires full name, address, and phone number! Fortunately,
they have no way of knowing whether the info you give them is fake,
so that's what I did.
Since I don't have permission to share the code directly, I've checked
in a patch that updates their library so it can play arbitrary tracks,
not just sequential ones, and can re-play the same track. It's here:
Music Shield
library on GitHub, along with my sample app, called play-repeat.
Conclusions
So my app is working now. Well, mostly; sometimes the volume randomly
jumps in the middle of the night, which I think is a hardware glitch,
but since it only happens after several hours of play, it's hard to debug.
But if you're looking for an Arduino sound project, I can't recommend
either the Wave Shield or the Seeed Music Shield. The Wave Shield
seems too fragile and its formats are limited, though the
tutorials and support are great.
And I'll certainly never buy anything from Seeed again.
If I had it to do over again, I'd spend the big bucks and buy
the Sparkfun
MP3 Player Shield. It's more expensive ($40) and doesn't have nice
buttons like the Seeed shield, but it plays all the formats the Seeed
shield does, and they offer tons of documentation and examples,
including an open-source library and code contributed by users.
Tags: arduino, hardware, music, maker
[
12:37 Feb 17, 2013
More hardware |
permalink to this entry |
]
Fri, 02 Mar 2012
Working on projects that might be fun for a proposed Arduino high school
workshop, I realized I hadn't done much with Arduinos and sound.
I'd made clicking noise for my
sonar
echolocation device, but nothing more than that.
But the Arduino library has a nice function to control a speaker:
tone(int pin,
int frequency, int length).
tone()
works much better than trying to make your own
square wave, because it uses interrupts and doesn't glitch when
the processor gets busy doing other things. You can leave off the
length parameter and the tone will continue until you
tell it to stop or change frequency.
Random tones
So you can produce random tones like this (SPEAKER is the pin the
speaker is plugged into):
uint8_t SPEAKER = 8;
void setup()
{
pinMode(SPEAKER, OUTPUT);
// Seed the random number generator from floating analog pin 0:
randomSeed(analogRead(0));
}
void loop()
{
// Random frequency between 20 and 1400 (Hz).
unsigned long freq = random(20, 1400);
long duration = random(5, 50);
tone(SPEAKER, freq, duration);
delay(random(100, 300));
}
Light theremin
Purely random tones aren't very interesting to listen to, though, as
it turns out.
How about taking input from a photo-resistor, to make
a light theremin that wails as I move my hand up and down above the
sensor? The photoresistor I was using typically reads, on the Arduino,
between 110 (with my hand over the sensor) and 800. So I wanted
to map that range to audible frequencies the speaker could handle,
between about 20 Hz and 5000.
uint8_t LIGHTSENSOR = 0;
void loop()
{
// Set the frequency according to the light value read off analog pin 0.
#define MAX_SIGNAL 800
#define MAX_FREQ 5000
#define MIN_SIGNAL 380
#define MIN_FREQ 20
int lightsensor = analogRead(LIGHTSENSOR);
int freq = (lightsensor - MIN_SIGNAL)
* (float)(MAX_FREQ - MIN_FREQ)
/ (MAX_SIGNAL - MIN_SIGNAL)
+ MIN_FREQ;
tone(SPEAKER, freq);
}
Random music (chiptunes)
That was fun, but
I still wanted to try some random music that actually sounded ... musical.
So how about programming the standard scale, and choosing frequencies from
that list?
I looked up the frequency for Middle C, then used fractions to
calculate the rest of the
"just" diatonic
scale for C major:
float middle_c = 262.626;
float just[] = { 1., 9./8, 5./4, 4./3, 3./2, 5./3, 15./8 };
#define NUMNOTES (sizeof(just)/sizeof(*just))
float cur_octave = 1.;
Multiplying the frequency by 2 transposes a note up one octave;
dividing by two, down one octave. cur_octave will keep track
of that.
Now if whichnote is a number from 0 to 7,
cur_octave * just[whichnote] * middle_c
will give the next frequency to play.
Just choosing notes from this list wasn't all that interesting either.
So I adjusted the code to make it more likely to choose a note just one
step up or down from the current note, so you'd get more runs.
rand = random(0, 6);
if (rand == 0)
whichnote = (whichnote + 1) % NUMNOTES;
else if (rand == 1)
whichnote = (whichnote + 1) % NUMNOTES;
else
whichnote = random(0, NUMNOTES);
float freq = middle_c * just[whichnote];
// Change octave?
rand = random(0, 10);
if (rand == 1 && cur_octave <= 3) {
cur_octave *= 2.;
} else if (rand == 2 && cur_octave >= 1) {
cur_octave /= 2.;
}
freq *= cur_octave;
It's still not great music, but it's a fun experiment and I'm looking
forward to adding more rules and seeing how the music improves.
Bach
But this left me hungry for real music. What if I wanted to play
a real piece of music? Certainly I wouldn't want to type in an array
of frequency numbers, or even fractions. I'd like to be able to say
A, Ab (for A-flat), Cs (for C-sharp), etc.
So I defined the frequency for each of the notes in the scale:
#define NOTE_Ab 207.652
#define NOTE_A 220.000
#define NOTE_As 233.082
#define NOTE_Bb NOTE_As
#define NOTE_B 246.942
#define NOTE_C 261.626
#define NOTE_Cs 277.183
#define NOTE_Db NOTE_Cs
#define NOTE_D 293.665
#define NOTE_Ds 311.127
#define NOTE_Eb NOTE_Ds
#define NOTE_E 329.628
#define NOTE_F 349.228
#define NOTE_Fs 369.994
#define NOTE_Gb NOTE_Fs
#define NOTE_G 391.995
#define NOTE_Gs 415.305
#define NOTE_REST 0.0
#define NOTE_SUSTAIN -1.0
Then the first part of Bach's 2-part invention #4 in D minor
looks like this:
float composition[] = {
NOTE_D, NOTE_E, NOTE_F, NOTE_G, NOTE_A*2, NOTE_As*2,
NOTE_Db, NOTE_As*2, NOTE_A*2, NOTE_G, NOTE_F, NOTE_E,
NOTE_F, NOTE_REST, NOTE_A*2, NOTE_REST, NOTE_D*2, NOTE_REST,
NOTE_G, NOTE_REST, NOTE_Cs*2, NOTE_REST, NOTE_E*2, NOTE_REST,
NOTE_D*2, NOTE_E*2, NOTE_F*2, NOTE_G*2, NOTE_A*4, NOTE_As*4,
NOTE_Db*2, NOTE_As*4, NOTE_A*4, NOTE_G*2, NOTE_F*2, NOTE_E*2,
};
And the code to play it looks like:
unsigned long note = composition[i++];
if (note == NOTE_REST)
noTone(SPEAKER);
else if (note == NOTE_SUSTAIN)
; // Don't do anything, just let the current tone continue
else
tone(SPEAKER, note);
It's a bit tedious to type in the notes one by one like that, which
is why I stopped when I did. And as far as I know, the Arduino can
only emit one tone at once -- to play the real 2-part invention,
you either need a second Arduino, or extra hardware like a
wave shield.
Anyway, it was a fun series of experiments, even if none of it
produces great music. You can see the source at
github:
akkana/arduino/music.
Tags: arduino, hardware, music, maker
[
19:54 Mar 02, 2012
More hardware |
permalink to this entry |
]