rockbox_ffi 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65435e6c7a7b4ef8e59f3bc088ce2c9eb978b34d49e134c3e42413e9790bb333
4
- data.tar.gz: 0d14838882902eaa6818a9726518f0c782848ad34e09b6afe6ca9ddbbf6cdd1a
3
+ metadata.gz: 9e881324e0bb82a716a98417325a1ec9823d3a0f1f015444c6e2332f7b942c65
4
+ data.tar.gz: 70e45aa728fb5d2449e1849f993780a0dad201f32113eb4f352344df0bed1fb6
5
5
  SHA512:
6
- metadata.gz: f4275075ebc6d35b7b495dfc3a081b97960f5dc81f8f279372acf5b852fc0723776f536f9f87602811499a23d1653de9a8c5b072144444fe15dd0cd4b4dc1066
7
- data.tar.gz: 5b4a35ca244aed1f570cf2d639a131eb8244645fe4ebe86513193345a95716107c72c67f7037f195e8048bff4f885c1d3c8af1fdd218ffabcf200860b841e363
6
+ metadata.gz: b76132c6b6db3f4eee20a990707b9e65e4a7a65cd490f1d690dbf0c8c72338a7c855cf75c12deb74171d6dd3833f2394dc33ad745e87172b0d1423e631e32f59
7
+ data.tar.gz: 7ef952e10d6a0728a4ef251ef43480ab6bc4d5d7fe3b7514b3c933f9cef99768ec129552f964cf3641ed98973e5831ab6272690f30b4c0fc6eca8a02d06d0f0e
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module RockboxFFI
6
+ # Decode a local audio file to interleaved-stereo S16 PCM, one chunk at a
7
+ # time, using the Rockbox codec engine.
8
+ #
9
+ # The codec state is process-wide, so only one Decoder may decode at a time
10
+ # and it must be used from one thread. Call #close when done, or use the block
11
+ # form Decoder.open(path) { |dec| ... }.
12
+ class Decoder
13
+ # Open a Decoder for +path+; if a block is given, close it automatically
14
+ # afterwards.
15
+ def self.open(path)
16
+ dec = new(path)
17
+ return dec unless block_given?
18
+
19
+ begin
20
+ yield dec
21
+ ensure
22
+ dec.close
23
+ end
24
+ end
25
+
26
+ def initialize(path)
27
+ @ptr = Lib.rb_decoder_open(path.to_s)
28
+ raise "could not open decoder for #{path.inspect}" if @ptr.null?
29
+
30
+ @finalizer = self.class.send(:finalizer, @ptr)
31
+ ObjectSpace.define_finalizer(self, @finalizer)
32
+ end
33
+
34
+ # -- lifecycle --------------------------------------------------------
35
+ def close
36
+ return if @ptr.nil?
37
+
38
+ ObjectSpace.undefine_finalizer(self)
39
+ Lib.rb_decoder_free(@ptr)
40
+ @ptr = nil
41
+ end
42
+
43
+ def closed?
44
+ @ptr.nil?
45
+ end
46
+
47
+ def self.finalizer(ptr)
48
+ proc { Lib.rb_decoder_free(ptr) }
49
+ end
50
+ private_class_method :finalizer
51
+
52
+ # -- metadata ---------------------------------------------------------
53
+ # Tags and stream properties (same shape as Metadata.read). Returns a Hash
54
+ # with symbol keys. Raises on failure.
55
+ def metadata
56
+ s = RockboxFFI.take_string(Lib.rb_decoder_metadata_json(@ptr))
57
+ raise "rb_decoder_metadata_json returned NULL" if s.nil?
58
+
59
+ JSON.parse(s, symbolize_names: true)
60
+ end
61
+
62
+ # -- decoding ---------------------------------------------------------
63
+ # Next buffer of decoded PCM as +[samples, sample_rate]+, where +samples+
64
+ # is an Array of interleaved stereo int16 Integers. Returns nil at end of
65
+ # track (or after a codec error — see #finished).
66
+ def next_chunk
67
+ out_len = "\0" * Fiddle::SIZEOF_VOIDP # size_t* out-param (i16 count)
68
+ out_rate = "\0" * Fiddle::SIZEOF_INT # uint32_t* out-param (Hz)
69
+ ptr = Lib.rb_decoder_next_chunk(@ptr, out_len, out_rate)
70
+
71
+ produced = out_len.unpack1(Fiddle::SIZEOF_VOIDP == 8 ? "Q" : "L")
72
+ return nil if ptr.null? || produced.zero?
73
+
74
+ rate = out_rate.unpack1("L")
75
+ begin
76
+ ptr.size = produced * 2
77
+ [ptr[0, produced * 2].unpack("s<*"), rate]
78
+ ensure
79
+ Lib.rb_buffer_free(ptr, produced)
80
+ end
81
+ end
82
+
83
+ # Yield each +[samples, sample_rate]+ chunk until end of track. Returns an
84
+ # Enumerator when no block is given.
85
+ def each_chunk
86
+ return enum_for(:each_chunk) unless block_given?
87
+
88
+ while (chunk = next_chunk)
89
+ yield chunk
90
+ end
91
+ end
92
+
93
+ # Request a seek to +ms+ milliseconds.
94
+ def seek_ms(ms)
95
+ Lib.rb_decoder_seek_ms(@ptr, Integer(ms))
96
+ end
97
+
98
+ # Playback position last reported by the codec, in milliseconds.
99
+ def elapsed_ms
100
+ Lib.rb_decoder_elapsed_ms(@ptr)
101
+ end
102
+
103
+ # +[done, code]+: +done+ is true once the track has ended; +code+ is the
104
+ # exit status (0 = clean end, negative = codec error), valid only when
105
+ # +done+.
106
+ def finished
107
+ out_code = "\0" * Fiddle::SIZEOF_INT # int32_t* out-param
108
+ r = Lib.rb_decoder_finished(@ptr, out_code)
109
+ done = r == true || r == 1
110
+ [done, out_code.unpack1("l")]
111
+ end
112
+ end
113
+ end
@@ -98,6 +98,15 @@ module RockboxFFI
98
98
  extern "void* rb_meta_read_json(void*)"
99
99
  extern "void* rb_meta_probe(void*)"
100
100
 
101
+ # ---- decoder ------------------------------------------------------
102
+ extern "void* rb_decoder_open(void*)"
103
+ extern "void rb_decoder_free(void*)"
104
+ extern "void* rb_decoder_metadata_json(void*)"
105
+ extern "int16_t* rb_decoder_next_chunk(void*, void*, void*)"
106
+ extern "void rb_decoder_seek_ms(void*, uint64_t)"
107
+ extern "uint64_t rb_decoder_elapsed_ms(void*)"
108
+ extern "bool rb_decoder_finished(void*, void*)"
109
+
101
110
  # ---- player -------------------------------------------------------
102
111
  extern "void* rb_player_new()"
103
112
  extern "void* rb_player_new_with_config(uint32_t, float, float, int32_t, float, bool, int32_t, uint32_t, uint32_t, uint32_t, uint32_t, int32_t)"
@@ -116,9 +125,11 @@ module RockboxFFI
116
125
  extern "void rb_player_skip_to(void*, size_t)"
117
126
  extern "void rb_player_seek_ms(void*, uint64_t)"
118
127
  extern "void rb_player_set_volume(void*, float)"
128
+ extern "void rb_player_set_balance(void*, int32_t)"
119
129
  extern "void rb_player_set_crossfade(void*, int32_t, uint32_t, uint32_t, uint32_t, uint32_t, int32_t)"
120
130
  extern "void rb_player_set_replaygain(void*, int32_t, float, bool)"
121
131
  extern "float rb_player_volume(void*)"
132
+ extern "int32_t rb_player_balance(void*)"
122
133
  extern "uint32_t rb_player_sample_rate(void*)"
123
134
  extern "void* rb_player_status_json(void*)"
124
135
  extern "void rb_player_set_shuffle(void*, bool)"
@@ -169,10 +169,21 @@ module RockboxFFI
169
169
  self
170
170
  end
171
171
 
172
+ # Stereo balance, -100 (full left) to +100 (full right); 0 = centre.
173
+ def set_balance(balance)
174
+ Lib.rb_player_set_balance(@ptr, Integer(balance))
175
+ self
176
+ end
177
+
172
178
  def volume
173
179
  Lib.rb_player_volume(@ptr)
174
180
  end
175
181
 
182
+ # Current stereo balance, -100 (full left) to +100 (full right).
183
+ def balance
184
+ Lib.rb_player_balance(@ptr)
185
+ end
186
+
176
187
  def sample_rate
177
188
  Lib.rb_player_sample_rate(@ptr)
178
189
  end
@@ -1,3 +1,3 @@
1
1
  module RockboxFFI
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/rockbox_ffi.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  # Ruby bindings for the Rockbox DSP / metadata / playback engine.
4
4
  #
5
5
  # Thin Fiddle wrappers over the librockbox_ffi C ABI. See RockboxFFI::Metadata,
6
- # RockboxFFI::Dsp, and RockboxFFI::Player.
6
+ # RockboxFFI::Dsp, RockboxFFI::Player, and RockboxFFI::Decoder.
7
7
 
8
8
  require "rockbox_ffi/version"
9
9
  require "rockbox_ffi/ffi"
@@ -11,6 +11,7 @@ require "rockbox_ffi/enums"
11
11
  require "rockbox_ffi/metadata"
12
12
  require "rockbox_ffi/dsp"
13
13
  require "rockbox_ffi/player"
14
+ require "rockbox_ffi/decoder"
14
15
 
15
16
  require "json"
16
17
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rockbox_ffi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tsiry Sandratraina
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-12 00:00:00.000000000 Z
11
+ date: 2026-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fiddle
@@ -37,6 +37,7 @@ files:
37
37
  - examples/play.rb
38
38
  - examples/smoke.rb
39
39
  - lib/rockbox_ffi.rb
40
+ - lib/rockbox_ffi/decoder.rb
40
41
  - lib/rockbox_ffi/dsp.rb
41
42
  - lib/rockbox_ffi/enums.rb
42
43
  - lib/rockbox_ffi/ffi.rb