class AudioPlayback::Playback::Action

Action of playing back an audio file

Attributes

buffer_size[R]
channels[R]
data[R]
num_channels[R]
output[R]
sounds[R]
stream[R]
truncate[R]

Public Class Methods

new(sounds, output, options = {}) click to toggle source

@param [Array<Sound>, Sound] sounds @param [Output] output @param [Hash] options @option options [Integer] :buffer_size @option options [Array<Integer>, Integer] :channels (or: :channel) @option options [Numeric] :duration Play for given time in seconds @option options [Numeric] :end_position Stop at given time position in seconds (will use :duration if both are included) @option options [Boolean] :is_looping Whether to loop audio @option options [IO] :logger @option options [Numeric] :seek Start at given time position in seconds @option options [Stream] :stream

# File lib/audio-playback/playback.rb, line 52
def initialize(sounds, output, options = {})
  @sounds = Array(sounds)
  @buffer_size = options[:buffer_size] || DEFAULT[:buffer_size]
  @output = output
  @stream = options[:stream] || Device::Stream.new(@output, options)
  populate(options)
  report(options[:logger]) if options[:logger]
end

Public Instance Methods

block() click to toggle source

Block process until playback finishes @return [Stream]

# File lib/audio-playback/playback.rb, line 77
def block
  @stream.block
end
channels_requested?() click to toggle source

Has a different channel configuration than the default been requested? @return [Boolean]

# File lib/audio-playback/playback.rb, line 110
def channels_requested?
  !@channels.nil?
end
data_size() click to toggle source

Total size of the playback’s sound frames in bytes @return [Integer]

# File lib/audio-playback/playback.rb, line 103
def data_size
  frames = size * @num_channels
  frames * FRAME_SIZE.size
end
looping?() click to toggle source

Is audio looping ? @return [Boolean]

# File lib/audio-playback/playback.rb, line 116
def looping?
  @is_looping
end
play()
Alias for: start
report(logger) click to toggle source

Log a report about playback @param [IO] logger @return [Boolean]

# File lib/audio-playback/playback.rb, line 91
def report(logger)
  paths = @sounds.map(&:audio_file).map(&:path)
  logger.puts("Playback report for #{paths}")
  logger.puts("  Number of channels: #{@num_channels}")
  logger.puts("  Direct audio to channels #{@channels.to_s}") unless @channels.nil?
  logger.puts("  Buffer size: #{@buffer_size}")
  logger.puts("  Latency: #{@output.latency}")
  true
end
sample_rate() click to toggle source

Sample rate of the playback sound @return [Integer]

# File lib/audio-playback/playback.rb, line 63
def sample_rate
  @sounds.last.sample_rate
end
start() click to toggle source

Start playback @return [Playback]

# File lib/audio-playback/playback.rb, line 69
def start
  @stream.play(self)
  self
end
Also aliased as: play
truncate?() click to toggle source

Should playback be truncated?

eg :start 3 seconds, :duration 1 second

@return [Boolean]

# File lib/audio-playback/playback.rb, line 84
def truncate?
  !@truncate.nil? && !@truncate.values.empty?
end

Private Instance Methods

number_of_seconds_to_number_of_frames(num_seconds) click to toggle source

Convert number of seconds to number of sample frames given the sample rate @param [Numeric] num_seconds @return [Integer]

# File lib/audio-playback/playback.rb, line 190
def number_of_seconds_to_number_of_frames(num_seconds)
  (num_seconds * sample_rate).to_i
end
populate(options = {}) click to toggle source

Populate the playback action @param [Hash] options @option options [Integer, Array<Integer>] :channels (or: :channel) @option options [Numeric] :duration Play for given time in seconds @option options [Numeric] :end_position Stop at given time position in seconds (will use :duration if both are included) @option options [Boolean] :is_looping Whether to loop audio @option options [Numeric] :seek Start at given time position in seconds @return [Playback::Action]

# File lib/audio-playback/playback.rb, line 237
def populate(options = {})
  populate_channels(options)
  if truncate_requested?(options)
    if truncate_valid?(options)
      seek, duration, end_position = *truncate_options_as_positions(options)
      populate_truncation(seek, duration, end_position)
    else
      message = "Truncation options are not valid"
      raise(InvalidTruncation.new(message))
    end
  end
  @is_looping = !!options[:is_looping]
  @data = StreamData.new(self)
  self
end
populate_channels(options = {}) click to toggle source

Populate the playback channels @param [Hash] options @option options [Integer, Array<Integer>] :channels (or: :channel) @return [Boolean]

# File lib/audio-playback/playback.rb, line 153
def populate_channels(options = {})
  request = options[:channels] || options[:channel]
  if request.nil?
    @num_channels = @output.num_channels
    true
  else
    populate_requested_channels(request)
  end
end
populate_requested_channels(request) click to toggle source

Validate and populate the variables containing information about the requested channels @param [Integer, Array<Integer>] request Channel(s) @return [Boolean]

# File lib/audio-playback/playback.rb, line 137
def populate_requested_channels(request)
  request = Array(request)
  requested_channels = request.map(&:to_i).uniq
  if validate_requested_channels(requested_channels)
    @num_channels = requested_channels.count
    @channels = requested_channels
    true
  else
    false
  end
end
populate_truncation(seek, duration, end_position) click to toggle source

Populate the truncation parameters. Converts the seconds based Position arguments to number of frames @param [Position, nil] seek Start at given time position in seconds @param [Position, nil] duration Play for given time in seconds @param [Position, nil] end_position Stop at given time position in seconds (will use duration arg if both are included) @return [Hash]

# File lib/audio-playback/playback.rb, line 169
def populate_truncation(seek, duration, end_position)
  @truncate = {}
  end_position = if duration.nil?
    end_position
  elsif seek.nil?
    duration || end_position
  else
    duration + seek || end_position
  end
  unless seek.nil?
    @truncate[:start_frame] = number_of_seconds_to_number_of_frames(seek)
  end
  unless end_position.nil?
    @truncate[:end_frame] = number_of_seconds_to_number_of_frames(end_position)
  end
  @truncate
end
truncate_options_as_positions(options = {}) click to toggle source

Populate Position objects using the the truncation parameters. @param [Hash] options @option options [Numeric] :duration Play for given time in seconds @option options [Numeric] :end_position Stop at given time position in seconds (will use :duration if both are included) @option options [Numeric] :seek Start at given time position in seconds @return [Array<Position>]

# File lib/audio-playback/playback.rb, line 222
def truncate_options_as_positions(options = {})
  seek = Position.new(options[:seek]) unless options[:seek].nil?
  duration = Position.new(options[:duration]) unless options[:duration].nil?
  end_position = Position.new(options[:end_position]) unless options[:end_position].nil?
  [seek, duration, end_position]
end
truncate_requested?(options) click to toggle source

Has truncation been requested in the constructor options? @param [Hash] options @option options [Numeric] :duration Play for given time in seconds @option options [Numeric] :end_position Stop at given time position in seconds (will use :duration if both are included) @option options [Numeric] :seek Start at given time position in seconds @return [Boolean]

# File lib/audio-playback/playback.rb, line 212
def truncate_requested?(options)
  !options[:seek].nil? || !options[:duration].nil? || !options[:end_position].nil?
end
truncate_valid?(options) click to toggle source

Are the options for truncation valid? eg is the :end_position option after the :seek option? @param [Hash] options @option options [Numeric] :duration Play for given time in seconds @option options [Numeric] :end_position Stop at given time position in seconds (will use :duration if both are included) @option options [Numeric] :seek Start at given time position in seconds @return [Boolean]

# File lib/audio-playback/playback.rb, line 201
def truncate_valid?(options)
  options[:end_position].nil? || options[:seek].nil? ||
    options[:end_position] > options[:seek]
end
validate_requested_channels(channels) click to toggle source

Are the requested channels available in the current environment? @param [Array<Integer>] channels @return [Boolean]

# File lib/audio-playback/playback.rb, line 125
def validate_requested_channels(channels)
  if channels.count > @output.num_channels
    message = "Only #{@output.num_channels} channels available on #{@output.name} output"
    raise(InvalidChannels.new(message))
    false
  end
  true
end