Module: Muze::Core::Audio

Defined in:
lib/muze/core/audio.rb

Overview

Small audio-array helpers shared by public convenience APIs.

Class Method Summary collapse

Class Method Details

.normalize(y, peak: 1.0, axis: nil) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/muze/core/audio.rb', line 30

def normalize(y, peak: 1.0, axis: nil)
  raise Muze::ParameterError, "peak must be positive" unless peak.respond_to?(:positive?) && peak.positive?
  raise Muze::ParameterError, "axis must be nil or :channels" unless axis.nil? || axis == :channels

  signal = validate_audio!(y, allow_empty: true)
  return signal if signal.empty?

  return normalize_channels(signal, peak:) if axis == :channels && signal.ndim == 2

  current_peak = signal.abs.max.to_f
  return signal if current_peak <= 0.0

  (signal * (peak.to_f / current_peak)).cast_to(Numo::SFloat)
end

.remix(y, intervals, units: :samples, sr: nil, hop_length: 512) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/muze/core/audio.rb', line 45

def remix(y, intervals, units: :samples, sr: nil, hop_length: 512)
  signal = validate_audio!(y, allow_empty: true)
  raw_intervals = intervals.respond_to?(:to_a) ? intervals.to_a : Array(intervals)
  raw_intervals = [raw_intervals] if raw_intervals.length == 2 && !raw_intervals.first.respond_to?(:to_a)

  sample_ranges = raw_intervals.map do |interval|
    raise Muze::ParameterError, "intervals must contain [start, end] pairs" unless interval.respond_to?(:to_a) && interval.to_a.length == 2

    start_sample = convert_position(interval.to_a[0], units:, sr:, hop_length:)
    end_sample = convert_position(interval.to_a[1], units:, sr:, hop_length:)
    raise Muze::ParameterError, "interval end must be >= start" if end_sample < start_sample

    [start_sample, end_sample]
  end

  chunks = sample_ranges.map { |start_sample, end_sample| slice_samples(signal, start_sample, end_sample) }
  concatenate_chunks(chunks, channel_count: signal.ndim == 2 ? signal.shape[1] : nil)
end

.valid_audio?(y, allow_empty: false) ⇒ Boolean

Returns:

  • (Boolean)


23
24
25
26
27
28
# File 'lib/muze/core/audio.rb', line 23

def valid_audio?(y, allow_empty: false)
  validate_audio!(y, allow_empty:)
  true
rescue Muze::ParameterError
  false
end

.validate_audio!(y, allow_empty: false) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/muze/core/audio.rb', line 9

def validate_audio!(y, allow_empty: false)
  raise Muze::ParameterError, "audio must not be nil" if y.nil?

  signal = Numo::SFloat.cast(y)
  raise Muze::ParameterError, "audio must be one- or two-dimensional" unless [1, 2].include?(signal.ndim)
  raise Muze::ParameterError, "audio must not be empty" if !allow_empty && signal.empty?
  raise Muze::ParameterError, "audio must contain only finite numeric values" unless finite_values?(signal)
  raise Muze::ParameterError, "audio channel count must be positive" if signal.ndim == 2 && signal.shape[1].zero?

  signal
rescue NoMethodError, TypeError, ArgumentError => e
  raise Muze::ParameterError, "audio must be Array<Float> or Numo::NArray: #{e.message}"
end