///|
pub fn signal_rms(signal : ArrayView[Double]) -> Double raise SpectrumError {
signal_stats(signal).rms
}
///|
pub fn crest_factor(signal : ArrayView[Double]) -> Double raise SpectrumError {
let stats = signal_stats(signal)
if stats.rms == 0.0 {
raise InvalidArgument(message="crest factor is undefined for zero signal")
}
let peak = if stats.minimum.abs() > stats.maximum.abs() {
stats.minimum.abs()
} else {
stats.maximum.abs()
}
peak / stats.rms
}
///|
pub fn dynamic_range_db(
signal : ArrayView[Double],
) -> Double raise SpectrumError {
let stats = signal_stats(signal)
let mut minimum = 0.0
let mut maximum = 0.0
for value in signal {
let magnitude = value.abs()
if magnitude > 0.0 && (minimum == 0.0 || magnitude < minimum) {
minimum = magnitude
}
if magnitude > maximum {
maximum = magnitude
}
}
if stats.count == 0 || minimum == 0.0 || maximum == 0.0 {
raise InvalidArgument(message="dynamic range needs non-zero samples")
}
20.0 * @math.log10(maximum / minimum)
}
///|
pub fn spectral_flux(
previous : ArrayView[Double],
current : ArrayView[Double],
) -> Double raise SpectrumError {
if previous.length() == 0 || current.length() == 0 {
raise EmptySignal
}
if previous.length() != current.length() {
raise LengthMismatch
}
let mut denominator = 0.0
let mut increase = 0.0
for i in 0.. 0.0 {
increase = increase + delta
}
}
if denominator == 0.0 {
return 0.0
}
increase / denominator
}
///|
pub fn spectral_band_energy(
magnitudes : ArrayView[Double],
sample_rate : Double,
low_hz : Double,
high_hz : Double,
) -> Double raise SpectrumError {
let half = positive_spectrum_length(magnitudes)
if sample_rate <= 0.0 ||
low_hz < 0.0 ||
high_hz < low_hz ||
high_hz > sample_rate / 2.0 {
raise InvalidArgument(message="invalid spectral band")
}
let mut energy = 0.0
for i in 0..= low_hz && frequency <= high_hz {
energy = energy + magnitudes[i] * magnitudes[i]
}
}
energy
}
///|
pub fn next_power_of_two(value : Int) -> Int raise SpectrumError {
if value <= 0 {
raise InvalidArgument(message="value must be positive")
}
let mut result = 1
while result < value {
result = result * 2
}
result
}
///|
pub fn pad_to_power_of_two(
signal : ArrayView[Double],
) -> Array[Double] raise SpectrumError {
if signal.length() == 0 {
raise EmptySignal
}
let length = next_power_of_two(signal.length())
let output = Array::make(length, 0.0)
for i in 0.. Array[Double] raise SpectrumError {
if signal.length() == 0 {
raise EmptySignal
}
if attack <= 0.0 || attack > 1.0 || release <= 0.0 || release > 1.0 {
raise InvalidArgument(message="attack and release must be in (0, 1]")
}
let output = Array::make(signal.length(), 0.0)
let mut previous = signal[0].abs()
output[0] = previous
for i in 1.. previous { attack } else { release }
previous = previous + coefficient * (target - previous)
output[i] = previous
}
output
}