ruby osc seqencer version2

Nikolaus Gradwohl2009-04-13T14:57:00+02:00

i updated my osc sequencer in ruby. now it doesn't just send osc events but also react to it. i made a small processing sketch that sends osc play,pause,stop events for each track in the sequencer. i also refactored the ruby code a bit, to use classes. next steps i plan are to separate the sequencer code from the sequences and allow sequences to be added or deleted at runtime via osc messages.

the code isn't very reusable now, so i still considere this more as a prove of concept, but i like the idea of separating the frontend and the backend via osc events and having sequences that can run independently.

that should enable some nice osc controlled audio/video installations.

write me a comment or mail if you have some ideas for improvement or if you use the code in one of your projects

the ruby code

require 'osc'
Host = 'localhost'
Port = 3334

class BaseSequence 
    attr_accessor :seq, :pos, :msg, :name, :res

    def initialize( osc, name, res,  host = 'localhost', port = 3334 )
        @pos = 0;
        @res = res
        @name = name;
        @running = false;
        @osc = osc
        @host = host
        @port = port
    end

    def play()
        @running = true;
    end

    def stop()
        @running = false;
        @pos = 0;
    end

    def pause()
        @running = false;
    end

    def update()
    end
end

class Sequence < BaseSequence
    def update()
        if @running then
            @msg.args = [@seq[ @pos % @seq.length]] 
            @osc.send( @msg, 0, @host, @port ) if @seq[ @pos % @seq.length ] != 0
            @pos+=1
        end
    end
end

class DrumSequence < BaseSequence
    def update()
        if @running then
            (0..@msg.length-1).each { |i|
                @osc.send(@msg[i], 0, @host, @port) if @seq[i][@pos % @seq[i].length] == 1
            }
            @pos+=1
        end
    end
end

c = OSC::UDPSocket.new

bpm = 120 
step = 1.0/96;
s = bpm * step / 60.0 ;


drum = DrumSequence.new(c, "drum", 1.0/8 )

hh = OSC::Message.new('/drum', 's', "hh" )
bd = OSC::Message.new('/drum', 's', "bd" )
sn = OSC::Message.new('/drum', 's', "sn" )

drum.msg = [ bd, sn, hh ]
drum.seq = [
[1, 0, 0, 1, 0, 1, 0, 0 ],
[0, 0, 1, 0, 0, 0, 1, 1 ],
[1, 1, 1, 1, 1, 1, 1, 1 ]
]

bass = Sequence.new(c, "bass", 1.0/8) 
bass.seq = [ 45, 45, 0, 45, 45, 0, 48, 0, 
             45, 45, 0, 45, 45, 0, 43, 0 ]
bass.msg = OSC::Message.new('/bass','i', 64 )
mel = Sequence.new(c, "mel", 1.0/16,  'localhost', 57120)
mel.seq = [ 57, 57, 0, 60, 57, 0, 50 ]
mel.msg = OSC::Message.new('/melody', 'i', 64 )

count = 0;
count2 = 0


sequences = {
bass.name => bass, 
mel.name => mel, 
drum.name => drum
}

bass.play()
mel.play()
drum.play()


srv = OSC::UDPServer.new
srv.bind Host, 3333
srv.add_method '/seq/*', 's' do |msg|
  domain, port, host, ip = msg.source
  puts "#{msg.address} -> #{msg.args.inspect} from #{host}:#{port}"
  puts msg.address,  msg.args[0]
  if msg.args[0] == "play" then
    sequences[msg.address.split("/")[-1]].play
  elsif msg.args[0] == "stop" then
    sequences[msg.address.split("/")[-1]].stop
  elsif msg.args[0] == "pause" then
    sequences[msg.address.split("/")[-1]].pause
  end
end
Thread.new do
  srv.serve
end

count =0;
while(true) 
    sequences.each{ |k,v|
        v.update if (count % 96 * v.res == 0)
    }
    count+=1
    sleep s
end

and the processing code

import oscP5.*;
import netP5.*;

OscP5 oscP5;
String oscP5event; 
NetAddress myRemoteLocation;

void setup() {
  size(300,300);
  oscP5 = new OscP5(this,12000);
  myRemoteLocation = new NetAddress("127.0.0.1",3333);
}

void draw() {
  line( 0, 100, 300, 100 );
  line( 0, 200, 300, 200 );
  line( 100, 0, 100, 300 );
  line( 200, 0, 200, 300 );
}

void mousePressed() {
  String track = "";
  String cmd = "";
  if (mouseY < 100) {
     track = "drum"; 
  } else if ( mouseY < 200 ) {
    track = "bass";
  } else {
    track = "mel";
  }

  if (mouseX < 100) {
    cmd = "play"; 
  } else if ( mouseX < 200 ) {
    cmd = "pause";
  } else {
    cmd = "stop";
  }

  println( track + " " + cmd );
  OscMessage msg = oscP5.newMsg( "/seq/" + track );
  msg.add( cmd );
  oscP5.send(msg, myRemoteLocation);
}
Tweet This! submit to reddit Digg!   Tags: | no comments | no trackbacks

See also:

Mapping linux input events to OSC
osc sequencer in ruby
ruby rhyme generator
Android Monome-Clone in Processing
Curling Animation II

Trackbacks

Comments

Leave a response

Leave a comment