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,52 @@
1
+ module AudioPlayback
2
+
3
+ module Playback
4
+
5
+ # Playback data for the Device::Stream
6
+ class StreamData
7
+
8
+ # A C pointer version of the audio data
9
+ def self.to_pointer(playback)
10
+ stream_data = new(playback)
11
+ stream_data.to_pointer
12
+ end
13
+
14
+ # @param [Playback::Action] playback
15
+ def initialize(playback)
16
+ @playback = playback
17
+ populate
18
+ end
19
+
20
+ # A C pointer version of the audio data
21
+ # @return [FFI::Pointer]
22
+ def to_pointer
23
+ pointer = FFI::LibC.malloc(@playback.data_size)
24
+ pointer.write_array_of_float(@data.flatten)
25
+ pointer
26
+ end
27
+
28
+ private
29
+
30
+ # Populate the playback stream data
31
+ # @return [FrameSet]
32
+ def populate
33
+ @data = FrameSet.new(@playback)
34
+ add_metadata
35
+ @data
36
+ end
37
+
38
+ # Add playback metadata to the stream data
39
+ # @return [FrameSet]
40
+ def add_metadata
41
+ @data.unshift(0.0) # 3. is_eof
42
+ @data.unshift(0.0) # 2. counter
43
+ @data.unshift(@playback.output.num_channels.to_f) # 1. num_channels
44
+ @data.unshift(@playback.sound.size.to_f) # 0. sample size
45
+ @data
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,54 @@
1
+ module AudioPlayback
2
+
3
+ class Sound
4
+
5
+ extend Forwardable
6
+
7
+ attr_reader :audio_file, :data, :size
8
+ def_delegators :@audio_file, :num_channels, :sample_rate
9
+
10
+ # Load a sound from the given file path
11
+ # @param [::File, String] file_or_path
12
+ # @param [Hash] options
13
+ # @option options [IO] logger
14
+ # @return [Sound]
15
+ def self.load(file_or_path, options = {})
16
+ file = AudioPlayback::File.new(file_or_path)
17
+ new(file, options)
18
+ end
19
+
20
+ # @param [AudioPlayback::File] audio_file
21
+ # @param [Hash] options
22
+ # @option options [IO] logger
23
+ def initialize(audio_file, options = {})
24
+ @audio_file = audio_file
25
+ populate(options)
26
+ report(options[:logger]) if options[:logger]
27
+ end
28
+
29
+ # Log a report about the sound
30
+ # @param [IO] logger
31
+ # @return [Boolean]
32
+ def report(logger)
33
+ logger.puts("Sound report for #{@audio_file.path}")
34
+ logger.puts(" Sample rate: #{@audio_file.sample_rate}")
35
+ logger.puts(" Channels: #{@audio_file.num_channels}")
36
+ logger.puts(" File size: #{@audio_file.size}")
37
+ true
38
+ end
39
+
40
+ private
41
+
42
+ # Populate the sound meta/data
43
+ # @param [Hash] options
44
+ # @option options [IO] :logger
45
+ # @return [Sound]
46
+ def populate(options = {})
47
+ @data = @audio_file.read(options)
48
+ @size = data.size
49
+ self
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,141 @@
1
+ require "helper"
2
+
3
+ class AudioPlayback::Device::OutputTest < Minitest::Test
4
+
5
+ context "Output" do
6
+
7
+ setup do
8
+ @outputs = AudioPlayback::Device::Output.all
9
+ end
10
+
11
+ context ".all" do
12
+
13
+ should "return available outputs" do
14
+ refute_nil @outputs
15
+ refute_empty @outputs
16
+ assert_equal TestHelper::OUTPUT_INFO.map { |info| info[:name] }, @outputs.map(&:name)
17
+ end
18
+
19
+ end
20
+
21
+ context ".by_id" do
22
+
23
+ should "return an output with the given id" do
24
+ @outputs.each do |output|
25
+ assert_equal output, AudioPlayback::Device::Output.by_id(output.id)
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ context ".by_name" do
32
+
33
+ should "return an output with the given name" do
34
+ @outputs.each do |output|
35
+ assert_equal output, AudioPlayback::Device::Output.by_name(output.name)
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ context "#populate" do
42
+
43
+ setup do
44
+ @id = 0
45
+ @output = AudioPlayback::Device::Output.new(@id)
46
+ end
47
+
48
+ should "populate id" do
49
+ refute_nil @output.id
50
+ assert_kind_of Fixnum, @output.id
51
+ end
52
+
53
+ should "populate latency" do
54
+ refute_nil @output.latency
55
+ assert_kind_of Numeric, @output.latency
56
+ end
57
+
58
+ should "populate number of channels" do
59
+ refute_nil @output.num_channels
60
+ assert_kind_of Fixnum, @output.num_channels
61
+ end
62
+
63
+ should "populate name" do
64
+ refute_nil @output.name
65
+ assert_kind_of String, @output.name
66
+ assert_equal "Test Output #{@id+1}", @output.name
67
+ end
68
+
69
+ end
70
+
71
+ context "#latency" do
72
+
73
+ setup do
74
+ @test_id = (0..TestHelper::OUTPUT_INFO.size-1).to_a.sample
75
+ @test_info = TestHelper::OUTPUT_INFO[@test_id]
76
+ end
77
+
78
+ context "latency option" do
79
+
80
+ setup do
81
+ @output = AudioPlayback::Device::Output.new(@test_id, :latency => 20)
82
+ end
83
+
84
+ should "return correct latency" do
85
+ refute_nil @output.latency
86
+ assert_kind_of Float, @output.latency
87
+ assert_equal 20, @output.latency
88
+ end
89
+
90
+ end
91
+
92
+ context "no options" do
93
+
94
+ setup do
95
+ @output = AudioPlayback::Device::Output.new(@test_id)
96
+ end
97
+
98
+ should "return correct latency" do
99
+ refute_nil @output.latency
100
+ assert_kind_of Float, @output.latency
101
+ assert_equal @test_info[:defaultHighOutputLatency], @output.latency
102
+ end
103
+
104
+ end
105
+
106
+ end
107
+
108
+ context "#num_channels" do
109
+
110
+ setup do
111
+ @test_id = (0..TestHelper::OUTPUT_INFO.size-1).to_a.sample
112
+ @test_info = TestHelper::OUTPUT_INFO[@test_id]
113
+ @output = AudioPlayback::Device::Output.new(@test_id)
114
+ end
115
+
116
+ should "return correct num_channels" do
117
+ refute_nil @output.num_channels
118
+ assert_kind_of Fixnum, @output.num_channels
119
+ assert_equal @test_info[:maxOutputChannels], @output.num_channels
120
+ end
121
+
122
+ end
123
+
124
+ context "#id" do
125
+
126
+ setup do
127
+ @test_id = (0..TestHelper::OUTPUT_INFO.size-1).to_a.sample
128
+ @output = AudioPlayback::Device::Output.new(@test_id)
129
+ end
130
+
131
+ should "return correct id" do
132
+ refute_nil @output.id
133
+ assert_kind_of Fixnum, @output.id
134
+ assert_equal @test_id, @output.id
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+
141
+ end
@@ -0,0 +1,54 @@
1
+ require "helper"
2
+
3
+ class AudioPlayback::Device::StreamTest < Minitest::Test
4
+
5
+ context "Stream" do
6
+
7
+ setup do
8
+ @path = "test/media/1-mono-44100.wav"
9
+ @sound = AudioPlayback::Sound.load(@path)
10
+ @output = AudioPlayback::Device::Output.by_id(0)
11
+ end
12
+
13
+ context "#exit_callback" do
14
+
15
+ setup do
16
+ @stream = AudioPlayback::Device::Stream.new(@output)
17
+ @stream.expects(:close).once
18
+ end
19
+
20
+ teardown do
21
+ @stream.unstub(:close)
22
+ end
23
+
24
+ should "initialize exit callback" do
25
+ assert @stream.send(:exit_callback)
26
+ end
27
+
28
+ end
29
+
30
+ context "#play" do
31
+
32
+ setup do
33
+ @stream = AudioPlayback::Device::Stream.new(@output)
34
+ @playback = AudioPlayback::Playback.new(@sound, @output)
35
+ @stream.expects(:report).once
36
+ @stream.expects(:open_playback).once
37
+ @stream.expects(:start).once
38
+ end
39
+
40
+ teardown do
41
+ @stream.unstub(:report)
42
+ @stream.unstub(:open_playback)
43
+ @stream.unstub(:start)
44
+ end
45
+
46
+ should "return self" do
47
+ assert_equal @stream, @stream.play(@playback)
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,75 @@
1
+ require "helper"
2
+
3
+ class AudioPlayback::DeviceTest < Minitest::Test
4
+
5
+ context "Device" do
6
+
7
+ setup do
8
+ @outputs = AudioPlayback::Device.outputs
9
+ end
10
+
11
+ context ".outputs" do
12
+
13
+ should "return available outputs" do
14
+ refute_nil @outputs
15
+ refute_empty @outputs
16
+ assert_equal TestHelper::OUTPUT_INFO.map { |info| info[:name] }, @outputs.map(&:name)
17
+ end
18
+
19
+ end
20
+
21
+ context ".output?" do
22
+
23
+ should "return whether device is an output" do
24
+ assert @outputs.all? { |output| AudioPlayback::Device.send(:output?, output.id) }
25
+ end
26
+
27
+ end
28
+
29
+ context ".device_info" do
30
+
31
+ should "return requested device info" do
32
+ assert @outputs.all? do |output|
33
+ info = AudioPlayback::Device.send(:device_info, output.id)
34
+ TestHelper::OUTPUT_INFO.include?(info)
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ context ".by_id" do
41
+
42
+ should "return an output with the given id" do
43
+ @outputs.each do |output|
44
+ assert_equal output, AudioPlayback::Device.by_id(output.id)
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ context ".by_name" do
51
+
52
+ should "return an output with the given name" do
53
+ @outputs.each do |output|
54
+ assert_equal output, AudioPlayback::Device.by_name(output.name)
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ context ".default_output" do
61
+
62
+ setup do
63
+ @output = AudioPlayback::Device.default_output
64
+ end
65
+
66
+ should "return the default output" do
67
+ refute_nil @output
68
+ assert_equal TestHelper::DEFAULT_OUTPUT_ID, @output.id
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1,105 @@
1
+ require "helper"
2
+
3
+ class AudioPlayback::FileTest < Minitest::Test
4
+
5
+ context "AudioFile" do
6
+
7
+ context ".new" do
8
+
9
+ context "mono" do
10
+
11
+ setup do
12
+ @path = "test/media/1-mono-44100.wav"
13
+ @file = AudioPlayback::File.new(@path)
14
+ end
15
+
16
+ should "populate" do
17
+ refute_nil @file
18
+ refute_nil @file.num_channels
19
+ refute_nil @file.sample_rate
20
+ refute_nil @file.path
21
+ refute_nil @file.size
22
+ end
23
+
24
+ should "have correct information" do
25
+ assert_equal 1, @file.num_channels
26
+ assert_equal 44100, @file.sample_rate.to_i
27
+ assert_equal @path, @file.path
28
+ assert_equal File.size(@path), @file.size
29
+ end
30
+
31
+ end
32
+
33
+ context "stereo" do
34
+
35
+ setup do
36
+ @path = "test/media/1-stereo-44100.wav"
37
+ @file_obj = File.new(@path)
38
+ @file = AudioPlayback::File.new(@file_obj)
39
+ end
40
+
41
+ should "populate" do
42
+ refute_nil @file
43
+ refute_nil @file.num_channels
44
+ refute_nil @file.sample_rate
45
+ refute_nil @file.path
46
+ refute_nil @file.size
47
+ end
48
+
49
+ should "have correct information" do
50
+ assert_equal 2, @file.num_channels
51
+ assert_equal 44100, @file.sample_rate.to_i
52
+ assert_equal @path, @file.path
53
+ assert_equal File.size(@path), @file.size
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
60
+ context "#read" do
61
+
62
+ context "mono" do
63
+
64
+ setup do
65
+ @path = "test/media/1-mono-44100.wav"
66
+ @file = AudioPlayback::File.new(@path)
67
+ @data = @file.read
68
+ end
69
+
70
+ should "populate data" do
71
+ refute_nil @data
72
+ assert @data.kind_of?(Array)
73
+ refute_empty @data
74
+ assert @data.all? { |frame| frame.kind_of?(Float) }
75
+ assert @data.all? { |frame| frame >= -1 }
76
+ assert @data.all? { |frame| frame <= 1 }
77
+ end
78
+
79
+ end
80
+
81
+ context "stereo" do
82
+
83
+ setup do
84
+ @path = "test/media/1-stereo-44100.wav"
85
+ @file = AudioPlayback::File.new(@path)
86
+ @data = @file.read
87
+ end
88
+
89
+ should "populate data" do
90
+ refute_nil @data
91
+ assert @data.kind_of?(Array)
92
+ refute_empty @data
93
+ assert @data.all? { |frame_channels| frame_channels.kind_of?(Array) }
94
+ assert @data.all? { |frame_channels| frame_channels.all? { |frame| frame.kind_of?(Float) } }
95
+ assert @data.all? { |frame_channels| frame_channels.all? { |frame| frame >= -1 } }
96
+ assert @data.all? { |frame_channels| frame_channels.all? { |frame| frame <= 1 } }
97
+ end
98
+
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+
105
+ end