Reperforming Clapping Music with Python

Clapping Music by Steve Reich (front) Clapping Music by Steve Reich (back)

standard

python

Python is a so-called "general purpose" programming language. This means that the language hasn't been designed for one specific task, but that it can (and indeed is) used in a variety of context from academic research (computational linguistics, biology, sociology), commercial use (website development, data analytics and visualisation), and artistic practices. Typically when working in a particular field, you use specific "libraries" of code that provide additional functionality to work in a particular field (or fields). For instance, the numpy library is a popular extension to python that allows you to work with large quantities of data (which might for instance be pixel data from images) as arrays and matrixes of numbers.

Python's "standard library" (all the funcionality that comes with every python installation) is already quite capable for many uses. For instance python can quite handily open, read and write to files (both text and "binary").

In addition python's wave module can deal with some of the basics of an audio file such as reading from and generating the so-called "header" data.

First, if you don't have a wav file around, you can generate one using Audacity. In this case I used Audacity's "Generate -> Noise" function to make 30 seconds of "pink noise" and then used "Export Audio" to save a file named "pink.wav" (selecting an option labelled "WAV (Microsoft) signed 16-bit PCM").

Now in python:

import wave
pink = wave.open("pink.wav", "r")

And run it "interactively":

python -i wavstats.py

Now in python type:

pink

Try:

dir(pink)

Remember, to quit python's interactive mode, use CTRL-D or type exit().

OK, now to make the program slightly more flexible, instead of "hard-coding" the filename of the audio file ("pink.wav"), we can read from a special file called "standard in". This is a powerful idea as it allows the actual file used to be named later when we use the script. In this way you start to develop a custom tool(chain) that you can use in different contexts for different purposes.

import wave, sys

win = wave.open(sys.stdin, 'r')
channels = win.getnchannels()
width = win.getsampwidth()
rate = win.getframerate()

print "channels:", channels, "width:", width, "rate:", rate

You can run this program using the special "<" character that "sends a file" to stdin.

python wavstats.py < pink.wav

Alternately you can use the cat command to "dump" the audio (to standard out) and use a pipe character ("|") to connect this to standard in of the python script. This syntax has the advantage of reading from left to right (following the data flowing from "pink.wav" into the python script).

cat pink.wav | python wavstats.py

Audio "echo"

A simple program that just reads the bytes of one audio file (on standard in) and dumps them to another (on standard out).

import wave, sys

win = wave.open(sys.stdin, "r")
channels = win.getnchannels()
width = win.getsampwidth()
rate = win.getframerate()

wout = wave.open(sys.stdout, "w")
wout.setparams((channels, width, rate, 0, 'NONE', 'not compressed'))

while True:
    s = win.readframes(width)
    if s == '':
        break
    wout.writeframesraw(s)

To run this script you need to provide both standard input and output. Note the use of ">" which takes the standard output of the python script and "saves as" a filename.

cat pink.wav | python wavecho.py > pinkcopy.wav

This script doesn't actually do anything (it just passes data through) but provides a template for using python to play with the flow of data to do different (potentially) interesting things.

Actually: this script would not work if the input was not mono (single channel) -- Needs fixing!

Time

How to output 1 second of audio?

# TO DO

How to output 1 second of audio and 1 second of silence?

from __future__ import print_function 
import wave, sys

win = wave.open(sys.stdin, "r")
channels = win.getnchannels()
width = win.getsampwidth()
rate = win.getframerate()

wout = wave.open(sys.stdout, "w")
wout.setparams((channels, width, rate, 0, 'NONE', 'not compressed'))


t=1

for x in range (5):
    
    c=0

    while True: #after a ':' always an indent
        print (c, file=sys.stderr)
        c=c+1 #counting the number of samples
        s = win.readframes(1)
        if s == '':
            break
        #to output 1 second of audio    
        if c == t*rate: 
            break     
        wout.writeframesraw(s)

    print ("end", file=sys.stderr)

    c=0

    while True: #after a ':' always an indent
        print (c, file=sys.stderr)
        c=c+1 #counting the number of samples
        #to output 1 second of silence    
        if c == t*rate: 
            break     
        wout.writeframesraw("  ")

How to output 1 second of audio and 1 second silence in alteration.

# TO DO

Make a wave clapper

Implement a "wave clapper" that performs (one hand) of Steve Reich's clapping music.

To start, you could represent the "12 steps" of the pattern using a python string, and use a for loop to check each part of the pattern.

pat = "xxx xx x xx "

for c in pat:
    if c == 'x':
        print "clap"
    else:
        print " "

Now recombine with wave code to filter an incoming audio file to perform the pattern.

# it imports a function from python 3
from __future__ import print_function
import wave, sys
from random import randint

###### YOU OPEN IT LIKE: cat filetomodify.wav | python code-pink-write.py > newfilename.wav



win = wave.open(sys.stdin, "r")
channels = win.getnchannels()
width = win.getsampwidth()
rate = win.getframerate() # rate is the NUMBER OF SAMPLES FOR SECOND

wout = wave.open(sys.stdout, "w")
wout.setparams((channels, width, rate, 0, 'NONE', 'not compressed'))


t=0.05
n=int(t*rate)


for j in range(12):
    for i in "xxx xx x xx ":

        if i == "x":
            for c in range(n):
                print (c, file=sys.stderr)   
                s = win.readframes(1)
                wout.writeframesraw(s)

            for c in range(n):
                print (c, file=sys.stderr) 
                wout.writeframesraw("  ")



        if i == " ":

            for c in range(n*2):
                print (c, file=sys.stderr) 
                wout.writeframesraw("  ")

Editorial meeting

Franc

Landscape. How to make more environmental sound. Binaural sound... Make a box, recreation of specific Boxes that create a sound. Inspired by Pipilotti Rist / Video artist.

DEMO BOX

Translate to a story.

Giulia

Max

Margreet

Mapping physical object * What kinds of sensor

Claudia

Some end questions