wavify 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -1
- data/README.md +204 -22
- data/exe/wavify +6 -0
- data/lib/wavify/adapters.rb +81 -0
- data/lib/wavify/audio.rb +1066 -120
- data/lib/wavify/cli.rb +237 -0
- data/lib/wavify/codecs/aiff.rb +388 -87
- data/lib/wavify/codecs/base.rb +98 -5
- data/lib/wavify/codecs/flac.rb +660 -170
- data/lib/wavify/codecs/ogg_vorbis.rb +515 -155
- data/lib/wavify/codecs/raw.rb +235 -45
- data/lib/wavify/codecs/registry.rb +272 -10
- data/lib/wavify/codecs/wav.rb +453 -74
- data/lib/wavify/core/duration.rb +54 -2
- data/lib/wavify/core/format.rb +96 -11
- data/lib/wavify/core/sample_buffer.rb +648 -60
- data/lib/wavify/core/stream.rb +590 -34
- data/lib/wavify/dsl.rb +712 -100
- data/lib/wavify/dsp/automation.rb +109 -0
- data/lib/wavify/dsp/effects/auto_pan.rb +71 -0
- data/lib/wavify/dsp/effects/bitcrusher.rb +74 -0
- data/lib/wavify/dsp/effects/chorus.rb +15 -4
- data/lib/wavify/dsp/effects/compressor.rb +133 -23
- data/lib/wavify/dsp/effects/delay.rb +46 -1
- data/lib/wavify/dsp/effects/distortion.rb +3 -2
- data/lib/wavify/dsp/effects/effect_base.rb +69 -2
- data/lib/wavify/dsp/effects/effect_chain.rb +94 -0
- data/lib/wavify/dsp/effects/envelope_controlled_effect.rb +93 -0
- data/lib/wavify/dsp/effects/eq.rb +102 -0
- data/lib/wavify/dsp/effects/expander.rb +90 -0
- data/lib/wavify/dsp/effects/flanger.rb +112 -0
- data/lib/wavify/dsp/effects/limiter.rb +259 -0
- data/lib/wavify/dsp/effects/mastering_chain.rb +31 -0
- data/lib/wavify/dsp/effects/noise_gate.rb +72 -0
- data/lib/wavify/dsp/effects/phaser.rb +112 -0
- data/lib/wavify/dsp/effects/podcast_chain.rb +32 -0
- data/lib/wavify/dsp/effects/reverb.rb +100 -14
- data/lib/wavify/dsp/effects/soft_limiter.rb +55 -0
- data/lib/wavify/dsp/effects/stereo_widener.rb +73 -0
- data/lib/wavify/dsp/effects/tremolo.rb +66 -0
- data/lib/wavify/dsp/effects/vibrato.rb +102 -0
- data/lib/wavify/dsp/effects.rb +106 -0
- data/lib/wavify/dsp/envelope.rb +90 -19
- data/lib/wavify/dsp/filter.rb +149 -8
- data/lib/wavify/dsp/headroom.rb +57 -0
- data/lib/wavify/dsp/lfo.rb +65 -0
- data/lib/wavify/dsp/loudness_meter.rb +281 -0
- data/lib/wavify/dsp/oscillator.rb +261 -22
- data/lib/wavify/dsp/processor.rb +90 -0
- data/lib/wavify/errors.rb +2 -2
- data/lib/wavify/sequencer/engine.rb +405 -89
- data/lib/wavify/sequencer/note_sequence.rb +45 -7
- data/lib/wavify/sequencer/pattern.rb +121 -12
- data/lib/wavify/sequencer/track.rb +149 -10
- data/lib/wavify/version.rb +1 -1
- data/lib/wavify.rb +18 -0
- data/sig/audio.rbs +86 -0
- data/sig/codecs.rbs +77 -0
- data/sig/core.rbs +108 -0
- data/sig/dsl.rbs +32 -0
- data/sig/dsp.rbs +87 -0
- data/sig/effects.rbs +129 -0
- data/sig/public_api.yml +111 -0
- data/sig/sequencer.rbs +126 -0
- data/sig/stream.rbs +30 -0
- data/sig/wavify.rbs +24 -0
- metadata +44 -58
- data/.serena/.gitignore +0 -1
- data/.serena/memories/project_overview.md +0 -5
- data/.serena/memories/style_and_completion.md +0 -5
- data/.serena/memories/suggested_commands.md +0 -11
- data/.serena/project.yml +0 -126
- data/.simplecov +0 -18
- data/.yardopts +0 -4
- data/Rakefile +0 -190
- data/benchmarks/README.md +0 -46
- data/benchmarks/benchmark_helper.rb +0 -112
- data/benchmarks/dsp_effects_benchmark.rb +0 -46
- data/benchmarks/flac_benchmark.rb +0 -74
- data/benchmarks/streaming_memory_benchmark.rb +0 -94
- data/benchmarks/wav_io_benchmark.rb +0 -110
- data/examples/audio_processing.rb +0 -73
- data/examples/cinematic_transition.rb +0 -118
- data/examples/drum_machine.rb +0 -74
- data/examples/format_convert.rb +0 -81
- data/examples/hybrid_arrangement.rb +0 -165
- data/examples/streaming_master_chain.rb +0 -129
- data/examples/synth_pad.rb +0 -42
- data/tools/fixture_writer.rb +0 -85
data/lib/wavify/codecs/raw.rb
CHANGED
|
@@ -25,11 +25,19 @@ module Wavify
|
|
|
25
25
|
# @param io_or_path [String, IO]
|
|
26
26
|
# @param format [Wavify::Core::Format]
|
|
27
27
|
# @return [Wavify::Core::SampleBuffer]
|
|
28
|
-
def read(io_or_path, format: nil)
|
|
28
|
+
def read(io_or_path, format: nil, endianness: :little, signed: nil, float_domain: :normalized, **codec_options)
|
|
29
|
+
validate_no_codec_options!(codec_options, operation: "raw read")
|
|
29
30
|
target_format = validate_format!(format)
|
|
31
|
+
encoding = normalize_raw_encoding(
|
|
32
|
+
target_format,
|
|
33
|
+
endianness: endianness,
|
|
34
|
+
signed: signed,
|
|
35
|
+
float_domain: float_domain
|
|
36
|
+
)
|
|
30
37
|
io, close_io = open_input(io_or_path)
|
|
31
|
-
data = io
|
|
32
|
-
|
|
38
|
+
data = read_to_end(io)
|
|
39
|
+
validate_frame_alignment!(data.bytesize, target_format)
|
|
40
|
+
samples = decode_samples(data, target_format, **encoding)
|
|
33
41
|
Core::SampleBuffer.new(samples, target_format)
|
|
34
42
|
ensure
|
|
35
43
|
io.close if close_io && io
|
|
@@ -41,16 +49,24 @@ module Wavify
|
|
|
41
49
|
# @param sample_buffer [Wavify::Core::SampleBuffer]
|
|
42
50
|
# @param format [Wavify::Core::Format]
|
|
43
51
|
# @return [String, IO]
|
|
44
|
-
def write(io_or_path, sample_buffer, format:
|
|
52
|
+
def write(io_or_path, sample_buffer, format:, endianness: :little, signed: nil, float_domain: :normalized,
|
|
53
|
+
**codec_options)
|
|
54
|
+
validate_no_codec_options!(codec_options, operation: "raw write")
|
|
45
55
|
raise InvalidParameterError, "sample_buffer must be Core::SampleBuffer" unless sample_buffer.is_a?(Core::SampleBuffer)
|
|
46
56
|
|
|
47
57
|
target_format = validate_format!(format)
|
|
58
|
+
encoding = normalize_raw_encoding(
|
|
59
|
+
target_format,
|
|
60
|
+
endianness: endianness,
|
|
61
|
+
signed: signed,
|
|
62
|
+
float_domain: float_domain
|
|
63
|
+
)
|
|
48
64
|
buffer = sample_buffer.format == target_format ? sample_buffer : sample_buffer.convert(target_format)
|
|
49
65
|
|
|
50
66
|
io, close_io = open_output(io_or_path)
|
|
51
|
-
io
|
|
52
|
-
io.
|
|
53
|
-
io
|
|
67
|
+
prepare_output!(io, owned: close_io)
|
|
68
|
+
write_all(io, encode_samples(buffer.samples, target_format, **encoding))
|
|
69
|
+
finalize_output!(io, owned: close_io)
|
|
54
70
|
io_or_path
|
|
55
71
|
ensure
|
|
56
72
|
io.close if close_io && io
|
|
@@ -62,23 +78,48 @@ module Wavify
|
|
|
62
78
|
# @param format [Wavify::Core::Format]
|
|
63
79
|
# @param chunk_size [Integer]
|
|
64
80
|
# @return [Enumerator]
|
|
65
|
-
def stream_read(io_or_path, format:, chunk_size: 4096
|
|
66
|
-
|
|
81
|
+
def stream_read(io_or_path, format:, chunk_size: 4096, endianness: :little, signed: nil,
|
|
82
|
+
float_domain: :normalized, **codec_options)
|
|
83
|
+
validate_no_codec_options!(codec_options, operation: "raw stream_read")
|
|
84
|
+
unless block_given?
|
|
85
|
+
return enum_for(
|
|
86
|
+
__method__,
|
|
87
|
+
io_or_path,
|
|
88
|
+
format: format,
|
|
89
|
+
chunk_size: chunk_size,
|
|
90
|
+
endianness: endianness,
|
|
91
|
+
signed: signed,
|
|
92
|
+
float_domain: float_domain,
|
|
93
|
+
**codec_options
|
|
94
|
+
)
|
|
95
|
+
end
|
|
67
96
|
|
|
68
97
|
target_format = validate_format!(format)
|
|
98
|
+
encoding = normalize_raw_encoding(
|
|
99
|
+
target_format,
|
|
100
|
+
endianness: endianness,
|
|
101
|
+
signed: signed,
|
|
102
|
+
float_domain: float_domain
|
|
103
|
+
)
|
|
69
104
|
io, close_io = open_input(io_or_path)
|
|
70
105
|
bytes_per_frame = target_format.block_align
|
|
71
106
|
raw_chunk_size = chunk_size * bytes_per_frame
|
|
107
|
+
pending = +"".b
|
|
72
108
|
|
|
73
109
|
loop do
|
|
74
110
|
chunk = io.read(raw_chunk_size)
|
|
75
111
|
break if chunk.nil? || chunk.empty?
|
|
76
112
|
|
|
77
|
-
|
|
113
|
+
pending << chunk
|
|
114
|
+
usable_bytes = pending.bytesize - (pending.bytesize % bytes_per_frame)
|
|
115
|
+
next if usable_bytes.zero?
|
|
78
116
|
|
|
79
|
-
|
|
117
|
+
frame_data = pending.byteslice(0, usable_bytes)
|
|
118
|
+
pending = pending.byteslice(usable_bytes, pending.bytesize - usable_bytes) || +"".b
|
|
119
|
+
samples = decode_samples(frame_data, target_format, **encoding)
|
|
80
120
|
yield Core::SampleBuffer.new(samples, target_format)
|
|
81
121
|
end
|
|
122
|
+
raise InvalidFormatError, "raw data ends with a partial sample frame" unless pending.empty?
|
|
82
123
|
ensure
|
|
83
124
|
io.close if close_io && io
|
|
84
125
|
end
|
|
@@ -88,22 +129,40 @@ module Wavify
|
|
|
88
129
|
# @param io_or_path [String, IO]
|
|
89
130
|
# @param format [Wavify::Core::Format]
|
|
90
131
|
# @return [Enumerator, String, IO]
|
|
91
|
-
def stream_write(io_or_path, format:
|
|
92
|
-
|
|
132
|
+
def stream_write(io_or_path, format:, endianness: :little, signed: nil, float_domain: :normalized,
|
|
133
|
+
**codec_options)
|
|
134
|
+
validate_no_codec_options!(codec_options, operation: "raw stream_write")
|
|
135
|
+
unless block_given?
|
|
136
|
+
return enum_for(
|
|
137
|
+
__method__,
|
|
138
|
+
io_or_path,
|
|
139
|
+
format: format,
|
|
140
|
+
endianness: endianness,
|
|
141
|
+
signed: signed,
|
|
142
|
+
float_domain: float_domain,
|
|
143
|
+
**codec_options
|
|
144
|
+
)
|
|
145
|
+
end
|
|
93
146
|
|
|
94
147
|
target_format = validate_format!(format)
|
|
148
|
+
encoding = normalize_raw_encoding(
|
|
149
|
+
target_format,
|
|
150
|
+
endianness: endianness,
|
|
151
|
+
signed: signed,
|
|
152
|
+
float_domain: float_domain
|
|
153
|
+
)
|
|
95
154
|
io, close_io = open_output(io_or_path)
|
|
155
|
+
prepare_output!(io, owned: close_io)
|
|
96
156
|
|
|
97
157
|
writer = lambda do |sample_buffer|
|
|
98
158
|
raise InvalidParameterError, "stream chunk must be Core::SampleBuffer" unless sample_buffer.is_a?(Core::SampleBuffer)
|
|
99
159
|
|
|
100
160
|
buffer = sample_buffer.format == target_format ? sample_buffer : sample_buffer.convert(target_format)
|
|
101
|
-
io
|
|
161
|
+
write_all(io, encode_samples(buffer.samples, target_format, **encoding))
|
|
102
162
|
end
|
|
103
163
|
|
|
104
164
|
yield writer
|
|
105
|
-
io
|
|
106
|
-
io.rewind if io.respond_to?(:rewind)
|
|
165
|
+
finalize_output!(io, owned: close_io)
|
|
107
166
|
io_or_path
|
|
108
167
|
ensure
|
|
109
168
|
io.close if close_io && io
|
|
@@ -114,10 +173,13 @@ module Wavify
|
|
|
114
173
|
# @param io_or_path [String, IO]
|
|
115
174
|
# @param format [Wavify::Core::Format]
|
|
116
175
|
# @return [Hash]
|
|
117
|
-
def metadata(io_or_path, format:)
|
|
176
|
+
def metadata(io_or_path, format:, endianness: :little, signed: nil, float_domain: :normalized, **codec_options)
|
|
177
|
+
validate_no_codec_options!(codec_options, operation: "raw metadata")
|
|
118
178
|
target_format = validate_format!(format)
|
|
179
|
+
normalize_raw_encoding(target_format, endianness: endianness, signed: signed, float_domain: float_domain)
|
|
119
180
|
io, close_io = open_input(io_or_path)
|
|
120
|
-
byte_size = io
|
|
181
|
+
byte_size = byte_size_without_consuming!(io)
|
|
182
|
+
validate_frame_alignment!(byte_size, target_format)
|
|
121
183
|
sample_frames = byte_size / target_format.block_align
|
|
122
184
|
|
|
123
185
|
{
|
|
@@ -137,54 +199,182 @@ module Wavify
|
|
|
137
199
|
format
|
|
138
200
|
end
|
|
139
201
|
|
|
140
|
-
def
|
|
202
|
+
def validate_frame_alignment!(byte_size, format)
|
|
203
|
+
return if (byte_size % format.block_align).zero?
|
|
204
|
+
|
|
205
|
+
raise InvalidFormatError, "raw data size does not align with format frame size"
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def byte_size_without_consuming!(io)
|
|
209
|
+
return io.size - io.pos if io.respond_to?(:size) && io.respond_to?(:pos)
|
|
210
|
+
return io.size if io.respond_to?(:size)
|
|
211
|
+
|
|
212
|
+
if io.respond_to?(:pos) && io.respond_to?(:seek)
|
|
213
|
+
original_position = io.pos
|
|
214
|
+
io.seek(0, IO::SEEK_END)
|
|
215
|
+
byte_size = io.pos - original_position
|
|
216
|
+
io.seek(original_position, IO::SEEK_SET)
|
|
217
|
+
return byte_size
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
raise InvalidParameterError, "raw metadata requires IO with size or seek support"
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def decode_samples(data, format, endianness:, signed:, float_domain:)
|
|
141
224
|
if format.sample_format == :float
|
|
142
|
-
|
|
143
|
-
|
|
225
|
+
directive = if format.bit_depth == 32
|
|
226
|
+
endianness == :little ? "e*" : "g*"
|
|
227
|
+
else
|
|
228
|
+
endianness == :little ? "E*" : "G*"
|
|
229
|
+
end
|
|
230
|
+
samples = data.unpack(directive)
|
|
231
|
+
validate_normalized_float_samples!(samples) if float_domain == :normalized
|
|
232
|
+
return samples
|
|
144
233
|
elsif format.sample_format == :pcm
|
|
145
|
-
return data
|
|
146
|
-
return data
|
|
147
|
-
return decode_pcm24(data) if format.bit_depth == 24
|
|
148
|
-
return data
|
|
234
|
+
return decode_pcm8(data, signed: signed) if format.bit_depth == 8
|
|
235
|
+
return decode_pcm_word(data, bits: 16, endianness: endianness, signed: signed) if format.bit_depth == 16
|
|
236
|
+
return decode_pcm24(data, endianness: endianness, signed: signed) if format.bit_depth == 24
|
|
237
|
+
return decode_pcm_word(data, bits: 32, endianness: endianness, signed: signed) if format.bit_depth == 32
|
|
149
238
|
end
|
|
150
239
|
|
|
151
240
|
raise UnsupportedFormatError, "unsupported raw format: #{format.sample_format}/#{format.bit_depth}"
|
|
152
241
|
end
|
|
153
242
|
|
|
154
|
-
def encode_samples(samples, format)
|
|
243
|
+
def encode_samples(samples, format, endianness:, signed:, float_domain:)
|
|
155
244
|
if format.sample_format == :float
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
245
|
+
values = if float_domain == :normalized
|
|
246
|
+
samples.map { |sample| sample.to_f.clamp(-1.0, 1.0) }
|
|
247
|
+
else
|
|
248
|
+
samples.map(&:to_f)
|
|
249
|
+
end
|
|
250
|
+
directive = if format.bit_depth == 32
|
|
251
|
+
endianness == :little ? "e*" : "g*"
|
|
252
|
+
else
|
|
253
|
+
endianness == :little ? "E*" : "G*"
|
|
254
|
+
end
|
|
255
|
+
return values.pack(directive)
|
|
159
256
|
elsif format.sample_format == :pcm
|
|
160
257
|
min = -(2**(format.bit_depth - 1))
|
|
161
258
|
max = (2**(format.bit_depth - 1)) - 1
|
|
162
259
|
ints = samples.map { |sample| sample.to_i.clamp(min, max) }
|
|
163
|
-
return ints
|
|
164
|
-
return ints
|
|
165
|
-
return encode_pcm24(ints) if format.bit_depth == 24
|
|
166
|
-
return ints
|
|
260
|
+
return encode_pcm8(ints, signed: signed) if format.bit_depth == 8
|
|
261
|
+
return encode_pcm_word(ints, bits: 16, endianness: endianness, signed: signed) if format.bit_depth == 16
|
|
262
|
+
return encode_pcm24(ints, endianness: endianness, signed: signed) if format.bit_depth == 24
|
|
263
|
+
return encode_pcm_word(ints, bits: 32, endianness: endianness, signed: signed) if format.bit_depth == 32
|
|
167
264
|
end
|
|
168
265
|
|
|
169
266
|
raise UnsupportedFormatError, "unsupported raw format: #{format.sample_format}/#{format.bit_depth}"
|
|
170
267
|
end
|
|
171
268
|
|
|
172
|
-
def
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
269
|
+
def decode_pcm8(data, signed:)
|
|
270
|
+
return data.unpack("c*") if signed
|
|
271
|
+
|
|
272
|
+
data.each_byte.map { |byte| byte - 128 }
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def encode_pcm8(samples, signed:)
|
|
276
|
+
return samples.pack("c*") if signed
|
|
277
|
+
|
|
278
|
+
samples.map { |sample| sample + 128 }.pack("C*")
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def decode_pcm_word(data, bits:, endianness:, signed:)
|
|
282
|
+
directive = pcm_word_directive(bits, endianness, signed)
|
|
283
|
+
values = data.unpack("#{directive}*")
|
|
284
|
+
return values if signed
|
|
285
|
+
|
|
286
|
+
midpoint = 2**(bits - 1)
|
|
287
|
+
values.map! { |value| value - midpoint }
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def encode_pcm_word(samples, bits:, endianness:, signed:)
|
|
291
|
+
directive = pcm_word_directive(bits, endianness, signed)
|
|
292
|
+
values = if signed
|
|
293
|
+
samples
|
|
294
|
+
else
|
|
295
|
+
midpoint = 2**(bits - 1)
|
|
296
|
+
samples.map { |sample| sample + midpoint }
|
|
297
|
+
end
|
|
298
|
+
values.pack("#{directive}*")
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def pcm_word_directive(bits, endianness, signed)
|
|
302
|
+
base = if bits == 16
|
|
303
|
+
signed ? "s" : "S"
|
|
304
|
+
else
|
|
305
|
+
signed ? "l" : "L"
|
|
306
|
+
end
|
|
307
|
+
"#{base}#{endianness == :little ? '<' : '>'}"
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def decode_pcm24(data, endianness:, signed:)
|
|
311
|
+
midpoint = 0x800000
|
|
312
|
+
samples = Array.new(data.bytesize / 3)
|
|
313
|
+
samples.length.times do |index|
|
|
314
|
+
offset = index * 3
|
|
315
|
+
first = data.getbyte(offset)
|
|
316
|
+
middle = data.getbyte(offset + 1)
|
|
317
|
+
last = data.getbyte(offset + 2)
|
|
318
|
+
value = if endianness == :little
|
|
319
|
+
first | (middle << 8) | (last << 16)
|
|
320
|
+
else
|
|
321
|
+
last | (middle << 8) | (first << 16)
|
|
322
|
+
end
|
|
323
|
+
samples[index] = signed ? (value.anybits?(midpoint) ? value - 0x1000000 : value) : value - midpoint
|
|
324
|
+
end
|
|
325
|
+
samples
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def encode_pcm24(samples, endianness:, signed:)
|
|
329
|
+
bytes = String.new(capacity: samples.length * 3, encoding: Encoding::BINARY)
|
|
330
|
+
samples.each do |sample|
|
|
331
|
+
value = signed ? (sample.negative? ? sample + 0x1000000 : sample) : sample + 0x800000
|
|
332
|
+
low = value & 0xFF
|
|
333
|
+
middle = (value >> 8) & 0xFF
|
|
334
|
+
high = (value >> 16) & 0xFF
|
|
335
|
+
if endianness == :little
|
|
336
|
+
bytes << low << middle << high
|
|
337
|
+
else
|
|
338
|
+
bytes << high << middle << low
|
|
339
|
+
end
|
|
178
340
|
end
|
|
341
|
+
bytes
|
|
179
342
|
end
|
|
180
343
|
|
|
181
|
-
def
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
[value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF]
|
|
344
|
+
def normalize_raw_encoding(format, endianness:, signed:, float_domain:)
|
|
345
|
+
byte_order = endianness.to_sym
|
|
346
|
+
unless %i[little big].include?(byte_order)
|
|
347
|
+
raise InvalidParameterError, "endianness must be :little or :big"
|
|
186
348
|
end
|
|
187
|
-
|
|
349
|
+
|
|
350
|
+
domain = float_domain.to_sym
|
|
351
|
+
unless %i[normalized ieee].include?(domain)
|
|
352
|
+
raise InvalidParameterError, "float_domain must be :normalized or :ieee"
|
|
353
|
+
end
|
|
354
|
+
if format.sample_format == :float
|
|
355
|
+
raise InvalidParameterError, "signed is only valid for PCM raw audio" unless signed.nil?
|
|
356
|
+
|
|
357
|
+
return { endianness: byte_order, signed: nil, float_domain: domain }
|
|
358
|
+
end
|
|
359
|
+
unless signed.nil? || signed == true || signed == false
|
|
360
|
+
raise InvalidParameterError, "signed must be true, false, or nil"
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
{
|
|
364
|
+
endianness: byte_order,
|
|
365
|
+
signed: signed.nil? ? format.bit_depth != 8 : signed,
|
|
366
|
+
float_domain: domain
|
|
367
|
+
}
|
|
368
|
+
rescue NoMethodError
|
|
369
|
+
raise InvalidParameterError, "endianness and float_domain must be Symbol/String"
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def validate_normalized_float_samples!(samples)
|
|
373
|
+
invalid_index = samples.index { |sample| !sample.finite? || !sample.between?(-1.0, 1.0) }
|
|
374
|
+
return unless invalid_index
|
|
375
|
+
|
|
376
|
+
raise InvalidFormatError,
|
|
377
|
+
"normalized raw float sample #{invalid_index} must be finite and within -1.0..1.0"
|
|
188
378
|
end
|
|
189
379
|
|
|
190
380
|
end
|