audio-playback 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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