Sep 23
The Brown Sound

Brown noise can be simulated with a spinner. Of course, if we kept a running total for the Die object and added the ability to weight the faces, the Spinner and Die objects would be isomorphic. However, I can visualize a spinner with different sized slices more easily than a weighted die. Here’s the code.
class Spinner
attr_reader :state
def initialize(params={})
params.has_key?(:slice_values) ? @slice_values =
params[:slice_values] : @slice_values = [-1,0,1]
if params.has_key?(:slice_sizes)
if @slice_values.length != params[:slice_sizes].length
puts("error: length of :slice_sizes should = :slice_values")
@slice_sizes = []
for slice in @slice_values
@slice_sizes.push(1)
end
else
@slice_sizes = params[:slice_sizes]
end
else
@slice_sizes = [1,1,1]
end
params.has_key?(:minimum) ? @minimum = params[:minimum]
: @minimum = 0
params.has_key?(:maximum) ? @maximum = params[:maximum]
: @maximum = 9
params.has_key?(:state) ? @state = params[:state]
: @state = (@minimum + @maximum)/2
params.has_key?(:edge) ? @edge = params[:edge]
: @edge = 'bounce'
@summed_sizes = 0
@slice_sizes.each {|size| @summed_sizes += size}
if @summed_sizes > 0
for i in 1..(@slice_sizes.length.-1)
@slice_sizes[i] += @slice_sizes[i-1]
end
else
@slice_sizes[0] = 1
@summed_sizes = 1
end
end
def spin
result = rand(@summed_sizes)
i = 0
until result < @slice_sizes[i]
i += 1
end
@state = @state + @slice_values[i]
if @state < @minimum
if @edge == 'bounce'
@state = @minimum + (@minimum - @state)
else # 're_enter opposite'
@state = @maximum - (@minimum - @state - 1)
end
elsif @state > @maximum
if @edge == 'bounce'
@state = @maximum - (@state - @maximum)
else # 're_enter opposite'
@state = @minimum + (@state - @maximum - 1)
end
end
return @state
end
end
By default the spinner is divided into 3 equal portions. Each spin will increment or decrement the state by one or leave it unchanged. Unlike white noise, where each note is completely independant, brown noise is highly correlated.
brown_noise = Spinner.new
10.times do
puts(brown_noise.spin)
end
> 8,9,8,7,7,7,6,7,8,8
As with the Die object you can use a Spinner object with a MidiWriter object to hear what it sounds like.
notes = [0, 3, 5, 7, 10, 12, 15, 17, 19, 22, 24] # two octaves of a pentatonic minor scale
note_spinner = Spinner.new({:maximum => 10, :edge => 're-enter',
:slice_values => [-3,-2,-1,1,2,3], :slice_sizes => [3,2,1,1,2,3]})
durations = ['8th','quarter','dotted quarter']
duration_spinner = Spinner.new({:maximum => 2})
midi_data = []
100.times do
event = {:note => (60 + notes[note_spinner.spin]),
:duration => durations[duration_spinner.spin]}
midi_data.push(event)
end
writer = MidiWriter.new(1,'brown')
writer.write(midi_data)
Here’s what it might sound like.
Sep 22
midilib
The easiest way to hear what white noise sounds like (when applied to a scale) is to download a copy of midilib and use it with the Die object explained previously.
$LOAD_PATH[0, 0] = File.join(File.dirname(__FILE__), '..', 'lib')
require 'midilib/sequence'
require 'midilib/consts'
include MIDI
class MidiWriter
def initialize(instrument=1, filename='midi.mid')
@filename = filename
@instrument = instrument
end
def write(data)
seq = Sequence.new()
track = Track.new(seq)
seq.tracks << track
track.events << Tempo.new(Tempo.bpm_to_mpq(120))
track.events << MetaEvent.new(META_SEQ_NAME, 'Sequence Name')
track = Track.new(seq)
seq.tracks << track
track.name = 'My New Track'
track.events << Controller.new(0, CC_VOLUME, 127)
track.events << ProgramChange.new(0, @instrument, 0)
for event in data
track.events << NoteOnEvent.new(0, event[:note], 127, 0)
track.events << NoteOffEvent.new(0, event[:note], 127,
seq.note_to_delta(event[:duration]))
end
File.open("#{@filename}.mid", 'wb') { | file |
seq.write(file)
}
end
end
notes = [0, 2, 4, 5, 7, 9, 11, 12, 14, 16, 17,
19, 21, 23, 24] # two octaves of a major scale
note_die = Die.new([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14])
durations = ['8th','quarter','dotted quarter','half',
'dotted half','whole']
duration_die = Die.new([0,1,2,3,4,5])
midi_data = []
100.times do
event = {:note => (60 + notes[note_die.roll]),
:duration => durations[duration_die.roll]}
midi_data.push(event)
end
writer = MidiWriter.new(1,'my_file_name')
writer.write(midi_data)
Here’s what it sounds like. As one might expect the results while sometimes interesting, are rather chaotic. Of course every run will produce different results. You can experiment with the scale, durations and properties of the ‘Die’ object as well.
If you want to read more about noise generators check out Martin Gardners’ Fractal Music, Hypercards and More…
No comments EditSep 9
White noise
Different noise generators can be useful for algorithmic composing. We can simulate white noise by rolling a die. Here’s how we might code a die object in Ruby. (My language of choice used to Perl but I’ve switched to Ruby).

class Die
attr_accessor :faces, :current_state
class << self
def roll(*args)
new(*args).roll
end
end
def initialize (faces=[1,2,3,4,5,6])
@faces = faces
@current_state = self.roll
end
def roll
@current_state = @faces[rand(@faces.length)]
end
end
The Die object defaults to a normal 6 sided die.
10.times do
puts Die.roll
end
Resulting in something like…
6,1,3,5,5,6,3,1,1,2
Or the number of sides and their values can be specified.
eight_sided = Die.new([0,0,0,0,1,1,2,3])
10.times do
puts(eight_sided.roll)
end
Which will produce something like…
0,0,0,2,1,2,1,0,0,2
No comments Edit
Sep 8
Critters
I used to sell a Mac app called Critters.
A few people liked it. If you’re running OSX 10.4 on a non-Intel Mac you can download a fully functional and free version. Converting to run on MacTels was not fun, but I now have a usable (if slightly buggy) Intel version of Critters. It may see the light of day at some point, but recently I’ve been concentrating on a more compelling composing app. More to follow.
