class CW::Read

Public Class Methods

new(filename) click to toggle source
# File lib/cw/read.rb, line 29
def initialize(filename)
  @tone = TONE
  @mag_max = 0
  @mag_min = 999999999
  @sample_rate = SAMPLE_RATE
  @n_val = n
  @coeff = coeff
  @n_delay_ms = n_delay_ms
  @filename = filename
  @code = []
  @q1 = 0
  @q2 = 0
  @magnitude_set_point = 10000
  @magnitude_set_point_low = @magnitude_set_point
  @wpm = 40
  @noise_blanking_ms = 6
  @last_start_time = 0
  @state = Array.new(5)
  @high = Array.new(3)
  @low = Array.new(2)
  @queue = Queue.new
  @cw_encoding = Encoding.new
  @print = Print.new
  @state[START] = 0
  @state[VALUE] = :low
  @state[BLANKING] = false
  @state[FILTERED] = false
  @state[PREV] = false
  @high[START] = 0
  @high[PERIOD] = 0
  @high[AVG] = 120
  @low[START] = 0
  @low[PERIOD] = 0
  @low[AVG] = 0
  @millisecs = 0
  @last = 0
  @need_space = false
  puts "@n_val  #{@n_val}"
  puts "@coeff  #{@coeff}"
  puts "@n_delay_ms #{@n_delay_ms}"
  input
end

Public Instance Methods

calc_coeff(data) click to toggle source
# File lib/cw/read.rb, line 253
def calc_coeff(data)
  q0 = @coeff * @q1 - @q2 + data
  @q2, @q1 = @q1, q0
end
calc_filtered_state() click to toggle source
# File lib/cw/read.rb, line 166
def calc_filtered_state
  if real_state_change?
    reset_noise_blanker
  end

  store_real_state

  if @state[BLANKING]
    if noise_blanked
      @state[FILTERED] = true
      if(@state[VALUE] == :high)
        @high[START] = @millisecs
        @high_mag = @magnitude
        #          dbg_print "high: #{@high_mag}\n  low: #{@low_mag}\n  set point: #{@magnitude_set_point}"
        @low[PERIOD] = (@millisecs - @low[START])
      else
        @low[START] = @millisecs;
        @low_mag = @magnitude
        @high[PERIOD] = @millisecs -  @high[START]
        if @high[PERIOD] < (2 * @high[AVG])
          @high[AVG] = ((@high[PERIOD] + @high[AVG] + @high[AVG]) / 3)  # now we know avg dit time ( rolling 3 avg)
        elsif(@high[PERIOD] > (5 * @high[AVG]))
          @high[AVG] = @high[PERIOD] + @high[AVG];     # if speed decrease fast ..
        end
      end
    end
  end
end
calc_real_state() click to toggle source
# File lib/cw/read.rb, line 160
def calc_real_state
  @state[VALUE] =
    (@magnitude > (@magnitude_set_point * 0.6)) ?
      :high : :low
end
coeff() click to toggle source
# File lib/cw/read.rb, line 25
def coeff ; 2 * cosine ; end
cosine() click to toggle source
# File lib/cw/read.rb, line 24
def cosine ; Math.cos(w) ; end
dbg_print(message) click to toggle source
# File lib/cw/read.rb, line 121
def dbg_print message
  if @millisecs > @last
    @last = @millisecs + 1000
    puts
    puts "  " + message
    @mag_min = 999999999
    @mag_max = 0
  end
end
decode_signal() click to toggle source
# File lib/cw/read.rb, line 195
    def decode_signal
      if(@state[FILTERED])
        @state[FILTERED] = false
        @need_space = true
        #dbg_print "wpm #{@wpm.to_s}\nhigh period: #{@high[PERIOD]}\nhigh avg: #{@high[AVG]}"
        if(@state[VALUE] == :low) #  we did end a HIGH
          if high_avg_compare?(@high[PERIOD], 0.6, 2.0)
            #  0.6 filter out false dits
            @code << :dot
#            $stdout.print '.'
          end
          if high_avg_compare?(@high[PERIOD], 2.0, 6.0)
            @code << :dash
#            $stdout.print '_'
            if @millisecs % 10 == 0
              @wpm = (@wpm + (1200 / ((@high[PERIOD]) / 3))) / 2;  # the most precise we can do ;o)
              # dbg_print "high #{@high[PERIOD]}"
            end
          end
        else # we did end a LOW
          @need_space = false
          if high_avg_compare?(@low[PERIOD], 2.0, 4.8) # letter space
            print_char
          elsif(high_avg_compare?(@low[PERIOD], 4.8, 6.0)) # word space
            print_char
            $stdout.print ' '
          end
        end
      end
#      dbg_print "millisecs #{@millisecs}"
      if @need_space
        if high_avg_compare?(@millisecs - @low[START], 6.0, 10)
          @need_space = false
          if @state[BLANKING] = false
          end
          print_char
          $stdout.print ' '
        end
      end
    end
high_avg_compare?(period, avg_x_low, avg_x_high) click to toggle source
# File lib/cw/read.rb, line 236
def high_avg_compare?(period, avg_x_low, avg_x_high)
  (period <= (@high[AVG] * avg_x_high).to_i) &&
    (period >= (@high[AVG] * avg_x_low).to_i)
end
input() click to toggle source
# File lib/cw/read.rb, line 83
    def input
      dly = @n_delay_ms
      open_sound_device
      nval = @n_val
      buf = @buf_in
      bufs = nil
      block_size = nval * 28
      thr = Thread.fork do
        loop do
          @queue.push buf.read(block_size)
        end
      end
      loop do
        loop do
          bufs = @queue.pop
          break if @queue.empty?
          sleep 0.001
        end
        count = 0
        28.times do
          nval.times do
            temp = bufs[count] + bufs[count + 1]
#            puts temp
            calc_coeff temp
            count += 2
          end
          @millisecs += dly
#          @millisecs += dly
          per_block_processing
          calc_real_state
          calc_filtered_state
          decode_signal
        end
      end
      @buf_in.stop
      $stdout.puts "done."
    end
k() click to toggle source
# File lib/cw/read.rb, line 22
def k ; (0.5 + ((n * @tone / @sample_rate))).to_i ; end
magnitude_filter() click to toggle source
# File lib/cw/read.rb, line 144
def magnitude_filter
  if(@magnitude > @magnitude_set_point_low)
    @magnitude_set_point = (@magnitude_set_point + ((@magnitude - @magnitude_set_point) / 6))  # moving average filter
  else
    @magnitude_set_point = @magnitude_set_point_low
  end
  #      dbg_print "@magnitude: #{@magnitude.to_s}\n  @magnitude_set_point: #{@magnitude_set_point.to_s}\n  @magnitude_set_point_low = #{@magnitude_set_point_low}"

  @mag_max = @magnitude if @magnitude > @mag_max
  @mag_min = @magnitude if @magnitude < @mag_min

  #      dbg_print "@magnitude: #{@magnitude.to_s}\n" +
  #                "  @mag_max: #{@mag_max.to_s}\n" +
  #                "  @mag_min: #{@mag_min.to_s}\n"
end
n() click to toggle source
# File lib/cw/read.rb, line 21
def n ; N ; end
n_delay_ms() click to toggle source
# File lib/cw/read.rb, line 26
def n_delay_ms ;  n * 1000/SAMPLE_RATE; end
noise_blanked() click to toggle source
# File lib/cw/read.rb, line 241
def noise_blanked
  if((@millisecs - @state[START]) > @noise_blanking_ms)
    @state[BLANKING] = false
    return true
  end
end
open_sound_device() click to toggle source
# File lib/cw/read.rb, line 72
def open_sound_device
  soundflower = nil
  CoreAudio.devices.each do |device|
    if device.name == 'Soundflower (2ch)'
      soundflower = device
    end
  end
  @buf_in = soundflower.input_buffer(44100)
  @buf_in.start
end
per_block_processing() click to toggle source
# File lib/cw/read.rb, line 131
def per_block_processing
  @magnitude = (@q1 * @q1) + (@q2 * @q2) - @q1 * @q2 * @coeff
  @magnitude = @magnitude.to_i / 1000000
  @magnitude = 0 if @magnitude < MAGNITUDE_CUTOFF
  #      if @magnitude >= 1000000000000.0
  #        @magnitude = Math.sqrt(magnitude_squared).to_i
  #      else
  #        @magnitude = 0
  #      end
  @q1, @q2 = 0, 0;
  #      p @magnitude
end
print() click to toggle source
print_char() click to toggle source

def matched_char

@cw_encoding.fetch_char @code

end

print_space() click to toggle source
real_state_change?() click to toggle source
# File lib/cw/read.rb, line 263
def real_state_change?
  #      if @real_state != @real_state_prev
  #        $stdout.print 'hi' if @real_state == true
  #        $stdout.print 'low' if @real_state == false
  #      end
  @state[VALUE] != @state[PREV]
end
reset_noise_blanker() click to toggle source
# File lib/cw/read.rb, line 258
def reset_noise_blanker
  @state[BLANKING] = true
  @state[START] = @millisecs
end
store_real_state() click to toggle source
# File lib/cw/read.rb, line 271
def store_real_state
  @state[PREV] = @state[VALUE]
end
w() click to toggle source
# File lib/cw/read.rb, line 23
def w ; ((2 * Math::PI) / n) * k ; end