rockbox_ffi 0.1.0-x86_64-linux → 0.2.0-x86_64-linux
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/README.md +15 -1
- data/lib/rockbox_ffi/enums.rb +13 -0
- data/lib/rockbox_ffi/ffi.rb +17 -0
- data/lib/rockbox_ffi/player.rb +71 -4
- data/lib/rockbox_ffi/version.rb +1 -3
- data/lib/rockbox_ffi.rb +32 -0
- data/vendor/librockbox_ffi.so +0 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c46c84d8fca6ec61a8a637bd6b1b25a088c8338ec414d079494fe281ed94a447
|
|
4
|
+
data.tar.gz: 0ad499276a0b1f1207741779ec046305147aaf7cff424f17199966ffd97f7c39
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d6db591ee68da90ad6cb735c392ceedfda59339ee0fb6b483aee49534e1a1dcba691b926ebbf600a23668b3d93f1e69796843bdbabd5b8c2dec03e29081efe07
|
|
7
|
+
data.tar.gz: bdcf51dde9e3096b267ee502bc316ac7dad9b93b29ffb4815aa3c96a3909741033fb7805f45ff58ec94bb7fa8fcc4cfacee4bfc5aa701829978fb5fd8be392a9
|
data/README.md
CHANGED
|
@@ -95,7 +95,7 @@ ruby -Ilib examples/play.rb [path] # play a file through the output device
|
|
|
95
95
|
## Interactive console
|
|
96
96
|
|
|
97
97
|
```sh
|
|
98
|
-
|
|
98
|
+
bundle exec rake console # or: ./bin/console
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
Drops into IRB with `RockboxFFI` loaded and `FIXTURE` pointing at a sample
|
|
@@ -108,6 +108,20 @@ p.set_queue([FIXTURE]); p.play
|
|
|
108
108
|
p.status[:state] # => "playing"
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
+
The console bundles `irb` + `reline`, so **Tab autocompletion** and **syntax
|
|
112
|
+
highlighting** work out of the box — start typing `RockboxFFI::` and press
|
|
113
|
+
`Tab`. Both are on by default; toggle per-session with `irb --noautocomplete`,
|
|
114
|
+
or persist preferences in `~/.irbrc`:
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
IRB.conf[:USE_AUTOCOMPLETE] = true
|
|
118
|
+
IRB.conf[:USE_COLORIZE] = true
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
> Run the console under a modern Ruby (3.x/4.x, e.g. Homebrew's
|
|
122
|
+
> `/opt/homebrew/opt/ruby`). macOS system Ruby 2.6 can't build `fiddle`'s
|
|
123
|
+
> native extension, so `bundle install` fails there.
|
|
124
|
+
|
|
111
125
|
## Test
|
|
112
126
|
|
|
113
127
|
```sh
|
data/lib/rockbox_ffi/enums.rb
CHANGED
|
@@ -32,6 +32,19 @@ module RockboxFFI
|
|
|
32
32
|
MIX = 1
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
# Where inserted tracks land in the queue (Player#insert / #import_m3u).
|
|
36
|
+
# INDEX (7) uses the explicit +index+ argument.
|
|
37
|
+
module InsertPosition
|
|
38
|
+
PREPEND = 0
|
|
39
|
+
INSERT = 1
|
|
40
|
+
INSERT_NEXT = 2
|
|
41
|
+
INSERT_LAST = 3
|
|
42
|
+
INSERT_SHUFFLED = 4
|
|
43
|
+
INSERT_LAST_SHUFFLED = 5
|
|
44
|
+
REPLACE = 6
|
|
45
|
+
INDEX = 7
|
|
46
|
+
end
|
|
47
|
+
|
|
35
48
|
module ChannelConfig
|
|
36
49
|
STEREO = 0
|
|
37
50
|
MONO = 1
|
data/lib/rockbox_ffi/ffi.rb
CHANGED
|
@@ -101,9 +101,12 @@ module RockboxFFI
|
|
|
101
101
|
# ---- player -------------------------------------------------------
|
|
102
102
|
extern "void* rb_player_new()"
|
|
103
103
|
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)"
|
|
104
|
+
extern "void* rb_player_new_with_config_ex(uint32_t, float, float, int32_t, float, bool, int32_t, uint32_t, uint32_t, uint32_t, uint32_t, int32_t, void*, uint32_t)"
|
|
104
105
|
extern "void rb_player_free(void*)"
|
|
105
106
|
extern "void rb_player_set_queue_json(void*, void*)"
|
|
106
107
|
extern "void rb_player_enqueue(void*, void*)"
|
|
108
|
+
extern "void rb_player_insert_json(void*, void*, int32_t, size_t)"
|
|
109
|
+
extern "void* rb_player_queue_json(void*)"
|
|
107
110
|
extern "void rb_player_play(void*)"
|
|
108
111
|
extern "void rb_player_pause(void*)"
|
|
109
112
|
extern "void rb_player_toggle(void*)"
|
|
@@ -118,6 +121,20 @@ module RockboxFFI
|
|
|
118
121
|
extern "float rb_player_volume(void*)"
|
|
119
122
|
extern "uint32_t rb_player_sample_rate(void*)"
|
|
120
123
|
extern "void* rb_player_status_json(void*)"
|
|
124
|
+
|
|
125
|
+
# ---- resume -------------------------------------------------------
|
|
126
|
+
extern "void* rb_player_resume(void*)"
|
|
127
|
+
extern "void rb_player_save_resume(void*)"
|
|
128
|
+
extern "void rb_player_clear_resume(void*)"
|
|
129
|
+
extern "void* rb_load_resume_json(void*)"
|
|
130
|
+
|
|
131
|
+
# ---- m3u / m3u8 playlists -----------------------------------------
|
|
132
|
+
extern "void* rb_player_import_m3u(void*, void*, int32_t, size_t)"
|
|
133
|
+
extern "void* rb_player_load_m3u(void*, void*)"
|
|
134
|
+
extern "int32_t rb_player_export_m3u(void*, void*)"
|
|
135
|
+
extern "void* rb_m3u_read_json(void*)"
|
|
136
|
+
extern "int32_t rb_m3u_write_json(void*, void*)"
|
|
137
|
+
extern "bool rb_is_url(void*)"
|
|
121
138
|
end
|
|
122
139
|
|
|
123
140
|
# true/false → 1/0 for the ABI's `bool` (declared as int above).
|
data/lib/rockbox_ffi/player.rb
CHANGED
|
@@ -24,7 +24,9 @@ module RockboxFFI
|
|
|
24
24
|
fade_out_duration_ms: 2000,
|
|
25
25
|
fade_in_delay_ms: 0,
|
|
26
26
|
fade_in_duration_ms: 2000,
|
|
27
|
-
mix_mode: MixMode::CROSSFADE
|
|
27
|
+
mix_mode: MixMode::CROSSFADE,
|
|
28
|
+
resume_file: nil, # an .m3u8 to auto-persist queue + position to
|
|
29
|
+
resume_save_interval_ms: 0 # 0 => 5 s default
|
|
28
30
|
}.freeze
|
|
29
31
|
|
|
30
32
|
# Open a Player; if a block is given, close it automatically afterwards.
|
|
@@ -47,16 +49,19 @@ module RockboxFFI
|
|
|
47
49
|
end
|
|
48
50
|
|
|
49
51
|
# Create a player with configuration overrides (see DEFAULT_CONFIG keys).
|
|
50
|
-
# sample_rate: 0 means the device default.
|
|
52
|
+
# sample_rate: 0 means the device default. Passing +resume_file:+ enables
|
|
53
|
+
# auto-persisting the queue + exact position to that .m3u8 file.
|
|
51
54
|
def initialize(**opts)
|
|
52
55
|
c = DEFAULT_CONFIG.merge(opts)
|
|
53
|
-
|
|
56
|
+
resume_file = c[:resume_file].nil? ? nil : c[:resume_file].to_s
|
|
57
|
+
ptr = Lib.rb_player_new_with_config_ex(
|
|
54
58
|
Integer(c[:sample_rate]), Float(c[:buffer_seconds]), Float(c[:volume]),
|
|
55
59
|
Integer(c[:replaygain_mode]), Float(c[:replaygain_preamp_db]),
|
|
56
60
|
RockboxFFI.b(c[:replaygain_prevent_clipping]), Integer(c[:crossfade_mode]),
|
|
57
61
|
Integer(c[:fade_out_delay_ms]), Integer(c[:fade_out_duration_ms]),
|
|
58
62
|
Integer(c[:fade_in_delay_ms]), Integer(c[:fade_in_duration_ms]),
|
|
59
|
-
Integer(c[:mix_mode])
|
|
63
|
+
Integer(c[:mix_mode]), resume_file,
|
|
64
|
+
Integer(c[:resume_save_interval_ms])
|
|
60
65
|
)
|
|
61
66
|
init_ptr(ptr)
|
|
62
67
|
end
|
|
@@ -88,6 +93,23 @@ module RockboxFFI
|
|
|
88
93
|
Lib.rb_player_enqueue(@ptr, path.to_s)
|
|
89
94
|
end
|
|
90
95
|
|
|
96
|
+
# Insert +paths+ (a path/URL or Array of them) into the queue at
|
|
97
|
+
# +position+ (see InsertPosition). +index+ is only used when position is
|
|
98
|
+
# InsertPosition::INDEX (7).
|
|
99
|
+
def insert(paths, position, index = 0)
|
|
100
|
+
Lib.rb_player_insert_json(
|
|
101
|
+
@ptr, JSON.generate(Array(paths).map(&:to_s)), Integer(position), Integer(index)
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# The current queue as an Array of String paths/URLs.
|
|
106
|
+
def queue
|
|
107
|
+
s = RockboxFFI.take_string(Lib.rb_player_queue_json(@ptr))
|
|
108
|
+
return [] if s.nil?
|
|
109
|
+
|
|
110
|
+
JSON.parse(s)
|
|
111
|
+
end
|
|
112
|
+
|
|
91
113
|
# -- transport --------------------------------------------------------
|
|
92
114
|
def play
|
|
93
115
|
Lib.rb_player_play(@ptr)
|
|
@@ -157,6 +179,51 @@ module RockboxFFI
|
|
|
157
179
|
JSON.parse(s, symbolize_names: true)
|
|
158
180
|
end
|
|
159
181
|
|
|
182
|
+
# -- resume -----------------------------------------------------------
|
|
183
|
+
# Restore the queue + exact position from the resume file (does NOT
|
|
184
|
+
# auto-play). Returns a Hash {tracks:, index:, elapsed_ms:} or nil.
|
|
185
|
+
def resume
|
|
186
|
+
s = RockboxFFI.take_string(Lib.rb_player_resume(@ptr))
|
|
187
|
+
return nil if s.nil?
|
|
188
|
+
|
|
189
|
+
JSON.parse(s, symbolize_names: true)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Force-persist the current queue + position to the resume file now.
|
|
193
|
+
def save_resume
|
|
194
|
+
Lib.rb_player_save_resume(@ptr)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Delete the resume file.
|
|
198
|
+
def clear_resume
|
|
199
|
+
Lib.rb_player_clear_resume(@ptr)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# -- m3u / m3u8 playlists ---------------------------------------------
|
|
203
|
+
# Import a playlist file into the queue at +position+ (see InsertPosition;
|
|
204
|
+
# +index+ only used for INDEX). Returns the imported paths as an Array.
|
|
205
|
+
def import_m3u(path, position, index = 0)
|
|
206
|
+
s = RockboxFFI.take_string(
|
|
207
|
+
Lib.rb_player_import_m3u(@ptr, path.to_s, Integer(position), Integer(index))
|
|
208
|
+
)
|
|
209
|
+
return [] if s.nil?
|
|
210
|
+
|
|
211
|
+
JSON.parse(s)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Replace the queue with a playlist file. Returns the loaded paths as an Array.
|
|
215
|
+
def load_m3u(path)
|
|
216
|
+
s = RockboxFFI.take_string(Lib.rb_player_load_m3u(@ptr, path.to_s))
|
|
217
|
+
return [] if s.nil?
|
|
218
|
+
|
|
219
|
+
JSON.parse(s)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Export the current queue to an .m3u8 (atomic). Returns true on success.
|
|
223
|
+
def export_m3u(path)
|
|
224
|
+
Lib.rb_player_export_m3u(@ptr, path.to_s).zero?
|
|
225
|
+
end
|
|
226
|
+
|
|
160
227
|
private
|
|
161
228
|
|
|
162
229
|
def init_ptr(ptr)
|
data/lib/rockbox_ffi/version.rb
CHANGED
data/lib/rockbox_ffi.rb
CHANGED
|
@@ -12,9 +12,41 @@ require "rockbox_ffi/metadata"
|
|
|
12
12
|
require "rockbox_ffi/dsp"
|
|
13
13
|
require "rockbox_ffi/player"
|
|
14
14
|
|
|
15
|
+
require "json"
|
|
16
|
+
|
|
15
17
|
module RockboxFFI
|
|
16
18
|
# ABI major version of the loaded library (bumped on breaking changes).
|
|
17
19
|
def self.abi_version
|
|
18
20
|
Lib.rb_ffi_abi_version
|
|
19
21
|
end
|
|
22
|
+
|
|
23
|
+
# Peek at a resume file without a Player. Returns a Hash
|
|
24
|
+
# {tracks:, index:, elapsed_ms:} or nil if the file is absent/invalid.
|
|
25
|
+
def self.load_resume(path)
|
|
26
|
+
s = take_string(Lib.rb_load_resume_json(path.to_s))
|
|
27
|
+
return nil if s.nil?
|
|
28
|
+
|
|
29
|
+
JSON.parse(s, symbolize_names: true)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Parse a playlist (.m3u / .m3u8) into an Array of Hashes
|
|
33
|
+
# {path:, duration_ms:, title:}. Returns nil on failure.
|
|
34
|
+
def self.m3u_read(path)
|
|
35
|
+
s = take_string(Lib.rb_m3u_read_json(path.to_s))
|
|
36
|
+
return nil if s.nil?
|
|
37
|
+
|
|
38
|
+
JSON.parse(s, symbolize_names: true)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Write +paths+ (a path/URL or Array of them) as an .m3u8. Returns true on
|
|
42
|
+
# success.
|
|
43
|
+
def self.m3u_write(path, paths)
|
|
44
|
+
Lib.rb_m3u_write_json(path.to_s, JSON.generate(Array(paths).map(&:to_s))).zero?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Whether +s+ looks like an http(s):// URL.
|
|
48
|
+
def self.is_url?(s)
|
|
49
|
+
r = Lib.rb_is_url(s.to_s)
|
|
50
|
+
r == true || r == 1
|
|
51
|
+
end
|
|
20
52
|
end
|
data/vendor/librockbox_ffi.so
CHANGED
|
Binary file
|
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.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: x86_64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Tsiry Sandratraina
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: fiddle
|