audio-playback 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6610c16cd941a9fac1b38c72500b6d7cabb6e065
4
+ data.tar.gz: c6e6902a5c28a811f05a0e5bbc1cd425cef60fb1
5
+ SHA512:
6
+ metadata.gz: e05488f906b9f0783b9b5fca1665bef683a37c0dfbf7c432bb5df866b34da7a11f32e57ba91bf5a3d3cdd6648ceab83d504c78934ff2be5ef5abf58315274ed4
7
+ data.tar.gz: 01dca1cea7cab6165770841b57ee11e7a7d136add803cd6a0ca6ac608325a43f4aa9e2ffad191a98ca880a85e59bd93d109b21a1ae6300f07c83faf28733f02b
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2015 Ari Russo
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,81 @@
1
+ # Audio Playback
2
+
3
+ Play audio files at the command line or using Ruby
4
+
5
+ ## Installation
6
+
7
+ These packages must be installed first:
8
+
9
+ * portaudio
10
+ * libsndfile
11
+
12
+ Install the gem using
13
+
14
+ gem install audio-playback
15
+
16
+ Or if you're using Bundler, add this to your Gemfile
17
+
18
+ gem "audio-playback"
19
+
20
+ ## Usage
21
+
22
+ ### Command line
23
+
24
+ `playback [filename] [options]`
25
+
26
+ #### options:
27
+
28
+ * `-l` Latency in seconds. Defaults to use the default latency for the selected output device
29
+
30
+ * `-b` Buffer size in bytes. Defaults to 4096
31
+
32
+ * `-c` Output audio to the given channel(s). Eg `-c 0,1` will direct audio to channels 0 and 1. Defaults to use all available channels
33
+
34
+ * `-o` Output device id or name. Defaults to the system default
35
+
36
+ * `-v` or `--verbose` Verbose
37
+
38
+ * `--list-devices` List the available audio output devices
39
+
40
+
41
+ #### example:
42
+
43
+ `playback test/media/1-stereo-44100.wav -v -c 1`
44
+
45
+ ### With Ruby
46
+
47
+ ```ruby
48
+ require "audio-playback"
49
+
50
+ # Prompt the user to select an audio output
51
+ @output = AudioPlayback::Device::Output.gets
52
+
53
+ options = {
54
+ :channels => [0,1],
55
+ :latency => 1,
56
+ :output_device => @output
57
+ }
58
+
59
+ @playback = AudioPlayback.play("test/media/1-stereo-44100.wav", options)
60
+
61
+ @playback.block
62
+
63
+ ```
64
+
65
+ #### options:
66
+
67
+ * `:buffer_size` Buffer size in bytes. Defaults to 4096
68
+
69
+ * `:channel` or `:channels` Output audio to the given channel(s). Eg `:channels => [0,1]` will direct the audio to channels 0 and 1. Defaults to use all available channels
70
+
71
+ * `:latency` Latency in seconds. Defaults to use the default latency for the selected output device
72
+
73
+ * `:logger` Logger object
74
+
75
+ * `:output_device` Output device id or name
76
+
77
+ ## License
78
+
79
+ Licensed under Apache 2.0, See the file LICENSE
80
+
81
+ Copyright (c) 2015 [Ari Russo](http://arirusso.com)
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ #
5
+ # ## Usage
6
+ #
7
+ # `playback [filename] [options]`
8
+ #
9
+ # #### options:
10
+ #
11
+ # * `-l` Latency in seconds. Defaults to use the default latency for the selected output device
12
+ #
13
+ # * `-b` Buffer size in bytes. Defaults to 4096
14
+ #
15
+ # * `-c` Output audio to the given channel(s). Eg `-c 0,1` will direct audio to channels 0 and 1. Defaults to use all available channels
16
+ #
17
+ # * `-o` Output device id or name. Defaults to the system default
18
+ #
19
+ # * `-v` Verbose
20
+ #
21
+ #
22
+
23
+ require "audio-playback"
24
+ require "audio-playback/commandline"
25
+ require "optparse"
26
+
27
+ def help(opts)
28
+ puts(opts)
29
+ exit
30
+ end
31
+
32
+ options = {}
33
+
34
+ parser = OptionParser.new do |opts|
35
+
36
+ opts.banner = "Usage: playback [file] [options]"
37
+ opts.separator ""
38
+ opts.separator "Specific options:"
39
+
40
+ AudioPlayback::Commandline::OPTIONS.each do |key, spec|
41
+ opts.on(spec[:short], spec[:long], spec[:type], spec[:name]) do |value|
42
+ if value.is_a?(TrueClass) && !spec[:when_true].nil?
43
+ value = spec[:when_true]
44
+ end
45
+ options[key] = value
46
+ end
47
+ end
48
+
49
+ opts.on_tail("-h", "--help", "Show this message") { help(opts) }
50
+
51
+ opts.on_tail("--version", "Show version") do
52
+ puts AudioPlayback::VERSION
53
+ exit
54
+ end
55
+
56
+ help(opts) if ARGV.empty?
57
+ end
58
+
59
+ parser.parse!
60
+
61
+ if options[:list_devices]
62
+ AudioPlayback.list_devices
63
+ else
64
+ playback = AudioPlayback.play(ARGV[0], options)
65
+ playback.block
66
+ end
@@ -0,0 +1,55 @@
1
+ #
2
+ # AudioPlayback
3
+ # Play audio files at the command line or with Ruby
4
+ #
5
+ # (c)2015 Ari Russo
6
+ # Apache 2.0 License
7
+ # https://github.com/arirusso/audio-playback
8
+ #
9
+
10
+ # libs
11
+ require "ffi/libc"
12
+ require "ffi-portaudio"
13
+ require "forwardable"
14
+ require "ruby-audio"
15
+
16
+ # modules
17
+ require "audio-playback/device"
18
+ require "audio-playback/playback"
19
+
20
+ # classes
21
+ require "audio-playback/file"
22
+ require "audio-playback/sound"
23
+
24
+ # Play audio files
25
+ module AudioPlayback
26
+
27
+ VERSION = "0.0.2"
28
+
29
+ # Convenience method to play an audio file
30
+ # @param [::File, String] file_path
31
+ # @param [Hash] options
32
+ # @option options [Fixnum] :buffer_size Buffer size in bytes. Defaults to 4096
33
+ # @option options [Array<Fixnum>, Fixnum] :channels (or: :channel) Output audio to the given channel(s). Eg `:channels => [0,1]` will direct the audio to channels 0 and 1. Defaults to use all available channels
34
+ # @option options [Float] :latency Latency in seconds. Defaults to use the default latency for the selected output device
35
+ # @option options [IO] :logger Logger object
36
+ # @option options [Fixnum, String] :output_device Output device id or name
37
+ def self.play(file_path, options = {})
38
+ sound = Sound.load(file_path, options)
39
+ output = Device::Output.by_name(options[:output_device]) || Device::Output.by_id(options[:output_device]) || Device.default_output
40
+ Playback.play(sound, output, options)
41
+ end
42
+
43
+ # List the available audio output devices
44
+ # @return [Array<String>]
45
+ def self.list_devices
46
+ Device::Output.list
47
+ end
48
+
49
+ # Ensure that the audio system is initialized
50
+ # @return [Boolean]
51
+ def self.ensure_initialized
52
+ @initialized ||= FFI::PortAudio::API.Pa_Initialize
53
+ end
54
+
55
+ end
@@ -0,0 +1,50 @@
1
+ module AudioPlayback
2
+
3
+ # Using the AudioPlayback module from the command line
4
+ module Commandline
5
+
6
+ OPTIONS = {
7
+ :buffer_size => {
8
+ :short => "-b",
9
+ :long => "--buffer-size [bytes]",
10
+ :type => Integer,
11
+ :name => "Buffer size"
12
+ },
13
+
14
+ :channels => {
15
+ :short => "-c",
16
+ :long => "--channels [channel1, channel2]",
17
+ :type => Array,
18
+ :name => "Direct to channel(s)"
19
+ },
20
+
21
+ :latency => {
22
+ :short => "-l",
23
+ :long => "--latency [seconds]",
24
+ :type => Float,
25
+ :name => "Latency"
26
+ },
27
+
28
+ :list_devices => {
29
+ :long => "--list-devices",
30
+ :name => "List devices"
31
+ },
32
+
33
+ :logger => {
34
+ :short => "-v",
35
+ :long => "--verbose",
36
+ :name => "Run verbosely",
37
+ :when_true => $>
38
+ },
39
+
40
+ :output_device => {
41
+ :short => "-o",
42
+ :long => "--output [name or id]",
43
+ :type => String,
44
+ :name => "Output device for playback"
45
+ }
46
+ }
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,61 @@
1
+ require "audio-playback/device/output"
2
+ require "audio-playback/device/stream"
3
+
4
+ module AudioPlayback
5
+
6
+ # Audio IO devices
7
+ module Device
8
+
9
+ extend self
10
+
11
+ # All output devices
12
+ # @return [Array<Output>]
13
+ def outputs
14
+ AudioPlayback.ensure_initialized
15
+ if @devices.nil?
16
+ count = FFI::PortAudio::API.Pa_GetDeviceCount
17
+ ids = (0..count-1).to_a.select { |id| output?(id) }
18
+ @devices = ids.map { |id| Output.new(id) }
19
+ end
20
+ @devices
21
+ end
22
+
23
+ # Get a device by its ID
24
+ # @param [Fixnum] id
25
+ # @return [Output]
26
+ def by_id(id)
27
+ outputs.find { |device| [device, device.id].include?(id) }
28
+ end
29
+
30
+ # Get a device by its name
31
+ # @param [String] name
32
+ # @return [Output]
33
+ def by_name(name)
34
+ outputs.find { |device| device.name == name }
35
+ end
36
+
37
+ # The system default output
38
+ # @return [Output]
39
+ def default_output
40
+ by_id(FFI::PortAudio::API.Pa_GetDefaultOutputDevice)
41
+ end
42
+
43
+ # Get system device info given a device ID
44
+ # @param [Fixnum] id
45
+ # @return [FFI::PortAudio::API::PaDeviceInfo]
46
+ def device_info(id)
47
+ FFI::PortAudio::API.Pa_GetDeviceInfo(id)
48
+ end
49
+
50
+ private
51
+
52
+ # Is the device with the given ID an output?
53
+ # @param [Fixnum] id
54
+ # @return [Boolean]
55
+ def output?(id)
56
+ device_info(id)[:maxOutputChannels] > 0
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,113 @@
1
+ module AudioPlayback
2
+
3
+ module Device
4
+ # An output device
5
+ class Output
6
+
7
+ attr_reader :id, :name, :resource
8
+
9
+ # All output devices
10
+ # @return [Array<Output>]
11
+ def self.all
12
+ Device.outputs
13
+ end
14
+
15
+ # Prints ids and names of each device to standard out
16
+ # @return [Array<String>]
17
+ def self.list
18
+ all.map do |device|
19
+ name = "#{device.id}. #{device.name}"
20
+ $>.puts(name)
21
+ name
22
+ end
23
+ end
24
+
25
+ # Streamlined console prompt that asks the user (via standard in) to select a device
26
+ # When their input is received, the device is selected and enabled
27
+ # @return [Output]
28
+ def self.gets
29
+ device = nil
30
+ puts ""
31
+ puts "Select an audio output..."
32
+ while device.nil?
33
+ list
34
+ print "> "
35
+ selection = $stdin.gets.chomp
36
+ if selection != ""
37
+ selection = Integer(selection) rescue nil
38
+ device = all.find { |d| d.id == selection } unless selection.nil?
39
+ end
40
+ end
41
+ device
42
+ end
43
+
44
+ # Select an output device by ID
45
+ # @param [Fixnum] id
46
+ # @return [Output]
47
+ def self.by_id(id)
48
+ Device.by_id(id)
49
+ end
50
+
51
+ # Select an output device by name
52
+ # @param [String] name
53
+ # @return [Output]
54
+ def self.by_name(name)
55
+ Device.by_name(name)
56
+ end
57
+
58
+ # @param [Fixnum] id
59
+ # @param [Hash] options
60
+ # @option options [Float] :latency Device latency in seconds
61
+ def initialize(id, options = {})
62
+ # Init audio output resource
63
+ AudioPlayback.ensure_initialized
64
+ populate(id, options)
65
+ end
66
+
67
+ # Device latency in seconds
68
+ # @return [Float]
69
+ def latency
70
+ @resource[:suggestedLatency]
71
+ end
72
+
73
+ # Number of channels the device supports
74
+ # @return [Fixnum]
75
+ def num_channels
76
+ @resource[:channelCount]
77
+ end
78
+
79
+ # ID of the device
80
+ # @return [Fixnum]
81
+ def id
82
+ @resource[:device]
83
+ end
84
+
85
+ private
86
+
87
+ # The underlying resource info struct for this output
88
+ # @return [FFI::PortAudio::API::PaDeviceInfo]
89
+ def info
90
+ @info ||= Device.device_info(id)
91
+ end
92
+
93
+ # Populate the output
94
+ # @param [Fixnum] id
95
+ # @param [Hash] options
96
+ # @option options [Float] :latency
97
+ # @return [FFI::PortAudio::API::PaStreamParameters]
98
+ def populate(id, options = {})
99
+ @resource = FFI::PortAudio::API::PaStreamParameters.new
100
+ @resource[:device] = id
101
+ @name = info[:name]
102
+ @resource[:suggestedLatency] = options[:latency] || info[:defaultHighOutputLatency]
103
+ @resource[:hostApiSpecificStreamInfo] = nil
104
+ @resource[:channelCount] = info[:maxOutputChannels]
105
+ @resource[:sampleFormat] = FFI::PortAudio::API::Float32
106
+ @resource
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+
113
+ end