A sequencer and a synthesizer in Perl? Why not?

This is a side project from a side project, but it turned out to be a lot of fun so that I'll probably continue to spend some of my spare time on it.

It started with my interest for the Corinna project to bring "modern" object orientation into the core of the Perl programming language.

Then I noticed (a few years ago) that my favourite editor Emacs does not understand newer Perl syntax, and as a side project I added missing stuff to CPerl mode. So, upcoming Emacs 30 will understand Perl syntax including Perl 5.40.

While working on this I noticed that - as could be expected - there is not much code out there in the wild which already uses the new Perl syntax. So, to get some test and practice, I had to write my own. The stuff I wrote would not need to serve any practical purpose, but exercise lots of syntactical variations.

So this project was started to test CPerl mode and at the same time have fun. For the Perl code this means that it isn't very consistent in its style intentionally because I needed CPerl mode to cover different coding styles. The repository also contains some dead code and many undocumented features. Sorry for that. I also use Feature::Compat::Class instead of use feature 'class' because that way I can debug the objects by using "older" Perl versions which fall back to Object::Pad.

Part of this work was the specification of a file format which I could use to test the audio software: It should be easy to write for humans (unlike MIDI). This spec is now here, but unfortunately GitHub's POD rendering clobbers Unicode characters in Code sections. Also, HTML rendering of musical note symbols looks worse than I expected even when correctly decoded, so perhaps I'll drop that.

The `eg` directory has a few examples of music roll files which can be played with the program `bin/mrt_play`. This needs the `sox` program to be on your path.

Two of the samples created by mrt_play (~300kB, ~30 seconds each) are at https://haraldjoerg.github.io/i/entertainer.ogg and https://haraldjoerg.github.io/i/lvb_27_2.ogg.

The code is on GitHub.

Replies are listed 'Best First'.
Re: Sound from Scratch
by eyepopslikeamosquito (Archbishop) on Aug 14, 2024 at 11:19 UTC
Re: Sound from Scratch
by haj (Vicar) on Aug 17, 2024 at 18:49 UTC

    Followup: Fun with PDL

    The Perl code in the repository uses only two non-core modules. The first is Feature::Compat::Class, which in turn pulls in a few others. But this is non-core in some temporary way: With Perl 5.38, the OO system is in core, so at some point the module will be replaced by use feature 'class'. The second one is PDL, the Perl Data Language.

    I meant to learn a bit about PDL for a long time, and eventually the sound stuff gave me enough motivation to do it. We are not doing research, but acoustics is a branch of physics, so let's give it a try.

    The first nice match between PDL and sound is pulse-code modulation (PCM), a simple method to encode sound digitally. Sound comes as a wave where pressure changes over time, and if you measure the pressure at a not completely arbitrary rate of 44100, you get 44100 data points per second. PCM simply takes these data points as a representation of the sound, and the WAV format is a way to store these in a file. Players on all platforms can play .wav files back as sound.

    I use PDL to create the samples by calculation, not by measuring them. Creating one second of a 440Hz sine wave is a one-liner:

    use PDL; my $samples = sin(sequence(44100) * 2 * atan2(0,-1) * 440 / 44100);

    Of course, this is just the start. A sine wave sounds bland. You can use arbitrary functions to create the samples. Adding sine functions with a multiple of the frequency (overtones) give a richer tone. Changing the amplitude over time ("envelope") can give a sound like plucked strings. Or even like something which is not possible with physical instruments.

    PDL also makes it easy to display a waveform (screenshot). If the waveform looks to messy, you can apply Fast Fourier Transform (FFT) to a batch of samples to get a spectrum (screenshot). This spectrum shows sharp peaks because the waveform is a sum of sine functions with frequencies of n*220Hz. (The graphics stuff is not yet in the repository)

    While playing with spectra and wave forms, I was accidentally listening to Kaki King's Playing with Pink Noise. This song isn't actually pink noise, but it made me wonder whether it is possible to synthesize noise with different spectral properties using Perl. And of course it is: Fourier transforms are reversible. You can create a spectrum from a batch of samples, and as well you can create a batch of samples from a spectrum. So you create a one-dimensional spectrum to your liking, apply FFT, and the result is noise. There is a bit more math involved (complex numbers), but anyway: The repository now has another program bin/noise to create noise, and also to restrict it to a frequency range.

    Noise plus envelopes... these are the first steps to percussions. Let's see where this leads us.

    We recently had a thread about learning PDL: For me, playing with sound does the trick quite nicely.