Module: Muze::IO::AudioLoader::FFMPEGBackend

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

Overview

Generic audio backend implemented with ffmpeg/ffprobe CLI.

Constant Summary collapse

SUPPORTED_EXTENSIONS =
%w[.flac .mp3 .ogg].freeze
DEFAULT_TIMEOUT_SECONDS =
30
INSTALLATION_STEPS =
[
  "Install ffmpeg and ensure both `ffmpeg` and `ffprobe` are available on PATH.",
  "macOS: `brew install ffmpeg`.",
  "Ubuntu/Debian: `sudo apt-get install ffmpeg`."
].freeze

Class Method Summary collapse

Class Method Details

.applies_time_window?Boolean

Returns:

  • (Boolean)


42
43
44
# File 'lib/muze/io/audio_loader/ffmpeg_backend.rb', line 42

def applies_time_window?
  true
end

.available?Boolean

Returns:

  • (Boolean)


29
30
31
32
# File 'lib/muze/io/audio_loader/ffmpeg_backend.rb', line 29

def available?
  @available = command_available?("ffmpeg") && command_available?("ffprobe") if @available.nil?
  @available
end

.info(path) ⇒ Hash

Parameters:

  • path (String)

Returns:

  • (Hash)

Raises:



72
73
74
75
76
77
78
79
80
81
82
# File 'lib/muze/io/audio_loader/ffmpeg_backend.rb', line 72

def info(path)
  raise Muze::DependencyError, installation_message(File.extname(path).downcase) unless available?

  sample_rate, channels, duration = probe_stream(path, include_duration: true)
  {
    sample_rate: sample_rate,
    channels: channels,
    duration: duration,
    format: File.extname(path).delete_prefix(".")
  }
end

.installation_message(extension) ⇒ String

Parameters:

  • extension (String)

Returns:

  • (String)


36
37
38
39
# File 'lib/muze/io/audio_loader/ffmpeg_backend.rb', line 36

def installation_message(extension)
  format = extension.delete_prefix(".")
  "Unable to load #{format} because the FFmpeg backend is unavailable. #{INSTALLATION_STEPS.join(' ')}"
end

.read(path, offset: 0.0, duration: nil) ⇒ Array(Array<Float>, Integer, Integer)

Parameters:

  • path (String)
  • offset (Float) (defaults to: 0.0)
  • duration (Float, nil) (defaults to: nil)

Returns:

  • (Array(Array<Float>, Integer, Integer))

Raises:



50
51
52
53
54
55
# File 'lib/muze/io/audio_loader/ffmpeg_backend.rb', line 50

def read(path, offset: 0.0, duration: nil)
  raise Muze::DependencyError, installation_message(File.extname(path).downcase) unless available?

  source_sr, channels = probe_stream(path)
  [decode_samples(path, channels, offset:, duration:), source_sr, channels]
end

.read_stream(path, chunk_frames:, offset: 0.0, duration: nil) {|samples, sample_rate, channels| ... } ⇒ void

This method returns an undefined value.

Yield Parameters:

  • samples (Array<Float>, Array<Array<Float>>)
  • sample_rate (Integer)
  • channels (Integer)

Raises:



61
62
63
64
65
66
67
68
# File 'lib/muze/io/audio_loader/ffmpeg_backend.rb', line 61

def read_stream(path, chunk_frames:, offset: 0.0, duration: nil)
  raise Muze::DependencyError, installation_message(File.extname(path).downcase) unless available?

  source_sr, channels = probe_stream(path)
  stream_decoded_samples(path, source_sr:, channels:, chunk_frames:, offset:, duration:) do |samples|
    yield samples, source_sr, channels
  end
end

.supported_extension?(extension) ⇒ Boolean

Parameters:

  • extension (String)

Returns:

  • (Boolean)


24
25
26
# File 'lib/muze/io/audio_loader/ffmpeg_backend.rb', line 24

def supported_extension?(extension)
  SUPPORTED_EXTENSIONS.include?(extension)
end