class AudioStream::Fx::Tuner

Constants

FREQ_TABLE
NOTE_TABLE
Tune

Public Class Methods

new(soundinfo, window: nil) click to toggle source
# File lib/audio_stream/fx/tuner.rb, line 16
def initialize(soundinfo, window: nil)
  @samplerate = soundinfo.samplerate.to_f
  @window = window || HanningWindow.instance
end

Public Instance Methods

process(input) click to toggle source
# File lib/audio_stream/fx/tuner.rb, line 21
def process(input)
  window_size = input.window_size

  # mono window
  input = input.mono
  input = @window.process(input)
  stream = input.streams[0]

  gain = stream.map(&:abs).max
  freq = nil

  if 0.01<gain
    # fft
    na = input.to_float_na
    fft = FFTW3.fft(na, FFTW3::FORWARD) / na.length

    amp = fft.map {|c|
      c.real**2 + c.imag**2
    }.real.to_a.flatten

    # peak
    i = amp.index(amp.max)

    #if window_size/2<i
    #  j = window_size - i
    #  if (amp[i]-amp[j]).abs<=0.0000001
    #    i = j
    #  end
    #end

    # freq
    freq_rate = @samplerate / window_size

    if 0<i && i<window_size-1
      freq_sum = amp[i-1] * (i-1) * freq_rate
      freq_sum += amp[i] * i * freq_rate
      freq_sum += amp[i+1] * (i+1) * freq_rate

      amp_sum = amp[i-1] + amp[i] + amp[i+1]

      freq = freq_sum / amp_sum
    else
      freq = i * freq_rate
    end

    struct(freq)
  else
    Tune.new
  end
end
struct(freq) click to toggle source
# File lib/audio_stream/fx/tuner.rb, line 72
def struct(freq)
  index = FREQ_TABLE.bsearch_index {|x| x>=freq}
  if !index || FREQ_TABLE.length<=index+1
    return Tune.new
  end

  if 0<index && freq-FREQ_TABLE[index-1] < FREQ_TABLE[index]-freq
    diff = (freq-FREQ_TABLE[index-1]) / (FREQ_TABLE[index]-FREQ_TABLE[index-1]) * 100
    index -= 1
  else
    diff = (freq-FREQ_TABLE[index]) / (FREQ_TABLE[index+1]-FREQ_TABLE[index]) * 100
  end
  note_num = index + 9
  note = NOTE_TABLE[index%12]
  octave = (index-3)/12

  Tune.new(
    freq: freq,
    note_num: note_num,
    note: note,
    octave: octave,
    diff: diff
  )
end