Wishful Coding

Didn't you ever wish your
computer understood you?

Theremin

I made another silly thing. I came across a musical instrument called a Theremin. The real deal uses a really cool concept where your body and 2 antennas act as a capacitor in an LC circuit. By changing the distance between your body and the antennas, the capacitance changes, which changes the resonance frequency and modifies the pitch and amplitude of the output signal.

This thing is much more silly. It uses the IR sensor to measure the distance to your hand and generates a tone based on that. It works nothing like the real thing.

The sound quality of the EV3 is terrible, because it’s just a small speaker attached to a PWM port with a low-pass filter.

The IR sensor is slow, inaccurate and discrete. So you can do none of the slides and vibrato you can do with a Theremin. At first I tried to smooth the input to get a more natural sound, but that made it even slower and impossible to tune. So in the end I mapped the discrete input steps to discrete notes, so that it at least sounds in tune. You still can’t play anything on it though.

I wrote the code for this in C on ev3dev. I use ev3c to talk to the sensors and libasound to generate the sound. This took a while to get working.

#include "ev3c.h"
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include "alsa/asoundlib.h"

static char *device = "default";                        /* playback device */
snd_output_t *output = NULL;
unsigned char buffer[800];                          /* some random data */

int main(void)
{
  int err;
  unsigned int i;
  snd_pcm_t *handle;
  snd_pcm_sframes_t frames;
  if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
          printf("Playback open error: %s\n", snd_strerror(err));
          exit(EXIT_FAILURE);
  }
  if ((err = snd_pcm_set_params(handle,
                                SND_PCM_FORMAT_U8,
                                SND_PCM_ACCESS_RW_INTERLEAVED,
                                1,
                                8000,
                                1,
                                500000)) < 0) {   /* 0.5sec */
          printf("Playback open error: %s\n", snd_strerror(err));
          exit(EXIT_FAILURE);
  }

  const double interval = pow(2, 1.0/12.0);
  const double R=8000; // sample rate (samples per second)
  double F=440; // frequency of middle-C (hertz)
  double Fp = F;
  double V=127; // a volume constant
  double t; // doudle counter, yeaaaa


  //Loading all sensors
  ev3_sensor_ptr sensors = ev3_load_sensors();
  ev3_sensor_ptr prox1 = sensors;
  ev3_mode_sensor(prox1,0);
  ev3_open_sensor(prox1);
  while(1)
  {
    ev3_update_sensor_val(prox1);
    Fp = F;
    F=220*pow(interval, prox1->val_data[0].s32/4);
    t*=Fp/F; // scale time with frequency change
    // this is to maintain a continuous sine

    fprintf(stderr, "%d, %f\n", prox1->val_data[0].s32, F);
    
    for ( i=0; i<800; i++ ) {
      t+=1;
      buffer[i] = (sin(t*2*M_PI*F/R)+1)*V;
    }

    //printf("%d\n", snd_pcm_avail(handle));
    frames = snd_pcm_writei(handle, buffer, sizeof(buffer));
    if (frames < 0)
            frames = snd_pcm_recover(handle, frames, 0);
    if (frames < 0) {
            printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
            break;
    }
    if (frames > 0 && frames < (long)sizeof(buffer))
            printf("Short write (expected %li, wrote %li)\n", (long)sizeof(buffer), frames);
  }
  //Let's delete the list in the very end. It will also close the
  //sensors
  ev3_delete_sensors(sensors);
  snd_pcm_close(handle);
  return 0;
}
Published on

If Everyone Would Just...

While everyone was making new years resolutions for themselves, I was making new years resolutions for the world. Or rather, thinking how change happens.

It seems people are hardly able to change themselves, even if they set out to do so. So how can we even begin to think about changing humanity as a whole? It seems we just keep doing whatever is easiest/best/most comfortable, and change only happens when something easier/better/more comfortable comes around.

Sometimes you read about these civilizations that seemed to be really advanced for their time, but then just sort of died out. Looking back it is often obvious why, and you wonder if they did not see it coming. But what if they saw it coming all along, but were unable to change their ways?

The only mechanism we have for global change is governance. But as Douglas Adams explains

One of the many major problems with governing people is that of whom you get to do it; or rather of who manages to get people to let them do it to them: It is a well known fact, that those people who most want to rule people are, ipso facto, those least suited to do it. Anyone who is capable of getting themselves into a position of power should on no account be allowed to do the job.

Often times I have an idea to make something somewhere a little better. No grand plans to solve world hunger, just small things. Often by means of sharing or exchanging information or goods. Without exception, these ideas include the sentence “If everyone would just…” and you quickly learn about the Network Effect.

I’m just back from 32c3, where I saw a number of interesting art projects. Many of these projects used technology not to provide utility, but to convey a message. Thinking about all the above, I built The World Improvement Server; a caricature of global change.

Th World Improvement Server runs a program that speaks the SUN-RPC rwall protocol, listening for your world improvement ideas. These ideas are then broadcast over the QOTD protocol to anyone who cares to listen.

To start improving the world, simply run rwall 37.247.53.27 and type your idea, followed by EOF.

To learn more about ways to improve the world, simply telnet 37.247.53.27 17, which as of 2 January 2016 returns

$ telnet 37.247.53.27 17
Trying 37.247.53.27...
Connected to 37.247.53.27.
Escape character is '^]'.

If everyone would just [...]
the world would be a much better place!

Submit global world improvement using rwall.

Remote Broadcast Message from pepijn@pepijn-Latitude-E6420
	(/dev/pts/0) at 18:19 ...

If everyone would just use this service to make the world a better place
the world would be a better place.


Connection closed by foreign host.
Published on

The relation between harmonics and parallel resistance

I’m building a simple synth on a breadboard, where the frequency is defined as \(f=\frac{1}{RC}\), so by using different resistors with a row of buttons, different tones can be made. But what if you press two buttons simultaneously? You get 2 parallel resistors, giving:

\[R=\frac{R_1 \cdot R_2}{R_1 + R_2}\]

I stumbled on this while playing with it, and the combined tones seem to be nice intervals sometimes. So I started to wonder if there was a connection.

In 12-tone equal temperament, the ratio of the frequency between two notes is \(\sqrt[12]{2}\), so we could just plug it in and see what comes out. Take a series of notes:

\[f_b(n)=f_a\cdot\left(\sqrt[12]{2}\right)^{n} \\ T_a=\frac{1}{f_a} \\ T_b(n)=\frac{1}{f_b(n)}=\left(\sqrt[12]{2}\right)^{-n} \\\]

And a series of a combined frequencies:

\[T_t(n)=\frac{T_a \cdot T_b(n)}{T_a + T_b(n)} \\ f_t=\frac{1}{T_t}=\frac{T_a + T_b(n)}{T_a \cdot T_b(n)}\\\]

Plotting these in Matlab gives the following result

12et plot

base = 220;
bp = 1/base;

tones = base.*(nthroot(2,12).^(0:12));
periods = 1./tones;
r = (bp.*periods)./(bp+periods);
duotones = 1./r;


plot(0:12, tones.*2, 'o', 0:12, duotones,'o');
grid on
grid minor

As can be seen, some combined tones are indeed quite close, but most not exactly. But then equal temperament does not have exact harmonics either. So we still do not know if we are generating actual harmonics, or just frequencies that happen to be close.

So what if instead of starting with \(\sqrt[12]{2}\), we start with integer multiples of the base frequency and fold then back into one octave. This gives:

\[\frac{1}{1}, \frac{2}{1}, \frac{3}{2}, \frac{4}{2}, \frac{5}{3}, \frac{6}{3}, \frac{7}{4}, \frac{8}{4}, \frac{9}{5} \ldots\]

Plugging that into the parallel resistance equation, we can begin to search for exact harmonics giving exact harmonics.

harm = 1:31;
harm_cap = zeros();

for i = harm
  j = i;
  while j>2
      j= j/2;
  end
  harm_cap(i) = j;
end

period = 1./harm_cap;

par = (1.*period)./(1+period);

freq = 1./par;
freq_cap = zeros();

for i = harm
  j = freq(i);
  while j>2
      j= j/2;
  end
  freq_cap(i) = j;
end

[C,ia,ib] = intersect(harm_cap, freq_cap)
Combined Harmonic Name Button ratio Name
17 Minor second 9 Major second
9 Major second 5 Major third
19 Minor third 11 Tritone
5 Major third 3 Fifth
11 Tritone 7 Minor seventh
3 Fifth 2 Octave
2 Octave 1 Prime

And we can indeed verify that two resistors with a 2:1 ratio give a fifth (3:2):

\[f=\frac{1 + 2}{1 \cdot 2}=\frac{3}{2}\]

Likewise a resistor ratio for a fifth gives a major third (5:3)

\[f=\frac{1 + \frac{3}{2}}{1 \cdot \frac{3}{2}}=\frac{5}{3}\]

Math, music, physics. So beautiful.

Update:

As pointed out by Darius Bacon, this might not be a complete surprise, as there is a striking similarity between parallel resistance and the harmonic mean.

\[H = \frac{n}{\frac{1}{x_1} + \frac{1}{x_2} + \cdots + \frac{1}{x_n}} \\ R_\mathrm{total} = \frac{1}{\frac{1}{R_1} + \frac{1}{R_2} + \cdots + \frac{1}{R_n}}\\\]

Wikipedia also has the following to say about the harmonic series:

Its name derives from the concept of overtones, or harmonics in music: the wavelengths of the overtones of a vibrating string are 1/2, 1/3, 1/4, etc., of the string’s fundamental wavelength. Every term of the series after the first is the harmonic mean of the neighbouring terms; the phrase harmonic mean likewise derives from music.

\[\sum_{n=1}^\infty\,\frac{1}{n} \;\;=\;\; 1 \,+\, \frac{1}{2} \,+\, \frac{1}{3} \,+\, \frac{1}{4} \,+\, \frac{1}{5} \,+\, \cdots\]
Published on