Introduction

The Raspberry Pi and the BeagleBone are two very popular computers about the size of a deck of cards. These so-called "tinyware" devices contain USB ports, onboard ethernet, and audio/visual output capabilities. Both devices use Linux as an operating system, which allows them to utilize a large array of programming languages and applications available on the Linux platform, including Csound.

The goal of this article is to provide a brief introduction to using Csound on either one of these devices to create a real-time performance device. No prior experience is necessary with Linux, but some familiarity with basic Unix commands is recommended.

It should be noted that while many concepts for running Csound on both the BeagleBone and the Raspberry Pi overlap (enough to warrant a joint article on the two devices), there are a few notable differences between them. The Pi is built so that it works out-of-the-box as a functional desktop computer. The BeagleBone, on the other hand, has a modular approach to hardware, where one has to buy and configure external attachments (called "capes") for the utilization of audio and video. These differences will be addressed more in the article.

This article assumes that you have already flashed an SD card and we will not cover that aspect, as there is plenty of documentation readily available on the subject of SD cards.

For help in setting up the Raspberry Pi SD card, follow the link listed here:

For help in setting up the BeagleBone SD card, follow the link listed here:

 

I. About Debian Linux

This article was written running versions of Debian Linux specifically built for both the Pi and the BeagleBone. Debian is a distribution, or "distro" of Linux. A distribution can be thought of as a flavor of Linux, and is often made for a specific audience or task. Debian is one of the older and more stable Linux distributions and is very general-purpose. While it is the default Linux distribution for the Raspberry Pi, it is not for the BeagleBone. The BeagleBone ships with the Angstrom distribution, specifically made for the BeagleBone. This article will be using the Debian image found at the link listed here:

 

II. Setting Up

Installing Csound

The easiest way to install Csound is to use the package manager named apt. A package manager automatically maintains and updates software and all the libraries that software package requires. These required packages are called dependencies. Usually the version of Csound accessed from the repositories is an earlier version than the most recent release of Csound. For this reason, many Linux users choose to compile Csound. Compilation, due to the large number of variables involved, is beyond the scope of this article, but there is help for building Csound located in The Canonical Csound Reference Manual.

Once you have started your device, you can test the internet connection by pinging the Csound website (a wired ethernet connection is preferred). To do this, open a terminal and execute the command:

ping www.csounds.com

If an error is returned like "server not found", the internet connection needs to be checked. If successful, a series of lines will print out indicating that packets of data are being sent and received. Csound can then be installed on the device with the commands below, executed from the command line.

To install Csound, run:

sudo apt-get install csound

To update the package manager, run:

sudo apt-get update

The package manager will download the required packages and install them on the device automatically. These packages are pre-compiled binaries specifically for the ARM platform.

Setting up QuteCsound

Qutecsound (now known as CsoundQt) is a valuable cross-platform front-end for designing and testing CSDs. It is a user friendly interface complete with a console, the Csound manual, and more. You can develop CSD's on the tinyware itself, sidestepping any problems that arise from porting it from a foreign system. To use QuteCsound you will need a desktop environment. The Raspberry Pi's SD card comes with one preinstalled. BeagleBone users will need to install one. For this article LXDE will be used because it is a relatively lightweight desktop environment with a low CPU footprint.

To install LXDE, enter:

sudo apt-get install lxde

Installing LXDE takes quite a while. Once the desktop environment is installed, you can install QuteCsound (CsoundQT) with the following command:

sudo apt-get install qutecsound

After installation, reboot the device with:

sudo reboot

BeagleBone users will be prompted with a graphical login screen for LXDE. Raspberry Pi users need to login and then start LXDE with the command startx. QuteCsound should be available in the menu after it is installed.

Executing Csound from the command line

For real-time performance, Csound should be invoked from the command line. A typical CSD file could be run using these arguments[1]:

csound -odac -+rtaudio=alsa -B2048 -b2048 /path/to/file.csd

Alternatively, the command line flags can be placed in the CsOptions section of the CSD instead, allowing you to just run the following command:

csound /path/to/file.csd

Linux offers a few dedicated text editors, all of which can be used to edit CSD files. An easy one to get started with is nano. Another, called Vim, is much more sophisticated. With the csound-vim plugins by Luis Jure, Vim becomes a very powerful tool. However, Vim's learning curve is beyond the scope of this article.

 

III. Creating Csound Instruments

Setting Up Audio

A USB-powered soundcard is strongly recommended for any serious audio use. Unfortunately, it is quite difficult to find high-quality Linux-compatible soundcards. The ALSA wiki has a list of sound cards reported to work under Linux[2]. The best soundcard that has been known to work with the Bone/Pi is the Behringer UCA202. In addition to RCA input/output, there is also headphone output with adjustable volume control.

By default, Csound uses the PortAudio module to communicate with the hardware device. However, we prefer using ALSA (the Advanced Linux Sound Architecture) on Linux systems. BeagleBone users will need to install ALSA using the command:

sudo apt-get install alsa-utils

Raspberry Pi users should already have ALSA installed. To use ALSA instead of PortAudio, use the flag -odac -+rtaudio=alsa as part of the Csound command.

To specify a specific audio device, you can utilize the command:

aplay -l

The above command will list the available soundcards[3] such as those shown below:

**** List of PLAYBACK Hardware Devices ****
card 0: EVM [AM335X EVM], device 0: AIC3X tlv320aic3x-hifi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: CODEC [USB Audio CODEC], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Using the Csound flag -odac:hw:1 will select card 1, which is the Berhinger USB audio soundcard.

Specifying Csound input is done by typing -i adc. The same procedure that is used for selecting specific cards for -o applies to -i as well. For example: -iadc:hw:

To test your speakers and to make sure audio is working, run the following ALSA command, which will play white noise out of the speakers:

speaker-test

To adjust the volume of your speakers, run the ALSA command below, which will provide a set of "faders" with which you can use the arrow keys to move up or down:

alsamixer

 

Setting up Audio hardware for the BeagleBone

Lacking the Raspberry Pi's built in analogue audio and video outputs, the BeagleBone requires an external attachment called a cape. The "DVI-D with audio" cape is a more integrated alternative for the platform than using a USB soundcard. In addition to having two channels of audio input and output, it provides HDMI video output as well which is essential for using a Csound frontend. Using this cape also frees the BeagleBone's single USB port.

If the audio cape is to be fitted onto the BeagleBone with no capes in between, then it is imperative to leave as much space as possible between the boards. The input audio jack is situated directly above the 5V power jack. Forcing both cables into their jacks when the boards are too close together will gradually weaken the audio input jack's connection to the cape. Should this happen, it can be carefully soldered back onto the board again using a soldering iron with a fine point tip.

In order to initialize the cape during boot-up and to restore alsamixer settings, open the file /etc/rc.local in nano:

sudo nano /etc/rc.local

Type these following lines into /etc/rc.local[4]:

# Load DVI-D w/ Audio Cape.
modprobe snd_soc_davinci_mcasp
modprobe snd_soc_davinci
modprobe snd_soc_evm
modprobe snd_soc_tlv320aic3x

# Now restore alsamixer settings.
alsactl restore

Since there are many parameters that require adjusting, we will use a script. Create and copy the following into a script file named cape_config.h:

amixer set PCM 100%
amixer set HP unmute
amixer set 'HP DAC' 100%
amixer set 'Left HP Mixer DACL1' unmute
amixer set 'Left PGA Mixer Line1L' unmute
amixer set 'Right HP Mixer DACR1' unmute
amixer set 'Right PGA Mixer Line1R' unmute
amixer set 'AGC' mute
amixer set 'Left HP Mixer DACR1' mute
amixer set 'Left PGA Mixer Line1R' mute
amixer set 'Right HP Mixer DACL1' mute
amixer set 'Right PGA Mixer Line1L' mute
amixer set 'PGA' 0%

Then run the script using the following command:

    sh cape_config.sh

To save the alsamixer settings, enter the following code:

    sudo alsactl store

The /etc/rc.local file will prompt the BeagleBone to detect the cape and restore alsamixer settings on boot before logging in.

Setting Up MIDI for the Raspberry Pi/BeagleBone

Most standard MIDI controllers should work on a Linux system without any issues. By default, Csound uses PortMIDI, but we recommend to use ALSA. To use ALSA, use -+rtmidi=alsa when running Csound.

MIDI device selection with Csound is done using the -M flag. To use all available MIDI devices as input, use the Csound flag -Ma.

To use a specific MIDI controller, you can list all the available MIDI devices using the Linux command below[5]:

cat /proc/asound/cards

The output will look something like this:

0 [EVM            ]: AM335X_EVM - AM335X EVM
                     AM335X EVM
1 [O25            ]: USB-Audio - Oxygen 25
                     M-Audio Oxygen 25 at usb-musb-hdrc.1-1, full speed

Each listed MIDI controller will have a specific number assigned to it. For instance, to use the Oxygen 25 (device number 1), you would use the Csound command-line flag -+rtmidi=alsa -M hw:1.

 

IV. Optimizing Csound Instruments

The Raspberry Pi and BeagleBone have a fraction of the processing power that a modern computer has. A real-time Csound instrument that runs well on a Macbook Pro may run quite poorly on a Raspberry Pi or BeagleBone, and therefore some modifications to the instrument must be made to prevent unwanted clicks and drop-outs. There is a true art to making good-sounding instruments on platforms with limited CPU resources, and below are some quick tricks that can help optimize realtime instruments created on other computers.

The first thing that should be changed is the buffer size in the CsOptions. The hardware buffer size (-B) specifies the size of the buffer used by the audio hardware connected or built into the device and is especially important[1]. The software buffer size dictates the buffer size used by Csound[1]. These should be set as low as possible without causing dropouts in the rendered audio. On the BeagleBone, optimal performance can be achieved by defining a hardware buffer size of 512 samples. On the Raspberry Pi, software buffer sizes in the range of 1024-4096 will bring good results. Some experimentation may be required for optimal performance on your particular system. Bear in mind that raising the buffer size will introduce more latency. It should also be noted that on the BeagleBone, the software buffer size has to be 1/16th of the hardware buffer size. In fact, Csound will not allow it to exceed this if a BeagleBone audio cape is being used.

Lowering the sample rate (sr) of an orchestra can also be quite a beneficial optimization for real-time performance. Many CPU-intensive instruments can run smoothly at a samplerate as low 24 kHz. Be mindful about sample rate when using audio input: aliasing effects will be much more audible with sample rates lower than 44.1 kHz. Some frequency dependent opcodes will crash Csound if values above the sampling rate are used.

The third option that dramatically affects performance is the control rate (ksmps). This should be set so that the CSD runs without errors and dropouts. Try to get this as low as possible; it is not uncommon to have a ksmps value at around 40. However, be aware that using larger ksmps values can introduce more apparent "stair-stepping" distortion into the control signal.

Limiting the number of voices that an instrument can play is also a good way to prevent CPU overloads. The maxalloc opcode will limit the number of voices that can be played at once, reducing the likelihood of crashing by pressing too many keys down at once, for example from a keyboard controller. Also, be careful with release times, because long releases may negatively affect the playability of the instrument.

Changing the length of your GEN routines can also be a easy way to dramatically optimize the instrument. Since most GEN routines only take power of two, this will require halving lengths. For instance, a GEN 10 sine wave with a size of 8192 can be too CPU-expensive for a Pi/BeagleBone. You may want to try a value of 4096, 2048, or even 1024 instead. Be aware that with smaller GEN routine lengths, the fidelity of the wave form will be reduced, and you will need to find an acceptable balance between sound quality and performance.

When control over the above options still do not bring the desired results, there is another powerful tool: the --sched flag. This flag gives the system's computational priority to Csound. This requires root privileges so you will need to run Csound with sudo csound --sched FLAGS foo.csd. The user will also need to be careful as the --sched flag may lock up the system!

 

V. Running Headless (Standalone)

This section will illustrate how to set up a BeagleBone/Raspberry Pi to run as a Csound instrument without the aid of a computer screen. This is also known as running "headless."

Configuring Auto-Login

To set it up your device so that it automatically logs in at start-up, edit the /etc/inittab file with administrative privileges.

Run nano to edit the file /etc/inittab with administrative privilages:

sudo nano /etc/inittab

Scroll down using the arrow keys to this line:

1:2345:respawn:/sbin/getty 115200 tty1

Comment it out with the # character so that it looks like this:

#1:2345:respawn:/sbin/getty 115200 tty1

Write this line underneath it, substituting "USERNAME" with the name of the user to be logged in [7]:

1:2345:respawn:/bin/login -f USERNAME tty1 /dev/tty1 2>&1

Enter ctrl-X to exit nano. Enter Y to save the changes, and then press Enter to overwrite the file. When the device is rebooted it will login automatically, and this can be verified by connecting a monitor to the Raspberry Pi, or to the BeagleBone with a video output cape. If a mistake is made and the device hangs on boot, entering ctrl-alt-f2 will allow you to login using the next virtual terminal window, where /etc/inittab can be repaired. Note that if the screen application is being used to monitor the device, it will not recognize the automatic login and login will still need to be performed manually.

Execute Csound at Boot

When using your device as a musical instrument, Csound will need to start automatically. Once automatic log-in is setup for your device, commands can be added to the file in ~/.bash_profile, which will be executed after the login process. To do this, run the command:

nano ~/.bash_profile

Then add the following line:

csound foo.csd

"foo.csd" should be the name of the .csd file to be executed at boot. If the directory is not explicitly navigated to with the cd command, Csound will automatically look for the .csd in the home (~) directory. If all the necessary command-line flags are added in the CsOptions part of the .csd, then there is no need to set any flags in ~/.bash_profile. The next time the device reboots, the .csd will automatically execute after automatically logging in.

To run Csound in the background, thus enabling other programs to be executed concurrently, add an ampersand to the end of the command in ~/.bash_profile:

csound foo.csd &

To stop Csound from running, execute the following command:

sudo killall csound

Csound can also be executed from the file /etc/rc.local, but ~/.bash_profile is more convenient because it does not need root privileges.

Setting up SSH

SSH is a network protocol that allows users to remotely access another computer through a network. It is also a way of sending files from one computer to another. SSH is a convenient way of accessing your headless Pi/BeagleBone without having to utilize an external screen and keyboard.

Please note that these steps have only been tested on Linux and Mac OSX computers. Windows users may have to do some additional research to get SSH working properly.

By default, SSH is enabled on the device, but it needs to be configured to have a static IP address. Open the file /etc/network/interfaces in nano or another text editor:

sudo nano /etc/network/interfaces

Find a line that says the following:

iface eth0 inet dhcp 

And comment it out with the # key:

#iface eth0 inet dhcp

Below it add these lines, including the indentation as indicated[6]:

iface eth0 inet static:
	address 169.254.0.1

Save the file and exit. This will be the IP address that other computers will use to connect to the Pi. Note that the address is somewhat arbitrary, but it will be the one used for this article. Reboot the device. Plug one end of a standard ethernet cable into the network port on the device, and the other into the port of a Linux or OSX computer. On the Linux or Mac, open up the terminal and test that the connection works with ping 169.254.0.1. This should output the same result as pinging csounds.com. If not, check to make sure you have configured everything correctly and try again.

After successfully pinging the device, remote log in can be done with the command ssh USER@169.254.0.1, where "USER" should be substituted with whatever the username is on the device. On the Raspberry Pi, the default is pi, and on the BeagleBone the default is debian. Enter the password. On the Raspberry Pi it is raspberry and on BeagleBone it is temppwd. Once logged in, the command line of the device will be directly accessed. To exit, simply enter the command exit.

Sending files to and from the device via SSH is done with scp, which is short for "Secure CoPy". To send a file called foo.csd to the device, change to the directory that foo.csd is in, and run the command scp foo.csd USER@169.254.0.1:foo.csd. As above, change "USER" to whatever the username on the target device is. This will copy foo.csd into the home directory (/usr/home/USER) of the device. To copy a folder foo onto the device, run the same command with the -r (recursive) flag: scp -r foo USER@169.254.0.1.

Remembering "169.254.0.1" can be inconvenient, especially when using multiple devices with unique IP addresses. On the computer accessing the device, give the IP address a host name that will be easier to remember by adding this line to the end of /etc/hosts:

169.254.0.1 tinyware

Now run ssh USER@tinyware and it will log into the device.

 

VI. Example Instruments

Below are four example instruments which have been created and/or optimized to run well on the BeagleBone and the Pi, and these are freely available for use and modification. You can download the code for these examples here: pi_bone.zip. The sound generation and synthesis techniques utilized in these instruments are frequency modulation and sampling. Historically those techniques have proven to be CPU-efficient which is why they are utilized as examples.

The Pangelis instrument utilizes a single FM operator pair to create a plucked timbre, which is then fed through the reverbsc opcode. MIDI CC values 11, 12, 13, 14, and 18 control pitch bend, vibrato, attack time, modulation index, and reverb level, respectively. Also noteworthy is the maxalloc opcode that limits the maximum number of notes played at once to be eight. This is an easy way to prevent the user from overloading the audio by playing too many notes.

Pangelis:
A vangelis inspired synthesizer built specifically for the Raspberry Pi.
By Paul Batchelor
March 2013
<CsoundSynthesizer>
<CsOptions>
-odac:hw:0 -+rtaudio=alsa -B 2048 -b 2048 -+rtmidi=alsa -Ma
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 256
0dbfs = 1
nchnls = 2

alwayson 1
alwayson 999
gisine ftgen 0, 0, 4096, 10, 1

garvbL init 0
garvbR init 0

initc7 1, 11, 0
initc7 1, 18, 1
initc7 1, 12, 0
initc7 1, 13, 0
initc7 1, 14, 0

maxalloc 1, 12

instr 1 ;Pangelis
iamp = .2
icps cpsmidi

kbend linseg 1, 6, .75
kbend port kbend, 0.001

;vibratro level CC 12
klev ctrl7 1, 12, 0, 0.02
;manual bend amount CC 11
kbend2 ctrl7 1, 11, 1, 1.3
;modulation index CC 14
kmod ctrl7 1, 14, 1, 5
;attack time CC 13
iatk ctrl7 1, 13, 0.01, 1.1
kvib oscil klev, 5, gisine
kjit jitter 0.002, 6, 3
kenv expsegr .1, iatk, 1, 2, 0.0001, 2, 0.0001
a1 foscil iamp*kenv, icps*kbend*(1+kjit)*(1+kvib)*kbend2, 2, 3, kenv*kmod, gisine
outs a1, a1
garvbL = garvbL + (a1 * .5) 
garvbR = garvbR + (a1 * .5) 
endin

instr 999 ;reverb
;reverb level 18
krev ctrl7 1, 18, 0, 1
aL, aR reverbsc garvbL, garvbR, .95, 15000
outs aL * krev, aR * krev
garvbL = 0
garvbR = 0
endin
</CsInstruments>
<CsScore>

t 0 180
f 0 999



</CsScore>
</CsoundSynthesizer>

Lorenz FM is an instrument that consists of another FM operator pair, but what makes it interesting is that the famous Lorenz Strange Attractor influences its parameters. The Prandtl number influences the attack behavior, the ratio of the box width and length control its timbre, and the Rayleigh number causes the sound to behave chaotically. This example also uses the reverbsc opcode. MIDI CC values of 11, 12, 13, 14, 15 ,16, 17, and 18 control the Prandtl Number, modulator, the ratio of width and length of the box, the Raleigh number, attack, decay, sustain, and reverb amount respectively.

<CsoundSynthesizer>
<CsOptions>
-+rtaudio=alsa  -B1024 -+rtmidi=alsa -M hw:1 -odac
</CsOptions>
<CsInstruments>
sr 		= 		24000
ksmps 	= 		45
0dbfs	=		1
 
gisin	ftgen   8, 0, 512, 10, 1
garvbL init 0
garvbR init 0

ctrlinit  1, 7,64,  11,52,12,30,13,11, 14,47, 15,0, 16,64, 17,64, 18,64   
 				
;=============================================================================				
maxalloc 1, 6 						
	instr 1	; Lorenz FM	

icps		cpsmidi
iamp		ampmidi	1

ihtim	=	.01		;port time

   
kvol		midic7 7, 0, .5
kpvol		port kvol, ihtim
   
ksv      	midic7  	11,.1,8    			; The Prandtl Number or Sigma
kpsv		port ksv, ihtim

kmod		midic7	12,0,24			
kpmod		port kmod, ihtim

kbv      	midic7  	13, .1,1.667 		; Ratio Of the Length And Width 
kpbv		port kbv, ihtim					; of the box

krv      	midic7  	14, 2, 10 			; The Rayleigh Number
kprv		port krv, ihtim

ax,ay,az 	lorenz   	kpsv, kprv, kpbv, .01, .6, .6, .6, 1
kx   		downsamp  ax
ky  	 	downsamp  ay
kz  		downsamp  az
                 
imatk    	midic7  	15,.001, 4 
imdec    	midic7  	16,.001, 1 
imsus    	midic7  	17, 0, 1
   
kenv		madsr	imatk, imdec, imsus, .01
afm		foscil	kenv*iamp, icps+kx, 1, 1+kz, kpmod*ky, gisin				
 		out		afm * kpvol
garvbL = garvbL + (afm * .5) 
garvbR = garvbR + (afm * .5) 

endin

;=============================================================================

instr 999 ;Reverb
;vibrato amount
krev ctrl7 1, 18, 0, .5
aL, aR reverbsc garvbL, garvbR, .8 + .15*krev, 15000
outs aL * krev, aR * krev
garvbL = 0
garvbR = 0
endin

;=============================================================================





</CsInstruments>
<CsScore>

f0  600
i999 0 600

</CsScore>
</CsoundSynthesizer>

Diskin Looper uses the diskin2 opcode to load a drum loop from BT's (aka Brian Transeau) freely available OLPC drum loop library. The playback speed can be controlled with MIDI CC value 11. A toggle has been created so that when the user presses the space bar, it toggles the manual playback speed on/off.

<CsoundSynthesizer>
<CsOptions>
-odac -Ma -+rtmidi=alsa -+rtaudio=alsa -B 2048 -b 2048
</CsOptions>
; ==============================================
<CsInstruments>

sr	=	44100
ksmps	=	10
nchnls	=	2
0dbfs	=	1


initc7 1, 11, 0.75

instr 1	
key sensekey 

ktog_pch init 1
printk2 key
printk2 ktog_pch

;MIDI CC1 controls pitch
kcps ctrl7 1, 11, -2, 2
kcps portk kcps, 0.01


;midi controlled diskin loop
a1 diskin2 "FunkSoulSista.wav", kcps, 0, 1
;normal diskin loop
a2 diskin2 "FunkSoulSista.wav", 1, 0, 1


;space bar toggles the normal and midi controlled loop
if(key == 32) then
	if(ktog_pch == 0) then
		ktog_pch = 1
	elseif(ktog_pch == 1) then 
		ktog_pch = 0
	endif
endif


if(ktog_pch == 1) then
	;send midi controlled loop to outputs
	aout = a1
elseif(ktog_pch == 0) then 
	;send normal loop to outputs
	aout = a2
endif

outs aout, aout

endin

</CsInstruments>
; ==============================================
<CsScore>

i1 0 10000

</CsScore>
</CsoundSynthesizer>

Monophonic Synth is a modified instrument from the OLPC collection. It is particularly due to it being strictly monophonic. It is a very stable instrument for performance because it is impossible to overload it by playing too many notes at once.

<CsoundSynthesizer>
<CsOptions>
-odac -Ma -b 2048 -B 2048 -+rtaudio=alsa -+rtmidi=alsa 
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 10 
nchnls	=	2

; MidiMonoSyn, Version A: 1 osc, 1 filter, pitch and vel portamento

#define ON 		#1#
#define OFF 		#0#
#define NOTEON		#144#	; midi status num for note on
#define NOTEOFF	#128# 		; midi status num for note off


; values for synthstate to keep track of what's happening
#define NEWDETACHED #1#		
#define DETACHED	#2#
#define NEWLEGATO   #3#
#define LEGATO		#4#	
#define NEWRELEASE  #5#
#define RELEASING	#6#

gaSig init 0
initc7 1, 18, .5
	instr 128
; dummy instr to catch the annoyning default midi routing
; if this is not here, instr 130 gets turned on and off by the keyboard
	endin


	instr 130

; Control variable initialization. Change these as desired

; The stuff here can be turned into real time controls in later versions

iampatt		init		0.001
iampdec		init		0.3
iampsus		init		0.8
iamprel		init		0.01
iampmute	init		0.0005		; time to damp previous note

idetfrqprt	init		0.001		; pitch portamento for non legato
ilegfrqprt	init		0.05		; pitch portamento time for legato

kvolume		init		20000			; amp value for full velocity. ( 1 )

ichan		init		1			; which midi channel to pay attention to		


;******************************************************************************
; Variable initialization. This only happens once. Don't change these.


kactive		init		0			; number of active midi notes
ksynstate	init		$NEWRELEASE ; starts as playing with envelopes closed

kampenv		init		0			; amp env starts at 0
kamprelenv	init		0.0001		; rel env starts at 0 so we hear silence 
kamp			init		0.0001	; final kamp (either main env or rel env)
kfrq			init		440		; need some dummy starting pitch 

ifrqprt		init		0.001		; meaningless initialization
		
; Note, ksynstate tells us what is happening. 
; It only lasts for one kpass for new notes.

;******************************************************************************
; Midi Parser section.

; This section receives midi input and decides what state the synth is in.
; You can change this section to change how midi input is interpreted.
; In this version any held note will keep the synth in legato and playing
; the most recently played note.


; Get any waiting midi message
kstat, kchan, kdata1, kdata2	midiin

; ignore messages on other channels
if ( kchan != ichan ) kgoto DoneMidiIn

; if we get a note on and vel is not 0, goto note on section
if ( ( kstat == $NOTEON ) && ( kdata2 != 0 ) ) kgoto NoteOn

; if we get a note off or note on vel 0, goto note off section
if (( kstat == $NOTEOFF )||( ( kstat==$NOTEON )&&(kdata2 == 0))) kgoto NoteOff 

; any other incoming midi messages are ignored for now
kgoto DoneMidiIn


; Note on section
NoteOn:

	; increment kactive ( active note counter )
	kactive = kactive + 1

	; if this is the only active note, we have a new detached note
	ksynstate = ( kactive == 1 ? $NEWDETACHED : ksynstate )
	
	; if there are other active notes, we have a new legato note
	ksynstate = ( kactive > 1 ? $NEWLEGATO : ksynstate )
	
	kgoto DoneMidiIn
		
		
; Note off section
NoteOff:

; if there is more than one note playing, ignore this note off
; or if no notes are playing, ignore the note off (in case of panic button)
	if ( ( kactive > 1 ) || ( kactive == 0 ) ) kgoto IgnoreNoteOff

	; otherwise, decrement kactive 
	kactive = kactive - 1
	
	; and set ksynstate to $NEWRELEASE
	ksynstate = $NEWRELEASE
	
	kgoto DoneMidiIn
	
	
IgnoreNoteOff:

	; we update the active note counter, but don't do anything else
	; the note counter is held at minimum 0
	kactive = ( kactive <= 0 ? 0 : kactive - 1 )


DoneMidiIn:


;******************************************************************************
; New Note section:

;For a new detached note we need to restart the envelopes and portamento ramps.
;For a new legato note we restart the portamento ramps, but not the envelopes.

;The reinit code only affects anything on a reinit pass, else it is ignored.
;However the reinit section must also enclose the envelope code so it restarts.
;When we are not actually reiniting, we pass through the envelope code as well.

;******************************************************************************
; Amp env section

; if we are in a release stage, skip to release env section
if ( ksynstate == $NEWRELEASE || ksynstate == $RELEASING ) kgoto ReleaseSection


; If this is the first kpass of a new detached note, kgoto to the NewAmpEnv 
; reinit
; On all other passes we must continue to the AmpEnv section

if ( ksynstate == $NEWDETACHED ) kgoto NewAmpEnv
	kgoto AmpEnv

; The reinit section. We only get here on a new detached note.
NewAmpEnv:

	; on a new detached note we must reinit the envelopes
	reinit NewAmpEnv

	; freezing of any controls for detached notes goes here, ie env values

	; freeze last amp value, new env starts from there.
	iampstrt		init		i( kamp )
	

; The actual amp env section, we get here on both reinit and continuing passes
; However, the reinit pass *restarts* the envelope. 
AmpEnv:

	; Amp envelope section, we must hit this on all passes

	; Envelope starts from the last value used, 0.001 if a note finished the 
	; release
	; Envelope just ends parked on the sus level.	
	; Uncomment whichever version of the env you want to use
	
	; "String damping" version of the env
	; quickly goes to 0.001 before the attack
	kampenv	linseg iampstrt,iampmute,0.001,iampatt,1,iampdec,iampsus,1,iampsus	 

	; "Continuous sound" version of the env
	; env starts from last value. long release time will change slope of attack
	;kampenv	linseg	iampstrt, iampatt, 1, iampdec, iampsus, 1, iampsus
	
	; End the reint pass for the NewAmpEnv
	; ( This has no effect during non reinit passes )
	rireturn


; skip the release section
kgoto DoneAmpControl


;******************************************************************************
;The Release Envelope section.

;The release env starts from the last amp value used, and closes to 0.0001
;Between notes ( after release time ) it is held at 0.0001 so we hear silence.

;On the first kpass of a release we do the reinit section and the release 
;env code.
;On subsequent kpasses we hop ahead to the release env code.

ReleaseSection:

if ( ksynstate == $NEWRELEASE ) kgoto NewRelease	
	kgoto Releasing

NewRelease:

	; reinit the release env, only happens on $NEWRELEASE passes
	reinit NewRelease

	; freeze the ampenv starting points here
	iampstrt	init	i( kamp )	
	
		
Releasing:

	; release env starts from last amp value used and parks on 0.0001
	kamprelenv	expseg	iampstrt, iamprel, 0.0001, 0.2, 0.00001

	; end the reinit pass, this has no effect on $RELEASING passes
	rireturn


; ( label we hop to when skipping the release code )
DoneAmpControl:


;******************************************************************************
; Pitch and Velocity portamento section

; We have finished the env code. Now we do the pitch ramp code
; Note: we should be here on all passes, even release passes, as we might
; play a very short note with a long port time, and have the pitch still
; be gliding during the release stage.


; On either new detached or new legato notes, we must reinit the frq ramps
; We merely choose which port time to use based on detached or legato
if ( ksynstate == $NEWDETACHED || ksynstate == $NEWLEGATO ) kgoto NewFrq
	
	; on all other passes continue the pitch ramps
	kgoto FrqRamp
	
NewFrq:

	; start the reinit pass from NewFrq
	reinit NewFrq

	; freeze the starting pitch for the portamento
	; the start pitch is the last used pitch from the previous note
	; this is working
	ifrqstrt 	init		i( kfrq )

	; choose which portamento speed to use
	isynstate	init		i( ksynstate )
	ifrqprt	= 		( isynstate == $NEWDETACHED ? idetfrqprt : ilegfrqprt ) 

	; freeze the destination pitch from the midi note number
	inotenum	init		i( kdata1 )
	
	; convert the midi note num to cps, ( thanks Istvan! )
	ifrqdest	init		cpsoct( inotenum * 0.08333333 + 3 )		


; we get here on all passes, including the reinit ones	
FrqRamp:	
	
	; the pitch ramp straightens out on the destination pitch
	kfrq		expseg	ifrqstrt, ifrqprt, ifrqdest, 1, ifrqdest

	; end the NewFrq reinit pass
	rireturn


;******************************************************************************
; Sound Section

; The envelopes and pitch ramps have been generated, now we make some noise.

; Three detuned oscillators so we can hear beating

; Add jitter to simulate analogue oscillators
kjit jitter 1.5, 1, 8
kjit2 jitter 1.5, 1, 8
kjit3 jitter 1.5, 1, 8

asig1 vco2 0.33, kfrq + kjit
asig2 vco2 0.33, kfrq * 0.995 + kjit
asig3 vco2 0.33, kfrq * 1.005 + kjit

; Combine the oscillators
asigcomp	=		asig1 + asig2 + asig3

; Keyboard-scaled 
asigfilt moogvcf asigcomp, 2000 + kfrq, 0.2

asigcomp balance asigfilt, asigcomp

; choose which envelope we should use based on ksynstate
kamp=(ksynstate==$NEWRELEASE || ksynstate==$RELEASING ? kamprelenv : kampenv)

;amplify using linear interpolation of the envelope for smoothness \
;(and MIDI volume control)
asigout	=		asigcomp * a(kamp) * kvolume

; output the signal
		outs		asigout, asigout
		gaSig = asigout*0.8 + gaSig	


;******************************************************************************
; Update the synstate.

; $NEWRELEASE will change to $RELEASING
; $NEWDETACHED and $NEWLEGATO will change to $PLAYING

ksynstate = ( ksynstate == $NEWDETACHED ? $DETACHED : ksynstate )
ksynstate = ( ksynstate == $NEWLEGATO ? $LEGATO : ksynstate )
ksynstate = ( ksynstate == $NEWRELEASE ? $RELEASING : ksynstate )

		endin

	instr 999 ;Reverb with MIDI control
klev ctrl7 1, 18, 0, 1
aoutL, aoutR reverbsc gaSig, gaSig, .7, 10000
outs aoutL*klev, aoutR * klev
gaSig = 0
	endin

</CsInstruments>
<CsScore>

;sawtooth wave with gen 7
f4	0 4096 7 -1 4096 1


; turn on the instrument, for some reason ihold won't work with reinits
i130 0 1000		
i999 0 1000		

e

</CsScore>

</CsoundSynthesizer>

 

VII. Conclusion

It is an unexpected surprise to see the world of tiny Linux computers (so-called "tinyware") become popular so quickly amongst the DIY and tech community. The open source platform is an ideal medium for ideas to be shared and spread quickly, and a very large Raspberry Pi/BeagleBone community has grown as a result of this. The Csound community is fortunately open source as well, and can participate in this exponential growth of inexpensive computing devices. It is the hope of both authors that more interesting sounds, beautiful music, and mini, musical, interactive instruments will be created on both the Raspberry Pi and the BeagleBone. These new platforms should provide a new and unique twist on the constantly changing musical language, as well as help draw a new audience to Csound.

References

[1] Barry Vercoe et Al.. 2005. "Csound Command Line," The Canonical Csound Reference Manual. [Online]. Available: http://www.csounds.com/manual/html/CommandFlags.html [Accessed March 19, 2013].

[2] AlsaProjet Wiki. "Alsa SoundCard Matrix". [Online], Available: http://www.alsa-project.org/main/index.php/Matrix:Main [Accessed March 19, 2013].

[3] Barry Vercoe et Al.. 2005, "Real-Time Audio," The Canonical Csound Reference Manual. [Online]. Available: http://www.csounds.com/manual/html/UsingRealTime.html#RealTimeLinux [Accessed March 19, 2013].

[4] Google Groups. "BeagleBone Audio Cape". [Online]. Available: https://groups.google.com/forum/?fromgroups=#!topic/beagleboard/qdLcceqH3ms [Accessed March 19, 2013].

[5] Barry Vercoe et Al.. 2005. "Real-time MIDI Support," The Canonical Csound Reference Manual. [Online]. Available: http://www.csounds.com/manual/html/MidiTop.html [Accessed March 19, 2013].

[6] Cyberciti. "Linux Static IP Address Configuration". [Online]. Available: http://www.cyberciti.biz/faq/linux-configure-a-static-ip-address-tutorial/ [Accessed March 19, 2013]

[7] eLinux.og. "RPi Debian Auto Login". [Online]. Available: http://elinux.org/RPi_Debian_Auto_Login [Accessed March 19, 2013]

Additional Resources

Audio optimizations for the Raspberry Pi:
 
Linuxaudio.org. "Linux Audio Wiki". http://wiki.linuxaudio.org/wiki/raspberrypi
 
BeagleBone and Raspberry Pi accessories:
 
Adafruit Industries. http://www.adafruit.com
 
BeagleBone DVI-Audio Cape:
 
Beagle Board Toys. http://beagleboardtoys.info/index.php?title=BeagleBone_DVI-D_with_Audio