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 =

Returns:

  • (::Integer)
512
DEFAULT_SEPARATION_HZ =

One resonance can split into twin envelope peaks; closer pairs 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 =

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.



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

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)

  Check.positive!(@count, "count")
  Check.at_least!(@resolution, 2, "resolution")

  @order = (2 * @count) + 2
  @envelope = Lpc::Envelope.for(points: @resolution, order: @order)
  freeze
end

Instance Attribute Details

#count::Integer (readonly)

Returns the value of attribute count.

Returns:

  • (::Integer)


23
24
25
# File 'lib/dsprb/formants.rb', line 23

def count
  @count
end

#edge_margin::Float (readonly)

Returns the value of attribute edge_margin.

Returns:

  • (::Float)


23
24
25
# File 'lib/dsprb/formants.rb', line 23

def edge_margin
  @edge_margin
end

#maximum_frequency::Float (readonly)

Returns the value of attribute maximum_frequency.

Returns:

  • (::Float)


23
24
25
# File 'lib/dsprb/formants.rb', line 23

def maximum_frequency
  @maximum_frequency
end

#order::Integer (readonly)

Returns the value of attribute order.

Returns:

  • (::Integer)


23
24
25
# File 'lib/dsprb/formants.rb', line 23

def order
  @order
end

#resolution::Integer (readonly)

Returns the value of attribute resolution.

Returns:

  • (::Integer)


23
24
25
# File 'lib/dsprb/formants.rb', line 23

def resolution
  @resolution
end

#separation::Float (readonly)

Returns the value of attribute separation.

Returns:

  • (::Float)


23
24
25
# File 'lib/dsprb/formants.rb', line 23

def separation
  @separation
end

Instance Method Details

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

Parameters:

Returns:

  • (::Array[::Float])


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

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

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

Parameters:

Returns:



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

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

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

  merge(extrema(@envelope.call(model.coefficients), reduced.sample_rate)).first(@count)
end