Class: RockboxFFI::Player

Inherits:
Object
  • Object
show all
Defined in:
lib/rockbox_ffi/player.rb

Overview

Queue-based player with native ReplayGain and Rockbox crossfade.

A Player owns a live audio output device and a background engine thread — construct it only where an output device exists. Call #close when done, or use the block form Player.open(...) { |p| ... }.

ReplayGain mode here uses the player values: 0 off, 1 track, 2 album (see ReplayGainMode) — distinct from the DSP encoding.

Mutating setters (queue, transport, settings, DSP) return self so calls can be fluently chained, e.g. player.set_queue([file]).set_shuffle(true).play Getters/queries and lifecycle methods keep their own return values.

Constant Summary collapse

DEFAULT_CONFIG =
{
  sample_rate: 0, # 0 => device default
  buffer_seconds: 4.0,
  volume: 1.0,
  replaygain_mode: ReplayGainMode::OFF,
  replaygain_preamp_db: 0.0,
  replaygain_prevent_clipping: true,
  crossfade_mode: CrossfadeMode::OFF,
  fade_out_delay_ms: 0,
  fade_out_duration_ms: 2000,
  fade_in_delay_ms: 0,
  fade_in_duration_ms: 2000,
  mix_mode: MixMode::CROSSFADE,
  resume_file: nil, # an .m3u8 to auto-persist queue + position to
  resume_save_interval_ms: 0 # 0 => 5 s default
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**opts) ⇒ Player

Create a player with configuration overrides (see DEFAULT_CONFIG keys). sample_rate: 0 means the device default. Passing resume_file: enables auto-persisting the queue + exact position to that .m3u8 file.



59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/rockbox_ffi/player.rb', line 59

def initialize(**opts)
  c = DEFAULT_CONFIG.merge(opts)
  resume_file = c[:resume_file].nil? ? nil : c[:resume_file].to_s
  ptr = Lib.rb_player_new_with_config_ex(
    Integer(c[:sample_rate]), Float(c[:buffer_seconds]), Float(c[:volume]),
    Integer(c[:replaygain_mode]), Float(c[:replaygain_preamp_db]),
    RockboxFFI.b(c[:replaygain_prevent_clipping]), Integer(c[:crossfade_mode]),
    Integer(c[:fade_out_delay_ms]), Integer(c[:fade_out_duration_ms]),
    Integer(c[:fade_in_delay_ms]), Integer(c[:fade_in_duration_ms]),
    Integer(c[:mix_mode]), resume_file,
    Integer(c[:resume_save_interval_ms])
  )
  init_ptr(ptr)
end

Class Method Details

.defaultObject

Player on the default device with Rockbox default settings.



50
51
52
53
54
# File 'lib/rockbox_ffi/player.rb', line 50

def self.default
  player = allocate
  player.send(:init_ptr, Lib.rb_player_new)
  player
end

.open(**opts) ⇒ Object

Open a Player; if a block is given, close it automatically afterwards.



38
39
40
41
42
43
44
45
46
47
# File 'lib/rockbox_ffi/player.rb', line 38

def self.open(**opts)
  player = new(**opts)
  return player unless block_given?

  begin
    yield player
  ensure
    player.close
  end
end

Instance Method Details

#balanceObject

Current stereo balance, -100 (full left) to +100 (full right).



183
184
185
# File 'lib/rockbox_ffi/player.rb', line 183

def balance
  Lib.rb_player_balance(@ptr)
end

#clear_resumeObject

Delete the resume file.



392
393
394
# File 'lib/rockbox_ffi/player.rb', line 392

def clear_resume
  Lib.rb_player_clear_resume(@ptr)
end

#closeObject

-- lifecycle --------------------------------------------------------



75
76
77
78
79
80
81
# File 'lib/rockbox_ffi/player.rb', line 75

def close
  return if @ptr.nil?

  ObjectSpace.undefine_finalizer(self)
  Lib.rb_player_free(@ptr)
  @ptr = nil
end

#closed?Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/rockbox_ffi/player.rb', line 83

def closed?
  @ptr.nil?
end

#dsp_settingsObject

A snapshot of the current DSP settings as a Hash with symbol keys.



360
361
362
363
364
365
# File 'lib/rockbox_ffi/player.rb', line 360

def dsp_settings
  s = RockboxFFI.take_string(Lib.rb_player_dsp_settings_json(@ptr))
  raise "rb_player_dsp_settings_json returned NULL" if s.nil?

  JSON.parse(s, symbolize_names: true)
end

#enqueue(path) ⇒ Object

Append one track to the queue. path may be a local file path, an http(s):// URL to a finite remote file, or a live-radio / streaming URL.



102
103
104
105
# File 'lib/rockbox_ffi/player.rb', line 102

def enqueue(path)
  Lib.rb_player_enqueue(@ptr, path.to_s)
  self
end

#eq_enabled?Boolean

Whether the parametric equalizer is currently enabled.

Returns:

  • (Boolean)


237
238
239
# File 'lib/rockbox_ffi/player.rb', line 237

def eq_enabled?
  !Lib.rb_player_is_eq_enabled(@ptr).zero?
end

#export_m3u(path) ⇒ Object

Export the current queue to an .m3u8 (atomic). Returns true on success.



417
418
419
# File 'lib/rockbox_ffi/player.rb', line 417

def export_m3u(path)
  Lib.rb_player_export_m3u(@ptr, path.to_s).zero?
end

#import_m3u(path, position, index = 0) ⇒ Object

-- m3u / m3u8 playlists --------------------------------------------- Import a playlist file into the queue at position (see InsertPosition; index only used for INDEX). Returns the imported paths as an Array.



399
400
401
402
403
404
405
406
# File 'lib/rockbox_ffi/player.rb', line 399

def import_m3u(path, position, index = 0)
  s = RockboxFFI.take_string(
    Lib.rb_player_import_m3u(@ptr, path.to_s, Integer(position), Integer(index))
  )
  return [] if s.nil?

  JSON.parse(s)
end

#insert(paths, position, index = 0) ⇒ Object

Insert paths (a path/URL or Array of them) into the queue at position (see InsertPosition). index is only used when position is InsertPosition::INDEX (7).



110
111
112
113
114
115
# File 'lib/rockbox_ffi/player.rb', line 110

def insert(paths, position, index = 0)
  Lib.rb_player_insert_json(
    @ptr, JSON.generate(Array(paths).map(&:to_s)), Integer(position), Integer(index)
  )
  self
end

#load_m3u(path) ⇒ Object

Replace the queue with a playlist file. Returns the loaded paths as an Array.



409
410
411
412
413
414
# File 'lib/rockbox_ffi/player.rb', line 409

def load_m3u(path)
  s = RockboxFFI.take_string(Lib.rb_player_load_m3u(@ptr, path.to_s))
  return [] if s.nil?

  JSON.parse(s)
end

#nextObject



146
147
148
149
# File 'lib/rockbox_ffi/player.rb', line 146

def next
  Lib.rb_player_next(@ptr)
  self
end

#pauseObject



131
132
133
134
# File 'lib/rockbox_ffi/player.rb', line 131

def pause
  Lib.rb_player_pause(@ptr)
  self
end

#playObject

-- transport --------------------------------------------------------



126
127
128
129
# File 'lib/rockbox_ffi/player.rb', line 126

def play
  Lib.rb_player_play(@ptr)
  self
end

#previousObject



151
152
153
154
# File 'lib/rockbox_ffi/player.rb', line 151

def previous
  Lib.rb_player_previous(@ptr)
  self
end

#queueObject

The current queue as an Array of String paths/URLs.



118
119
120
121
122
123
# File 'lib/rockbox_ffi/player.rb', line 118

def queue
  s = RockboxFFI.take_string(Lib.rb_player_queue_json(@ptr))
  return [] if s.nil?

  JSON.parse(s)
end

#repeatObject

The current repeat mode as an Integer (see RepeatMode).



225
226
227
# File 'lib/rockbox_ffi/player.rb', line 225

def repeat
  Lib.rb_player_repeat(@ptr)
end

#resumeObject

-- resume ----------------------------------------------------------- Restore the queue + exact position from the resume file (does NOT auto-play). Returns a Hash index:, elapsed_ms: or nil.



379
380
381
382
383
384
# File 'lib/rockbox_ffi/player.rb', line 379

def resume
  s = RockboxFFI.take_string(Lib.rb_player_resume(@ptr))
  return nil if s.nil?

  JSON.parse(s, symbolize_names: true)
end

#sample_rateObject



187
188
189
# File 'lib/rockbox_ffi/player.rb', line 187

def sample_rate
  Lib.rb_player_sample_rate(@ptr)
end

#save_resumeObject

Force-persist the current queue + position to the resume file now.



387
388
389
# File 'lib/rockbox_ffi/player.rb', line 387

def save_resume
  Lib.rb_player_save_resume(@ptr)
end

#seek_ms(ms) ⇒ Object



161
162
163
164
# File 'lib/rockbox_ffi/player.rb', line 161

def seek_ms(ms)
  Lib.rb_player_seek_ms(@ptr, Integer(ms))
  self
end

#set_balance(balance) ⇒ Object

Stereo balance, -100 (full left) to +100 (full right); 0 = centre.



173
174
175
176
# File 'lib/rockbox_ffi/player.rb', line 173

def set_balance(balance)
  Lib.rb_player_set_balance(@ptr, Integer(balance))
  self
end

#set_bass(bass_db) ⇒ Object

Bass gain in dB.



270
271
272
273
# File 'lib/rockbox_ffi/player.rb', line 270

def set_bass(bass_db)
  Lib.rb_player_set_bass(@ptr, Integer(bass_db))
  self
end

#set_bass_cutoff(hz) ⇒ Object

Bass tone-control cutoff frequency in Hz.



282
283
284
285
# File 'lib/rockbox_ffi/player.rb', line 282

def set_bass_cutoff(hz)
  Lib.rb_player_set_bass_cutoff(@ptr, Integer(hz))
  self
end

#set_bass_enhancement(strength, precut) ⇒ Object

Bass enhancement: strength and precut (in dB).



305
306
307
308
# File 'lib/rockbox_ffi/player.rb', line 305

def set_bass_enhancement(strength, precut)
  Lib.rb_player_set_bass_enhancement(@ptr, Integer(strength), Integer(precut))
  self
end

#set_channel_mode(mode) ⇒ Object

Channel mode (see ChannelMode).



326
327
328
329
# File 'lib/rockbox_ffi/player.rb', line 326

def set_channel_mode(mode)
  Lib.rb_player_set_channel_mode(@ptr, Integer(mode))
  self
end

#set_compressor(threshold_db, makeup_gain, ratio, knee, attack_ms, release_ms) ⇒ Object

Dynamic-range compressor: threshold (dB), makeup gain, ratio, knee, attack (ms), release (ms).



339
340
341
342
343
344
345
# File 'lib/rockbox_ffi/player.rb', line 339

def set_compressor(threshold_db, makeup_gain, ratio, knee, attack_ms, release_ms)
  Lib.rb_player_set_compressor(
    @ptr, Integer(threshold_db), Integer(makeup_gain), Integer(ratio),
    Integer(knee), Integer(attack_ms), Integer(release_ms)
  )
  self
end

#set_crossfade(mode, fade_out_delay_ms: 0, fade_out_duration_ms: 2000, fade_in_delay_ms: 0, fade_in_duration_ms: 2000, mix_mode: MixMode::CROSSFADE) ⇒ Object



191
192
193
194
195
196
197
198
199
# File 'lib/rockbox_ffi/player.rb', line 191

def set_crossfade(mode, fade_out_delay_ms: 0, fade_out_duration_ms: 2000,
                  fade_in_delay_ms: 0, fade_in_duration_ms: 2000,
                  mix_mode: MixMode::CROSSFADE)
  Lib.rb_player_set_crossfade(
    @ptr, Integer(mode), Integer(fade_out_delay_ms), Integer(fade_out_duration_ms),
    Integer(fade_in_delay_ms), Integer(fade_in_duration_ms), Integer(mix_mode)
  )
  self
end

#set_crossfeed(mode, direct_gain, cross_gain, hf_gain, hf_cutoff) ⇒ Object

Crossfeed for headphone listening. mode (see CrossfeedMode: OFF=0, MEIER=1, CUSTOM=2), plus direct/cross/high-frequency gains and the high-frequency cutoff (Hz) used in CUSTOM mode.



296
297
298
299
300
301
302
# File 'lib/rockbox_ffi/player.rb', line 296

def set_crossfeed(mode, direct_gain, cross_gain, hf_gain, hf_cutoff)
  Lib.rb_player_set_crossfeed(
    @ptr, Integer(mode), Integer(direct_gain), Integer(cross_gain),
    Integer(hf_gain), Integer(hf_cutoff)
  )
  self
end

#set_dither(enabled) ⇒ Object

Enable/disable output dithering.



348
349
350
351
# File 'lib/rockbox_ffi/player.rb', line 348

def set_dither(enabled)
  Lib.rb_player_set_dither(@ptr, RockboxFFI.b(enabled))
  self
end

#set_eq_band(band, cutoff_hz, q, gain_db) ⇒ Object

Configure one EQ band: band index, cutoff_hz center frequency, q factor, gain_db gain in dB.



243
244
245
246
# File 'lib/rockbox_ffi/player.rb', line 243

def set_eq_band(band, cutoff_hz, q, gain_db)
  Lib.rb_player_set_eq_band(@ptr, Integer(band), Integer(cutoff_hz), Float(q), Float(gain_db))
  self
end

#set_eq_enabled(enabled) ⇒ Object

-- DSP -------------------------------------------------------------- Enable/disable the parametric equalizer.



231
232
233
234
# File 'lib/rockbox_ffi/player.rb', line 231

def set_eq_enabled(enabled)
  Lib.rb_player_set_eq_enabled(@ptr, RockboxFFI.b(enabled))
  self
end

#set_eq_precut(db) ⇒ Object

Global EQ pre-cut in dB.



249
250
251
252
# File 'lib/rockbox_ffi/player.rb', line 249

def set_eq_precut(db)
  Lib.rb_player_set_eq_precut(@ptr, Float(db))
  self
end

#set_eq_preset(preset) ⇒ Object

Apply a built-in EQ preset (see EqPreset).



255
256
257
258
# File 'lib/rockbox_ffi/player.rb', line 255

def set_eq_preset(preset)
  Lib.rb_player_set_eq_preset(@ptr, Integer(preset))
  self
end

#set_fatigue_reduction(strength) ⇒ Object

Listening-fatigue reduction (treble roll-off): strength.



311
312
313
314
# File 'lib/rockbox_ffi/player.rb', line 311

def set_fatigue_reduction(strength)
  Lib.rb_player_set_fatigue_reduction(@ptr, Integer(strength))
  self
end

#set_pitch(ratio) ⇒ Object

Pitch shift ratio.



354
355
356
357
# File 'lib/rockbox_ffi/player.rb', line 354

def set_pitch(ratio)
  Lib.rb_player_set_pitch(@ptr, Integer(ratio))
  self
end

#set_queue(paths) ⇒ Object

-- queue ------------------------------------------------------------ Replace the queue. Each entry may be a local file path, an http(s):// URL to a finite remote file, or a live-radio / streaming URL.



95
96
97
98
# File 'lib/rockbox_ffi/player.rb', line 95

def set_queue(paths)
  Lib.rb_player_set_queue_json(@ptr, JSON.generate(Array(paths).map(&:to_s)))
  self
end

#set_repeat(mode) ⇒ Object

Set the repeat mode (see RepeatMode: OFF=0, ONE=1, ALL=2).



219
220
221
222
# File 'lib/rockbox_ffi/player.rb', line 219

def set_repeat(mode)
  Lib.rb_player_set_repeat(@ptr, Integer(mode))
  self
end

#set_replaygain(mode, preamp_db, prevent_clipping) ⇒ Object

mode: see ReplayGainMode (OFF=0, TRACK=1, ALBUM=2).



202
203
204
205
# File 'lib/rockbox_ffi/player.rb', line 202

def set_replaygain(mode, preamp_db, prevent_clipping)
  Lib.rb_player_set_replaygain(@ptr, Integer(mode), Float(preamp_db), RockboxFFI.b(prevent_clipping))
  self
end

#set_shuffle(enabled) ⇒ Object

Enable/disable shuffle.



208
209
210
211
# File 'lib/rockbox_ffi/player.rb', line 208

def set_shuffle(enabled)
  Lib.rb_player_set_shuffle(@ptr, RockboxFFI.b(enabled))
  self
end

#set_stereo_width(percent) ⇒ Object

Stereo width as a percentage.



332
333
334
335
# File 'lib/rockbox_ffi/player.rb', line 332

def set_stereo_width(percent)
  Lib.rb_player_set_stereo_width(@ptr, Integer(percent))
  self
end

#set_surround(delay_ms, balance, cutoff_low_hz, cutoff_high_hz) ⇒ Object

Surround effect: delay (ms), balance, low/high cutoff frequencies (Hz).



317
318
319
320
321
322
323
# File 'lib/rockbox_ffi/player.rb', line 317

def set_surround(delay_ms, balance, cutoff_low_hz, cutoff_high_hz)
  Lib.rb_player_set_surround(
    @ptr, Integer(delay_ms), Integer(balance),
    Integer(cutoff_low_hz), Integer(cutoff_high_hz)
  )
  self
end

#set_tone(bass_db, treble_db, bass_cutoff_hz, treble_cutoff_hz) ⇒ Object

Bass/treble tone controls with explicit cutoff frequencies.



261
262
263
264
265
266
267
# File 'lib/rockbox_ffi/player.rb', line 261

def set_tone(bass_db, treble_db, bass_cutoff_hz, treble_cutoff_hz)
  Lib.rb_player_set_tone(
    @ptr, Integer(bass_db), Integer(treble_db),
    Integer(bass_cutoff_hz), Integer(treble_cutoff_hz)
  )
  self
end

#set_treble(treble_db) ⇒ Object

Treble gain in dB.



276
277
278
279
# File 'lib/rockbox_ffi/player.rb', line 276

def set_treble(treble_db)
  Lib.rb_player_set_treble(@ptr, Integer(treble_db))
  self
end

#set_treble_cutoff(hz) ⇒ Object

Treble tone-control cutoff frequency in Hz.



288
289
290
291
# File 'lib/rockbox_ffi/player.rb', line 288

def set_treble_cutoff(hz)
  Lib.rb_player_set_treble_cutoff(@ptr, Integer(hz))
  self
end

#set_volume(vol) ⇒ Object

-- settings ---------------------------------------------------------



167
168
169
170
# File 'lib/rockbox_ffi/player.rb', line 167

def set_volume(vol)
  Lib.rb_player_set_volume(@ptr, Float(vol))
  self
end

#shuffle_enabled?Boolean

Whether shuffle is currently enabled.

Returns:

  • (Boolean)


214
215
216
# File 'lib/rockbox_ffi/player.rb', line 214

def shuffle_enabled?
  !Lib.rb_player_is_shuffle_enabled(@ptr).zero?
end

#skip_to(index) ⇒ Object



156
157
158
159
# File 'lib/rockbox_ffi/player.rb', line 156

def skip_to(index)
  Lib.rb_player_skip_to(@ptr, Integer(index))
  self
end

#statusObject

-- status ----------------------------------------------------------- A snapshot of the player's status as a Hash with symbol keys.



369
370
371
372
373
374
# File 'lib/rockbox_ffi/player.rb', line 369

def status
  s = RockboxFFI.take_string(Lib.rb_player_status_json(@ptr))
  raise "rb_player_status_json returned NULL" if s.nil?

  JSON.parse(s, symbolize_names: true)
end

#stopObject



141
142
143
144
# File 'lib/rockbox_ffi/player.rb', line 141

def stop
  Lib.rb_player_stop(@ptr)
  self
end

#toggleObject



136
137
138
139
# File 'lib/rockbox_ffi/player.rb', line 136

def toggle
  Lib.rb_player_toggle(@ptr)
  self
end

#volumeObject



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

def volume
  Lib.rb_player_volume(@ptr)
end