sound 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/examples/example.rb +1 -1
- data/lib/os/os.rb +20 -15
- data/lib/sound.rb +17 -19
- data/lib/sound/data.rb +0 -3
- data/lib/sound/device.rb +72 -33
- data/lib/sound/device_library.rb +19 -0
- data/lib/sound/device_library/alsa.rb +240 -0
- data/lib/sound/device_library/base.rb +44 -0
- data/lib/sound/device_library/mmlib.rb +237 -0
- data/lib/sound/format.rb +8 -29
- data/lib/sound/format_library.rb +15 -0
- data/lib/sound/format_library/alsa.rb +10 -0
- data/lib/sound/format_library/base.rb +16 -0
- data/lib/sound/format_library/mmlib.rb +61 -0
- metadata +14 -14
- data/lib/sound/alsa.rb +0 -211
- data/lib/sound/win32.rb +0 -150
data/lib/sound/alsa.rb
DELETED
@@ -1,211 +0,0 @@
|
|
1
|
-
require 'ffi'
|
2
|
-
|
3
|
-
module Sound
|
4
|
-
module ALSA
|
5
|
-
|
6
|
-
class Handle
|
7
|
-
def initialize
|
8
|
-
@handle = FFI::MemoryPointer.new(:pointer)
|
9
|
-
end
|
10
|
-
def pointer
|
11
|
-
@handle
|
12
|
-
end
|
13
|
-
def id
|
14
|
-
@handle.read_pointer
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
SND_PCM_STREAM_PLAYBACK = 0
|
19
|
-
SND_PCM_STREAM_CAPTURE = 1
|
20
|
-
DEFAULT_DEVICE_ID = "default"
|
21
|
-
|
22
|
-
extend FFI::Library
|
23
|
-
ffi_lib 'asound'
|
24
|
-
ffi_convention :stdcall
|
25
|
-
|
26
|
-
attach_function :snd_pcm_open, [:pointer, :string, :int, :int], :int
|
27
|
-
attach_function :snd_pcm_close, [:pointer], :int
|
28
|
-
attach_function :snd_pcm_drain, [:pointer], :int
|
29
|
-
attach_function :snd_pcm_prepare, [:pointer], :int
|
30
|
-
attach_function :write_noninterleaved, :snd_pcm_writen, [:pointer, :pointer, :ulong], :long
|
31
|
-
attach_function :snd_pcm_writei, [:pointer, :pointer, :ulong], :long
|
32
|
-
attach_function :snd_pcm_hw_params_malloc, [:pointer], :int
|
33
|
-
attach_function :snd_pcm_hw_params_any, [:pointer, :pointer], :int
|
34
|
-
attach_function :snd_pcm_hw_params_set_access, [:pointer, :pointer, :int], :int
|
35
|
-
attach_function :snd_pcm_hw_params_set_format, [:pointer, :pointer, :int], :int
|
36
|
-
attach_function :snd_pcm_hw_params_set_rate, [:pointer, :pointer, :uint, :int], :int
|
37
|
-
attach_function :snd_pcm_hw_params_set_channels, [:pointer, :pointer, :int], :int
|
38
|
-
attach_function :snd_pcm_hw_params, [:pointer, :pointer], :int
|
39
|
-
attach_function :snd_pcm_hw_params_free, [:pointer], :void
|
40
|
-
|
41
|
-
def snd_pcm_open(*args)
|
42
|
-
output = `aplay -l 2>&1`
|
43
|
-
if output.match(/no soundcard/m)
|
44
|
-
raise NoDeviceError, "No sound devices present"
|
45
|
-
elsif output.match(/not found/m)
|
46
|
-
raise NoDependencyError, "aplay is not present in your environment. Install alsa-utils package for audio playback."
|
47
|
-
else
|
48
|
-
snd_pcm_open(*args)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def open_device
|
53
|
-
begin
|
54
|
-
snd_pcm_open(handle.pointer, id, 0, ASYNC)
|
55
|
-
rescue NoDeviceError
|
56
|
-
Sound.no_device = true
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def prepare_buffer
|
61
|
-
|
62
|
-
unless Sound.no_device
|
63
|
-
buffer_length
|
64
|
-
|
65
|
-
snd_pcm_hw_params_malloc(params_handle.pointer)
|
66
|
-
snd_pcm_hw_params_any(handle.id, params_handle.id)
|
67
|
-
|
68
|
-
snd_pcm_hw_params_set_access(handle.id, params_handle.id, SND_PCM_ACCESS_RW_INTERLEAVED)
|
69
|
-
set_formsnd_pcm_hw_params_set_formatat(handle.id, params_handle.id, SND_PCM_FORMAT_S16_LE)
|
70
|
-
# need to change this to set_rate_near at some point
|
71
|
-
snd_pcm_hw_params_set_rate(handle.id, params_handle.id, data.format.sample_rate, 0)
|
72
|
-
snd_pcm_hw_params_set_channels(handle.id, params_handle.id, 1)
|
73
|
-
|
74
|
-
snd_pcm_hw_params(handle.id, params_handle.id)
|
75
|
-
snd_pcm_hw_params_free(params_handle.id)
|
76
|
-
|
77
|
-
snd_pcm_prepare(handle.id)
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
|
82
|
-
def write_to_device
|
83
|
-
snd_pcm_writei(handle.id, data_buffer, buffer_length) unless Sound.no_device
|
84
|
-
end
|
85
|
-
|
86
|
-
def unprepare_buffer
|
87
|
-
snd_pcm_drain(handle.id) unless Sound.no_device
|
88
|
-
end
|
89
|
-
|
90
|
-
def close_device
|
91
|
-
snd_pcm_close(handle.id) unless Sound.no_device
|
92
|
-
end
|
93
|
-
|
94
|
-
def handle
|
95
|
-
Thread.current[:handle] ||= Handle.new
|
96
|
-
end
|
97
|
-
|
98
|
-
def params_handle
|
99
|
-
Thread.current[:params_handle] ||= Handle.new
|
100
|
-
end
|
101
|
-
|
102
|
-
def data
|
103
|
-
Thread.current[:data]
|
104
|
-
end
|
105
|
-
|
106
|
-
def data_buffer
|
107
|
-
Thread.current[:data_buffer] ||= FFI::MemoryPointer.new(:int, data.pcm_data.size).write_array_of_int data.pcm_data
|
108
|
-
end
|
109
|
-
|
110
|
-
def buffer_length
|
111
|
-
Thread.current[:buffer_length] ||= data_buffer.size/2
|
112
|
-
end
|
113
|
-
|
114
|
-
SND_PCM_ASYNC = 2
|
115
|
-
ASYNC = SND_PCM_ASYNC
|
116
|
-
#snd_pcm formats
|
117
|
-
# Unknown
|
118
|
-
SND_PCM_FORMAT_UNKNOWN = -1
|
119
|
-
# Signed 8 bit
|
120
|
-
SND_PCM_FORMAT_S8 = 0
|
121
|
-
# Unsigned 8 bit
|
122
|
-
SND_PCM_FORMAT_U8 = 1
|
123
|
-
# Signed 16 bit Little Endian
|
124
|
-
SND_PCM_FORMAT_S16_LE = 2
|
125
|
-
# Signed 16 bit Big Endian
|
126
|
-
SND_PCM_FORMAT_S16_BE = 3
|
127
|
-
# Unsigned 16 bit Little Endian
|
128
|
-
SND_PCM_FORMAT_U16_LE = 4
|
129
|
-
# Unsigned 16 bit Big Endian
|
130
|
-
SND_PCM_FORMAT_U16_BE = 5
|
131
|
-
# Signed 24 bit Little Endian using low three bytes in 32-bit word
|
132
|
-
SND_PCM_FORMAT_S24_LE = 6
|
133
|
-
# Signed 24 bit Big Endian using low three bytes in 32-bit word
|
134
|
-
SND_PCM_FORMAT_S24_BE = 7
|
135
|
-
# Unsigned 24 bit Little Endian using low three bytes in 32-bit word
|
136
|
-
SND_PCM_FORMAT_U24_LE = 8
|
137
|
-
# Unsigned 24 bit Big Endian using low three bytes in 32-bit word
|
138
|
-
SND_PCM_FORMAT_U24_BE = 9
|
139
|
-
# Signed 32 bit Little Endian
|
140
|
-
SND_PCM_FORMAT_S32_LE = 10
|
141
|
-
# Signed 32 bit Big Endian
|
142
|
-
SND_PCM_FORMAT_S32_BE = 11
|
143
|
-
# Unsigned 32 bit Little Endian
|
144
|
-
SND_PCM_FORMAT_U32_LE = 12
|
145
|
-
# Unsigned 32 bit Big Endian
|
146
|
-
SND_PCM_FORMAT_U32_BE = 13
|
147
|
-
# Float 32 bit Little Endian, Range -1.0 to 1.0
|
148
|
-
SND_PCM_FORMAT_FLOAT_LE = 14
|
149
|
-
# Float 32 bit Big Endian, Range -1.0 to 1.0
|
150
|
-
SND_PCM_FORMAT_FLOAT_BE = 15
|
151
|
-
# Float 64 bit Little Endian, Range -1.0 to 1.0
|
152
|
-
SND_PCM_FORMAT_FLOAT64_LE = 16
|
153
|
-
# Float 64 bit Big Endian, Range -1.0 to 1.0
|
154
|
-
SND_PCM_FORMAT_FLOAT64_BE = 17
|
155
|
-
# IEC-958 Little Endian
|
156
|
-
SND_PCM_FORMAT_IEC958_SUBFRAME_LE = 18
|
157
|
-
# IEC-958 Big Endian
|
158
|
-
SND_PCM_FORMAT_IEC958_SUBFRAME_BE = 19
|
159
|
-
# Mu-Law
|
160
|
-
SND_PCM_FORMAT_MU_LAW = 20
|
161
|
-
# A-Law
|
162
|
-
SND_PCM_FORMAT_A_LAW = 21
|
163
|
-
# Ima-ADPCM
|
164
|
-
SND_PCM_FORMAT_IMA_ADPCM = 22
|
165
|
-
# MPEG
|
166
|
-
SND_PCM_FORMAT_MPEG = 23
|
167
|
-
# GSM
|
168
|
-
SND_PCM_FORMAT_GSM = 24
|
169
|
-
# Special
|
170
|
-
SND_PCM_FORMAT_SPECIAL = 31
|
171
|
-
# Signed 24bit Little Endian in 3bytes format
|
172
|
-
SND_PCM_FORMAT_S24_3LE = 32
|
173
|
-
# Signed 24bit Big Endian in 3bytes format
|
174
|
-
SND_PCM_FORMAT_S24_3BE = 33
|
175
|
-
# Unsigned 24bit Little Endian in 3bytes format
|
176
|
-
SND_PCM_FORMAT_U24_3LE = 34
|
177
|
-
# Unsigned 24bit Big Endian in 3bytes format
|
178
|
-
SND_PCM_FORMAT_U24_3BE = 35
|
179
|
-
# Signed 20bit Little Endian in 3bytes format
|
180
|
-
SND_PCM_FORMAT_S20_3LE = 36
|
181
|
-
# Signed 20bit Big Endian in 3bytes format
|
182
|
-
SND_PCM_FORMAT_S20_3BE = 37
|
183
|
-
# Unsigned 20bit Little Endian in 3bytes format
|
184
|
-
SND_PCM_FORMAT_U20_3LE = 38
|
185
|
-
# Unsigned 20bit Big Endian in 3bytes format
|
186
|
-
SND_PCM_FORMAT_U20_3BE = 39
|
187
|
-
# Signed 18bit Little Endian in 3bytes format
|
188
|
-
SND_PCM_FORMAT_S18_3LE = 40
|
189
|
-
# Signed 18bit Big Endian in 3bytes format
|
190
|
-
SND_PCM_FORMAT_S18_3BE = 41
|
191
|
-
# Unsigned 18bit Little Endian in 3bytes format
|
192
|
-
SND_PCM_FORMAT_U18_3LE = 42
|
193
|
-
# Unsigned 18bit Big Endian in 3bytes format
|
194
|
-
SND_PCM_FORMAT_U18_3BE = 43
|
195
|
-
SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_U18_3BE
|
196
|
-
|
197
|
-
#snd_pcm access
|
198
|
-
# mmap access with simple interleaved channels
|
199
|
-
SND_PCM_ACCESS_MMAP_INTERLEAVED = 0
|
200
|
-
# mmap access with simple non interleaved channels
|
201
|
-
SND_PCM_ACCESS_MMAP_NONINTERLEAVED = 1
|
202
|
-
# mmap access with complex placement
|
203
|
-
SND_PCM_ACCESS_MMAP_COMPLEX = 2
|
204
|
-
# snd_pcm_readi/snd_pcm_writei access
|
205
|
-
SND_PCM_ACCESS_RW_INTERLEAVED = 3
|
206
|
-
# snd_pcm_readn/snd_pcm_writen access
|
207
|
-
SND_PCM_ACCESS_RW_NONINTERLEAVED = 4
|
208
|
-
SND_PCM_ACCESS_LAST = SND_PCM_ACCESS_RW_NONINTERLEAVED
|
209
|
-
|
210
|
-
end
|
211
|
-
end
|
data/lib/sound/win32.rb
DELETED
@@ -1,150 +0,0 @@
|
|
1
|
-
require 'ffi'
|
2
|
-
|
3
|
-
module Sound
|
4
|
-
module Win32
|
5
|
-
|
6
|
-
class Handle
|
7
|
-
def initialize
|
8
|
-
@handle = HWAVEOUT.new
|
9
|
-
end
|
10
|
-
def pointer
|
11
|
-
@handle.pointer
|
12
|
-
end
|
13
|
-
def id
|
14
|
-
@handle[:i]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
extend FFI::Library
|
19
|
-
|
20
|
-
typedef :ulong, :dword
|
21
|
-
typedef :uintptr_t, :hwaveout
|
22
|
-
typedef :uint, :mmresult
|
23
|
-
|
24
|
-
ffi_lib :winmm
|
25
|
-
|
26
|
-
attach_function :waveOutOpen, [:pointer, :uint, :pointer, :dword, :dword, :dword], :mmresult
|
27
|
-
attach_function :waveOutPrepareHeader, [:hwaveout, :pointer, :uint], :mmresult
|
28
|
-
attach_function :waveOutWrite, [:hwaveout, :pointer, :uint], :mmresult
|
29
|
-
attach_function :waveOutUnprepareHeader, [:hwaveout, :pointer, :uint], :mmresult
|
30
|
-
attach_function :waveOutClose, [:hwaveout], :mmresult
|
31
|
-
|
32
|
-
WAVE_FORMAT_PCM = 1
|
33
|
-
WAVE_MAPPER = -1
|
34
|
-
DEFAULT_DEVICE_ID = WAVE_MAPPER
|
35
|
-
|
36
|
-
def open_device
|
37
|
-
waveOutOpen(handle.pointer, id, data.format.pointer, 0, 0, 0)
|
38
|
-
end
|
39
|
-
|
40
|
-
def prepare_buffer
|
41
|
-
waveOutPrepareHeader(handle.id, header.pointer, header.size)
|
42
|
-
end
|
43
|
-
|
44
|
-
def write_to_device
|
45
|
-
waveOutWrite(handle.id, header.pointer, header.size)
|
46
|
-
end
|
47
|
-
|
48
|
-
def unprepare_buffer
|
49
|
-
while waveOutUnprepareHeader(handle.id, header.pointer, header.size) == 33
|
50
|
-
sleep 0.001
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def close_device
|
55
|
-
waveOutClose(handle.id)
|
56
|
-
end
|
57
|
-
|
58
|
-
def handle
|
59
|
-
Thread.current[:handle] ||= Handle.new
|
60
|
-
end
|
61
|
-
|
62
|
-
def data
|
63
|
-
Thread.current[:data]
|
64
|
-
end
|
65
|
-
|
66
|
-
def header
|
67
|
-
Thread.current[:header] ||= WAVEHDR.new(data_buffer, buffer_length)
|
68
|
-
end
|
69
|
-
|
70
|
-
def data_buffer
|
71
|
-
Thread.current[:data_buffer] ||= FFI::MemoryPointer.new(:int, data.pcm_data.size).write_array_of_int data.pcm_data
|
72
|
-
end
|
73
|
-
|
74
|
-
def buffer_length
|
75
|
-
Thread.current[:buffer_length] ||= data.format.avg_bps*data.duration/1000
|
76
|
-
end
|
77
|
-
|
78
|
-
# Define an HWAVEOUT struct for use by all the waveOut functions.
|
79
|
-
# It is a handle to a waveOut stream, so starting up multiple
|
80
|
-
# streams using different handles allows for simultaneous playback.
|
81
|
-
# You never need to actually look at the struct, C takes care of
|
82
|
-
# its value.
|
83
|
-
#
|
84
|
-
class HWAVEOUT < FFI::Struct
|
85
|
-
layout :i, :int
|
86
|
-
end
|
87
|
-
|
88
|
-
# Define WAVEFORMATEX which defines the format (PCM in this case)
|
89
|
-
# and various properties like sampling rate, number of channels, etc.
|
90
|
-
#
|
91
|
-
class WAVEFORMATEX < FFI::Struct
|
92
|
-
|
93
|
-
# Initializes struct with sensible defaults for most commonly used
|
94
|
-
# values. While setting these manually is possible, please be
|
95
|
-
# sure you know what changes will result in, as an incorrectly
|
96
|
-
# set struct will result in unpredictable behavior.
|
97
|
-
#
|
98
|
-
def initialize(nSamplesPerSec = 44100, wBitsPerSample = 16, nChannels = 1, cbSize = 0)
|
99
|
-
self[:wFormatTag] = WAVE_FORMAT_PCM
|
100
|
-
self[:nChannels] = nChannels
|
101
|
-
self[:nSamplesPerSec] = nSamplesPerSec
|
102
|
-
self[:wBitsPerSample] = wBitsPerSample
|
103
|
-
self[:cbSize] = cbSize
|
104
|
-
self[:nBlockAlign] = (self[:wBitsPerSample] >> 3) * self[:nChannels]
|
105
|
-
self[:nAvgBytesPerSec] = self[:nBlockAlign] * self[:nSamplesPerSec]
|
106
|
-
end
|
107
|
-
|
108
|
-
layout(
|
109
|
-
:wFormatTag, :ushort,
|
110
|
-
:nChannels, :ushort,
|
111
|
-
:nSamplesPerSec, :ulong,
|
112
|
-
:nAvgBytesPerSec, :ulong,
|
113
|
-
:nBlockAlign, :ushort,
|
114
|
-
:wBitsPerSample, :ushort,
|
115
|
-
:cbSize, :ushort
|
116
|
-
)
|
117
|
-
end
|
118
|
-
|
119
|
-
#define WAVEHDR which is a header to a block of audio
|
120
|
-
#lpData is a pointer to the block of native memory that,
|
121
|
-
# in this case, is an integer array of PCM data
|
122
|
-
|
123
|
-
class WAVEHDR < FFI::Struct
|
124
|
-
|
125
|
-
# Initializes struct with sensible defaults for most commonly used
|
126
|
-
# values. While setting these manually is possible, please be
|
127
|
-
# sure you know what changes will result in, as an incorrectly
|
128
|
-
# set struct will result in unpredictable behavior.
|
129
|
-
#
|
130
|
-
def initialize(lpData, dwBufferLength, dwFlags = 0, dwLoops = 1)
|
131
|
-
self[:lpData] = lpData
|
132
|
-
self[:dwBufferLength] = dwBufferLength
|
133
|
-
self[:dwFlags] = dwFlags
|
134
|
-
self[:dwLoops] = dwLoops
|
135
|
-
end
|
136
|
-
|
137
|
-
layout(
|
138
|
-
:lpData, :pointer,
|
139
|
-
:dwBufferLength, :ulong,
|
140
|
-
:dwBytesRecorded, :ulong,
|
141
|
-
:dwUser, :ulong,
|
142
|
-
:dwFlags, :ulong,
|
143
|
-
:dwLoops, :ulong,
|
144
|
-
:lpNext, :pointer,
|
145
|
-
:reserved, :ulong
|
146
|
-
)
|
147
|
-
end
|
148
|
-
|
149
|
-
end
|
150
|
-
end
|