Update site.
This commit is contained in:
@@ -1,31 +1,31 @@
|
||||
#+title: Sound Programming
|
||||
#+summary: Programming sound in Live-Sequencer and ChucK
|
||||
#+license: wtfpl, unless otherwise noted
|
||||
#+startup: showall
|
||||
#&toc
|
||||
---
|
||||
abstract: Programming sound in Live-Sequencer and ChucK
|
||||
---
|
||||
|
||||
* Sound Programming
|
||||
Sound Programming
|
||||
=================
|
||||
|
||||
Much can be programmed, and that includes sound. In the digital world, sound is
|
||||
typically represented by sequences of about 90 kB per second, so "printing"
|
||||
sound is merely a matter of printing bytes. As such, any general purpose
|
||||
language can be used to generate sounds.
|
||||
Much can be programmed, and that includes sound. In the digital world,
|
||||
sound is typically represented by sequences of about 90 kB per second,
|
||||
so "printing" sound is merely a matter of printing bytes. As such, any
|
||||
general purpose language can be used to generate sounds.
|
||||
|
||||
However, it's boring to create a program that does nothing but print bytes, and
|
||||
it's potentially difficult to make those bytes sound nice; we want abstractions
|
||||
to simplify matters for us: instruments, drums, musical notes, and a high-level
|
||||
program structure. Many programming languages have good libraries that allow us
|
||||
to achieve just that, but to keep it simple we'll focus on how to program sound
|
||||
in two languages designed to output sound: ChucK and Live-Sequencer.
|
||||
However, it's boring to create a program that does nothing but print
|
||||
bytes, and it's potentially difficult to make those bytes sound nice; we
|
||||
want abstractions to simplify matters for us: instruments, drums,
|
||||
musical notes, and a high-level program structure. Many programming
|
||||
languages have good libraries that allow us to achieve just that, but to
|
||||
keep it simple we'll focus on how to program sound in two languages
|
||||
designed to output sound: ChucK and Live-Sequencer.
|
||||
|
||||
Let's create some sounds.
|
||||
|
||||
|
||||
* The square wave
|
||||
The square wave
|
||||
===============
|
||||
|
||||
We'll start with ChucK and a small square wave program:
|
||||
|
||||
#+BEGIN_SRC c
|
||||
``` {.c}
|
||||
// Connect a square oscillator to the sound card.
|
||||
SqrOsc s => dac;
|
||||
|
||||
@@ -39,16 +39,17 @@ SqrOsc s => dac;
|
||||
while (true) {
|
||||
1000::second => now;
|
||||
}
|
||||
#+END_SRC
|
||||
```
|
||||
|
||||
ChucK is an imperative language. Instructions on how to install and run it can
|
||||
be found on its [[http://chuck.cs.princeton.edu/][website]], along with other useful information. You can listen to
|
||||
the above sound [[square.flac][here]].
|
||||
ChucK is an imperative language. Instructions on how to install and run
|
||||
it can be found on its [website](http://chuck.cs.princeton.edu/), along
|
||||
with other useful information. You can listen to the above sound
|
||||
[here](square.flac).
|
||||
|
||||
To do the same in Live-Sequencer, we must find a square wave "instrument" and use
|
||||
that.
|
||||
To do the same in Live-Sequencer, we must find a square wave
|
||||
"instrument" and use that.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
``` {.haskell}
|
||||
module SquareWave where
|
||||
|
||||
-- Basic imports.
|
||||
@@ -65,22 +66,24 @@ main = concat [ program lead1Square -- Use a square wave instrument.
|
||||
note 1000000 (a 4) -- Play 1000000 milliseconds of the musical note A4
|
||||
) -- about 440 Hz.
|
||||
]; -- End with a semicolon.
|
||||
#+END_SRC
|
||||
```
|
||||
|
||||
Live-Sequencer differs from ChucK in that it is functional, but another major
|
||||
difference is that while ChucK (in general) generates raw sound bytes,
|
||||
Live-Sequencer generates so-called MIDI codes, which another program converts to
|
||||
the actual audio. Live-Sequencer has a couple of funky features such as
|
||||
highlighting which part of one's program is played; read about it and how to
|
||||
install and run it at [[http://www.haskell.org/haskellwiki/Live-Sequencer][this wiki]]. You can listen to the above sound [[squarewave.flac][here]].
|
||||
Live-Sequencer differs from ChucK in that it is functional, but another
|
||||
major difference is that while ChucK (in general) generates raw sound
|
||||
bytes, Live-Sequencer generates so-called MIDI codes, which another
|
||||
program converts to the actual audio. Live-Sequencer has a couple of
|
||||
funky features such as highlighting which part of one's program is
|
||||
played; read about it and how to install and run it at [this
|
||||
wiki](http://www.haskell.org/haskellwiki/Live-Sequencer). You can listen
|
||||
to the above sound [here](squarewave.flac).
|
||||
|
||||
Something more advanced
|
||||
=======================
|
||||
|
||||
* Something more advanced
|
||||
Let's try to create a small piece of music which can be expressed easily
|
||||
in Live-Sequencer (listen [here](melodyexample.flac)):
|
||||
|
||||
Let's try to create a small piece of music which can be expressed easily in
|
||||
Live-Sequencer (listen [[melodyexample.flac][here]]):
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
``` {.haskell}
|
||||
module MelodyExample where
|
||||
|
||||
import Prelude
|
||||
@@ -137,19 +140,20 @@ mel2 x y n = concat [ twice (note qn (x 3))
|
||||
, concatMap (note hn . y) [3, 4, 4]
|
||||
, note wn (x n) =:= note wn (y n)
|
||||
];
|
||||
#+END_SRC
|
||||
```
|
||||
|
||||
When you play the program from the Live-Sequencer GUI, the code in use is
|
||||
highlighted:
|
||||
When you play the program from the Live-Sequencer GUI, the code in use
|
||||
is highlighted:
|
||||
|
||||
#&img;url=sound-highlight.png, width=640, center, caption=Highlighting of sound, screenshot
|
||||
{width=700}
|
||||
|
||||
The same could be expressed in ChucK, but the comparison wouldn't be fair. While
|
||||
Live-Sequencer is designed for describing melodies, ChucK's purpose is sound
|
||||
synthesis, which is more general. We'll create something more fitting of ChucK's
|
||||
capabilities, while still focusing on the use of instruments (listen [[more_advanced.flac][here]]):
|
||||
The same could be expressed in ChucK, but the comparison wouldn't be
|
||||
fair. While Live-Sequencer is designed for describing melodies, ChucK's
|
||||
purpose is sound synthesis, which is more general. We'll create
|
||||
something more fitting of ChucK's capabilities, while still focusing on
|
||||
the use of instruments (listen [here](more_advanced.flac)):
|
||||
|
||||
#+BEGIN_SRC c
|
||||
``` {.c}
|
||||
// Background music for an old sci-fi horror B movie.
|
||||
|
||||
// Filters.
|
||||
@@ -209,32 +213,33 @@ while (true) {
|
||||
a_melody(mandolin, Math.random2(0, 350));
|
||||
a_melody(sitar, Math.random2(200, 360));
|
||||
}
|
||||
#+END_SRC
|
||||
```
|
||||
|
||||
|
||||
* Algorithmic composition
|
||||
Algorithmic composition
|
||||
=======================
|
||||
|
||||
Why not have the computer generate the melody as well as the sound? That
|
||||
*sounds* like a great idea!
|
||||
**sounds** like a great idea!
|
||||
|
||||
Enter [[https: / / en.wikipedia.org / wiki / L-system][L-systems]]. An L-system has an alphabet and a set of rules, where each rule
|
||||
is used to transform the symbol on the left-hand side to the sequence of symbols
|
||||
on the right-hand side. We'll use this L-system to generate music:
|
||||
Enter [L-systems](https: / / en.wikipedia.org / wiki / L-system). An
|
||||
L-system has an alphabet and a set of rules, where each rule is used to
|
||||
transform the symbol on the left-hand side to the sequence of symbols on
|
||||
the right-hand side. We'll use this L-system to generate music:
|
||||
|
||||
#+BEGIN_SRC c
|
||||
``` {.c}
|
||||
-- Based on https://en.wikipedia.org/wiki/L-system#Example_7:_Fractal_plant
|
||||
Alphabet: X, F, A, B, P, M
|
||||
Rules:
|
||||
X -> FMAAXBPXBPFAPFXBMX
|
||||
F -> FF
|
||||
#+END_SRC
|
||||
```
|
||||
|
||||
If we evaluate a L-system on a list, the system's rules are applied to each
|
||||
element in the list, and results are concatenated to make a new list. If we
|
||||
assign each symbol to a sequence of sounds and run the L-system a few times, we
|
||||
get [[lsystem.flac][this]].
|
||||
If we evaluate a L-system on a list, the system's rules are applied to
|
||||
each element in the list, and results are concatenated to make a new
|
||||
list. If we assign each symbol to a sequence of sounds and run the
|
||||
L-system a few times, we get [this](lsystem.flac).
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
``` {.haskell}
|
||||
module LSystem where
|
||||
|
||||
import Prelude
|
||||
@@ -277,17 +282,19 @@ getLSystemSound expand interpret iterations start
|
||||
|
||||
-- Use the third iteration of the L-System, and start with just X.
|
||||
main = channelInsts ++ getLSystemSound expand interpret 3 [X];
|
||||
#+END_SRC
|
||||
```
|
||||
|
||||
Using an L-system is one of many ways to take composition to a high
|
||||
level. L-systems can be used to generate fractals, which are nice.
|
||||
|
||||
|
||||
* And so on
|
||||
And so on
|
||||
=========
|
||||
|
||||
Many abstractions in sound generation allow for fun sounds to happen. Interested
|
||||
people might want to also take a look at e.g. [[http://haskell.cs.yale.edu/euterpea-2/][Euterpea]], [[http://puredata.info/][Pure Data]], or [[http://csounds.com/][Csound]].
|
||||
Many abstractions in sound generation allow for fun sounds to happen.
|
||||
Interested people might want to also take a look at e.g.
|
||||
[Euterpea](http://haskell.cs.yale.edu/euterpea-2/), [Pure
|
||||
Data](http://puredata.info/), or [Csound](http://csounds.com/).
|
||||
|
||||
#&line
|
||||
|
||||
Originally published [[http://dikutal.dk/artikler/sound-programming][here]].
|
||||
Originally published
|
||||
[here](http://dikutal.metanohi.name/artikler/sound-programming).
|
||||
Reference in New Issue
Block a user