Module: Muze::IO::AudioLoader

Defined in:
lib/muze/io/audio_loader.rb,
lib/muze/io/audio_loader/ffmpeg_backend.rb,
lib/muze/io/audio_loader/wavify_backend.rb

Overview

Audio file loader with mono mixdown and optional resampling.

Defined Under Namespace

Modules: FFMPEGBackend, WavifyBackend

Constant Summary collapse

BACKENDS =
[
  WavifyBackend,
  FFMPEGBackend
].freeze
SUPPORTED_FORMATS =
BACKENDS.flat_map { |backend| backend::SUPPORTED_EXTENSIONS }.map { |ext| ext.delete_prefix(".") }.sort.freeze

Class Method Summary collapse

Class Method Details

.info(path, format: nil) ⇒ Hash

Parameters:

  • path (String, Pathname, IO)

Returns:

  • (Hash)


84
85
86
87
88
89
90
91
92
93
94
# File 'lib/muze/io/audio_loader.rb', line 84

def info(path, format: nil)
  source = resolve_source(path, format:)

  select_backend(source).info(source.fetch(:input))
rescue Muze::AudioLoadError
  raise
rescue Muze::UnsupportedFormatError, Muze::DependencyError => e
  raise Muze::AudioLoadError, e.message
rescue StandardError => e
  raise Muze::AudioLoadError, "Failed to inspect #{path}: #{e.message}"
end

.load(path, sr: 22_050, mono: true, offset: 0.0, duration: nil, dtype: Numo::SFloat, normalize: false, format: nil, weights: nil, max_bytes: nil) ⇒ Array(Numo::SFloat, Integer)

Returns waveform and sample rate.

Parameters:

  • path (String, Pathname, IO)
  • sr (Integer, nil) (defaults to: 22_050)

    destination sample rate; nil preserves source rate

  • mono (Boolean, Symbol) (defaults to: true)
  • offset (Float) (defaults to: 0.0)

    seconds from start

  • duration (Float, nil) (defaults to: nil)

    duration in seconds

  • dtype (Class, Symbol) (defaults to: Numo::SFloat)
  • normalize (Boolean) (defaults to: false)
  • format (Symbol, String, nil) (defaults to: nil)
  • weights (Array<Float>, nil) (defaults to: nil)
  • max_bytes (Integer, nil) (defaults to: nil)

Returns:

  • (Array(Numo::SFloat, Integer))

    waveform and sample rate



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/muze/io/audio_loader.rb', line 29

def load(path, sr: 22_050, mono: true, offset: 0.0, duration: nil, dtype: Numo::SFloat, normalize: false, format: nil, weights: nil, max_bytes: nil)
  source = resolve_source(path, format:)
  validate_args!(sr:, mono:, offset:, duration:, dtype:, normalize:, weights:, max_bytes:)
  validate_source_size!(source, max_bytes:)

  backend = select_backend(source)
  raw_samples, source_sr, _channels = backend.read(source.fetch(:input), offset:, duration:)
  sliced = backend.applies_time_window? ? raw_samples : slice_by_time(raw_samples, source_sr, offset:, duration:)

  signal = downmix(sliced, mono:, weights:)
  target_sr = sr || source_sr

  resampled = resample(signal, source_sr, target_sr)
  output = cast_signal(resampled, dtype)
  output = normalize_signal(output) if normalize
  [output, target_sr]
rescue Muze::AudioLoadError, Muze::ParameterError
  raise
rescue Muze::UnsupportedFormatError, Muze::DependencyError => e
  raise Muze::AudioLoadError, e.message
rescue StandardError => e
  raise Muze::AudioLoadError, "Failed to load #{path}: #{e.message}"
end

.load_stream(path, sr: nil, mono: true, offset: 0.0, duration: nil, dtype: Numo::SFloat, format: nil, weights: nil, max_bytes: nil, chunk_frames: 16_384) {|chunk, sample_rate| ... } ⇒ Enumerator?

Parameters:

  • path (String, Pathname, IO)
  • chunk_frames (Integer) (defaults to: 16_384)

Yield Parameters:

  • chunk (Numo::SFloat, Numo::DFloat)
  • sample_rate (Integer)

Returns:

  • (Enumerator, nil)


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/muze/io/audio_loader.rb', line 58

def load_stream(path, sr: nil, mono: true, offset: 0.0, duration: nil, dtype: Numo::SFloat, format: nil, weights: nil, max_bytes: nil, chunk_frames: 16_384)
  return enum_for(__method__, path, sr:, mono:, offset:, duration:, dtype:, format:, weights:, max_bytes:, chunk_frames:) unless block_given?

  source = resolve_source(path, format:)
  validate_args!(sr:, mono:, offset:, duration:, dtype:, normalize: false, weights:, max_bytes:)
  validate_stream_args!(chunk_frames:)
  validate_source_size!(source, max_bytes:)

  backend = select_backend(source)
  backend.read_stream(source.fetch(:input), chunk_frames:, offset:, duration:) do |raw_samples, source_sr, _channels|
    target_sr = sr || source_sr
    signal = downmix(raw_samples, mono:, weights:)
    resampled = resample(signal, source_sr, target_sr)
    yield cast_signal(resampled, dtype), target_sr unless resampled.empty?
  end
  nil
rescue Muze::AudioLoadError, Muze::ParameterError
  raise
rescue Muze::UnsupportedFormatError, Muze::DependencyError => e
  raise Muze::AudioLoadError, e.message
rescue StandardError => e
  raise Muze::AudioLoadError, "Failed to stream #{path}: #{e.message}"
end