Class: RockboxFFI::Decoder
- Inherits:
-
Object
- Object
- RockboxFFI::Decoder
- Defined in:
- lib/rockbox_ffi/decoder.rb
Overview
Decode a local audio file to interleaved-stereo S16 PCM, one chunk at a time, using the Rockbox codec engine.
The codec state is process-wide, so only one Decoder may decode at a time and it must be used from one thread. Call #close when done, or use the block form Decoder.open(path) { |dec| ... }.
Class Method Summary collapse
-
.open(path) ⇒ Object
Open a Decoder for
path; if a block is given, close it automatically afterwards.
Instance Method Summary collapse
-
#close ⇒ Object
-- lifecycle --------------------------------------------------------.
- #closed? ⇒ Boolean
-
#each_chunk ⇒ Object
Yield each
[samples, sample_rate]chunk until end of track. -
#elapsed_ms ⇒ Object
Playback position last reported by the codec, in milliseconds.
-
#finished ⇒ Object
[done, code]:doneis true once the track has ended;codeis the exit status (0 = clean end, negative = codec error), valid only whendone. -
#initialize(path) ⇒ Decoder
constructor
A new instance of Decoder.
-
#metadata ⇒ Object
-- metadata --------------------------------------------------------- Tags and stream properties (same shape as Metadata.read).
-
#next_chunk ⇒ Object
-- decoding --------------------------------------------------------- Next buffer of decoded PCM as
[samples, sample_rate], wheresamplesis an Array of interleaved stereo int16 Integers. -
#seek_ms(ms) ⇒ Object
Request a seek to
msmilliseconds.
Constructor Details
#initialize(path) ⇒ Decoder
Returns a new instance of Decoder.
26 27 28 29 30 31 32 |
# File 'lib/rockbox_ffi/decoder.rb', line 26 def initialize(path) @ptr = Lib.rb_decoder_open(path.to_s) raise "could not open decoder for #{path.inspect}" if @ptr.null? @finalizer = self.class.send(:finalizer, @ptr) ObjectSpace.define_finalizer(self, @finalizer) end |
Class Method Details
.open(path) ⇒ Object
Open a Decoder for path; if a block is given, close it automatically
afterwards.
15 16 17 18 19 20 21 22 23 24 |
# File 'lib/rockbox_ffi/decoder.rb', line 15 def self.open(path) dec = new(path) return dec unless block_given? begin yield dec ensure dec.close end end |
Instance Method Details
#close ⇒ Object
-- lifecycle --------------------------------------------------------
35 36 37 38 39 40 41 |
# File 'lib/rockbox_ffi/decoder.rb', line 35 def close return if @ptr.nil? ObjectSpace.undefine_finalizer(self) Lib.rb_decoder_free(@ptr) @ptr = nil end |
#closed? ⇒ Boolean
43 44 45 |
# File 'lib/rockbox_ffi/decoder.rb', line 43 def closed? @ptr.nil? end |
#each_chunk ⇒ Object
Yield each [samples, sample_rate] chunk until end of track. Returns an
Enumerator when no block is given.
85 86 87 88 89 90 91 |
# File 'lib/rockbox_ffi/decoder.rb', line 85 def each_chunk return enum_for(:each_chunk) unless block_given? while (chunk = next_chunk) yield chunk end end |
#elapsed_ms ⇒ Object
Playback position last reported by the codec, in milliseconds.
99 100 101 |
# File 'lib/rockbox_ffi/decoder.rb', line 99 def elapsed_ms Lib.rb_decoder_elapsed_ms(@ptr) end |
#finished ⇒ Object
[done, code]: done is true once the track has ended; code is the
exit status (0 = clean end, negative = codec error), valid only when
done.
106 107 108 109 110 111 |
# File 'lib/rockbox_ffi/decoder.rb', line 106 def finished out_code = "\0" * Fiddle::SIZEOF_INT # int32_t* out-param r = Lib.rb_decoder_finished(@ptr, out_code) done = r == true || r == 1 [done, out_code.unpack1("l")] end |
#metadata ⇒ Object
-- metadata --------------------------------------------------------- Tags and stream properties (same shape as Metadata.read). Returns a Hash with symbol keys. Raises on failure.
55 56 57 58 59 60 |
# File 'lib/rockbox_ffi/decoder.rb', line 55 def s = RockboxFFI.take_string(Lib.(@ptr)) raise "rb_decoder_metadata_json returned NULL" if s.nil? JSON.parse(s, symbolize_names: true) end |
#next_chunk ⇒ Object
-- decoding ---------------------------------------------------------
Next buffer of decoded PCM as [samples, sample_rate], where samples
is an Array of interleaved stereo int16 Integers. Returns nil at end of
track (or after a codec error — see #finished).
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/rockbox_ffi/decoder.rb', line 66 def next_chunk out_len = "\0" * Fiddle::SIZEOF_VOIDP # size_t* out-param (i16 count) out_rate = "\0" * Fiddle::SIZEOF_INT # uint32_t* out-param (Hz) ptr = Lib.rb_decoder_next_chunk(@ptr, out_len, out_rate) produced = out_len.unpack1(Fiddle::SIZEOF_VOIDP == 8 ? "Q" : "L") return nil if ptr.null? || produced.zero? rate = out_rate.unpack1("L") begin ptr.size = produced * 2 [ptr[0, produced * 2].unpack("s<*"), rate] ensure Lib.rb_buffer_free(ptr, produced) end end |
#seek_ms(ms) ⇒ Object
Request a seek to ms milliseconds.
94 95 96 |
# File 'lib/rockbox_ffi/decoder.rb', line 94 def seek_ms(ms) Lib.rb_decoder_seek_ms(@ptr, Integer(ms)) end |