Module: RockboxFFI

Defined in:
lib/rockbox_ffi.rb,
lib/rockbox_ffi/dsp.rb,
lib/rockbox_ffi/ffi.rb,
lib/rockbox_ffi/enums.rb,
lib/rockbox_ffi/player.rb,
lib/rockbox_ffi/decoder.rb,
lib/rockbox_ffi/version.rb,
lib/rockbox_ffi/metadata.rb

Defined Under Namespace

Modules: ChannelConfig, ChannelMode, CrossfadeMode, CrossfeedMode, DspReplayGainMode, EqPreset, InsertPosition, Lib, Metadata, MixMode, RepeatMode, ReplayGainMode Classes: Decoder, Dsp, Player

Constant Summary collapse

VERSION =
"0.4.0"

Class Method Summary collapse

Class Method Details

.abi_versionObject

ABI major version of the loaded library (bumped on breaking changes).



20
21
22
# File 'lib/rockbox_ffi.rb', line 20

def self.abi_version
  Lib.rb_ffi_abi_version
end

.b(flag) ⇒ Object

true/false → 1/0 for the ABI's bool (declared as int above).



178
179
180
# File 'lib/rockbox_ffi/ffi.rb', line 178

def self.b(flag)
  flag ? 1 : 0
end

.is_url?(s) ⇒ Boolean

Whether s looks like an http(s):// URL.

Returns:

  • (Boolean)


49
50
51
52
# File 'lib/rockbox_ffi.rb', line 49

def self.is_url?(s)
  r = Lib.rb_is_url(s.to_s)
  r == true || r == 1
end

.library_pathObject

Locate the prebuilt shared library. Precedence:

1. ROCKBOX_FFI_LIB env var (explicit override)
2. the platform binary bundled in the gem's vendor/ dir (published gems)
3. target/release, by walking up from here (repo checkout / dev)

Raises:

  • (LoadError)


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/rockbox_ffi/ffi.rb', line 18

def self.library_path
  names = %w[librockbox_ffi.dylib librockbox_ffi.so rockbox_ffi.dll]
  tried = []

  if (env = ENV["ROCKBOX_FFI_LIB"])
    tried << env
    return env if File.exist?(env)
  end

  # Bundled binary (platform gems ship one under <gem_root>/vendor/).
  vendor = File.expand_path("../../vendor", __dir__)
  names.each do |name|
    cand = File.join(vendor, name)
    tried << cand
    return cand if File.exist?(cand)
  end

  # Walk up from this file looking for target/release (repo checkout).
  dir = File.expand_path(__dir__)
  loop do
    rel = File.join(dir, "target", "release")
    if File.directory?(rel)
      names.each do |name|
        cand = File.join(rel, name)
        tried << cand
        return cand if File.exist?(cand)
      end
    end
    parent = File.dirname(dir)
    break if parent == dir

    dir = parent
  end

  raise LoadError, "could not locate librockbox_ffi shared library. Set " \
                   "ROCKBOX_FFI_LIB or run `cargo build --release -p " \
                   "rockbox-ffi`. Tried:\n  #{tried.join("\n  ")}"
end

.load_resume(path) ⇒ Object

Peek at a resume file without a Player. Returns a Hash index:, elapsed_ms: or nil if the file is absent/invalid.



26
27
28
29
30
31
# File 'lib/rockbox_ffi.rb', line 26

def self.load_resume(path)
  s = take_string(Lib.rb_load_resume_json(path.to_s))
  return nil if s.nil?

  JSON.parse(s, symbolize_names: true)
end

.m3u_read(path) ⇒ Object

Parse a playlist (.m3u / .m3u8) into an Array of Hashes duration_ms:, title:. Returns nil on failure.



35
36
37
38
39
40
# File 'lib/rockbox_ffi.rb', line 35

def self.m3u_read(path)
  s = take_string(Lib.rb_m3u_read_json(path.to_s))
  return nil if s.nil?

  JSON.parse(s, symbolize_names: true)
end

.m3u_write(path, paths) ⇒ Object

Write paths (a path/URL or Array of them) as an .m3u8. Returns true on success.



44
45
46
# File 'lib/rockbox_ffi.rb', line 44

def self.m3u_write(path, paths)
  Lib.rb_m3u_write_json(path.to_s, JSON.generate(Array(paths).map(&:to_s))).zero?
end

.sine_stereo(freq_hz, seconds, rate, amplitude = 16_000) ⇒ Object

Generate seconds of a sine as interleaved stereo int16 (an Array).



152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/rockbox_ffi/dsp.rb', line 152

def self.sine_stereo(freq_hz, seconds, rate, amplitude = 16_000)
  n = (seconds * rate).to_i
  buf = Array.new(n * 2)
  (0...n).each do |i|
    s = (Math.sin(i * 2.0 * Math::PI * freq_hz / rate) * amplitude).to_i
    s = -32_768 if s < -32_768
    s = 32_767 if s > 32_767
    buf[i * 2] = s
    buf[(i * 2) + 1] = s
  end
  buf
end

.take_string(ptr) ⇒ Object

Copy a heap C string returned by the ABI into a String, then free it. Returns nil for a NULL pointer (the ABI's error/absent signal).



184
185
186
187
188
189
190
191
192
# File 'lib/rockbox_ffi/ffi.rb', line 184

def self.take_string(ptr)
  return nil if ptr.null?

  begin
    ptr.to_s.force_encoding("UTF-8")
  ensure
    Lib.rb_string_free(ptr)
  end
end