class AudioPlayback::Playback::Action
Action
of playing back an audio file
Attributes
Public Class Methods
@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 process until playback finishes @return [Stream]
# File lib/audio-playback/playback.rb, line 77 def block @stream.block end
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
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
Is audio looping ? @return [Boolean]
# File lib/audio-playback/playback.rb, line 116 def looping? @is_looping end
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 of the playback sound @return [Integer]
# File lib/audio-playback/playback.rb, line 63 def sample_rate @sounds.last.sample_rate end
Start playback @return [Playback]
# File lib/audio-playback/playback.rb, line 69 def start @stream.play(self) self end
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
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 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 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
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 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
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
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
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
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