class Aubio::Pitches

Public Class Methods

new(aubio_source, params) click to toggle source
# File lib/aubio/pitches.rb, line 5
def initialize(aubio_source, params)
  # TODO: cleanup param dups
  @sample_rate = params[:sample_rate] || 44_100
  @window_size = params[:window_size] || 1024
  @hop_size    = params[:hop_size]    || 512

  # Set the tolerance for the pitch detection algorithm.
  # Typical values range between 0.2 and 0.9.
  # Pitch candidates found with a confidence less than this threshold will not be selected.
  # The higher the threshold, the more confidence in the candidates.
  @confidence_thresh = params[:confidence_thresh] || 0.9

  @pitch_method = params[:pitch_method] || 'yinfast'

  @source = aubio_source
  @pitch = Api.new_aubio_pitch(@pitch_method, @window_size, @hop_size, @sample_rate)
  Api.aubio_pitch_set_unit(@pitch, 'midi')
  Api.aubio_pitch_set_tolerance(@pitch, @confidence_thresh)

  # create output for source
  @sample_buffer = Api.new_fvec(@hop_size)
  # create output for pitch and beat
  @out_fvec = Api.new_fvec(1)
end

Public Instance Methods

each() { |output| ... } click to toggle source
# File lib/aubio/pitches.rb, line 30
def each
  return enum_for(:each) unless block_given?

  total_frames_counter = 0
  read_buffer = FFI::MemoryPointer.new(:int)
  last_pitch = 0

  loop do
    # Perform pitch calculation
    Api.aubio_source_do(@source, @sample_buffer, read_buffer)
    Api.aubio_pitch_do(@pitch, @sample_buffer, @out_fvec)

    # Retrieve result
    pitch = Api.fvec_get_sample(@out_fvec, 0)
    confidence = Api.aubio_pitch_get_confidence(@pitch)
    no_of_bytes_read = read_buffer.read_int
    total_frames_counter += no_of_bytes_read

    if ((last_pitch - pitch).abs >= 1) && (confidence > @confidence_thresh)
      output = {
        pitch: pitch,
        confidence: confidence,
        start: (total_frames_counter == 0 ? 1 : 0),
        end: 0
      }
      yield output
    end

    last_pitch = pitch

    next unless no_of_bytes_read != @hop_size

    # there's no more audio to look at

    # Let's output one last pitch to mark the end of the file
    total_time = total_frames_counter.to_f / @sample_rate.to_f
    output = {
      pitch: pitch,
      confidence: confidence,
      start: 0,
      end: 1
    }
    yield output

    # clean up
    Api.del_aubio_pitch(@pitch)
    Api.del_fvec(@sample_buffer)
    Api.del_fvec(@out_fvec)

    break
  end
end