Class: DSP::Formants

Inherits:
Object
  • Object
show all
Defined in:
lib/dsprb/formants.rb,
sig/dsprb.rbs

Defined Under Namespace

Classes: Peak

Constant Summary collapse

DEFAULT_MAXIMUM_HZ =

Conventional ceiling for adult speech; the first four formants fall below it.

Returns:

  • (::Float)
5500.0
DEFAULT_COUNT =

Returns:

  • (::Integer)
4
DEFAULT_RESOLUTION =

Envelope samples taken over [0, Nyquist].

Returns:

  • (::Integer)
512
DEFAULT_SEPARATION_HZ =

One resonance can split into twin envelope peaks; peaks closer than this are merged.

Returns:

  • (::Float)
250.0
DEFAULT_EDGE_MARGIN_HZ =

Peaks pinned against the band edges are artifacts of the truncated envelope.

Returns:

  • (::Float)
150.0
MINIMUM_SAMPLES =

Below this the frame is too short to fit the predictor reliably.

Returns:

  • (::Integer)
40
ENERGY_FLOOR =

Returns:

  • (::Float)
1e-10
LOG_FLOOR =

Returns:

  • (::Float)
1e-18

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(maximum_frequency: DEFAULT_MAXIMUM_HZ, count: DEFAULT_COUNT, resolution: DEFAULT_RESOLUTION, separation: DEFAULT_SEPARATION_HZ, edge_margin: DEFAULT_EDGE_MARGIN_HZ) ⇒ Formants

Returns a new instance of Formants.

Raises:

  • (ArgumentError)


28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/dsprb/formants.rb', line 28

def initialize(
  maximum_frequency: DEFAULT_MAXIMUM_HZ,
  count: DEFAULT_COUNT,
  resolution: DEFAULT_RESOLUTION,
  separation: DEFAULT_SEPARATION_HZ,
  edge_margin: DEFAULT_EDGE_MARGIN_HZ
)
  @maximum_frequency = Float(maximum_frequency)
  @count = Integer(count)
  @resolution = Integer(resolution)
  @separation = Float(separation)
  @edge_margin = Float(edge_margin)

  raise ArgumentError, "count must be positive, got #{@count}" unless @count.positive?
  raise ArgumentError, "resolution must be at least two, got #{@resolution}" unless @resolution >= 2

  freeze
end

Instance Attribute Details

#count::Integer (readonly)

Returns the value of attribute count.

Returns:

  • (::Integer)


26
27
28
# File 'lib/dsprb/formants.rb', line 26

def count
  @count
end

#edge_margin::Float (readonly)

Returns the value of attribute edge_margin.

Returns:

  • (::Float)


26
27
28
# File 'lib/dsprb/formants.rb', line 26

def edge_margin
  @edge_margin
end

#maximum_frequency::Float (readonly)

Returns the value of attribute maximum_frequency.

Returns:

  • (::Float)


26
27
28
# File 'lib/dsprb/formants.rb', line 26

def maximum_frequency
  @maximum_frequency
end

#resolution::Integer (readonly)

Returns the value of attribute resolution.

Returns:

  • (::Integer)


26
27
28
# File 'lib/dsprb/formants.rb', line 26

def resolution
  @resolution
end

#separation::Float (readonly)

Returns the value of attribute separation.

Returns:

  • (::Float)


26
27
28
# File 'lib/dsprb/formants.rb', line 26

def separation
  @separation
end

Instance Method Details

#call(waveform) ⇒ ::Array[::Float]

Parameters:

Returns:

  • (::Array[::Float])


47
# File 'lib/dsprb/formants.rb', line 47

def call(waveform) = peaks(waveform).map(&:frequency)

#peaks(waveform) ⇒ ::Array[Peak]

Parameters:

Returns:



49
50
51
52
53
54
55
56
57
# File 'lib/dsprb/formants.rb', line 49

def peaks(waveform)
  reduced = reduce(waveform)
  return [] if reduced.length < MINIMUM_SAMPLES

  model = fit(reduced)
  return [] if model.nil?

  merge(extrema(model.envelope(points: @resolution), reduced.sample_rate)).first(@count)
end