Skip to content

Instantly share code, notes, and snippets.

@wacaw
Created January 16, 2012 12:58
Show Gist options
  • Save wacaw/1620758 to your computer and use it in GitHub Desktop.
Save wacaw/1620758 to your computer and use it in GitHub Desktop.
simple ruby sound visualization - with ruby processing
require 'ruby-processing'
# Pird
class Pird < Processing::App
load_library "minim"
import "ddf.minim"
import "ddf.minim.analysis"
load_library "control_panel"
attr_accessor :m,:x,:y,:input
#co się dzieje onload
def setup
@viscircles = []
setup_sound
control_panel do |c|
c.slider(:fft_smoothing,0..0.99,0.8 )
c.slider(:number,0..4,0)
# => c.menu(:options, ['03 Winter Winds.mp3', '16 The Legend of Jesse James.mp3', 'majk'], '16 The Legend of Jesse James.mp3') {|m| load_from(m) }
# => c.slider(:volume,1..100,50){|v| voll(m)}
c.checkbox :show_waveform
c.checkbox :show_frequency
c.checkbox :show_clicked
c.checkbox :onplace
c.button :pause_vis
c.button :clear_clicked
end
smooth # smoother == prettier
size(800,600) # let's pick a more interesting size
background 0.50
@loo=true
end
def clear_clicked
@viscircles.each do |vc|
vc = vc.stop()
end
@viscircles=[]
end
def mouse_pressed
return if mouse_x == 0 || mouse_y == 0
return if viscircle_grab
@viscircles << VisCircle.new(mouse_x,mouse_y)
end
def mouse_released
@grabbed = nil
end
def viscircle_grab
return if @onplace
@grabbed = @viscircles.detect {|p| dist(mouse_x, mouse_y, p.x0, p.y0) < 100 }
unless @grabbed.nil?
#if @grabbed.size =1
@grabbed.changestate
#else
# @grabbed.each {|vc| vc.changestate} unless @grabbed.nil?
#end
end
end
def pause_vis
@loo= (@loo==true) ? false : true
#@input.close()
#load_from
#@input.play()
#@loo=true
end
def load_from(m=nil)
@input.close() unless @input.nil?
case m
when "majk"
@input = @minim.get_line_in
@fft = FFT.new(@input.left.size, 44100)
else
@input = @minim.loadFile(m)
@input.play();
@fft = FFT.new(@input.bufferSize(), @input.sampleRate());
end
end
def draw
if @loo
update_sound
animate_sound
draw_waveform if @show_waveform
draw_frequency if @show_frequency
end
#t = Time.now
#if @frame_time
# fps = 1.0 / (t - @frame_time)
# printf "%0.1ffps\n", fps
#end
#@frame_time = t
end
def draw_waveform
if @number < 1
@red1 = @scaled_ffts[2]*255
@green1 = @scaled_ffts[3]*255
@blue1 = @scaled_ffts[4]*255
fill @red1, @green1, @blue1
end
scale = height / 4
(@input.buffer_size - 1).times do |i|
line(i, scale + @input.left.get(i)*scale,
i+1, scale + @input.left.get(i+1) * scale)
end
end
def draw_frequency
if @number < 1
@red1 = @scaled_ffts[2]*255
@green1 = @scaled_ffts[3]*255
@blue1 = @scaled_ffts[4]*255
fill @red1, @green1, @blue1
end
num=20
@fft.forward @input.left
scale = width / num
num.times do |i|
@fft.scale_band i, i * 0.35 + 1
@fft.scale_band i, 0.3
line i*scale, height, i*scale+5, height - @fft.get_band(i)*4
end
end
def setup_sound
@number=1
@onplace=false
@radius = 0
# Creates a Minim object
@minim = Minim.new(self)
#mikrofon
#@input = @minim.get_line_in
#@fft = FFT.new(@input.left.size, 44100)
#plik
#@input = @minim.loadFile("03 Winter Winds.mp3")
#load_from("03 Winter Winds.mp3")
load_from("majk")
#@input = @minim.loadFile("16 The Legend of Jesse James.mp3")
#@input.play();
#@fft = FFT.new(@input.bufferSize(), @input.sampleRate());
#FFT
#@fft = FFT.new(@input.left.size, 44100)
#@fft = FFT.new(@input.bufferSize(), @input.sampleRate());
# Our beat detector object
@beat = BeatDetect.new
# Tablica częstotliwości które chcemy zbadać
# -- skopiowane z VLC
@freqs = [60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000]
# Create arrays to store the current FFT values,
# previous FFT values, highest FFT values we've seen,
# and scaled/normalized FFT values (which are easier to work with)
@current_ffts = Array.new(@freqs.size, 0.001)
@previous_ffts = Array.new(@freqs.size, 0.001)
@max_ffts = Array.new(@freqs.size, 0.001)
@scaled_ffts = Array.new(@freqs.size, 0.001)
# We'll use this value to adjust the "smoothness" factor
# of our sound responsiveness
@fft_smoothing = 0.8
end
def update_sound
@fft.forward(@input.left)
@previous_ffts = @current_ffts
# Itaracja po wszystkich zdefiniowanych czestotliwoscicach by znalesc ich wartosci FFT
@freqs.each_with_index do |freq, i|
# Nowa wartosc FFT dla tej czestotliwosci
new_fft = @fft.get_freq(freq)
# maksymalna czestotliwosc
@max_ffts[i] = new_fft if new_fft > @max_ffts[i]
# Połącznie poprzedniej i aktualnej próbki,
@current_ffts[i] = ((1 - @fft_smoothing) * new_fft) + (@fft_smoothing * @previous_ffts[i])
# Skalowanie wartości FFT by ogarnąć pracę z częstotliwością
@scaled_ffts[i] = (@current_ffts[i]/@max_ffts[i])
end
# Check if there's a beat, will be stored in @beat.is_onset
@beat.detect(@input.left)
end
def animate_sound
if @number > 0
@size = @scaled_ffts[1]*height
@size *= 3 if @beat.is_onset
@x1 = @scaled_ffts[0]*width + width/2
@y1 = @scaled_ffts[2]*height + height/2
@red1 = @scaled_ffts[2]*255
@green1 = @scaled_ffts[3]*255
@blue1 = @scaled_ffts[4]*255
fill @red1, @green1, @blue1
stroke @red1+20, @green1+20, @blue1+20
ellipse(@x1, @y1, @size, @size)
end
if @number > 1
@size = @scaled_ffts[2]*height
@size *= 3 if @beat.is_onset
@x2 = width/2 + @scaled_ffts[4]*width
@y2 = height/2 + @scaled_ffts[6]*height
@red2 = @scaled_ffts[7]*255
@green2 = @scaled_ffts[8]*255
@blue2 = @scaled_ffts[9]*255
fill @red2, @green2, @blue2
stroke @red2+20, @green2+20, @blue2+20
ellipse(@x2, @y2, @size, @size)
end
if @number > 2
@size = @scaled_ffts[3]*height
@size *= 3 if @beat.is_onset
@x2 = width/2 - @scaled_ffts[7]*width
@y2 = height/2 - @scaled_ffts[9]*height
@red2 = @scaled_ffts[9]*255
@green2 = @scaled_ffts[0]*255
@blue2 = @scaled_ffts[1]*255
fill @red2, @green2, @blue2
stroke @red2+20, @green2+20, @blue2+20
ellipse(@x2, @y2, @size, @size)
end
if @number > 3
@size = @scaled_ffts[4]*height
@size *= 3 if @beat.is_onset
@x4 = @x ||=@scaled_ffts[2]*width
@y4 = @y ||=@scaled_ffts[8]*height
@red2 = @scaled_ffts[4]*255
@green2 = @scaled_ffts[5]*255
@blue2 = @scaled_ffts[9]*255
fill @red2, @green2, @blue2
stroke @red2+20, @green2+20, @blue2+20
ellipse(@x4, @y4, @size, @size)
end
if @show_clicked
@viscircles.each do |vc|
vc.draw(@scaled_ffts,@beat)
end
end
end
def stop
@input.close()
end
class VisCircle
attr_reader :x0, :y0, :a1, :a1, :a3, :a4, :a5, :a6,:free
def initialize(x, y)
#r = Random.new
@x0, @y0 = x, y
@a1,@a2,@a3,@a4,@a5,@a6 = rand(9),rand(9),rand(9),rand(9),rand(9),rand(9)
@free = false
end
def changestate
@free= (@free==true) ? false :true
end
def stop
@stop=true
end
def draw(scaled_ffts,beat)
unless @stop
@size = scaled_ffts[@a1]*height/2
@size *= 3 if beat.is_onset
@red = scaled_ffts[@a4]*255
@green = scaled_ffts[@a5]*255
@blue = scaled_ffts[@a6]*255
fill @red, @green, @blue
stroke @red+20, @green+20, @blue+20
if @free
#@x0=(scaled_ffts[@a3]*width + @x0/2)%width
#@y0=(scaled_ffts[@a2]*height + @y0/2)%height
@x0=(scaled_ffts[@a3]*@x0 + width/2)%width
@y0=(scaled_ffts[@a2]*@y0 + height/2)%height
end
ellipse(@x0, @y0, @size, @size)
end
end
end
end
Pird.new :title => "Pird"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment