Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0

Showing posts with label library. Show all posts
Showing posts with label library. Show all posts

Monday, 26 January 2015

Cranky keyboard (unless you are a northern European) sound library example

# This example shows how to make a simple sampler and sequencer with the Sound
# library. In this sketch 5 different short samples are loaded and played back
# at different pitches, in this when 5 different octaves. The sequencer
# triggers and event every 200-1000 mSecs randomly. Each time a sound is
# played a colored rect with a random color is displayed.
load_library :sound

include_package 'processing.sound'

# Define the number of samples
NUM_SOUNDS = 5
attr_reader :device, :file, :value

def setup
  size(640, 360)
  background(255)
  # Create a Sound renderer and an array of empty soundfiles
  @device = AudioDevice.new(self, 48_000, 32)
  @file = []
  @value = Array.new(3, 0)
  # Load 5 soundfiles from a folder in a for loop. By naming the files 1., 2.,
  # 3., n.aif it is easy to iterate through the folder and load all files in
  # one line of code.
  NUM_SOUNDS.times do |i|
    file << SoundFile.new(self, format('%d.aif', (i + 1)))
  end
end

def draw
  background(*value) # splat array values
end

def key_pressed
  defined = true
  case key
  when 'a'
    file[0].play(0.5, 1.0)
  when 's'
    file[1].play(0.5, 1.0)
  when 'd'
    file[2].play(0.5, 1.0)
  when 'f'
    file[3].play(0.5, 1.0)
  when 'g'
    file[4].play(0.5, 1.0)
  when 'h'
    file[0].play(1.0, 1.0)
  when 'j'
    file[1].play(1.0, 1.0)
  when 'k'
    file[2].play(1.0, 1.0)
  when 'l'
    file[3].play(1.0, 1.0)
  when 'ö'
    file[4].play(1.0, 1.0)
  when 'ä'
    file[0].play(2.0, 1.0)
  when 'q'
    file[1].play(2.0, 1.0)
  when 'w'
    file[2].play(2.0, 1.0)
  when 'e'
    file[3].play(2.0, 1.0)
  when 'r'
    file[4].play(2.0, 1.0)
  when 't'
    file[0].play(3.0, 1.0)
  when 'z'
    file[1].play(3.0, 1.0)
  when 'u'
    file[2].play(3.0, 1.0)
  when 'i'
    file[3].play(3.0, 1.0)
  when 'o'
    file[4].play(3.0, 1.0)
  when 'p'
    file[0].play(4.0, 1.0)
  when 'ü'
    file[1].play(4.0, 1.0)
  else
    defined = false # only set background color value, if key is defined
  end
  @value = [rand(0..255), rand(0..255), rand(0..255)] if defined
end

Sunday, 25 January 2015

Another sound library example translated to ruby-processing


The original sketch was a blank-screen here is lame attempt to make it a bit more interesting, note use of ruby-processings map1d convenience method in favour of vanilla processings map convenience method (map is used for a different function in ruby, and python and a host of other languages for that matter). This one of those sketches that needs to use jruby-complete (some permission thing according to headius).
#
# This is a sound file player.
# NB: requires jruby-complete to run
# either --nojruby flag or use config
#

load_library :sound
include_package 'processing.sound'

attr_reader :sound_file

def setup
  size 640, 360
  background 255
  no_stroke
  # Load a soundfile
  @sound_file = SoundFile.new(self, 'vibraphon.aiff')
  report_settings
  # Play the file in a loop
  sound_file.loop
end

def draw
  red = map1d(mouse_x, (0..width), (30..255))
  green = map1d(mouse_y, (height..0), (30..255))
  fill(red, green, 0, 100)
  ellipse(mouse_x, mouse_y, 10, 10)
  manipulate_sound
end

def manipulate_sound
  # Map mouse_x from 0.25 to 4.0 for playback rate. 1 equals original playback
  # speed 2 is an octave up 0.5 is an octave down.
  sound_file.rate(map1d(mouse_x, (0..width), (0.25..4.0)))
  # Map mouse_y from 0.2 to 1.0 for amplitude
  sound_file.amp(map1d(mouse_y, (0..width), (0.2..1.0)))
  # Map mouse_y from -1.0 to 1.0 for left to right
  sound_file.pan(map1d(mouse_y, (0..height), (-1.0..1.0)))
end

def report_settings
  # These methods return useful infos about the file
  p format('SFSampleRate= %d Hz', sound_file.sample_rate)
  p format('SFSamples= %d samples', sound_file.frames)
  p format('SFDuration= %d seconds', sound_file.duration)
end

Testing the new processing sound library in ruby-processing

There is a new processing sound library for processing-3.0 (that also works with processing-2.0), I thought I would give it a run-out in ruby-processing:-
# This example shows how to create a cluster of sine oscillators, change the
# frequency and detune them depending on the position of the mouse in the
# renderer window. The Y position determines the basic frequency of the
# oscillator and X the detuning of the oscillator. The basic frequncy ranges
# between 150 and 1150 Hz

load_library :sound

include_package 'processing.sound'

# The number of oscillators
NUM_SINES = 5

# A for calculating the amplitudes
attr_reader :sine_volume, :sine_waves

def setup
  size 500, 500
  background 255
  no_stroke
  create_oscillators
end

def create_oscillators
  # Create the oscillators and amplitudes
  @sine_waves = []
  @sine_volume = []
  NUM_SINES.times do |i|
    # The overall amplitude shouldn't exceed 1.0
    # The ascending waves will get lower in volume the higher the frequency
    sine_volume << (1.0 / NUM_SINES) / (i + 1)
    # Create the Sine Oscillators and start them
    wav = SinOsc.new(self)
    wav.play
    sine_waves << wav
  end
end

def draw
  fill mouse_x, mouse_y, 0, 100
  ellipse(mouse_x, mouse_y, 10, 10)
  # Use mouse_y to get values from 0.0 to 1.0
  yoffset = (height - mouse_y) / height.to_f
  # Set that value logarithmically to 150 - 1150 Hz
  frequency = 1000**yoffset + 150
  # Use mouse_x from -0.5 to 0.5 to get a multiplier for detuning the
  # oscillators
  detune = mouse_x.to_f / width - 0.5
  # Set the frequencies, detuning and volume
  sine_waves.each_with_index do |wav, i|
    wav.freq(frequency * (i + 1 + i * detune))
    wav.amp(sine_volume[i])
  end
end

Sunday, 2 March 2014

Updating to use Dan Shiffmans new Box2D library

Caught this on twitter

So here is the liquidy.rb example updated:-
# The Nature of Code
# <http:#www.shiffman.net/teaching/nature>
# Spring 2011
# Updated to use the updated library
# translated to ruby-processing 2 March 2014 by Martin Prout
# Box2DProcessing example

load_libraries :box2d_processing, :particle_system


# module PS is a wrapper for java packages, and Boundary and Particle classes
include PS

attr_reader :box2d, :boundaries, :systems

def setup
  size(400,300)
  smooth
  # Initialize box2d physics and create the world
  @box2d = PS::Box2DProcessing.new(self)
  box2d.create_world
  # We are setting a custom gravity
  box2d.set_gravity(0, -20)
  # Create Arrays 
  @systems = []
  @boundaries = []
  # Add a bunch of fixed boundaries
  boundaries << Boundary.new(box2d, 50, 100, 300, 5, -0.3)
  boundaries << Boundary.new(box2d, 250, 175, 300, 5, 0.5)
end
def draw
  background(255)
  # We must always step through time!
  box2d.step
  # Run all the particle systems
  if systems.size > 0
    systems.each do |system|
      system.run
      system.add_particles(box2d, rand(0 .. 2))
    end
  end
  # Display all the boundaries
  boundaries.each do |wall|
    wall.display
  end
end
def mouse_pressed
  # Add a new Particle System whenever the mouse is clicked
  systems << ParticleSystem.new(box2d, 0, mouse_x, mouse_y)
end

Here is the particle_system library, particle_system.rb
module PS
  include_package 'org.jbox2d.collision.shapes'
  include_package 'org.jbox2d.common'
  include_package 'org.jbox2d.dynamics'
  include_package 'shiffman.box2d'

  # Box2D Particle System
  # <http://www.shiffman.net/teaching/nature>
  # Spring 2010
  # translated to ruby-processing Martin Prout

  # A class to describe a group of Particles
  # An Array is used to manage the list of Particles 

  class ParticleSystem

    attr_reader :particles, :x, :y

    def initialize(bd, num, x, y)
      @particles = []          # Initialize the Array
      @x, @y = x, y            # Store the origin point  
      num.times do
        particles << PS::Particle.new(bd, x, y)
      end
    end

    def run
      # Display all the particles
      particles.each do |p|
        p.display
      end
      # Particles that leave the screen, we delete them
      # (note they have to be deleted from both the box2d world and our list

      particles.delete_if { |p| p.done}

    end

    def add_particles(bd, n)
      n.times do
        particles << PS::Particle.new(bd, x, y)
      end
    end

    # A method to test if the particle system still has particles
    def dead
      particles.empty?
    end

  end

  # The Nature of Code
  # <http://www.shiffman.net/teaching/nature>
  # Spring 2012
  # PBox2D example

  # A Particle

  class Particle
    TRAIL_SIZE = 6
    # We need to keep track of a Body

    attr_reader :trail, :body, :box2d

    # Constructor
    def initialize(b2d, x, y)
      @box2d = b2d
      @trail = Array.new(TRAIL_SIZE, [x, y])

      # Add the box to the box2d world
      # Here's a little trick, let's make a tiny tiny radius
      # This way we have collisions, but they don't overwhelm the system
      make_body(PS::Vec2.new(x,y), 0.2)
    end

    # This function removes the particle from the box2d world
    def kill_body
      box2d.destroy_body(body)
    end

    # Is the particle ready for deletion?
    def done
      # Let's find the screen position of the particle
      pos = box2d.get_body_pixel_coord(body)
      # Is it off the bottom of the screen?
      if (pos.y > $app.height + 20)
        kill_body
        return true
      end
      return false
    end

    # Drawing the box
    def display
      # We look at each body and get its screen position
      pos = box2d.get_body_pixel_coord(body)

      # Keep track of a history of screen positions in an array
      (TRAIL_SIZE - 1).times do |i|
        trail[i] = trail[i + 1]
      end
      trail[TRAIL_SIZE - 1] = [pos.x, pos.y]

      # Draw particle as a trail
      begin_shape
        noFill
        stroke_weight(2)
        stroke(0,150)
        trail.each do |v|
          vertex(v[0], v[1])
        end
      end_shape
    end

    # This function adds the rectangle to the box2d world
    def make_body(center, r)
      # Define and create the body
      bd = PS::BodyDef.new
      bd.type = PS::BodyType::DYNAMIC

      bd.position.set(box2d.coord_pixels_to_world(center))
      @body = box2d.create_body(bd)

      # Give it some initial random velocity
      body.set_linear_velocity(PS::Vec2.new(rand(-1 .. 1), rand(-1 .. 1)))

      # Make the body's shape a circle
      cs = PS::CircleShape.new
      cs.m_radius = box2d.scalar_pixels_to_world(r)

      fd = PS::FixtureDef.new
      fd.shape = cs

      fd.density = 1
      fd.friction = 0  # Slippery when wet!
      fd.restitution = 0.5

      # We could use this if we want to turn collisions off
      #cd.filter.groupIndex = -10

      # Attach fixture to body
      body.create_fixture(fd)

    end

  end
  # The Nature of Code
  # <http://www.shiffman.net/teaching/nature>
  # Spring 2012
  # PBox2D example

  # A fixed boundary class (now incorporates angle)



  class Boundary

    attr_reader :box2d, :b, :x, :y, :w, :h #, :a

    def initialize(b2d, x, y, w, h, a)
      @box2d = b2d
      @x = x
      @y = y
      @w = w
      @h = h

      # Define the polygon
      sd = PS::PolygonShape.new

      # Figure out the box2d coordinates
      box2dW = box2d.scalar_pixels_to_world(w/2)
      box2dH = box2d.scalar_pixels_to_world(h/2)
      # We're just a box
      sd.set_as_box(box2dW, box2dH)


      # Create the body
      bd = PS::BodyDef.new
      bd.type = PS::BodyType::STATIC
      bd.angle = a
      bd.position.set(box2d.coord_pixels_to_world(x,y))
      @b = box2d.create_body(bd)

      # Attached the shape to the body using a Fixture
      b.create_fixture(sd,1)
    end

    # Draw the boundary, it doesn't move so we don't have to ask the Body for location
    def display
      fill(0)
      stroke(0)
      stroke_weight(1)
      rect_mode(CENTER)
      a = b.get_angle
      push_matrix
      translate(x,y)
      rotate(-a)
      rect(0,0,w,h)
      pop_matrix
    end
  end
end
It occurs to me, that with a bit more work and I could create a ruby-processing library to simplify the use of JBox2D? Thus replacing need for both fisica and box2d_processing libraries. Except that Ricard Marxer and Daniel Shiffman have both created some very nice examples. See other examples here.

Sunday, 17 June 2012

A Gui for my pixelation library

Over on my other blog I recently described an application for pixelating pictures in processing, but also using the cfdg program (CF3), here is the program adapted for ruby-processing, with an added gui using "control_panel"




load_libraries 'pde2cfdg', 'control_panel'
import "pde2cfdg"

#
# Two cfdg files are written to the sketch folder one for design one for data,
# this means it easier to edit the design (eg to replace CIRCLE with a custom shape)
# The output png file is written to the sketch folder,
#

attr_reader :cfdg, :dot_size

def setup
    size(640, 512)
    background(255)
    setup_panel
    colorMode(HSB, 1.0)
    @cfdg = ProcessingToCF.new(self)
    cfdg.set_dot_size(dot_size)
    cfdg.setPathToCFDG("/home/tux/CF3/cfdg")
    cfdg.get_input
    cfdg.writeCFDG
end

def setup_panel
    control_panel do |c|
      c.title = "Control:"
      c.slider(:dot_size, 1..6, 3)
      c.button(:re_run)
    end
end

def re_run
  cfdg.set_dot_size(dot_size)
  cfdg.writeCFDG
end

def draw
  if (cfdg.finished)
    img = load_image(cfdg.outFile)
    image(img, 0, 0, img.width, img.height)
  end
end
Here's a screenshot of application in action, the artist is Phil Sutton RA

Followers

About Me

My photo
I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2