Livecoding with one hand
I’m typing this post with the Twiddler (well, I started at least). I’ve been practising now for some months and developing the interface for ‘Etudes pour le livecoding a une main’, basically since the notification came in that the performance got accepted for the ICLC.
Backups
An important thing I got reminded of, it how important it is to have backups of your device. On January 2nd my Twiddler broke down… One of the keys was not working anymore. So I had to order a new one, which with some delay from UPS came in still in time. On the forum I had read I can get them with the back not glued on, so that in the future I can repair the Twiddler myself. The broken one I can send in to be repaired. So I’m happy about the customer service. And once the broken one comes back repaired I will have two Twiddlers available.
In the meantime, I also started on a DIY version, using a MiniBee. It’s mostly working, but the timing for detecting the chords still needs some tuning. Developing the algorithm for that has been quite interesting though: when do you detect that something is a chord? When do you send out the ‘chord-down’ press, when the ‘repeat’, and when the ‘up’. And how do you transition from one to the other? Some advantages of building it yourself are that you can really shape the device according to your own hand. That is quite promising for the future. On the other hand, the buttons will need some sort of caps to feel nice to type on. So - a promising development, but still some work to do.
The coding interface subsequently had to be adapted to accept either the keyboard input, or the MiniBee input, which was a good reason to disentangle the GUI from the model of the tutor a bit more.
Creating an editor
While developing the interface for the performance, I realised that to speed up the actual performance, I would need to be able to edit previously typed code. So I made options to browse the evaluated code, copy blocks to the ‘typed code’ view, and then cut lines from that, paste them elsewhere, insert lines, and select a line to edit. At some moment it felt like re-writing vi
.
The other challenge there was to navigate through the edited line. Moving the cursor single steps is easy, making it jump in sensible ways was a bit more tricky, but more or less works now. One improvement I wish for is still to not jump to .
within a number, but only to .
that separate a variable (or Class) and method. That is for later.
The current version is like this: the extension to the String
-class:
+ String {
findOneOf{ arg strings, ignoreCase=false, offset = 0;
var res;
res = strings.collect{ |c| this.find( c, ignoreCase, offset ); }.select{ |it| it.notNil };
if ( res.notNil ){
res = res.minItem;
};
^res;
}
findOneOfBackwards{ arg strings, ignoreCase=false, offset = 0x7FFFFFFE;
var res;
res = strings.collect{ |c| this.findBackwards( c, ignoreCase, offset ); }.select{ |it| it.notNil };
if ( res.notNil ){
res = res.maxItem;
};
^res;
}
}
And using it like this in the Tutor:
jumpForwardCursorPosition{
// var curChar = currentLineTyped.at( cursorPosition );
var stringsToFind = [".", "," , "(", " ", ")" ];
//.select{ |it| it != curChar };
var newpos = currentLineTyped.findOneOf( stringsToFind, false, cursorPosition+1 );
if ( newpos.notNil ){
this.setCursorPosition( newpos );
^true;
}{
// nil, but do jump a bit
this.setCursorPosition( cursorPosition + 5 );
^true;
};
^false;
}
jumpBackwardCursorPosition{
// var curChar = currentLineTyped.at( cursorPosition );
var stringsToFind = [".", "," , "(", " ", ")" ];
// .select{ |it| it != curChar };
var newpos = currentLineTyped.findOneOfBackwards( stringsToFind, false, cursorPosition-1 );
if ( newpos.notNil ){
this.setCursorPosition( newpos );
^true;
}{
// nil, but do jump a bit
this.setCursorPosition( cursorPosition - 5 );
^true;
};
^false;
}
And then: a blinking cursor! The SuperCollider GUI interface does not let you control the cursor position in a TextField or TextView. But TextView allowed me to control the color and font of selections of the text. So I now have a really nice red blinking cursor.
cursorBlinkOn = cursorBlinkOn + 1;
if ( cursorBlinkOn > 6 ){
if ( tutor.cursorPosition == tutor.currentLineTyped.size ){
typing.setString( "_", tutor.currentLineTyped.size, 1 );
}{
if ( tutor.currentLineTyped.at( tutor.cursorPosition ).isSpace ){
typing.setString( "_", tutor.cursorPosition, 1 );
};
};
typing.setStringColor( Color.red, tutor.cursorPosition, 1 );
};
if ( cursorBlinkOn > 12 ){
cursorBlinkOn = 0;
typing.setStringColor( Color.black, tutor.cursorPosition, 1 );
};
typing.setFont( blinkFont, tutor.cursorPosition, 1 );
Rehearsals
Rehearsing the piece, I realise that I am still half as fast as Redfrik’s original performance. Going through the piece, I am wondering also in how far can I change the original? I already had to adapt some things to ensure that the piece would run under current SuperCollider versions, and to ensure that the length of the lines fitted in the Tutor.
But Redfrik also made a mistake during the performance, as he writes on his website: “it’s a bit embarrassing if you study it more carefully. the use of ~pub near the end is a big mistake for instance. i meant ~out and i don’t know what i was thinking there…” The mistake had a big influence on the following lines of code he executed, as he was trying to figure out what went wrong. Should I correct the mistake when I reperform the piece?
Dramatical effects
To add to the dramaturgy of the performance and create a kind of ‘classical instrumentalist impression’, I got myself a music stand to put my laptop on, and I’ll put my sound card and DMX controller at the foot of that stand. I’ll sit on a chair a short distance behind the music stand. And I’ll dress up nicely with a jacket.
Also I’ve added DMX RGB lights so that my actions on the typing will be reflected in the color:
- green for a correctly typed character
- red fro a wrongly typed character
- blue for navigation characters
- lila for a mode change of the editor
- yellow for correctly evaluated code
- orange for wrong evaluated code