Class: Wavify::Codecs::Registry
- Inherits:
-
Object
- Object
- Wavify::Codecs::Registry
- Defined in:
- lib/wavify/codecs/registry.rb,
sig/codecs.rbs
Overview
Selects a codec implementation by extension and/or magic bytes.
Constant Summary collapse
- MAGIC_PROBES =
Probe lambdas used to match container signatures from leading bytes.
{ "RIFF" => lambda do |bytes| bytes.bytesize >= 12 && bytes.start_with?("RIFF") && bytes[8, 4] == "WAVE" end, "fLaC" => ->(bytes) { bytes.start_with?("fLaC") }, "OggS" => ->(bytes) { bytes.start_with?("OggS") }, "FORM" => lambda do |bytes| bytes.bytesize >= 12 && bytes.start_with?("FORM") && %w[AIFF AIFC].include?(bytes[8, 4]) end }.freeze
- EXTENSIONS =
Extension-to-codec mapping for path-based detection.
{ ".wav" => Wav, ".wave" => Wav, ".flac" => Flac, ".ogg" => OggVorbis, ".oga" => OggVorbis, ".aiff" => Aiff, ".aif" => Aiff, ".aifc" => Aiff, ".raw" => Raw, ".pcm" => Raw }.freeze
- MAGIC_CODEC_ORDER =
Probe order for magic-byte detection.
[ ["RIFF", Wav], ["fLaC", Flac], ["OggS", OggVorbis], ["FORM", Aiff] ].freeze
- MAX_MAGIC_PROBE_SIZE =
Maximum leading-byte window allowed for a custom magic probe.
65_536- BUILTIN_MAGIC_ENTRIES =
MAGIC_CODEC_ORDER.each_with_index.map do |(magic_key, codec), index| { extension: nil, codec: codec, probe: MAGIC_PROBES.fetch(magic_key), probe_size: 12, priority: 0, sequence: index, custom: false }.freeze end.freeze
- CODEC_POSITIONAL_ARITY =
{ read: 1, write: 2, stream_read: 1, stream_write: 1, metadata: 1 }.freeze
Class Method Summary collapse
-
.available_formats ⇒ Array<String>
Extension names whose codec dependencies are available.
-
.detect(io_or_path, strict: false, filename: nil) ⇒ Class
Detects the codec for a path or IO object.
-
.detect_for_read(io_or_path, strict: false, filename: nil) ⇒ Class
Detects the codec for reading.
-
.detect_for_write(io_or_path, filename: nil) ⇒ Class
Detects the codec for writing.
-
.register(extension, codec, magic: nil, priority: 0, probe_size: 12) ⇒ Class
Registers or replaces a codec for a filename extension.
-
.resolve(codec) ⇒ singleton(Base)
Resolves an explicit codec class or registered extension name.
-
.supported_formats ⇒ Array<String>
Supported extension names without leading dots.
-
.unregister(extension) ⇒ singleton(Base)?
Removes a custom codec mapping or restores the built-in mapping.
Class Method Details
.available_formats ⇒ Array<String>
Returns extension names whose codec dependencies are available.
175 176 177 178 179 180 181 |
# File 'lib/wavify/codecs/registry.rb', line 175 def available_formats extension_snapshot.filter_map do |extension, codec| next if codec.respond_to?(:available?) && !codec.available? extension.delete_prefix(".") end.uniq.sort.freeze end |
.detect(io_or_path, strict: false, filename: nil) ⇒ Class
Detects the codec for a path or IO object. Read detection prefers magic bytes when available.
71 72 73 |
# File 'lib/wavify/codecs/registry.rb', line 71 def detect(io_or_path, strict: false, filename: nil) detect_for_read(io_or_path, strict: strict, filename: filename) end |
.detect_for_read(io_or_path, strict: false, filename: nil) ⇒ Class
Detects the codec for reading.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/wavify/codecs/registry.rb', line 81 def detect_for_read(io_or_path, strict: false, filename: nil) extension_codec = detect_by_extension(io_or_path, filename: filename) magic_codec = if non_rewindable_io?(io_or_path) if strict raise InvalidParameterError, "strict codec detection requires rewindable IO" end unless extension_codec raise InvalidParameterError, "codec detection requires rewindable IO; pass filename: as a codec hint" end else detect_by_magic(io_or_path) end if strict && extension_codec && magic_codec && extension_codec != magic_codec raise InvalidFormatError, "codec mismatch: extension implies #{extension_codec.name}, magic bytes imply #{magic_codec.name}" end magic_codec || extension_codec || raise_not_found(filename || io_or_path) end |
.detect_for_write(io_or_path, filename: nil) ⇒ Class
Detects the codec for writing. Write detection intentionally prefers the target filename extension.
107 108 109 |
# File 'lib/wavify/codecs/registry.rb', line 107 def detect_for_write(io_or_path, filename: nil) detect_by_extension(io_or_path, filename: filename) || detect_by_magic(io_or_path) || raise_not_found(filename || io_or_path) end |
.register(extension, codec, magic: nil, priority: 0, probe_size: 12) ⇒ Class
Registers or replaces a codec for a filename extension.
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/wavify/codecs/registry.rb', line 128 def register(extension, codec, magic: nil, priority: 0, probe_size: 12) normalized_extension = normalize_extension(extension) validate_codec!(codec) magic_probe, normalized_probe_size = normalize_magic_probe(magic, probe_size) unless priority.is_a?(Integer) raise InvalidParameterError, "priority must be an Integer" end extensions_mutex.synchronize do extensions[normalized_extension] = codec magic_entries.delete_if { |entry| entry[:custom] && entry[:extension] == normalized_extension } if magic_probe magic_entries << { extension: normalized_extension, codec: codec, probe: magic_probe, probe_size: normalized_probe_size, priority: priority, sequence: next_magic_sequence, custom: true }.freeze end end codec end |
.resolve(codec) ⇒ singleton(Base)
Resolves an explicit codec class or registered extension name.
112 113 114 115 116 117 118 119 120 121 |
# File 'lib/wavify/codecs/registry.rb', line 112 def resolve(codec) if codec.respond_to?(:read) && codec.respond_to?(:write) validate_codec!(codec) return codec end key = codec.to_s normalized = normalize_extension(key) extensions_mutex.synchronize { extensions[normalized] } || raise_not_found(codec) end |
.supported_formats ⇒ Array<String>
Returns supported extension names without leading dots.
170 171 172 |
# File 'lib/wavify/codecs/registry.rb', line 170 def supported_formats extension_snapshot.keys.map { |extension| extension.delete_prefix(".") }.uniq.sort.freeze end |
.unregister(extension) ⇒ singleton(Base)?
Removes a custom codec mapping or restores the built-in mapping.
155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/wavify/codecs/registry.rb', line 155 def unregister(extension) normalized_extension = normalize_extension(extension) extensions_mutex.synchronize do previous = extensions[normalized_extension] if EXTENSIONS.key?(normalized_extension) extensions[normalized_extension] = EXTENSIONS.fetch(normalized_extension) else extensions.delete(normalized_extension) end magic_entries.delete_if { |entry| entry[:custom] && entry[:extension] == normalized_extension } previous end end |