#RaspberryPi Pico – let’s make an atrocious synthesiser

Inspired by the electrical musical inventions on the YT channel “Look Mum No computer“, I wondered if we could turn the Pico into a synthesiser.

I think it’s kinda cool because it shows what the Pico can do that might be more difficult on a Raspberry Pi. If you run Linux then real-time behaviour is thrown out of the water.

It might be possible to write a barebones system for the Pi, and get realtime behaviour that way. I had started one myself. When I heard of the Pico a few days ago, I realised that the Pico would likely be a much better bet. I have therefore abandoned the idea of writing a Pi unikernel, at least for the foreseeable future. I reckon that the Pico is where the action should be.

OK, so here’s the code:

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"

using  u64 = uint64_t;

#define SPK 15

u64 count = 0;
u64 invert_every = 0;
bool repeating_timer_callback(struct repeating_timer *t) {
	static bool hi = false;
	if(invert_every == 0) return true;
	if((count++ % invert_every) == 0) {
		gpio_put(SPK, hi);
		hi = ! hi;
	}
	return true;
}


int main() 
{
	stdio_init_all();
	printf("freq-adj started\n");

	gpio_init(SPK);
	gpio_set_dir(SPK, GPIO_OUT);

	struct repeating_timer timer;

	//long int us = 1'000'000UL/8000/2;
	// negative means regardless of how long it took to execute
	add_repeating_timer_us(-10, repeating_timer_callback, NULL, &timer);


	for(;;) {
		int c = getchar();
		putchar(c);
		if( 'a' <= c && c <= 'z' ) {
			u64 freq = (c-'a') * (4000-100)/26 + 100; // scale notes from 100Hz to 4000Hz
			invert_every = 1'000'000UL/freq/2/10;
		}
		if( c == ' ') invert_every = 0;
	c
	return 0;
}

Less than 50 lines! Visit my github directory for downloadable code.

Compile the code, and upload it to the Pico. Add a speaker, with one end in GP15, and the other end in GND. It doesn’t have to be a fancy or big speaker. I haven’t tried it with a piezo speaker, but I’m guessing that the results from it are likely to be poor.

Connect to the Pico via USB serial. Start typing away. The letters a..z control the frequency. Type a space to stop the tone. Frequencies are linearly spaces from a..z, starting at 100 and ending at 4000.

The code works by setting a repeating timer every 10us. It flips the speaker GPIO pin when a count is 0 modulo invert_every. invert_every is a time measurement in microseconds scaled by a factor of 10 (because that’s how often the repeater repeats).

The formula for invert_every is therefore related to desired frequency by:

invert_every = 1'000'000UL/freq/2/10;

The factor “2” is due to the fact that we must flip the pin in a square-wave.

Is my implementation the best possible? Probably not! If you have a better idea, then let me know. I’m not sure, for example, how accurate the repeater is. Is it achieved via interrupts, or through some counter? Maybe it is a good candidate for experimenting with PIO. Dunno. Feel free to make suggestions.

I decided to activate the repeater every 10us. I was worried that every 1us might tax the MCU too much.

Also, I haven’t investigated if there is any counter hardware in the Pico. I know, for example, that you can set a comparator in an STM32 so that you can achieve both frequency and duty-cycle modulation. You can also buffer the output, resulting in changes to the wave synching nicely with a new counting cycle. I’ve forgotten exactly how this is all achieved, but as you can see, the STM32 offers some quite nice hardware.

One thing I did discover is that MicroPython didn’t seem to offer a very good fit. Their guide showed that it was simple to adjust frequency of outputs. I used their code with a potentiometer. So you read an ADC, and set the frequency. The results were really bad.

I’m not entirely sure why. The ADC readings were subject to significant fluctuation, so it adjusted the frequency often. I suspect that changing the frequency messes it up a little bit, producing unusable output.

The poor results that I achieved by uPython guided my current approach. Rather than adjust some kind of frequency, I keep the frequency constant, but adjust when I toggle the output pins. maybe I can figure out how to combine it with PWM.

I am a little worried that I’m gobbling up a lot of CPU cycles with my approach, though. Perhaps I should investigate a hardware approach. I’ve found that it’s very easy to reach the limits of what an MCU can do if you start upping your processing requirements.

There are so many directions in which this project could be developed. I could keep with a serial interface, for example. Maybe have one row of the keyboard per octave, with the successive rows giving higher or lower octaves. You can get 4 octaves that way. I’m not sure how to tackle the problem of the duration of the note, though.

Another option would be to use a potentiometer. Maybe that’s more suitable to generating constant tones, though.

Yet another option would be to use a DAC. I could generate sine waves, triangular and sawtooth waves that way.

I also have in mind making a “kitchen-table piano” make out of aluminium foil and a spoon. Stay tuned for that one! Or maybe a piano “keyboard” made out of just two wires. I have an idea as to how it would work, I’m just not sure yet if it will.

Hmmm, so many possibilities.

Anyways, I’m really fired up with what the Pico offers.

About mcturra2000

Computer programmer living in Scotland.
This entry was posted in Uncategorized. Bookmark the permalink.

2 Responses to #RaspberryPi Pico – let’s make an atrocious synthesiser

  1. Pingback: Creating an poor man’s Schmitt trigger inverter and oscillator circuit using a #RaspberryPi Pico | Mark Carter's blog

  2. Pingback: #RaspberryPi Pico A stylus piano “synthesiser” | Mark Carter's blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s