Live hauntings #three

Sounds from the Second Salon showing of hauntology.

Posted by joe

08 October, 2009

haunted-story, audio, recording, installation.

Exhibit number 3: Second Salon

Wednesday was the launch night of Second Salon in which the hauntology project is currently being exhibited. This is the third time it has been displayed, following the two Screengrab09 shows in Brick Lane and Bournemouth. Each exhibition teaches me something new about this project, and the launch night taught me more about audience participation.


Hauntology


 

In the previous shows I created a small poster which explained that the exhibit invites you to interact with it: variously worded instructions along the lines of 'pick up the picture, explore the drawers, find the casket, leave a haunting'. Something about this troubled me though - not least the fact that by labelling the interactions, I was in some sense removing the possibility of surprise: if you are invited to pick up the picture, then you ought to expect something to happen when you do so. I wondered if this might anaesthetise some aspects of what should be a spooky ghost story. So I thought I'd use the 3 hours of the show just to test out some ideas about how to deal with the balance between instruction and exploration.

I initially set up the plinth and chest with no instructions at all, to see what people did with it. The plinth concealed the computer controlling the exhibit; the chest stood next to the plinth; some leads trailed from the underside of the chest and disappeared into the plinth; finally, a set of headphones rested on the plinth.


Hauntology and plinth


 

There is clearly a grammar about exhibitions: plinths as a rule are not a part of the artwork itself (though Banksy's Bristol show and even the various uses of the fourth plinth in Trafalgar Square play with that idea). And of course, headphones are not generally understood to be for looking at alone. So people had no hesitation to stand by the plinth, and try on the headset.

Another part of the lexicon of the gallery, however, is a kind of permission culture: you must be given permission to touch things, because the norm is to not touch (or in some galleries, speak, laugh, smile, look at each other, or enjoy anything at all). Some exhibits clearly embody an invitation - Olu Taiwo's camera installation in Avatars of Being (also in the Second Salon show) clearly invite the audience to enter the space of the work and see themselves move and twist in the infinite corridor of mirror space produced by the filming of the projection of the filming. But such embodied interaction does not require that the participant touch anything. I quickly found that unless they knew to do so because they had seen the work before, no-one was willing to pick up the picture, open the drawers, find the casket, leave their voice. Without permission to pick up the picture, people merely perplexedly listened to the ambient sounds of hauntology, but never triggered the narrative elements, since these do not start until the picture frame is physically removed from the top of the chest.


Shaun listens


 

I had however prepared a small poster with some notes which, rather than provide instructions, instead gave some ambiguous hints that the exhibit should be interacted with: 'Don the headpiece, touch, move, explore, haunt'. This was an effort to provide permission to touch and interact with the exhibit, while still keeping enough ambiguity that the consequences of specific affordances (such as the start of the narrative in response to picking up the picture frame) might still be surprising. The poster also had a picture of the chest with the top drawer open, showing the casket inside, demonstrating that there were things to find.


The drawer


 

I was a little surprised, though, to find that the words were still being interpreted in an unexpected way - though I know I should not be surprised by unexpected interpretations of ambiguity... The hints seemed to provoke people to open the drawers, and touch the chest and picture frame, and even the fairly obvious infra-red sensor fixed to the side of the chest. All of this is excellent: the permission problem seemed to be solved. However, the words 'touch, move' were interpreted fairly literally. Sometimes, people would understand the instruction 'move' to refer to themselves - they tried walking around the chest and plinth. Sometimes I think the combination of 'touch, move' was understood to mean 'touch and move the picture frame' - so that some people tried to slide the picture frame around the top of the chest - an action which I had not anticipated and so is not detected.

So two things seem to stand out from these observations: the first is not so much a problem as an inspiration provided directly by the audience which I would not have had myself; the second is the problem of ordering the interactions to ensure they are part of the story.


Shaun and casket


 

The first issue is actually a nice idea which arose on the night in conversation with Lena and Lizzie. The user's action of sliding the picture frame around the top of the chest is actually reminiscent of the way a ouija board is used - the glass is pushed around the board until the group finds the place it should sit. Perhaps rather than endlessly search for the correct but ambiguous wording to encourage interaction, I can just tweak the settings so that, as well as the lifting of the picture frame, simply moving it across the chest, ouija fashion, seance-like, will suffice. There are some technical difficulties here, which I'll perhaps go into another time; I also quite like the more fully engaged and embodied action of holding a picture frame in your hands, and turning it between your fingers, rather than simply sliding it across the chest. But it's something to investigate, anyway.



 

The second outstanding issue from observing the interaction - the ordering of interaction and participation - is a problem because although hauntology is designed to change in response to audience interaction, I think there need to be boundaries to the nature of those changes. There is a core narrative, albeit made ambiguous by both an element of randomness in order, and by the inherent openness of possible interpretation: who is Michael? who is speaking? who is the picture of? who is 'she'? etc. The casket records the input from the headset's microphone when it is opened, and those recordings are then randomly overlaid onto the core narrative in subsequent replayings, and so any imaginative response to the work is then incorporated into it. However, it is possible (and common in the circumstances I've described above, in which the core narrative is not triggered by the lifting of the picture frame) for the audience to record themselves without ever hearing the core narrative: hence they never get to enter the diegesis the piece invites them to contribute to.

While such recordings are certainly legitimate 'hauntings' - permanent and retrievable records of the unique times and places in which the chest, picture and casket have found themselves - they are not and cannot be legitimate responses to the ghost story. But there is a conundrum here which I can't really answer adequately: a recording of the kind in which the user leaves their odd questions - 'er, what, I'm being recorded..? arrgh' which are fairly frequent - may be left both by people who have not triggered the narrative, but also by people who have heard the ghost story too. I am making a conceptual distinction between the value of the two (the former are welcome, the latter are problematic) which is independent of the type, style, nature and quality of the recordings themselves. This is, strangely, quite like the Gettier problem.


Shaun recorded


 

Of course I can close the loophole - only record when the narrative has been triggered, prompting those who find the casket to continue looking for a way to make the light turn on - but that doesn't answer the philosophical question about what is a legitimate contribution to the diegesis of a participatory narrative. Of course, as the maker of the work, I am free to impose my vision on the logic of the piece. But as someone interested in the consequences of opening the process of authorship, I also need to find a good way of dealing with this dilemma: my selfish authorial pride in the sanctity of the diegesis, in conflict with the open-armed embrace of anarchic, carnivalesque participation.

Posted by joe

03 October, 2009

interaction, participation, gallery, surprise, diegesis, ambiguity, authorship, observation, exhibition.

Exhibit display #three

Poster display from 3rd hauntology showing at Second Salon, KUBE Gallery, 30 September 2009.

Posted by joe

30 September, 2009

poster-display, pdf, haunted-story, installation.

Ghosts in the machine

With the launch of Second Salon approaching, I dusted off the chest, the chips and the code; unwrapped and unmothballed the hauntology bric-a-brac ready for exhibition. Putting the intricate wires and controllers and sub-routines back into place ... almost impossible, and once achieved - without effect. Nothing would work.

What gremlins had found their way into the innards of the bits and pieces! Had some entropy creeped in, as if it were an instrument gone gradually out of tune? The flex sensor was inverted, its values sky-rocketed beyond the thresholds in the code. The LED, switched, came on when it should go off, and blinked out when I expected it to remain lit. The wires - were they switched? The code, been tampered with?

What has haunted these objects since the last time they creaked into place, wound into the machine assemblage, and flickered into diegetic existence? I am collaborating not only with ghosts but with random acts of agency by inanimate materials.

Posted by joe

28 September, 2009

real-haunting.

Second Salon announced

Kube LogoSecond Salon Invitiation

The Second Salon exhibition at the KUBE Gallery Poole has been announced - this is the show in which I'll be exhibiting hauntology work alongside a number of other artists.

"The second show at the gallery by local informal art collective The Salon, featuring works by 11 artists from across the South of England exploring traditional and new media. Exhibition by: Stephen Bell, Jeannie Driver + Mike Blackman, Joe Flintham, Peter Hardie, Poor Photographer, Mark Shufflebottom, Lizzy Sykes + Cathy Seago, Olu Taiwo & Sarah Thompson. The Second Salon show brings together both finished and works in progress, and open-to-the-public events include physical computing workshops, performances, talks and audience involvement. "

Read more

Posted by joe

09 September, 2009

second-salon, exhibition.

Embedded audio hacking

Today I took receipt of two Adafruit wave shields - kits which let your Arduino read and play audio from an SD card.

These kits will be used in the Second Salon exhibition which starts later this month in which I'm showing the hauntology work. I'm planning to rig them up to sensors which will detect movement in the gallery and play sounds in response.

In particular I'm looking at using several sensors dispersed through the building, which when triggered together will fire a set of sounds through the building's tannoy and into the ears of not only the gallery visitors, but the people getting on with their working lives elsewhere in the building.

More details and code here as the piece is constructed.

Posted by joe

03 September, 2009

architecture, arduino, audio, physical-computing.

Intellectual development #1

Part of a series about trying to make sense of #hauntology

I was trying to think about how to make interactive narrative immersive and engaging. I had recently led a 6-part lecture series on narratives for media students, and so was suffused with diegesis, sjuzet, structure, framing, metonymy; oozing Midas-like drips of narrative thinking on everything I touched.

I also had many discussions with my colleague Jim Pope, whose doctoral work had explored the 'vernacular' response to non-linear narrative and hypertext, and showed that a common response to what academics and critics might acclaim as continuing a modern/postmodern development in literature was actually bemusement and alienation. The 'common reader' found hypertext narrative hard to engage with, uninvolving and dissatisfying. Jim recently wrote about this work at interjunction and I implore you to read his hard-earned thoughts instead of my groundless, buffeted words.

In this context I found myself thinking that one of dominant topics in my teaching area, (what we easily call 'interactive narrative' without worrying too much about what that might really mean), might actually be an oxymoron: that a narrative is something provided by a narrator - a voice of providence, a hidden logic, an overarching guide, to wit, an author; and that interactivity is the effacement of the author, the rejection of a providential God who guides and oversees, and an acknowledgement of the tangible, workable, universally masterable, demotic, participatory, revolutionary, anarchic interception of the narratee.

The listener speaks, the spectator mounts the stage, the viewer is seen, the user creates, the reader writes, the audience become the makers, the recipients participate, the public revolt. These role-changes may have been prefigured as the death of the author in the sense of interpretive freedom, but not in the sense that the author must concede even their original skill: the conception of the story and the control of the plot. The writerly text made manifest is not simply that numinous text which is brought to life in every act of reading: it is much more - it is patricide and regicide, it is author reduced to facilitator, god reduced to resource manager, maker reduced to supplier.

In short, interactive narratives are like palpable obscures and darknesses visible: conceptual possibilities designed to confound us by their actual impossibility. To experience a story is to be a fish caught in the net: to tell a story is to weave the webbing for the catch. They are opposites, and there is no overlap, only repulsion.

Posted by joe

16 June, 2009

haunted-story, meta, narrative, interactivity, oxymoron.

Live hauntings #two

Sounds from second showing at Screengrab09, Bournemouth Media School.

Posted by joe

07 June, 2009

recording, audio, haunted-story, installation.

Exhibit display #two

Poster display from 2nd hauntology showing at Screengrab09, Bournemouth Media School, 5 June 2009.


Posted by joe

06 June, 2009

installation, haunted-story, pdf, poster-display.

Exhibit display #one

The poster display which accompanied the first exhibition of "haunted story" - or as Fran has called it, "what's in the box?"

Posted by joe

01 June, 2009

haunted-story, pdf, poster-display, installation.

First live hauntings

Some sounds from the first haunting

Posted by joe

29 May, 2009

haunted-story, audio, recording, installation.

Haunted story poem

A recording of all the lines of Tim Wright's poem:

[0xx.r... denotes lines which continue the rhyme]
See the whole poem at Flickr; Tim's website; Tim on twitter:

Posted by joe

25 May, 2009

haunted-story, audio, recording, poem.

playRandomSounds.pde

A Processing sketch which loads random sounds at random intervals from a specific location until no further unplayed sounds are available.

Following on from an earlier post in which I record sounds and list all recordings in a text file, this sketch reads the text file, and plays each of the sounds listed, in random order, and at random intervals.

Why would I want to do this? The destination for these sketches is an installation in which the user is invited to speak. This is recorded and added to the library of sounds. The library of sounds forms part of the installation, and so the user contributes to the unfolding experience - enters the diegesis, and takes part in the story.

You could download playRandomSounds.pde here..


// use the minim library
import ddf.minim.*;
Minim minim;
AudioPlayer player;

// the library file
String audioListFile = "data/rec/fileList.txt";

// an array of file names
String[] listOfFiles;

// the next file to play 
String fileToPlay;

// when to play the next file (seconds)
int timeToPlay;

// an incremental counter for time comparisons
int timeMonitor = 0;

// a boolean which will tell us to close the audioplayer
Boolean endSounds = false;

// on first run, call setUpSound()
void setup(){
	size(512,200);
	minim = new Minim(this);
	listOfFiles = loadStrings(audioListFile);
	setupSound();
}
				

setUpSound() will do most of the graft - choosing a file, picking a time to play it, and keeping track of the list of sounds. This example has decided that the next sound will be played randomly sometime inside the next 10 seconds. In a production version, I might actually fire these sounds some time between the next 20 and 45 seconds, since there needs to be room for other elements of the diegesis to be distinct.

// this function will be called every time I need
// to initialise a new sound to play
void setupSound(){
	int soundCount = listOfFiles.length;
	if (soundCount > 0){
	
	// pick a random sound
		int rIndex = int(random(listOfFiles.length));
		fileToPlay = listOfFiles[rIndex];
		
		// remove chosen sound from array
		// laborious replacement of missing 'slice' functionality???
		String[] tempA = subset(listOfFiles, 0, rIndex);
		String[] tempB = subset(listOfFiles, rIndex+1);
		tempA = splice(tempA, tempB, rIndex);
		listOfFiles = tempA;
		
		// pick a random time from now to play the sound
		// sometime inside the next 10 seconds seems good for now
		timeToPlay = int(random(10));
	} else {
		// there are no more unplayed sounds
		endSounds = true;  
	}
}
				

As I write, a bee is vainly struggling against a windowpane a couple of feet from my left ear. Even this sound is not as irritating as the discovery that Processing has a array 'splice' function, but no array 'slice'. I should perhaps use an ArrayList, rater than an Array, but for now, I invent something called a wheel. In the meantime, if you wanted to have the sounds play indefinitely and so were not averse to repetitions, you could just as well remove the lines which 'slice' the next sound file from the list.

// what to do every frame		
void draw(){
	background(0);
	
	// how long has the app been running?
	int now = int(millis()/1000);
	
	// check that we haven't run out of sounds
	if (!endSounds){
	
		// okay, this check calculates:
		// how long we've been running
		// and if we've reached the next scheduled 
		// trigger to play the next sound
		// timeMonitor accumulates the amount of 
		// time that has passed from sound to sound
		if (now > (timeMonitor + timeToPlay)){
			initSound();
			timeMonitor = timeMonitor + timeToPlay;
			setupSound();
		}
	} else {
		player.close();
	}
}
				

draw() adds nothing to the screen but does decide whether it is time to initialise another sound. I imagine that the vagaries introduced by the time taken to execute lines here and there means that over time, the amount of time the app has been running, and my record of the time that has elpased (i.e. the discrepancy between 'now' and 'timeMonitor') will increase. No matter, this is not life and death.

				
void stop(){
	player.close();
	minim.stop();
	super.stop();  
}
				

initSound simply plays the sound file on demand. As it does so, it pushes the next scheduled 'play-time' further away by the length of the currently playing track.

				
void initSound(){
	player = minim.loadFile(fileToPlay, 2048);
	
	// get available meta data for this sound file
	AudioMetaData meta = player.getMetaData();
	
	// we're interested in the length of the sound (ms)
	int curTrackLength = meta.length();
	
	// this line increases 'timeToPlay' 
	// (and therefore 'timeMonitor' in draw() above)
	// by:
	// the track length (to avoid overlapping sounds)
	// (you may want overlapping sounds - I don't)
	// and '1' (i.e. a second, just to make sure)
	timeToPlay = timeToPlay + int((curTrackLength/1000)) + 1;
	player.play();
}
				

The need to access the metadata of the currently playing file at play.getMetaData() is a consequence of the current inability of AudioPlayer.isPlaying() to detect when a sound has finished. I'm not thrilled at the thought of relying on metadata being available for every sound file. I have no idea if AudioMetaData will always know how long the file in question is. Nevertheless, I don't mind glitches entering into the experience, haunting it with extra, brutal randomness.

Posted by joe

25 May, 2009

processing, code, audio-playback, array-slice.

Records.pde

An adaptation of Processing example code.

The original code records the default line-in source and saves it to a local file. Pressing the 'r' key toggles the recorder on and off; pressing 's' saves the file to the specified file. Repeating this process over-writes the specified file which is baked into the script.

I needed a variation on this: to create a new file on each recording, augmenting the library of sounds, rather than replacing it; and to provide a mechanism giving me a list of existing files in the library.

Here's my adaptation of Processing > Examples > Libraries > Minim > RecordLineIn. Download records.pde here.

// the minim library class 
// which gives access to audio functionality
import ddf.minim.*; 
Minim minim;	

// minim connection to line-in							
AudioInput in;				

// minim line-in recorder class
AudioRecorder recorder;		

// destination filename name of 
// the current recording
String audioFileName;		
							
// the text file in which I'll
// keep a list of all the recordings created
// note the relative location "data/rec/..."
String audioListFile = "data/rec/fileList.txt";

// Processing's built-in file I/O functionality
PrintWriter output;			
				

The usual location for external files (e.g. fonts, images, etc) is the 'data' subdirectory. In this case, I'm placing all the recordings generated into a subdirectory of 'data' called 'rec'. That's also where I'll store the file list.

				
// the setup routine is called once upon initialisation
void setup(){
	size(512,200);
	minim = new Minim(this);
	in = minim.getLineIn(Minim.STEREO, 512);
	
	
	// on first run, get the current timestamp, 
	// and pass it to our 'initRecorder' function
	// which will initialise a recorder 
	// and prepare a file for storage
	int getnow = getUnixTS(); // this function is defined below
	initRecorder(getnow); // as is this
}
				

Grabbing a current timestamp is an easy way of ensuring that I use a virgin filename and avoid over-writing older files. It turns out this is quite tricky, as I note below.

				
// draw is called in every frame
// it displays a line-drawing of the audio waveform
void draw(){
	background(0);
	stroke(255);
	for(int i=0; i < in.left.size()-1; i++){
		line(i,50 + in.left.get(i)*50, i+1, 50 + in.left.get(i+1)*50);
		line(i,150 + in.right.get(i)*50, i+1, 150 + in.right.get(i+1)*50);    
	}  
}
				

The draw function is where you might want to do more interesting things than draw the waveform. Likewise, when I put this into production, I won't expect the user to press 'r' and 's' - I'll control the recorder using the narrative logic of the overall piece.

				
// listen for a keypress
void keyReleased(){

	// a simple toggle
	if (key == 'r'){
		if (recorder.isRecording()){
			recorder.endRecord();  
		} else {
			recorder.beginRecord();  
		}
	}
	
  
	// the brains of the file storage system
	if (key == 's'){
		recorder.save();
		
		// load up the file containing the list of recordings
		// - each separated by a line break
		// and put each line (i.e. record) into an array
		String[] fileList = loadStrings(audioListFile);
		
		// add our new recording onto the end of the array
		fileList = append(fileList, audioFileName);
		
		// start a PrintWriter connection to the record file
		output = createWriter(audioListFile);
		
		// write each record in the array into the file
		// this also has the benefit of maintaining 
		// the order in which the recordings were created
		for (int i=0; i < fileList.length; i++){
		  output.println(fileList[i]);  
		}
		
		// business
		output.flush();
		output.close();
		
		// initialise another recording and file 
		// in which the recording will be stored
		int getnow = getUnixTS();
		initRecorder(getnow);
	}
}
				

You may be wondering why I even need a file which keeps track of all the recordings. Surely you could just dynamically read the contents of the directory at run time? Well I could, but that would cost a larger hit when I need to access the files - or I at least I assume that accessing and reading one file is faster than scouring a directory, but it is a weak assumption. So, when I need to read the file list later, I can just re-use that line above: String[] fileList = loadStrings(audioListFile)

// clean up the minim library class upon exit
void stop(){
	in.close();
	minim.stop();
	super.stop();  
}
				

The next function, initRecorder, is called each time a new recording is required. It accepts an integer which we anticipate is the latest generated unix timestamp. It translates the timestamp into a string, which it then uses as the destination filename for the audio recording.

void initRecorder(int t){
	String s = nf(t, 10);
	audioFileName = "data/rec/"+s+".wav";
	recorder = minim.createRecorder(in, audioFileName, true);
}
				

And finally, getUnixTS... so Processing runs on top of Java, and as far as I can see (and I am no expert on Java), the Calendar, Date and Timestamp classes all give you long numbers containing milliseconds since 1 Jan 1970, rather than an int number of seconds - hence the division by 1000 before storing in 'ts'. Processing's 'millis()' function returns the number of milliseconds since the current app was started - 'lapse'.

int getUnixTS(){
	Date date = new Date();
	int ts = int(date.getTime()/1000);
	int lapse = int(millis()/1000);
	int rts = ts + lapse;
	println(rts);
	return rts;
}
				

So... I add 'ts' and 'lapse' to get a new timestamp. Hmmm, that's wrong, surely? We instantiate a new Date object, which should contain a reference to the time now, shouldn't it? And then adding 'lapse' to it ought to give a time slightly in the future? Well... I thought so too. But it turns out that each time I test this, the new Date() object only ever refers to the time it was first created - hence the need to add 'lapse' for each new timestamp. For this reason, you may consider it more elegant to move the 'Date date = new Date();' to the global declarations at the top.

There is another gotcha to worry about as well, which seems to be an artefact of the Processing IDE. I run the sketch, and generate recordings. I stop the sketch, and restart it: millis() (the milliseconds since the app started) is reset to zero, but the Date object still refers to the already instantiated time, so will, if you are not careful, over-write the first recording from the last run. Occasionally I get the Date object to reset and update to a more recent time, but it seems the only definite way to make it reset is to restart the Processing IDE, which drives me a little crazy during debugging.

Posted by joe

25 May, 2009

recording, code, processing, file-i-o.

The sea

Sounds of the sea:

Posted by joe

20 May, 2009

atmosphere, sea, footsteps, audio-recording.

The cello

Sounds of a cello - ominous, sonorous, brooding, giving, threatening, encompassing, attacking:

Posted by joe

20 May, 2009

monotone, attack, cello, atmosphere, audio-recording, audio, recording.

The concrete battlement

Sounds - exterior, within the concrete battlement at Fort Henry, Studland:

Posted by joe

20 May, 2009

atmosphere, concrete, echo, whisper, footsteps, audio-recording.