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,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