Skip to content

Latest commit

 

History

History
194 lines (137 loc) · 8.45 KB

Intro.md

File metadata and controls

194 lines (137 loc) · 8.45 KB

Introduction

Csound-expression is a framework for creation of computer music. It's a Haskell library to make Csound much more friendly. It generates Csound files out of Haskell code.

Csound is an audio programming language. It is really awesome. It features unlimited polyphony, hundreds of synth-units including FM, granular synth, frequency domain transforms and many more. Midi and OSC control, compatible with JACK. With JACK it's easy to use with your DAW of choice. It can run on mobile devices and even in the web browser. It has the support for GUI-widgets.

But Csound is clumsy. It's an old C-style language. We can boost it with functional programming. The Csound-expression gives you eloquence of Haskell combined with power of Csound.

With the help of the library we can create our instruments on the fly. A few lines in the interpreter is enough to get the cool sound going out of your speakers. Some of the features of the library are heavily inspired by reactive programming. We can invoke the instruments with event streams. Event streams can be combined in the manner of reactive programming. The GUI-widgets are producing the event streams as a control messages. Moreover with Haskell we get all standard types and functions like lists, maps, trees. It's a great way to organize code and data.

Let's look at how we can create computer music with Haskell. If you are a Csounder that stumbled upon this page and got interested then it's better to learn some Haskell. The basic level is enough to use the library. I recommend the book Learn you a Haskell for a Great Good by Miran Lipovaca. It's a great book with an elephant on the cover. It's a wonderful introduction to the wisdom and miracles of the Haskell.

Installation guide

Let's install everything. The first thing we need is a csound compiler. When it's installed properly we can type in the terminal:

> csound

It will print the long message. Ubuntu/Debian users can install the Csound with apt-get:

> sudo apt-get install csound csound-gui

The next thing is a working Haskell environment with ghc and cabal-install It can be installed with Haskell Platform. If it works to install the csound-expression we can type in the terminal:

Installing with cabal

> cabal update
> cabal install csound-expression --lib

Let's have a break and take a cup of tea. The library contains a lot of modules to install.

Installing with Stack (recommended)

I prefer to use the library with stack. My usual workflow is to try ideas in the ghci and to save the expressions that sound cool in the file. To setup ghci with the most recent library we can clone the github repo. And create an alias in .bashrc file to load with dependency:

alias cei='stack exec ghci --stack-yaml /home/anton/dev/hs/csound/csound-expression/stack.yaml -- -XOverloadedStrings -ghci-script /home/anton/dev/hs/csound/csound-expression/scripts/default.ghci'

It launches the ghci interpreter and loads the needed default modules to the interpreter session. See file scripts/default.ghci for defaults.

Also we can add to this command -interactive-print=Csound.Base.dac. By default interpreter prints values to console, but when we work we sound we would like to listen to result. And with this line we can substitute the default print function with dac which sends the sound to speakers.

The first sound

Let's start the ghci and load the main module Csound.Base. It exports all modules:

> ghci
Prelude> :m +Csound.Base
Prelude Csound.Base> 

We can play a sine wave with 440 Hz:

> dac $ osc 440

Pressing Ctrl+C stops the sound. The expression osc 440 makes the sine wave and the function dac makes a file tmp.csd in the current directory invokes the csound on it and sends the output to speakers.

WARNING: the library works best within ghci. The real-time sound rendering function dac spawns a child process in the background which may continue to execute after you stop the main process that runs the program. It's not so in vim but it happens in the Sublime Editor and when you invoke runhaskell. So the best is to write you program in the separate file and then load it in the ghci and invoke the function main (which runs the sound rendering with the function dac or another sound rendering function).

Key principles

Here is an overview of the features:

  • Keep it simple and compact.

  • Try to hide low level Csound's wiring as much as we can (no ids for ftables, instruments, global variables).

  • Don't describe the whole Csound in all it's generality but give the user some handy tools to play with sound.

  • No distinction between audio and control rates on the type level. Derive all rates from the context. If the user plugs signal to an opcode that expects an audio rate signal the argument is converted to the right rate.

  • Watch out for side-effects. There is a special type called SE. It functions as IO in Haskell.

  • Less typing, more music. Use short names for all types. Make library so that all expressions can be built without type annotations. Make it simple for the compiler to derive all types. Don't use complex type classes.

  • Make low level opcode definitions simple. Let user define his own opcodes (if they are missing).

  • Ensure that output signal is limited by amplitude. Csound can produce signals with HUGE amplitudes. Little typo can damage your ears and your speakers. In generated code all signals are clipped by 0dbfs value. 0dbfs is set to 1. Just as in Pure Data. So 1 is absolute maximum value for amplitude.

  • No dependency on Score-generation libraries. Score (or list of events) is represented with type class. You can use your favorite Score-generation library if you provide an instance for the CsdSco type class. Currently there is support for temporal-music-notation library (see temporal-csound package).

  • Remove score/instrument barrier. Let instrument play a score within a note and trigger other instruments.

  • Set Csound flags with meaningful (well-typed) values. Derive as much as you can from the context.

  • Composable GUIs. Interactive instruments should be easy to make.

Acknowledgements

I'd like to mention those who supported me a lot with their music and ideas: