radio 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,102 +0,0 @@
1
- # Copyright 2012 The ham21/radio Authors
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.
14
-
15
-
16
- begin
17
- require 'coreaudio'
18
- rescue LoadError => e
19
- end
20
-
21
-
22
- class Radio
23
- module Input
24
-
25
- class CoreAudio
26
-
27
- def self.status
28
- if defined? ::CoreAudio
29
- return "Loaded: %d input devices" % sources.count
30
- end
31
- unless defined? @is_darwin
32
- @is_darwin = (`uname`.strip == 'Darwin') rescue false
33
- end
34
- return "Unsupported: requires Apple OS" unless @is_darwin
35
- return 'Unavailable: gem install coreaudio'
36
- end
37
-
38
- # I don't see a way to automatically set the CoreAudio CODEC rate.
39
- # We'll present the nominal_rate as the only option.
40
- def self.sources
41
- return {} unless defined? ::CoreAudio
42
- result = {}
43
- ::CoreAudio.devices.each do |dev|
44
- channels = dev.input_stream.channels
45
- if channels > 0
46
- result[dev.devid] = {
47
- name: dev.name,
48
- rates: [dev.nominal_rate.to_i],
49
- channels: channels
50
- }
51
- end
52
- end
53
- result
54
- end
55
-
56
- attr_reader :rate, :channels
57
-
58
- # id is the key from the sources hash.
59
- # rate is the desired hardware rate. do not decimate/interpolate here.
60
- def initialize id, rate, channel_i, channel_q
61
- @device = ::CoreAudio::AudioDevice.new id.to_i
62
- @rate = @device.nominal_rate
63
- raise 'I channel fail' unless channel_i < @device.input_stream.channels
64
- @channel_i = channel_i
65
- @channels = 1
66
- if channel_q
67
- raise 'Q channel fail' unless channel_q < @device.input_stream.channels
68
- @channel_q = channel_q
69
- extend IQ
70
- @channels = 2
71
- end
72
- # Half second of buffer
73
- coreaudio_input_buffer_size = @channels * rate / 2
74
- @buf = @device.input_buffer coreaudio_input_buffer_size
75
- @buf.start
76
- end
77
-
78
- # This is called on its own thread in Rig and is expected to block.
79
- def call samples
80
- # CoreAudio range of -32767..32767 makes easy conversion to -1.0..1.0
81
- @buf.read(samples)[@channel_i,true].to_f.div!(32767)
82
- end
83
-
84
- # Once stopped, rig won't attempt starting again on this object.
85
- def stop
86
- @buf.stop
87
- end
88
-
89
- module IQ
90
- def call samples
91
- b = @buf.read samples
92
- c_out = NArray.scomplex samples
93
- c_out[0..-1] = b[@channel_i,true].to_f.div!(32767)
94
- c_out.imag = b[@channel_q,true].to_f.div!(32767)
95
- c_out
96
- end
97
- end
98
-
99
- end
100
-
101
- end
102
- end
@@ -1,292 +0,0 @@
1
- # These are from LGPL licensed programs if they are even copyrightable.
2
- # They will be removed after I implement remez in Ruby.
3
-
4
-
5
- class Radio
6
- class PSK31
7
-
8
- # 48000 to 8000 decimation
9
- FIR_DEC6 = [
10
- -0.001026086585,
11
- -0.002131424398,
12
- -0.003473651912,
13
- -0.005415991401,
14
- -0.007094896149,
15
- -0.008685456592,
16
- -0.009325598368,
17
- -0.009096149588,
18
- -0.007453841473,
19
- -0.004787743788,
20
- -0.001155271744,
21
- 0.002594565142,
22
- 0.005930466661,
23
- 0.007902971637,
24
- 0.008117998323,
25
- 0.006209532708,
26
- 0.002565394219,
27
- -0.002211033166,
28
- -0.006928668876,
29
- -0.010456837484,
30
- -0.011638240040,
31
- -0.009915015895,
32
- -0.005261804435,
33
- 0.001469200215,
34
- 0.008865519609,
35
- 0.015027698257,
36
- 0.018157576105,
37
- 0.016869453853,
38
- 0.010745489111,
39
- 0.000474997075,
40
- -0.012015135186,
41
- -0.023901641616,
42
- -0.031878023716,
43
- -0.032876349281,
44
- -0.024689692215,
45
- -0.006586586958,
46
- 0.020417464549,
47
- 0.053543134171,
48
- 0.088652482149,
49
- 0.120891532319,
50
- 0.145553464727,
51
- 0.158910442030,
52
- 0.158910442030,
53
- 0.145553464727,
54
- 0.120891532319,
55
- 0.088652482149,
56
- 0.053543134171,
57
- 0.020417464549,
58
- -0.006586586958,
59
- -0.024689692215,
60
- -0.032876349281,
61
- -0.031878023716,
62
- -0.023901641616,
63
- -0.012015135186,
64
- 0.000474997075,
65
- 0.010745489111,
66
- 0.016869453853,
67
- 0.018157576105,
68
- 0.015027698257,
69
- 0.008865519609,
70
- 0.001469200215,
71
- -0.005261804435,
72
- -0.009915015895,
73
- -0.011638240040,
74
- -0.010456837484,
75
- -0.006928668876,
76
- -0.002211033166,
77
- 0.002565394219,
78
- 0.006209532708,
79
- 0.008117998323,
80
- 0.007902971637,
81
- 0.005930466661,
82
- 0.002594565142,
83
- -0.001155271744,
84
- -0.004787743788,
85
- -0.007453841473,
86
- -0.009096149588,
87
- -0.009325598368,
88
- -0.008685456592,
89
- -0.007094896149,
90
- -0.005415991401,
91
- -0.003473651912,
92
- -0.002131424398,
93
- -0.001026086585
94
- ].freeze
95
-
96
-
97
- # 64-tap raised-cosine
98
- FIR_DEC16 = [
99
- 0.000000,
100
- 0.000038,
101
- 0.000150,
102
- 0.000336,
103
- 0.000595,
104
- 0.000922,
105
- 0.001317,
106
- 0.001773,
107
- 0.002288,
108
- 0.002856,
109
- 0.003472,
110
- 0.004130,
111
- 0.004823,
112
- 0.005545,
113
- 0.006288,
114
- 0.007047,
115
- 0.007812,
116
- 0.008578,
117
- 0.009337,
118
- 0.010080,
119
- 0.010802,
120
- 0.011495,
121
- 0.012153,
122
- 0.012769,
123
- 0.013337,
124
- 0.013852,
125
- 0.014308,
126
- 0.014703,
127
- 0.015030,
128
- 0.015289,
129
- 0.015475,
130
- 0.015587,
131
- 0.015625,
132
- 0.015587,
133
- 0.015475,
134
- 0.015289,
135
- 0.015030,
136
- 0.014703,
137
- 0.014308,
138
- 0.013852,
139
- 0.013337,
140
- 0.012769,
141
- 0.012153,
142
- 0.011495,
143
- 0.010802,
144
- 0.010080,
145
- 0.009337,
146
- 0.008578,
147
- 0.007813,
148
- 0.007047,
149
- 0.006288,
150
- 0.005545,
151
- 0.004823,
152
- 0.004130,
153
- 0.003472,
154
- 0.002856,
155
- 0.002288,
156
- 0.001773,
157
- 0.001317,
158
- 0.000922,
159
- 0.000595,
160
- 0.000336,
161
- 0.000150,
162
- 0.000038
163
- ].freeze
164
-
165
-
166
- # Design method: Parks-McClellan method
167
- # Number of taps = 35
168
- # Number of bands = 2
169
- # Band Lower Upper Value Weight
170
- # edge edge
171
- # 1 0.0 .0125 1.0 1
172
- # 2 .125 .5 .000001 10
173
- FIR_DEC = [
174
- -0.00021203644,
175
- -0.00070252426,
176
- -0.0016680526,
177
- -0.0031934799,
178
- -0.0051899752,
179
- -0.0072862086,
180
- -0.0087714235,
181
- -0.0086272102,
182
- -0.0056735648,
183
- 0.0011784719,
184
- 0.01261353,
185
- 0.028615709,
186
- 0.048280707,
187
- 0.069812051,
188
- 0.090735013,
189
- 0.10830381,
190
- 0.12001897,
191
- 0.12413413,
192
- 0.12001897,
193
- 0.10830381,
194
- 0.090735013,
195
- 0.069812051,
196
- 0.048280707,
197
- 0.028615709,
198
- 0.01261353,
199
- 0.0011784719,
200
- -0.0056735648,
201
- -0.0086272102,
202
- -0.0087714235,
203
- -0.0072862086,
204
- -0.0051899752,
205
- -0.0031934799,
206
- -0.0016680526,
207
- -0.00070252426,
208
- -0.00021203644
209
- ].freeze
210
-
211
-
212
- # 16 Hz bw LP filter for data recovery
213
- # Filter type: Multiband filter
214
- # Design method: Parks-McClellan method
215
- # Number of taps = 65
216
- # Number of bands = 2
217
- # Band Lower Upper Value Weight
218
- # edge edge
219
- #
220
- # 1 0.0 .03125 1. 1.
221
- # 2 .0625 .5 .0000 286.
222
- FIR_BIT = [
223
- 4.3453566e-005,
224
- -0.00049122414,
225
- -0.00078771292,
226
- -0.0013507826,
227
- -0.0021287814,
228
- -0.003133466,
229
- -0.004366817,
230
- -0.0058112187,
231
- -0.0074249976,
232
- -0.0091398882,
233
- -0.010860157,
234
- -0.012464086,
235
- -0.013807772,
236
- -0.014731191,
237
- -0.015067057,
238
- -0.014650894,
239
- -0.013333425,
240
- -0.01099166,
241
- -0.0075431246,
242
- -0.0029527849,
243
- 0.0027546292,
244
- 0.0094932775,
245
- 0.017113308,
246
- 0.025403511,
247
- 0.034099681,
248
- 0.042895839,
249
- 0.051458575,
250
- 0.059444853,
251
- 0.066521003,
252
- 0.072381617,
253
- 0.076767694,
254
- 0.079481619,
255
- 0.080420311,
256
- 0.079481619,
257
- 0.076767694,
258
- 0.072381617,
259
- 0.066521003,
260
- 0.059444853,
261
- 0.051458575,
262
- 0.042895839,
263
- 0.034099681,
264
- 0.025403511,
265
- 0.017113308,
266
- 0.0094932775,
267
- 0.0027546292,
268
- -0.0029527849,
269
- -0.0075431246,
270
- -0.01099166,
271
- -0.013333425,
272
- -0.014650894,
273
- -0.015067057,
274
- -0.014731191,
275
- -0.013807772,
276
- -0.012464086,
277
- -0.010860157,
278
- -0.0091398882,
279
- -0.0074249976,
280
- -0.0058112187,
281
- -0.004366817,
282
- -0.003133466,
283
- -0.0021287814,
284
- -0.0013507826,
285
- -0.00078771292,
286
- -0.00049122414,
287
- 4.3453566e-005
288
- ].freeze
289
-
290
-
291
- end
292
- end
@@ -1,76 +0,0 @@
1
- require_relative '../lib/radio'
2
-
3
- # Basic loading of uncompressed wav files for testing
4
- def load_wav filename
5
- sample_rate = nil
6
- fmt = nil
7
- data = ''
8
- File.open(filename) do |file|
9
- head = file.read(12)
10
- until file.eof?
11
- type = file.read(4)
12
- size = file.read(4).unpack("V")[0].to_i
13
- case type
14
- when 'fmt '
15
- fmt = file.read(size)
16
- fmt = {
17
- :id => fmt.slice(0,2).unpack('c')[0],
18
- :channel => fmt.slice(2,2).unpack('c')[0],
19
- :hz => fmt.slice(4,4).unpack('V').join.to_i,
20
- :byte_sec => fmt.slice(8,4).unpack('V').join.to_i,
21
- :block_size => fmt.slice(12,2).unpack('c')[0],
22
- :bit_sample => fmt.slice(14,2).unpack('c')[0]
23
- }
24
- when 'data'
25
- data += file.read size
26
- else
27
- raise type
28
- end
29
- end
30
- end
31
- [fmt, data]
32
- end
33
-
34
- # Generate a float enumerator for binary string audio data.
35
- # Packing is defined with Array#pack/String#unpack formats.
36
- # Usage: floats = $iterators['C'].enum_for(:call, data)
37
- # 'C' should be almost as fast as String#each_byte.
38
- # If slow, you probably need to: data.force_encoding('binary')
39
- $iterators = Hash.new do |hash, packing|
40
- packing = packing.to_s.dup
41
- sample_size = [0].pack(packing).size
42
- case ("\x80"*16).unpack(packing)[0]
43
- when 128
44
- max = 128
45
- offset = -128
46
- when -128
47
- max = 128
48
- offset = 0
49
- when 32768 + 128
50
- max = 32768
51
- offset = -32768
52
- when -32768 + 128
53
- max = 32768
54
- offset = 0
55
- else
56
- raise 'unable to interpret packing format'
57
- end
58
- hash[packing] = Proc.new do |data, &block|
59
- pos = 0
60
- size = data.size
61
- while pos < size
62
- sample = data.slice(pos,sample_size).unpack(packing)[0] || 0
63
- block.call (sample + offset).to_f / max
64
- pos += sample_size
65
- end
66
- end
67
- end
68
-
69
-
70
- fmt, data = load_wav 'wav/bpsk8k.wav'
71
- data.force_encoding('binary')
72
- radio = Radio::PSK31::Rx.new 1000
73
-
74
- # "CQ CQ CQ de EA2BAJ EA2BAJ EA2BAJ\rPSE K\r"
75
- i = $iterators['C'].enum_for(:call, data)
76
- radio.call(i){|o| p o}