cw 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -72,7 +72,7 @@ module CWG
72
72
  end
73
73
  sleep 0.01
74
74
  end
75
- Cfg.config["exit"] = true
75
+ # Cfg.config["exit"] = true
76
76
  sleep 0.1
77
77
  end
78
78
 
@@ -46,12 +46,12 @@ module CWG
46
46
 
47
47
  def reset
48
48
  @print_count = 0
49
- puts "\r"
50
49
  end
51
50
 
52
51
  def newline
53
52
  reset
54
53
  update_console_size
54
+ puts "\r"
55
55
  end
56
56
 
57
57
  def force_newline_maybe
@@ -125,6 +125,18 @@ module CWG
125
125
  print paint("#{word}", list_colour)
126
126
  end
127
127
 
128
+ def tx word
129
+ print paint("#{word}", tx_colour)
130
+ end
131
+
132
+ def rx word
133
+ print paint("#{word}", rx_colour)
134
+ end
135
+
136
+ def menu word
137
+ print paint("#{word}", menu_colour)
138
+ end
139
+
128
140
  def success word
129
141
  newline_maybe word
130
142
  return if(@print_count == 0 && word == ' ')
@@ -143,6 +155,18 @@ module CWG
143
155
  Cfg.config["list_colour"].to_sym || :default
144
156
  end
145
157
 
158
+ def tx_colour
159
+ Cfg.config["tx_colour"].to_sym || :red
160
+ end
161
+
162
+ def rx_colour
163
+ Cfg.config["rx_colour"].to_sym || :blue
164
+ end
165
+
166
+ def menu_colour
167
+ Cfg.config["menu_colour"].to_sym || :yellow
168
+ end
169
+
146
170
  def print_advice name
147
171
  puts "#{name}: Press Q 4 times to Exit"
148
172
  end
@@ -58,23 +58,28 @@ module CWG
58
58
  end
59
59
  end
60
60
 
61
+ def threads
62
+ threads ||= CWThreads.new(self, thread_processes)
63
+ end
64
+
61
65
  def run words
62
66
  temp_words = words.all
63
67
  temp_words.each do |word|
64
68
  loop do
69
+ Cfg.config.params["exit"] = false
65
70
  break if test_env
66
71
  @input_word, @words = '', Words.new
67
72
  Cfg.config.params["quit"] = false
68
73
  @words.assign word
69
- @threads = CWThreads.new(self, thread_processes)
70
- @threads.start_threads
71
- @threads.wait_for_threads
74
+ threads.run
75
+ # threads.start_threads
76
+ # threads.wait_for_threads
72
77
  @play = nil
73
78
  system("stty -raw echo")
74
79
  break unless failed?
75
80
  end
76
81
  end
77
- # break if Cfg.config["exit"]
82
+ Cfg.config.params["exit"] = true
78
83
  end
79
84
  end
80
85
  end
@@ -1,5 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require 'oga'
4
+ require 'httpclient'
5
+ require "htmlentities"
6
+ require 'sanitize'
7
+
3
8
  module CWG
4
9
 
5
10
  #class Rss
@@ -22,25 +27,25 @@ module CWG
22
27
  end
23
28
 
24
29
  def read_rss(src, article_count = 3)
25
- require 'feedjira'
26
- require "htmlentities"
27
- require 'sanitize'
30
+
31
+ Cfg.config.params["words_counted"] = true
32
+ @rss_articles = []
33
+ count = 0
28
34
  coder = HTMLEntities.new
29
35
  url = source(src)
30
- # return a Hash - each url having a Feedjira::Feed object
31
- feed = Feedjira::Feed.fetch_and_parse url
32
- entry_count = 0
33
- @rss_articles = []
34
- feed.entries.each do |entry|
35
- title = entry.title
36
+ content = HTTPClient.new.get_content(url)
37
+ document = Oga.parse_xml(content)
38
+ document.xpath('rss/channel/item').each do |item|
39
+ title = item.at_xpath('title').text
40
+ description = item.at_xpath('description').text
36
41
  unless(title.include?('VIDEO:') ||
37
42
  title.include?('In pictures:') ||
38
43
  title.include?('Morning business round-up'))
39
- words = entry.summary
40
- entry_count += 1
44
+ @rss_articles << Sanitize.clean(coder.decode(title)) + '. ' +
45
+ Sanitize.clean(coder.decode(description))
46
+ count += 1
47
+ break if count >= article_count
41
48
  end
42
- @rss_articles << (Sanitize.clean coder.decode words).split(',')
43
- break if entry_count >= article_count
44
49
  end
45
50
  end
46
51
 
@@ -53,14 +58,12 @@ module CWG
53
58
  end
54
59
 
55
60
  def next_article
56
- temp = @rss_articles[article_index]
57
- return unless temp
61
+ article = @rss_articles[article_index]
62
+ return unless article
58
63
  inc_article_index
59
- quote = ''
60
- temp.map { |i| quote += i }
61
- (quote.split.collect { |article| cw_chars(article.strip.delete("\"").downcase)})
64
+ article.split.collect do |chars|
65
+ cw_chars(chars.strip.delete("\"").downcase)
66
+ end
62
67
  end
63
-
64
68
  end
65
-
66
69
  end
@@ -227,6 +227,11 @@ module CWG
227
227
  exit!
228
228
  end
229
229
 
230
+ def cw_threads
231
+ @cw_threads ||= CWThreads.new(self, thread_processes)
232
+ end
233
+
234
+
230
235
  def thread_processes
231
236
  [
232
237
  :monitor_keys_thread,
@@ -237,8 +242,7 @@ module CWG
237
242
 
238
243
  def run words
239
244
  @words = words
240
- @cw_threads = CWThreads.new(self, thread_processes)
241
- @cw_threads.run
245
+ cw_threads.run
242
246
  @play = nil
243
247
  reset_stdin
244
248
  print.newline
@@ -11,22 +11,48 @@ module CWG
11
11
  include ToneHelpers
12
12
  include FileDetails
13
13
 
14
+ attr_reader :code
15
+
16
+ class Code
17
+
18
+ include FileDetails
19
+
20
+ def initialize sample_rate, wpm
21
+ @sample_rate = sample_rate
22
+ @wpm = wpm
23
+ @spb_short = @sample_rate * 1.2 / @wpm
24
+ @spb_long = @sample_rate * 3.6 / @wpm
25
+ end
26
+
27
+ def filename element
28
+ self.send "#{element}_path"
29
+ end
30
+
31
+ def spb element
32
+ spb = element == :dash ?
33
+ @spb_long :
34
+ @spb_short
35
+ spb.to_i
36
+ end
37
+ end
38
+
14
39
  def initialize
40
+ @sample_rate = 2400
15
41
  @max_amplitude = (Cfg.config["volume"].to_f > 1.0 ?
16
42
  1.0 : Cfg.config["volume"].to_f)
17
43
  @wpm = Cfg.config["wpm"].to_f
18
44
  @frequency = Cfg.config["frequency"].to_i
19
45
  @effective_wpm = Cfg.config["effective_wpm"] ?
20
46
  Cfg.config["effective_wpm"].to_f : @wpm
21
- @sample_rate = 2400
22
47
  @print = Print.new
23
48
  end
24
49
 
25
- def generate wrds
50
+ def code
51
+ @code ||= Code.new(@sample_rate, @wpm)
52
+ end
26
53
 
54
+ def generate wrds
27
55
  word_parts(wrds)
28
- # progress.init elements.size * 3 + (wrds.size)
29
- create_element_methods
30
56
  compile_fundamentals
31
57
  write_word_parts
32
58
  end
@@ -35,11 +61,6 @@ module CWG
35
61
  @play_filename ||= File.join(audio_dir, audio_filename)
36
62
  end
37
63
 
38
- def play
39
- cmd = play_command + ' ' + play_filename
40
- @pid = ! @dry_run ? Process.spawn(cmd) : cmd
41
- end
42
-
43
64
  def cw_encoding
44
65
  @encoding ||= CwEncoding.new
45
66
  end
@@ -48,21 +69,6 @@ module CWG
48
69
  @progress ||= Progress.new('Compiling')
49
70
  end
50
71
 
51
- def data
52
- { :dot => {:name => :dot,
53
- :filename => dot_path,
54
- :spb => (@sample_rate * 1.2 / @wpm).to_i },
55
- :dash => {:name => :dash,
56
- :filename => dash_path,
57
- :spb => (@sample_rate * 3.6 / @wpm).to_i },
58
- :space => {:name => :space,
59
- :filename => space_path,
60
- :spb => (@sample_rate * 1.2 / @wpm).to_i },
61
- :e_space => {:name => :e_space,
62
- :filename => e_space_path,
63
- :spb => (@sample_rate * 1.2 / @effective_wpm).to_i }}
64
- end
65
-
66
72
  def filter_maybe(size, count)
67
73
  ramp = 0.05
68
74
  ramp_point = @max_amplitude / ramp
@@ -83,11 +89,13 @@ module CWG
83
89
  end
84
90
 
85
91
  def generate_buffer audio_samples, ele
86
- WaveFile::Buffer.new(audio_samples, WaveFile::Format.new(:mono, :float, data[ele][:spb]))
92
+ WaveFile::Buffer.new(audio_samples,
93
+ WaveFile::Format.new(:mono, :float, code.spb(ele)))
87
94
  end
88
95
 
89
96
  def write_element_audio_file ele, buffer
90
- WaveFile::Writer.new(data[ele][:filename], WaveFile::Format.new(:mono, :pcm_16, @sample_rate)) do |writer|
97
+ WaveFile::Writer.new(code.filename(ele),
98
+ WaveFile::Format.new(:mono, :pcm_16, @sample_rate)) do |writer|
91
99
  writer.write(buffer)
92
100
  end
93
101
  end
@@ -96,23 +104,9 @@ module CWG
96
104
  [:dot, :dash, :space, :e_space]
97
105
  end
98
106
 
99
- # create dot, dash, space or e_space method
100
-
101
- def create_element_method ele
102
- define_singleton_method(ele) {data[ele]}
103
- end
104
-
105
- # create dot, dash, space and e_space methods
106
-
107
- def create_element_methods
108
- elements.each do |ele|
109
- create_element_method ele
110
- end
111
- end
112
-
113
107
  def generate_samples ele
114
- return generate_space(data[ele][:spb]) if space_sample? ele
115
- generate_tone(data[ele][:spb]) unless space_sample? ele
108
+ return generate_space(code.spb(ele)) if space_sample? ele
109
+ generate_tone(code.spb(ele)) unless space_sample? ele
116
110
  end
117
111
 
118
112
  def compile_fundamentals
@@ -123,50 +117,43 @@ module CWG
123
117
  end
124
118
  end
125
119
 
120
+ def ewpm?
121
+ @effective_wpm != @wpm
122
+ end
123
+
126
124
  def space_or_espace
127
- (@effective_wpm == @wpm) ? space : e_space
125
+ { name: (ewpm? ? :e_space : :space) }
128
126
  end
129
127
 
130
128
  def push_enc chr
131
129
  arry = []
132
130
  chr.each_with_index do |c,idx|
133
131
  arry << c
134
- arry << ((last_element?(idx, chr)) ? (space_or_espace) : space)
132
+ arry << (last_element?(idx, chr) ? space_or_espace : { name: :space })
135
133
  end
136
134
  arry += char_space
137
135
  end
138
136
 
139
- def send_char c
140
- enc = nil
141
- if c == ' '
142
- enc = word_space
143
- else
144
- enc = cw_encoding.fetch(c).map { |e| send(e)}
145
- end
137
+ def send_char(c)
138
+ enc = c == ' ' ? [word_space] : cw_encoding.fetch(c).map { |e|
139
+ { :name => e }
140
+ }
146
141
  push_enc enc
147
142
  end
148
143
 
149
- def word_parts str = nil
144
+ def word_parts(str = nil)
150
145
  return @word_parts if @word_parts
151
146
  @word_parts = []
152
- str.split('').each { |part| @word_parts << part}
147
+ str.split('').each { |part| @word_parts << part }
153
148
  @word_parts
154
149
  end
155
150
 
156
- def make_word_parts
157
- parts = []
158
- @word_parts.each do |part|
159
- parts += send_char part.downcase
160
- end
161
- parts
162
- end
163
-
164
151
  def prepare_buffers
165
152
  @buffers = {}
166
153
  elements.each do |ele|
167
154
  @buffers[ele] = []
168
- WaveFile::Reader.new(data[ele][:filename]).
169
- each_buffer(data[ele][:spb]) do |buffer|
155
+ WaveFile::Reader.new(code.filename(ele))
156
+ .each_buffer(code.spb(ele)) do |buffer|
170
157
  @buffers[ele] = buffer
171
158
  end
172
159
  end
@@ -178,42 +165,40 @@ module CWG
178
165
  end
179
166
 
180
167
  def char_space
181
- @effective_wpm == @wpm ? [space,space] : [e_space,e_space]
168
+ Array.new(2, word_space)
182
169
  end
183
170
 
184
171
  def word_space
185
- @effective_wpm == @wpm ? [space] : [e_space]
172
+ { name: (ewpm? ? :e_space : :space) }
186
173
  end
187
174
 
188
- def word_composite word
175
+ def word_composite(word)
189
176
  send_char word.downcase
190
177
  end
191
178
 
192
- def write_audio
193
- WaveFile::Writer.
194
- new(play_filename,
195
- WaveFile::Format.
196
- new(:mono,
197
- :pcm_16,
198
- @sample_rate)) do |writer|
199
- yield.each do |char|
200
- char.each do |fta|
201
- writer.write(@buffers[fta[:name]])
202
- end
203
- end
204
- end
179
+ def format
180
+ WaveFile::Format.new(:mono, :pcm_16, @sample_rate)
205
181
  end
206
182
 
207
- def reset
208
- @word_parts = @progress = nil
209
- # puts "\r"
183
+ def write_buffer(writer, fta)
184
+ writer.write(@buffers[fta[:name]])
185
+ end
186
+
187
+ def write_audio
188
+ WaveFile::Writer.new(play_filename, format) do |writer|
189
+ yield.map { |ch| ch.map { |fta| write_buffer(writer, fta) } }
190
+ end
210
191
  end
211
192
 
212
193
  def write_audio_file
213
194
  write_audio do
214
- @word_parts.collect {|part| word_composite(part) }
195
+ @word_parts.collect { |part| word_composite(part) }
215
196
  end
216
197
  reset
217
198
  end
199
+
200
+ def reset
201
+ @word_parts = @progress = nil
202
+ end
218
203
  end
219
204
  end
@@ -4,7 +4,7 @@ module CWG
4
4
 
5
5
  module ToneHelpers
6
6
 
7
- TWO_PI = 2 * Math::PI
7
+ TWO_PI = 2 * Math::PI
8
8
 
9
9
  def convert_words wrds
10
10
  wrds.to_array.collect{ |wrd| wrd.delete("\n")}
@@ -0,0 +1,487 @@
1
+ # coding: utf-8
2
+ module CWG
3
+
4
+ class Tx < Tester
5
+
6
+ include ToneHelpers
7
+ include FileDetails
8
+
9
+ def initialize
10
+ @max_amplitude = (Cfg.config["volume"].to_f > 1.0 ?
11
+ 1.0 : Cfg.config["volume"].to_f)
12
+ @wpm = Cfg.config["wpm"].to_f
13
+ @frequency = Cfg.config["frequency"].to_i
14
+ @effective_wpm = Cfg.config["effective_wpm"] ?
15
+ Cfg.config["effective_wpm"].to_f : @wpm
16
+ @sample_rate = 2400
17
+ @print = Print.new
18
+ @words = []
19
+ @recording = []
20
+ print.rx "\n"
21
+ print.tx "\n"
22
+ print.menu "\n"
23
+ end
24
+
25
+ def core_audio
26
+ @core_audio ||= Coreaudio.new
27
+ end
28
+
29
+ def add_space words
30
+ str = ''
31
+ words.to_array.collect { |word| str << word + ' '}
32
+ str
33
+ end
34
+
35
+ def monitor_keys
36
+ @char = '#'
37
+ process_letter
38
+
39
+ loop do
40
+ @char = key_input.read
41
+ break if quit_key_input?
42
+ break if quit?
43
+ break if exit?
44
+ check_sentence_navigation(@char) if self.class == Book
45
+ check_clear @char
46
+ process_letter
47
+ end
48
+ end
49
+
50
+ def check_clear char
51
+ if char == "\e"
52
+ @words = []
53
+ end
54
+ end
55
+
56
+ def print_mode(mode)
57
+ msg = "\n\r" + (mode == :rx ?
58
+ "Receive Mode:" :
59
+ "Transmit Mode:") + "\n\r"
60
+ print.tx msg if :tx == mode
61
+ print.rx msg if :rx == mode
62
+ end
63
+
64
+ def receive_mode
65
+ print_mode :rx
66
+ loop do
67
+ char = key_input.read
68
+ check_clear char
69
+ case char
70
+ when '#'
71
+ print_mode :tx
72
+ return
73
+ when '|'
74
+ capture
75
+ when '\\'
76
+ info
77
+ when '>'
78
+ return '>'
79
+ when "\n"
80
+ puts "\n"
81
+ when "\r"
82
+ puts "\r"
83
+ when 'Q'
84
+ puts "Quitting..."
85
+ quit!
86
+ else
87
+ if(@recording.include? ' ')
88
+ @recording = [char]
89
+ else
90
+ @recording << char
91
+ end
92
+ puts 'here'
93
+ print.rx char
94
+ end
95
+ sleep 0.001
96
+ end
97
+ end
98
+
99
+ def quit!
100
+ Cfg.config.params["exit"] = true
101
+ end
102
+
103
+ def capture
104
+ puts "\n\r"
105
+ puts "\r Menu: [C]allsign, [N]ame, "
106
+ puts "\r [L]ocation, [R]st, "
107
+ puts "\r [T]emperature, [S]tore,"
108
+ puts "\r [I]nfo, [W]PM, "
109
+ puts "\r [Q]uit capture!"
110
+ puts "\r"
111
+ puts "\r Use CAPITAL to capture"
112
+
113
+ loop do
114
+ char = key_input.read
115
+ # print.menu char
116
+ upcase = /[[:upper:]]/.match(char)
117
+ case char.downcase
118
+ when 'c'
119
+ return capture_attribute :callsign, upcase
120
+ when 'n'
121
+ return capture_attribute :name, upcase
122
+ when 'l'
123
+ return capture_attribute :qth, upcase
124
+ when 'r'
125
+ return capture_attribute :rst, upcase
126
+ when 't'
127
+ return capture_attribute :temperature, upcase
128
+ when 'i'
129
+ return info
130
+ when 's'
131
+ return store
132
+ when 'q'
133
+ puts "\rCancelled!"
134
+ return
135
+ else
136
+ puts "\nInvalid letter(#{char}) - try again!"
137
+ end
138
+ sleep 0.001
139
+ end
140
+ end
141
+
142
+ def store
143
+ puts "\n\r"
144
+ puts "\rStoring info:"
145
+ info
146
+ @their_callsign
147
+ @their_name
148
+ @their_location
149
+ @their_rst
150
+ puts "\rCleared info!"
151
+ puts "\r"
152
+ end
153
+
154
+ def capture_attribute(attr_type, use_recording = false)
155
+ puts "\n\r"
156
+ puts "Enter their #{attr_type.to_s} followed by SPACE" unless use_recording
157
+ temp = use_recording ? @recording : []
158
+ print.menu temp.join('').delete(' ') if(@recording && ! use_recording)
159
+ @recording = []
160
+ if use_recording
161
+ write_attribute temp, attr_type
162
+ return
163
+ end
164
+ loop do
165
+ char = key_input.read
166
+ if key_input.is_relevant_char?(char)
167
+ temp << char
168
+ print.menu char unless use_recording
169
+ if ' ' == char
170
+ temp << char
171
+ write_attribute temp, attr_type
172
+ return
173
+ end
174
+ elsif char == 'Q'
175
+ puts "\n\n\rCancelled!\n\n\r"
176
+ return
177
+ end
178
+ end
179
+ end
180
+
181
+ def write_attribute attr, type
182
+ clip = attr.join('').delete(' ')
183
+ @their_callsign = clip if :callsign == type
184
+ @their_name = clip if :name == type
185
+ @their_rst = clip if :rst == type
186
+ @their_qth = clip if :qth == type
187
+ @temperature = clip if :temperature == type
188
+ puts "\n\n\r#{type.to_s}: #{@their_callsign.upcase}\n\n\r" if :callsign == type
189
+ unless :callsign == type
190
+ puts "\n\n\rAttr: #{@temperature}°C\n\n\r" if :temperature == type
191
+ puts "\n\n\rTheir #{type.to_s}: #{clip}\n\n\r" unless :temperature == type
192
+ end
193
+ end
194
+
195
+ def my_callsign
196
+ morsify "m0gzg "
197
+ end
198
+
199
+ def their_callsign
200
+ morsify @their_callsign unless @their_callsign.nil?
201
+ end
202
+
203
+ def return_with_k
204
+ acknowledge
205
+ morsify 'k '
206
+ end
207
+
208
+ def return_with_kn
209
+ morsify '+ '
210
+ acknowledge
211
+ morsify 'kn '
212
+ end
213
+
214
+ def acknowledge
215
+ their_callsign
216
+ morsify ' de '
217
+ my_callsign
218
+ end
219
+
220
+ def received_ok
221
+ acknowledge
222
+ morsify 'en en '
223
+ end
224
+
225
+ def sign_off
226
+ morsify "ok om #{@their_name} 73 es tnx fer nice qso = hpe 2cuagn sn + "
227
+ their_callsign
228
+ morsify ' de '
229
+ my_callsign
230
+ morsify ' sk '
231
+ end
232
+
233
+ def stop
234
+ morsify '= '
235
+ end
236
+
237
+ def long_cq
238
+ morsify "cqcq cqcq de m0gzg m0gzg k "
239
+ end
240
+
241
+ def morsify sentence
242
+ sentence.split('').collect{ |letr| char_to_tx letr }
243
+ end
244
+
245
+ def rst
246
+ morsify "rst is 599 5nn = "
247
+ end
248
+
249
+ def name
250
+ morsify "name is m a r t y n martyn = "
251
+ end
252
+
253
+ def qth
254
+ morsify "qth is o l d w o o d nr l i n c o l n lincoln = "
255
+ end
256
+
257
+ def weather
258
+ morsify "hr wx is sunny with some clouds = temp #{@temperature}c = "
259
+ end
260
+
261
+ def dit_dit
262
+ morsify 'e e '
263
+ end
264
+
265
+ def info
266
+ now = Time.now.utc
267
+ time = now.strftime("%H:%M:%S Z")
268
+ date = now.strftime("%d/%m/%y")
269
+ puts "\r----------------------------\r"
270
+ puts "Time: #{time}\r"
271
+ puts "Date: #{date}\r"
272
+ puts "Temp: #{@temperature}°C\r"
273
+ puts "\r"
274
+ callsign = @their_callsign.nil? ? '' : @their_callsign.upcase
275
+ puts "Their Call: #{callsign}\r"
276
+ puts "Their Name: #{@their_name}\r"
277
+ puts "Their RST: #{@their_rst}\r"
278
+ puts "Their qth: #{@their_qth}\r"
279
+ puts "\r----------------------------\r"
280
+ puts "\n\r"
281
+ end
282
+
283
+ def process_letter
284
+ @input_word ||= ''
285
+ case @char
286
+ when '#'
287
+ return_val = receive_mode
288
+ if '>' == return_val
289
+ return_with_k
290
+ else
291
+ @char = ''
292
+ end
293
+ when '.'
294
+ stop
295
+ when 'F'
296
+ @wpm += 1
297
+ @effective_wpm = @wpm
298
+ when 'S'
299
+ @wpm -= 1
300
+ @effective_wpm = @wpm
301
+ when '='
302
+ morsify '= '
303
+ when ','
304
+ morsify ', '
305
+ when '\\'
306
+ info
307
+ when '|'
308
+ capture
309
+ when '?'
310
+ morsify '? '
311
+ when '@'
312
+ long_cq
313
+ when '£'
314
+ my_callsign
315
+ when '$'
316
+ their_callsign
317
+ when '}'
318
+ sign_off
319
+ when '>'
320
+ return_with_k
321
+ when ')'
322
+ return_with_kn
323
+ when '('
324
+ received_ok
325
+ when '^'
326
+ qth
327
+ when '%'
328
+ rst
329
+ when '&'
330
+ name
331
+ when '*'
332
+ weather
333
+ when 'E'
334
+ dit_dit
335
+ when "\n"
336
+ puts "\n"
337
+ when "\r"
338
+ puts "\r"
339
+ when 'Q'
340
+ puts "Quitting..."
341
+ quit!
342
+ else
343
+ if key_input.is_relevant_char?(@char)
344
+ char_to_tx @char
345
+ end
346
+ end
347
+ @char = ''
348
+ end
349
+
350
+ def char_to_tx char
351
+ @words << char
352
+ # print.tx char
353
+ end
354
+
355
+ def thread_processes
356
+ [
357
+ :tx_words_thread,
358
+ :monitor_keys_thread,
359
+ # :print_words_thread
360
+ ]
361
+ end
362
+
363
+ def word_composite word
364
+ send_char word.downcase
365
+ end
366
+
367
+ def push_enc chr
368
+ arry = []
369
+ chr.each_with_index do |c,idx|
370
+ arry << c
371
+ arry << ((last_element?(idx, chr)) ? (space_or_espace) : space)
372
+ end
373
+ arry += char_space
374
+ end
375
+
376
+ def cw_encoding
377
+ @encoding ||= CwEncoding.new
378
+ end
379
+
380
+ def space_or_espace
381
+ (@effective_wpm == @wpm) ? space : e_space
382
+ end
383
+
384
+ def char_space
385
+ @effective_wpm == @wpm ? [space,space] : [e_space,e_space]
386
+ end
387
+
388
+ def word_space
389
+ @effective_wpm == @wpm ? [space] : [e_space]
390
+ end
391
+
392
+ def send_char c
393
+ enc = nil
394
+ if c == ' '
395
+ enc = word_space
396
+ else
397
+ enc = cw_encoding.fetch(c).map { |e| send(e)}
398
+ end
399
+ push_enc enc
400
+ end
401
+
402
+ def audio_thread
403
+ temp = @word_parts.collect {|part| word_composite(part) }
404
+ @word_parts = nil
405
+ wpm = 1.5
406
+ temp.each do |letr|
407
+ letr.each do |ele|
408
+ if (:space == ele[:name]) || (:e_space == ele[:name])
409
+ core_audio.generate_silence(tone.data[
410
+ ele[:name]][:spb] * 20)
411
+ else
412
+ core_audio.generate_tone( tone.data[
413
+ ele[:name]][:spb] * 20)
414
+ end
415
+ end
416
+ end
417
+ end
418
+
419
+ def generate wrds
420
+ word_parts(wrds)
421
+ create_element_methods
422
+ core_audio.start
423
+ cw_threads.add self, :audio_thread
424
+ # th = Thread.start do
425
+ cw_threads.join :audio_thread
426
+ sleep 0.001
427
+ core_audio.stop
428
+ cw_threads.kill_thread_x :audio_thread
429
+ # puts 'end thread'
430
+ end
431
+
432
+ def word_parts str = nil
433
+ return @word_parts if @word_parts
434
+ @word_parts = []
435
+ str.split('').each { |part| @word_parts << part}
436
+ @word_parts
437
+ end
438
+
439
+ def create_element_method ele
440
+ define_singleton_method(ele) {tone.data[ele]}
441
+ end
442
+
443
+ def create_element_methods
444
+ elements.each do |ele|
445
+ create_element_method ele
446
+ end
447
+ end
448
+
449
+ def elements
450
+ [:dot, :dash, :space, :e_space]
451
+ end
452
+
453
+ def tone
454
+ @tone ||= ToneGenerator.new
455
+ end
456
+
457
+ def cw_threads
458
+ @cw_threads ||= CWThreads.new(self, thread_processes)
459
+ end
460
+
461
+ def tx string
462
+ @winkey = Winkey.new
463
+ @winkey.on
464
+ @winkey.echo
465
+ @winkey.no_weighting
466
+ @winkey.wpm @wpm
467
+ # @winkey.string "ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890/=+?>(:;"
468
+ @winkey.string ' fb '
469
+ @winkey.wait_while_sending
470
+ cw_threads.run
471
+ # @winkey.close
472
+ end
473
+
474
+ def tx_words_thread
475
+ loop do
476
+ unless @words == []
477
+ temp = @words.shift
478
+ # generate temp
479
+ # p temp
480
+ @winkey.stringtemp.to_s.upcase
481
+ print.tx temp
482
+ end
483
+ sleep 0.01
484
+ end
485
+ end
486
+ end
487
+ end