Sep 23

The Brown Sound

Category: Uncategorized

spinner
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.

No comments

Sep 22

midilib

Category: Uncategorized

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

Sep 9

White noise

Category: Uncategorized

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).

die

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

Sep 8

Critters

Category: Uncategorized

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.

critters_screenshot

No comments