Sweetdreams softsynth, 2017-07-05

For 34 years I’ve loved the synthesizer sound in the Eurythmics’ “Sweet Dreams (Are Made of This)”, but I never knew how it was made. This week, I finally understood it: it’s a flanged broad-spectrum harmonic-rich note (a sawtooth or something similar) that’s amplitude-modulated (i.e. tremolo, but in this case at audio frequencies, so resulting in a rich set of sum and difference frequencies). In my C++ implementation of this sound, I’m using a triangle wave at C2 (“deep C”, “great C”, “low C”) to amplitude-modulate a sawtooth at C3 (“bass C”, one octave higher) that’s being flanged back and forth by ±1 ms according to a 1.5 Hz triangle wave; the dependency graph to the right shows how this is implemented. It sounds like this .

The code to generate it looks like this:

  float cfreq = 65.4064;
  sig c2 = triangle->speed(cfreq)
    , flanged = sawtooth->speed(2*cfreq)
        ->flange((triangle * .002)->speed(1.5))
    , flangeam = flanged * (c2 + 0.5)
    , s2 = flangeam + c2
    , sampled = (s2 * 20000)->speed(1.0/sampling_rate)
    ;

My waveform looks like this, and although it sounds similar, the original waveform has a noticeably different appearance:

I haven’t implemented the vibrato, initial pitch bending, or ADSR envelopes that I also seem to hear in the Eurythmics song.

The rest of the C++ file is just a quick softsynth I put together to support the above code and generate the diagram. I also wrote a JS version in Node.js which compiles the dataflow graph into a JS function in order to take advantage of runtime code generation. Instead of being faster than the C++ version, it’s about 10× slower. That’s still twice as fast as when it was just interpreting the dataflow graph the way the C++ version does, and 20× as fast as my first JS draft, where I had totally messed up the buffering. Also, even the JS version with the run-time code generation is still less code than the C++ version without.

I also wrote a two-line C bytebeat “remix” of it called eurybeat which sounds like this :

main(t,u){for(;;t++)u=t*((t>>13^t>>11)%7)/4,
putchar((u*4&127)+(u%254*4&127)|!(u&32)-1|128&30000/(t%2048+1));}

I haven’t worked all the bugs out of eurybeat yet, though.

Thanks to Alastair Porter for his help developing this.