Module: Beats::AudioUtils

Defined in:
lib/beats/audioutils.rb

Overview

This class contains some utility methods for working with sample data.

Class Method Summary collapse

Class Method Details

.composite(sample_arrays, num_channels) ⇒ Object

Combines multiple sample arrays into one, by adding them together. When the sample arrays are different lengths, the output array will be the length of the longest input array. WARNING: Incoming arrays can be modified.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/beats/audioutils.rb', line 9

def self.composite(sample_arrays, num_channels)
  if sample_arrays == []
    return []
  end

  # Sort from longest to shortest
  sample_arrays = sample_arrays.sort {|x, y| y.length <=> x.length}

  composited_output = sample_arrays.slice!(0)
  sample_arrays.each do |sample_array|
    unless sample_array == []
      if num_channels == 1
        sample_array.length.times {|i| composited_output[i] += sample_array[i] }
      elsif num_channels == 2
        sample_array.length.times do |i|
          composited_output[i] = [composited_output[i][0] + sample_array[i][0],
                                  composited_output[i][1] + sample_array[i][1]]
        end
      end
    end
  end

  composited_output
end

.scale(sample_array, num_channels, scale) ⇒ Object

Scales the amplitude of the incoming sample array by scale amount. Can be used in conjunction with composite() to make sure composited sample arrays don’t have an amplitude greater than 1.0.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/beats/audioutils.rb', line 37

def self.scale(sample_array, num_channels, scale)
  if sample_array == []
    return sample_array
  end

  if scale > 1
    if num_channels == 1
      sample_array = sample_array.map {|sample| sample / scale }
    elsif num_channels == 2
      sample_array = sample_array.map {|sample| [sample[0] / scale, sample[1] / scale]}
    else
      raise StandardError, "Invalid sample data array in AudioUtils.normalize()"
    end
  end

  sample_array
end

.step_sample_length(samples_per_second, tempo) ⇒ Object

Returns the number of samples that each step (i.e. a ‘X’ or a ‘.’) lasts at a given sample rate and tempo. The sample length can be a non-integer value. Although there’s no such thing as a partial sample, this is required to prevent small timing errors from creeping in. If they accumulate, they can cause rhythms to drift out of time.



60
61
62
63
64
65
66
# File 'lib/beats/audioutils.rb', line 60

def self.step_sample_length(samples_per_second, tempo)
   samples_per_minute = samples_per_second * 60.0
   samples_per_quarter_note = samples_per_minute / tempo

   # Each step is equivalent to a 16th note
   samples_per_quarter_note / 4.0
end

.step_start_sample(step_index, step_sample_length) ⇒ Object

Returns the sample index that a given step (offset from 0) starts on.



70
71
72
# File 'lib/beats/audioutils.rb', line 70

def self.step_start_sample(step_index, step_sample_length)
  (step_index * step_sample_length).floor
end