ruby-alsa 0.0.5 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt CHANGED
@@ -6,7 +6,12 @@ History.txt
6
6
  Manifest.txt
7
7
  README.rdoc
8
8
  Rakefile
9
+ debian/changelog
10
+ debian/compat
11
+ debian/control
12
+ debian/rules
9
13
  lib/alsa.rb
14
+ lib/alsa/ffi_ext.rb
10
15
  lib/alsa/logger.rb
11
16
  lib/alsa/native.rb
12
17
  lib/alsa/pcm/capture.rb
@@ -14,13 +19,25 @@ lib/alsa/pcm/hw_parameters.rb
14
19
  lib/alsa/pcm/native.rb
15
20
  lib/alsa/pcm/playback.rb
16
21
  lib/alsa/pcm/stream.rb
22
+ lib/alsa/pcm/sw_parameters.rb
23
+ lib/alsa/sine.rb
17
24
  log/test.log
25
+ refs/alsa_player
26
+ refs/alsa_player.c
27
+ refs/alsa_player.rb
28
+ refs/alsa_player_async
29
+ refs/alsa_player_async.c
30
+ refs/alsa_player_async.rb
31
+ refs/alsa_recorder.rb
32
+ refs/alsa_recorder_async.rb
33
+ refs/pcm_wrap.rb
18
34
  ruby-alsa.gemspec
19
35
  script/console
20
36
  script/destroy
21
37
  script/generate
22
38
  script/play
23
39
  script/record
40
+ setup.rb
24
41
  spec.html
25
42
  spec/alsa/logger_spec.rb
26
43
  spec/alsa/native_spec.rb
@@ -34,4 +51,5 @@ spec/spec.opts
34
51
  spec/spec_helper.rb
35
52
  spec/support/logger.rb
36
53
  tasks/buildbot.rake
54
+ tasks/debian.rake
37
55
  tasks/rspec.rake
data/debian/changelog ADDED
@@ -0,0 +1,11 @@
1
+ libalsa-ruby (0.7-1) unstable; urgency=low
2
+
3
+ * New upstream release
4
+
5
+ -- Alban Peignier <alban@tryphon.eu> Thu, 14 Oct 2010 10:09:54 +0200
6
+
7
+ libalsa-ruby (0.1-1) unstable; urgency=low
8
+
9
+ * Initial release
10
+
11
+ -- Alban Peignier <alban@tryphon.eu> Sun, 1 Aug 2010 17:57:43 +0200
data/debian/compat ADDED
@@ -0,0 +1 @@
1
+ 5
data/debian/control ADDED
@@ -0,0 +1,18 @@
1
+ Source: libalsa-ruby
2
+ Section: sound
3
+ Priority: optional
4
+ Maintainer: Alban Peignier <alban@tryphon.eu>
5
+ Build-Depends: debhelper, cdbs, ruby-pkg-tools, libsetup-ruby1.8
6
+ Build-Depends-Indep: ruby1.8
7
+ Standards-Version: 3.8.1
8
+ Homepage: http://projects.tryphon.eu/ruby-alsa
9
+
10
+ Package: libalsa-ruby1.8
11
+ Architecture: all
12
+ Depends: ruby1.8, libruby1.8, libasound2, libffi-ruby
13
+ Description: Ruby 1.8 binding for ALSA library.
14
+
15
+ Package: libalsa-ruby
16
+ Architecture: all
17
+ Depends: libalsa-ruby1.8
18
+ Description: Ruby binding for ALSA library.
data/debian/rules ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/make -f
2
+
3
+ include /usr/share/cdbs/1/rules/debhelper.mk
4
+ include /usr/share/ruby-pkg-tools/1/class/ruby-setup-rb.mk
5
+
6
+ install/libalsa-ruby::
7
+ # cp $(DEB_SRCDIR)/debian/alsa-backup.conf debian/$(cdbs_curpkg)/etc/
8
+ echo DEB_RUBY_LIB_PACKAGES
9
+ echo $(DEB_RUBY_LIB_PACKAGES)
10
+ echo DEB_RUBY_REAL_LIB_PACKAGES
11
+ echo $(DEB_RUBY_REAL_LIB_PACKAGES)
12
+ echo DEB_RUBY_DUMMY_LIB_PACKAGES
13
+ echo $(DEB_RUBY_DUMMY_LIB_PACKAGES)
14
+ echo DEB_RUBY_LIB_DOC_PACKAGES
15
+ echo $(DEB_RUBY_LIB_DOC_PACKAGES)
data/lib/alsa.rb CHANGED
@@ -5,15 +5,17 @@ require 'ffi'
5
5
 
6
6
  module ALSA
7
7
 
8
- VERSION = "0.0.5"
8
+ VERSION = "0.7"
9
9
 
10
10
  end
11
11
 
12
12
  require 'logger'
13
+ require 'alsa/ffi_ext'
13
14
  require 'alsa/logger'
14
15
  require 'alsa/native'
15
16
  require 'alsa/pcm/native'
16
17
  require 'alsa/pcm/hw_parameters'
18
+ require 'alsa/pcm/sw_parameters'
17
19
  require 'alsa/pcm/stream'
18
20
  require 'alsa/pcm/capture'
19
21
  require 'alsa/pcm/playback'
@@ -0,0 +1,35 @@
1
+ class Integer
2
+
3
+ def to_pointer
4
+ pointer = MemoryPointer.new(:int)
5
+ pointer.write_int(self)
6
+
7
+ unless block_given?
8
+ pointer
9
+ else
10
+ begin
11
+ return yield pointer
12
+ ensure
13
+ pointer.free
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ class Array
21
+
22
+ def to_pointers
23
+ pointers = map(&:to_pointer)
24
+ unless block_given?
25
+ pointers
26
+ else
27
+ begin
28
+ return yield pointers
29
+ ensure
30
+ pointers.each(&:free)
31
+ end
32
+ end
33
+ end
34
+
35
+ end
data/lib/alsa/native.rb CHANGED
@@ -8,5 +8,10 @@ module ALSA
8
8
  def self.error_code?(response)
9
9
  response and response < 0
10
10
  end
11
+
12
+ callback :async_callback, [:pointer], :void
13
+ attach_function :async_add_pcm_handler, :snd_async_add_pcm_handler, [ :pointer, :pointer, :async_callback, :pointer ], :int
14
+ attach_function :async_handler_get_pcm, :snd_async_handler_get_pcm, [ :pointer ], :pointer
15
+ attach_function :async_handler_get_callback_private, :snd_async_handler_get_callback_private, [ :pointer ], :pointer
11
16
  end
12
17
  end
@@ -2,15 +2,14 @@ module ALSA::PCM
2
2
  class Capture < Stream
3
3
 
4
4
  def native_constant
5
- ALSA::PCM::Native::STREAM_CAPTURE
5
+ ALSA::PCM::Native::Stream::CAPTURE
6
6
  end
7
7
 
8
8
  def read
9
9
  check_handle!
10
10
 
11
- ALSA.logger.debug { "start read with #{hw_params.sample_rate}, #{hw_params.channels} channels"}
11
+ ALSA.logger.debug { "start read with #{hw_params.inspect}"}
12
12
 
13
- ALSA.logger.debug { "allocate #{hw_params.buffer_size_for(buffer_frame_count)} bytes for #{buffer_frame_count} frames" }
14
13
  FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(buffer_frame_count)) do |buffer|
15
14
  begin
16
15
  read_buffer buffer, buffer_frame_count
@@ -18,6 +17,41 @@ module ALSA::PCM
18
17
  end
19
18
  end
20
19
 
20
+ def read_in_background(&block)
21
+ check_handle!
22
+
23
+ async_handler = FFI::MemoryPointer.new(:pointer)
24
+ buffer = FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(buffer_frame_count))
25
+
26
+ started = false
27
+
28
+ capture_callback = Proc.new do |async_handler|
29
+ if started
30
+ frame_to_read = buffer_frame_count
31
+ read_buffer buffer, frame_to_read
32
+ yield buffer, frame_to_read
33
+ end
34
+ end
35
+
36
+ ALSA::try_to "add pcm handler" do
37
+ ALSA::Native::async_add_pcm_handler(async_handler, handle, capture_callback, nil)
38
+ end
39
+
40
+ ALSA::try_to "start capture" do
41
+ ALSA::PCM::Native::start(handle)
42
+ end
43
+
44
+ hole_frame_count = ALSA::try_to "read available space" do
45
+ ALSA::PCM::Native::avail_update(self.handle)
46
+ end
47
+ ALSA.logger.debug { "read synchronously #{hole_frame_count} frames"}
48
+ FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(hole_frame_count)) do |hole|
49
+ ALSA::PCM::Native::readi self.handle, hole, hole_frame_count
50
+ end
51
+
52
+ started = true
53
+ end
54
+
21
55
  def read_buffer(buffer, frame_count)
22
56
  check_handle!
23
57
 
@@ -31,6 +65,8 @@ module ALSA::PCM
31
65
  end
32
66
  end
33
67
 
68
+ ALSA.logger.debug { "read frame count: #{read_count}/#{frame_count}"}
69
+
34
70
  missing_frame_count = frame_count - read_count
35
71
  if missing_frame_count > 0
36
72
  ALSA.logger.debug { "re-read missing frame count: #{missing_frame_count}"}
@@ -59,10 +59,62 @@ module ALSA::PCM
59
59
  end
60
60
  end
61
61
 
62
+ def period_time=(period_time)
63
+ ALSA::try_to "set period time (#{period_time})" do
64
+ value = FFI::MemoryPointer.new(:int)
65
+ value.write_int(period_time)
66
+
67
+ dir = FFI::MemoryPointer.new(:int)
68
+ dir.write_int(-1)
69
+ error_code = ALSA::PCM::Native::hw_params_set_period_time_near self.device.handle, self.handle, value, dir
70
+
71
+ value.free
72
+ dir.free
73
+
74
+ error_code
75
+ end
76
+ end
77
+
78
+ def period_time
79
+ value = nil
80
+ ALSA::try_to "get period time" do
81
+ value_pointer = FFI::MemoryPointer.new(:int)
82
+ dir_pointer = FFI::MemoryPointer.new(:int)
83
+ dir_pointer.write_int(0)
84
+
85
+ error_code = ALSA::PCM::Native::hw_params_get_period_time self.handle, value_pointer, dir_pointer
86
+
87
+ value = value_pointer.read_int
88
+
89
+ value_pointer.free
90
+ dir_pointer.free
91
+
92
+ error_code
93
+ end
94
+ value
95
+ end
96
+
97
+ def buffer_time=(buffer_time)
98
+ ALSA::try_to "set buffer time (#{buffer_time})" do
99
+ value = FFI::MemoryPointer.new(:int)
100
+ value.write_int(buffer_time)
101
+
102
+ dir = FFI::MemoryPointer.new(:int)
103
+ dir.write_int(-1)
104
+ error_code = ALSA::PCM::Native::hw_params_set_buffer_time_near self.device.handle, self.handle, value, dir
105
+
106
+ value.free
107
+ dir.free
108
+
109
+ error_code
110
+ end
111
+ end
112
+
62
113
  def sample_rate
63
114
  rate = nil
64
115
  ALSA::try_to "get sample rate" do
65
116
  rate_pointer = FFI::MemoryPointer.new(:int)
117
+
66
118
  dir_pointer = FFI::MemoryPointer.new(:int)
67
119
  dir_pointer.write_int(0)
68
120
 
@@ -106,6 +158,39 @@ module ALSA::PCM
106
158
  channels
107
159
  end
108
160
 
161
+ def period_size
162
+ value = nil
163
+ ALSA::try_to "get period size" do
164
+ value_pointer = FFI::MemoryPointer.new(:int)
165
+ dir_pointer = FFI::MemoryPointer.new(:int)
166
+ dir_pointer.write_int(0)
167
+
168
+ error_code = ALSA::PCM::Native::hw_params_get_period_size self.handle, value_pointer, dir_pointer
169
+
170
+ value = value_pointer.read_int
171
+
172
+ value_pointer.free
173
+ dir_pointer.free
174
+
175
+ error_code
176
+ end
177
+ value
178
+ end
179
+
180
+ def buffer_size
181
+ value = nil
182
+ ALSA::try_to "get buffer size" do
183
+ value_pointer = FFI::MemoryPointer.new(:int)
184
+ error_code = ALSA::PCM::Native::hw_params_get_buffer_size self.handle, value_pointer
185
+ value = value_pointer.read_int
186
+
187
+ value_pointer.free
188
+
189
+ error_code
190
+ end
191
+ value
192
+ end
193
+
109
194
  def buffer_size_for(frame_count)
110
195
  ALSA::PCM::Native::format_size(self.sample_format, frame_count) * self.channels
111
196
  end
@@ -120,5 +205,9 @@ module ALSA::PCM
120
205
  end
121
206
  end
122
207
 
208
+ def inspect
209
+ "#<ALSA::PCM::HwParameters:#{object_id} sample_rate=#{sample_rate}, channels=#{channels}, period_time=#{period_time}, period_size=#{period_size}, buffer_size=#{buffer_size}>"
210
+ end
211
+
123
212
  end
124
213
  end
@@ -4,14 +4,19 @@ module ALSA::PCM
4
4
  extend FFI::Library
5
5
  ffi_lib "libasound.so.2"
6
6
 
7
- STREAM_PLAYBACK = 0
8
- STREAM_CAPTURE = 1
7
+ module Stream
8
+ PLAYBACK = 0
9
+ CAPTURE = 1
10
+ end
9
11
 
10
12
  BLOCK = 0
11
13
  attach_function :open, :snd_pcm_open, [:pointer, :string, :int, :int], :int
12
14
  attach_function :prepare, :snd_pcm_prepare, [ :pointer ], :int
13
15
  attach_function :close, :snd_pcm_close, [:pointer], :int
14
16
 
17
+ attach_function :wait, :snd_pcm_wait, [:pointer, :int], :int
18
+ attach_function :avail_update, :snd_pcm_avail_update, [:pointer], :int
19
+
15
20
  attach_function :readi, :snd_pcm_readi, [ :pointer, :pointer, :ulong ], :long
16
21
  attach_function :writei, :snd_pcm_writei, [ :pointer, :pointer, :ulong ], :long
17
22
 
@@ -43,10 +48,25 @@ module ALSA::PCM
43
48
  attach_function :hw_params_get_rate, :snd_pcm_hw_params_get_rate, [ :pointer, :pointer, :pointer ], :int
44
49
  attach_function :hw_params_set_rate_near, :snd_pcm_hw_params_set_rate_near, [ :pointer, :pointer, :pointer, :pointer ], :int
45
50
  attach_function :hw_params_set_channels, :snd_pcm_hw_params_set_channels, [ :pointer, :pointer, :uint ], :int
46
- attach_function :hw_params_get_channels, :snd_pcm_hw_params_get_format, [ :pointer, :pointer ], :int
51
+ attach_function :hw_params_get_channels, :snd_pcm_hw_params_get_channels, [ :pointer, :pointer ], :int
47
52
  attach_function :hw_params_set_periods, :snd_pcm_hw_params_set_periods, [ :pointer, :pointer, :uint, :int ], :int
53
+ attach_function :hw_params_set_period_time_near, :snd_pcm_hw_params_set_period_time_near, [ :pointer, :pointer, :pointer, :pointer ], :int
54
+ attach_function :hw_params_get_period_time, :snd_pcm_hw_params_get_period_time, [ :pointer, :pointer, :pointer ], :int
55
+ attach_function :hw_params_get_period_size, :snd_pcm_hw_params_get_period_size, [ :pointer, :pointer, :pointer ], :int
56
+ attach_function :hw_params_get_buffer_size, :snd_pcm_hw_params_get_buffer_size, [ :pointer, :pointer ], :int
57
+ attach_function :hw_params_set_buffer_time_near, :snd_pcm_hw_params_set_buffer_time_near, [ :pointer, :pointer, :pointer, :pointer ], :int
58
+
59
+ attach_function :sw_params, :snd_pcm_sw_params, [:pointer, :pointer], :int
60
+ attach_function :sw_params_malloc, :snd_pcm_sw_params_malloc, [:pointer], :int
61
+ attach_function :sw_params_free, :snd_pcm_sw_params_free, [:pointer], :int
62
+ attach_function :sw_params_current, :snd_pcm_sw_params_current, [ :pointer, :pointer ], :int
63
+ attach_function :sw_params_set_avail_min, :snd_pcm_sw_params_set_avail_min, [ :pointer, :pointer, :uint ], :int
64
+ attach_function :sw_params_get_avail_min, :snd_pcm_sw_params_get_avail_min, [ :pointer, :pointer ], :int
48
65
 
49
66
  attach_function :format_size, :snd_pcm_format_size, [ :int, :uint ], :int
50
67
  attach_function :bytes_to_frames, :snd_pcm_bytes_to_frames, [ :pointer, :int ], :int
68
+
69
+ attach_function :start, :snd_pcm_start, [ :pointer ], :int
70
+
51
71
  end
52
72
  end
@@ -2,7 +2,7 @@ module ALSA::PCM
2
2
  class Playback < Stream
3
3
 
4
4
  def native_constant
5
- ALSA::PCM::Native::STREAM_PLAYBACK
5
+ ALSA::PCM::Native::Stream::PLAYBACK
6
6
  end
7
7
 
8
8
  def write_buffer(buffer, frame_count)
@@ -11,28 +11,75 @@ module ALSA::PCM
11
11
  write_count = ALSA::try_to "write in audio interface" do
12
12
  response = ALSA::PCM::Native::writei(self.handle, buffer, frame_count)
13
13
  if ALSA::Native::error_code?(response)
14
- ALSA.logger.warn { "try to recover '#{ALSA::Native::strerror(response)}' on read"}
14
+ ALSA.logger.warn { "try to recover '#{ALSA::Native::strerror(response)}' on write"}
15
15
  ALSA::PCM::Native::pcm_recover(self.handle, response, 1)
16
16
  else
17
17
  response
18
18
  end
19
19
  end
20
20
 
21
+ ALSA.logger.debug { "write frame count: #{write_count}/#{frame_count}"}
22
+
21
23
  missing_frame_count = frame_count - write_count
22
24
  if missing_frame_count > 0
23
25
  ALSA.logger.debug { "missing wroted frame count: #{missing_frame_count}"}
24
26
  end
25
27
  end
26
28
 
29
+ def write_in_background(&block)
30
+ check_handle!
31
+
32
+ async_handler = FFI::MemoryPointer.new(:pointer)
33
+ buffer = FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(buffer_frame_count))
34
+
35
+ started = false
36
+
37
+ playback_callback = Proc.new do |async_handler|
38
+ if started
39
+ audio_content = yield(buffer.size)
40
+ buffer.write_string audio_content
41
+
42
+ read_frame_count =
43
+ if audio_content.size == buffer.size
44
+ buffer_frame_count
45
+ else
46
+ hw_params.frame_count_for(audio_content.size)
47
+ end
48
+
49
+ write_buffer buffer, read_frame_count
50
+ end
51
+ end
52
+
53
+ ALSA::try_to "add pcm handler" do
54
+ ALSA::Native::async_add_pcm_handler(async_handler, handle, playback_callback, nil)
55
+ end
56
+
57
+ ALSA::try_to "start playback" do
58
+ ALSA::PCM::Native::start(handle)
59
+ end
60
+
61
+ silent_frame_count = ALSA::try_to "read available space" do
62
+ ALSA::PCM::Native::avail_update(self.handle)
63
+ end
64
+ ALSA.logger.debug { "write synchronously a silence of #{silent_frame_count} frames"}
65
+ FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(silent_frame_count)) do |silent|
66
+ ALSA::PCM::Native::writei self.handle, silent, silent_frame_count
67
+ end
68
+
69
+ started = true
70
+ end
71
+
27
72
  def write
28
73
  check_handle!
29
74
 
75
+ ALSA.logger.debug { "start write with #{hw_params.inspect}" }
76
+
30
77
  FFI::MemoryPointer.new(:char, hw_params.buffer_size_for(buffer_frame_count)) do |buffer|
31
78
  while audio_content = yield(buffer.size)
32
79
  buffer.write_string audio_content
33
80
 
34
81
  read_frame_count =
35
- if audio_content.size == buffer.size
82
+ if audio_content.size == buffer.size
36
83
  buffer_frame_count
37
84
  else
38
85
  hw_params.frame_count_for(audio_content.size)