Memory Slot

From Accident Designs Wiki

Jump to: navigation, search

Scripts developed for Annette Finnsdottirs exhibition Memory Slot, a part of Virtual Moves by Tagging Art.

Contents

Concept

Scripts

A combination of scripts in LSL, PHP, Processing and Arduino keeps this project running. main.lsl located in a prim in Second Life transmits information to switch.php on a webserver. switch.php writes this information to a .txt file that is then retrieved by processing. Through arduino the information controls two light bulbs.

main.lsl

 
//By Sophie Zhu - accidentdesigns.com
 
integer masterchannel = -1; //insert a relatively low negative integer to reduce lag
 
string token = "token";
integer i;
integer l1;
integer ready = TRUE;
 
key req_id;
req(integer switch)
{
     req_id = llHTTPRequest("http://example.com/path/to/switch.php", [HTTP_METHOD, "POST"], "y=" + "memslot" + "&x=" + (string)switch);
}
 
vector randVector(float min, float max)
{
    list floats = [];
    for(i=0;i<3;i++)
    {
        float f = llFrand(max - min) + min;
        if ( llFrand(1.) < .5) {
            f = f*-1;
        }
        floats = floats + [f];
    }
    return <llList2Float(floats, 0),llList2Float(floats, 1),llList2Float(floats, 2)>;
}
 
string path = "http://www.example.com/path/to/video";
string suffix = ".mov";
 
key client = "";
memory(key id) 
{
    ready = FALSE;
    client = id;
 
    llSetTimerEvent(0.);
    integer num = (integer)llFrand(9.0) + 1;
    string a = path + (string)num + suffix;
    llShout(masterchannel, "on");
    llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_URL,a,PARCEL_MEDIA_COMMAND_LOOP]); llSetTimerEvent(50.);
    llWhisper(0,  llKey2Name(id) + " have unlocked a memory: " +  a); 
 
    req(1);
    integer tempchannel = (integer)((llFrand(2000) * 2) * -1);
    l1 = llListen(tempchannel, "token", "", "");
    llRezObject(token, llGetPos() + randVector(1.5, 2), ZERO_VECTOR, ZERO_ROTATION, tempchannel);
}
 
default
{
    state_entry()
    {
    }
 
    listen(integer channel, string name, key id, string message)
    {
        if(message == "ready")
        {
            llSay(channel, client);
        }
        llListenRemove(l1);
        ready = TRUE;
    }
 
    touch_start(integer num_detected)
    {
        if(ready == TRUE){ memory(llDetectedKey(0));}
    }
 
    timer()
    {
        req(0);
        llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_UNLOAD]);
        llShout(masterchannel, "off");
        llSetTimerEvent(0.);
    }
 
    http_response(key request_id, integer status, list metadata, string body)
    {
        //llOwnerSay(body); //Debug 
    }
 
 
}
 

token.lsl

 
//By Sophie Zhu
//http://accidentdesigns.com
 
integer l1;
key id;
string name;
 
vector randColor() { 
 
    if ( llFrand(1.) < .5) {
        return <0.0,0.0,0.0>;
    }
    return <1.0,1.0,1.0>;
}
 
init() {
    llSetStatus(STATUS_DIE_AT_EDGE, TRUE);
 
    if ( llFrand(1.) < .5) {
 
        }
 
    llSetPrimitiveParams( [ PRIM_POINT_LIGHT, TRUE, randColor(), 1.0, 4.0, 0.5 ] ) ;
    llSetColor(randColor(), ALL_SIDES);
    llParticleSystem( [0, 355, 1, randColor(), 2, 1.00, 3, randColor(), 4, 0.00, 5, <0.35,0.35,0.00>, 6, <0.03,0.40,0.00>, 7, 1.50, 8, <0.00,0.00,0.00>, 9, 2, 10, 0.50, 11, 0.00, 13, 0.10, 15, 2, 16, 0.00, 17, 0.20, 18, 0.40, 19, 0.00, 20, llGetKey(), 21, <0.00,0.00,0.00>]);
 
 
    llSetStatus(STATUS_PHYSICS, TRUE);
    float mass = llGetMass(); // mass of this object
    float gravity = 9.8; // gravity constant
    llSetForce(mass * <0,0,gravity>, FALSE); // in global orientation
}    
 
 
vector randVector(float min, float max)
{
    list floats = [];
    integer i;
    for(i=0;i<3;i++)
    {
        float f = llFrand(max - min) + min;
        if ( llFrand(1.) < .5) {
            f = f*-1;
        }
        floats = floats + [f];
    }
    return <llList2Float(floats, 0),llList2Float(floats, 1),llList2Float(floats, 2)>;
}
 
default
{
    state_entry()
    {
        init();
    }
 
    touch_start(integer total_number)
    {
        llApplyImpulse(llGetMass()*randVector(0.1, 4),FALSE);
    }
 
    on_rez(integer start_param)
    {
        l1 = llListen(start_param, "", "", "");
        llSay(start_param, "ready");
    }
 
    listen(integer channel, string name, key id, string message)
    {
        id = (key)message;
        llListenRemove(l1);
        name = llKey2Name(id);
        llSetObjectName(name + " was here!");
        llSetText(name + " was here!", <1.,1.,1.>, 0.5);
        init();
    }
}
 
 

effectscontroller.lsl

 
//By Sophie Zhu
//http://accidentdesigns.com
 
integer masterchannel = -2; //insert same channel as in main.lsl
 
integer Side = ALL_SIDES;
fade_out()
{
    integer steps = 25;
    float base = 0.85;
    float delay = 1.0 / steps;
    integer i;
 
    // fade out
    for (i = 0; i < steps; i++)
    {
        llSetLinkAlpha(LINK_ALL_CHILDREN,llPow(base,i), Side);
        llSleep(delay);
    }
 
    llSetLinkAlpha(LINK_ALL_CHILDREN,0.0, Side);
}
 
fade_in()
{
    integer steps = 25;
    float base = 0.85;
    float delay = 1.0 / steps;
    integer i;
 
    // fade in
    for (i = 0; i < steps; i++)
    {
        llSetLinkAlpha(LINK_ALL_CHILDREN, 1.0 - llPow(base,i), Side);
        llSleep(delay);
    }
 
    llSetLinkAlpha(LINK_ALL_CHILDREN, 1.0, Side);
}
 
default
{
    state_entry()
    {
        llListen(masterchannel, "Frk. Memory Slot", "", "");
    }
 
    listen(integer channel, string name, key id, string message)
    {
        if(message == "off")
        {
            llSleep(3.0);
            fade_in();
        }
        else if(message == "on")
        {
            fade_out();
        }
    }
}
 
 

pyramidcontroller.lsl

This script is in the root prim of a linkset with all the 'pyramids'.

 
//By Sophie Zhu
//http://accidentdesigns.com
 
string mediatexture = "d864fe60-3743-9529-0238-b2170a55f29c";
string white = "34f2d0b0-6afd-c141-9562-b2d12d24ae4b";
integer masterchannel = -2; //insert same channel as in main.lsl
 
integer Side = ALL_SIDES;
fade_out()
{
    integer steps = 25;
    float base = 0.85;
    float delay = 1.0 / steps;
    integer i;
 
    // fade out
    for (i = 0; i < steps; i++)
    {
        llSetLinkAlpha(LINK_ALL_CHILDREN,llPow(base,i), Side);
        llSleep(delay);
    }
 
    llSetLinkAlpha(LINK_ALL_CHILDREN,0.0, Side);
}
 
fade_in()
{
    integer steps = 25;
    float base = 0.85;
    float delay = 1.0 / steps;
    integer i;
 
    // fade in
    for (i = 0; i < steps; i++)
    {
        llSetLinkAlpha(LINK_ALL_CHILDREN, 1.0 - llPow(base,i), Side);
        llSleep(delay);
    }
 
    llSetLinkAlpha(LINK_ALL_CHILDREN, 1.0, Side);
}
 
 
default
{
    state_entry()
    {
        llSetLinkTexture(LINK_ALL_CHILDREN, white, ALL_SIDES);
        llListen(masterchannel, "Frk. Memory Slot", "", "");
    }
 
    listen(integer channel, string name, key id, string message)
    {
        //llOwnerSay("message received");
        if(message == "off")
        {
            fade_out();
            llSetLinkTexture(LINK_ALL_CHILDREN, white, ALL_SIDES);
            fade_in();
        }
        else if(message == "on")
        {
            fade_out();
            llSetLinkTexture(LINK_ALL_CHILDREN, mediatexture, ALL_SIDES);
            fade_in();
        }
    }
}
 
 

switch.php

 
<?php
//By Johan Bichel Lindegaard 
//http://accidentdesigns.com
//Create an empty html file called 'switch.html' in the same directory as this script
 
//Get POST variables and put into superglobal array
$p_data = implode('', file('php://input'));
$p_data = explode('&', $p_data);
 
foreach ($p_data as $p_val) {
    $d_parts = explode('=', $p_val);
    $_POST[$d_parts[0]] = urldecode($d_parts[1]);
}
$switch = $_POST['x'];
$id = $_POST['y'];
if ($id == 'memslot') 
{
	$myFile = "switch.html";
	$fh = fopen($myFile, 'w') or die("can't open file");
	fwrite($fh, '<html><head></head><body>state:'.$switch.'</body></html>');
	fclose($fh);
	echo 'state: '.$switch.' succesfully written to file';
} else {
	echo 'error wrong id';
}
 
?>
 

processing code

 
/*
 =================================================
 == memory SLot ==================================
 == SL to arduino program by jacob sikker remin ==
 =========================== 26/02-2008: ver1.2 ==
 =================================================
 */
 
 import processing.serial.*; //serial communication
 import krister.Ess.*; //ESS sound package
 AudioChannel[] mySound = new AudioChannel[1]; // One channel of audio playback
 
 Serial port; // The serial port
 PFont font; // Text display variables
 String serialString = ""; // Serial variables
 boolean output13 = false; //Output PIN variables
 boolean change = false; //bool to check for change
 //String URL = "http://sl.accidentdesigns.com/taggingart/memslot/switch.html";
 // URL to read from
 //String URL = "http://campingsex.org/tagging_art/switch.html"; // URL
 to read from
 String URL = "http://8bitklubben.dk/taggingart/switch.html"; // URL
to read from
 //String[] data; //to store data from URL
 char dummychar = '0';
 boolean flipflop = false;
 
 void setup() {
 // GRAPHICS SETUP
 size(300, 200);
 font = loadFont("Ziggurat-HTF-Black-32.vlw");
 textFont(font);
 background(51);
 text("status:"+output13, 15, 30);
 
 // SERIAL / ARDUINO SETUP
 // Print a list of the serial ports, for debugging purposes:
 println("Serial ports");
 println(Serial.list());
 
 // the arduino is normally the third ([2]) port
 print("Selected port: ");
 println(Serial.list()[2]);
 port = new Serial(this, Serial.list()[2], 9600);
 
 Ess.start(this); // Start Ess
 // Sounds must be located in the sketch's "data" folder
 mySound[0] = new AudioChannel("Netfilm.mp3");
 
 print("Started listening: "+hour()+":"+minute()+":"+second()+" ");
 }
 
 void draw() {
 
 getstate(); // read from URL
 setOutput13(); // set pin according to URL state
 flipit(); // update progress cursor
 
 delay(500); //wait 0.5 sec
 }
 
 void getstate() {
 try {
 if (loadStrings(URL) != null){
   String[] data = loadStrings(URL);  //read data from URL
   dummychar = data[0].charAt(31);
 }
 if (dummychar == '1'){
   output13 = true;
   playsound ();
 } else {
   output13 = false;
   mySound[0].stop();
 }
 
 if (change != output13) {
   background(51); // clear screen w/ dark grey
   stroke(255);
   fill(255);
   text("status:"+output13, 15, 30);
   change = output13;
 }
 
 } catch(Exception e) {
   print("caught one exception: "+hour()+":"+minute()+":"+second()+" ");
   print(e);
   delay(1000); // if error wait 1sec and try again
   return;
 }
 }
 
 void playsound () {
   if (mySound[0].state == Ess.STOPPED) {
     mySound[0].play();
   }
 }
 
 void flipit () {
 if (flipflop == true){
   stroke(0,255,0);
   fill(0,255,0);
   rect(15,35,50,50);
 } else {
   stroke(51);
   fill(51);
   rect(15,35,50,50);
 }
 flipflop = !flipflop;
 }
 
 void setOutput13() {
 try {
 port.write("w d 13 "); // NOTE THE SPACE TRAILING THE 13
 if(output13==true) {
  port.write('1');  //NOTE THAT WE ARE SENDING A STRING AND NOT AN INTEGER
 } else {
  port.write('0');  //NOTE THAT WE ARE SENDING A STRING AND NOT AN INTEGER
 }
 port.write(13);
 } catch (Exception e) {
 print ("write exception!"+e);
 }
 }
 

arduino code

 
/*
 SL to arduino via processing
 by jacob sikker remin
 based heavily on simple message system
 
 ---- SimpleMessageSystem Example 1 ----
 Control Arduino board functions with the following messages:
 
 r a -> read analog pins
 r d -> read digital pins
 w d [pin] [value] -> write digital pin
 w a [pin] [value] -> write analog pin
 
 Base: Thomas Ouellet Fredericks
 Additions: Alexandre Quessy
 
 */
 
// Include de SimpleMessageSystem library
#include <SimpleMessageSystem.h>
 
void setup()
{
 
 Serial.begin(9600); //Baud set at 9600
 
 pinMode(12, OUTPUT);
 pinMode(13, OUTPUT);
 
 digitalWrite(13, HIGH);
 digitalWrite(12, HIGH);
}
 
void loop()
{
 
 if (messageBuild() > 0) { // Checks to see if the message is complete
and erases any previous messages
   switch (messageGetChar()) { // Gets the first word as a character
   case 'r': // Read pins (analog or digital)
     readpins(); // Call the readpins function
     break; // Break from the switch
   case 'w': // Write pin
     writepin(); // Call the writepin function
 
   }
 
 }
 
}
 
void readpins(){ // Read pins (analog or digital)
 
 switch (messageGetChar()) { // Gets the next word as a character
 
   case 'd': // READ digital pins
 
   messageSendChar('d');  // Echo what is being read
   for (char i=2;i<14;i++) {
     messageSendInt(digitalRead(i)); // Read pins 2 to 13
   }
   messageEnd(); // Terminate the message being sent
   break; // Break from the switch
 
 case 'a': // READ analog pins
 
   messageSendChar('a');  // Echo what is being read
   for (char i=0;i<6;i++) {
     messageSendInt(analogRead(i)); // Read pins 0 to 5
   }
   messageEnd(); // Terminate the message being sent
 
 }
 
}
 
void writepin() { // Write pin
 
 int pin;
 int state;
 
 switch (messageGetChar()) { // Gets the next word as a character
 
   case 'a' : // WRITE an analog pin
 
   pin = messageGetInt(); // Gets the next word as an integer
   state = messageGetInt(); // Gets the next word as an integer
   pinMode(pin, OUTPUT); //Sets the state of the pin to an output
   analogWrite(pin, state); //Sets the PWM of the pin
   break;  // Break from the switch
 
 
   // WRITE a digital pin
 case 'd' :
 
   pin = messageGetInt();  // Gets the next word as an integer
   state = messageGetInt();  // Gets the next word as an integer
   pinMode(pin, OUTPUT);  //Sets the state of the pin to an output
   digitalWrite(pin, state);  //Sets the state of the pin HIGH (1) or
LOW (0)
 
   // other lamp (pin 12) is opposite pin 13
   if (state == 1) {
     digitalWrite (12, 0);
   } else {
     digitalWrite (12, 1);
   }
 }
}
 
 
Personal tools