Class: AudioStream::Fx::Tuner

Inherits:
Object
  • Object
show all
Defined in:
lib/audio_stream/fx/tuner.rb

Defined Under Namespace

Classes: Tune

Constant Summary collapse

FREQ_TABLE =
10.times.map {|i|
  a = 13.75 * 2 ** i
  12.times.map {|j|
    a * (2 ** (j / 12.0))
  }
}.flatten.freeze
NOTE_TABLE =
["A", "A#/Bb", "B", "C", "C#/Db", "D", "D#/Eb", "E", "F", "F#/Gb", "G", "G#/Ab"].freeze

Instance Method Summary collapse

Constructor Details

#initialize(soundinfo, window: nil) ⇒ Tuner

Returns a new instance of Tuner.

[View source]

16
17
18
19
# File 'lib/audio_stream/fx/tuner.rb', line 16

def initialize(soundinfo, window: nil)
  @samplerate = soundinfo.samplerate.to_f
  @window = window || HanningWindow.instance
end

Instance Method Details

#process(input) ⇒ Object

[View source]

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# 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) ⇒ Object

[View source]

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# 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