No Description

modulator.go 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // Copyright (C) 2017 Keelan Lightfoot
  2. // Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
  3. // System (Univ. of Wisconsin-Madison, Trace R&D Center)
  4. // Copyright (C) 2007-2008 Omnitor AB
  5. // Copyright (C) 2007-2008 Voiceriver Inc
  6. //
  7. // This library is free software; you can redistribute it and/or modify it
  8. // under the terms of the GNU Lesser General Public License as published by
  9. // the Free Software Foundation; either version 2.1 of the License, or (at
  10. // your option) any later version.
  11. package gortty
  12. import (
  13. "context"
  14. "math"
  15. )
  16. const (
  17. modStateIdle = iota
  18. modStateReady
  19. modStateStart
  20. modStateBit
  21. modStateStop
  22. modStateHold
  23. )
  24. // Modulator is fun
  25. type Modulator struct {
  26. input chan byte
  27. output chan int16
  28. settings *ModemSettings
  29. samplesPerBit int // number of samples for one bit
  30. phaseQ16 uint16 // phase acc 0..2math.Pi -> 0..65536
  31. amplitude int16 // peak modulator amplitude for one tone
  32. numStopHalfBits int // number of stop bits
  33. numStopSamples int // number of samples for stop bit
  34. wOneQ16 uint16 // scaled one freq 0..2math.Pi -> 0..65536
  35. wZeroQ16 uint16 // scaled zero freq 0..2math.Pi -> 0..65536
  36. sinLutQ15 []int16 // sine lookup table
  37. callback Callback
  38. idleDelay int
  39. }
  40. // NewModulator is fun
  41. func NewModulator(ctx context.Context, s *ModemSettings, input chan byte, output chan int16) *Modulator {
  42. m := new(Modulator)
  43. m.input = input
  44. m.output = output
  45. m.settings = s
  46. m.samplesPerBit = int(float64(m.settings.SampleRate) / m.settings.Baud)
  47. m.numStopHalfBits = int(math.Floor(m.settings.StopBits / .5))
  48. m.numStopSamples = m.numStopHalfBits * m.samplesPerBit / 2
  49. m.amplitude = 16384
  50. m.idleDelay = m.settings.SampleRate
  51. wOne, wZero := calculateW(m.settings.OneFreq, m.settings.ZeroFreq, m.settings.SampleRate)
  52. m.wOneQ16 = uint16((65536 / (2.0 * math.Pi)) * wOne)
  53. m.wZeroQ16 = uint16((65536 / (2.0 * math.Pi)) * wZero)
  54. m.sinLutQ15 = make([]int16, 16384)
  55. for i := 0; i < 16384; i++ {
  56. m.sinLutQ15[i] = int16(32767 * math.Sin(2.0*math.Pi*float64(i)/float64(16384)))
  57. }
  58. go m.run(ctx)
  59. return m
  60. }
  61. // SetCallback is fun
  62. func (m *Modulator) SetCallback(callback Callback) {
  63. m.callback = callback
  64. }
  65. // SetIdleDelay sets how long (in samples) that the modulator must be in the ready state
  66. // before switching to the idle state
  67. func (m *Modulator) SetIdleDelay(d int) {
  68. m.idleDelay = d
  69. }
  70. func (m *Modulator) modulate(bit int) { //short *buffer, int samples)
  71. /* use of unsigned short in Q16 for format for phase
  72. accumulator leads to natural wrap-around at 2PI
  73. boundaries
  74. */
  75. /* sin_lut_q15 is in Q15 format, therefore we rightshift 15 to
  76. get Q0 at modulator output. We cast multiply arguments
  77. to 32 bit ints to ensure compiler uses a multiply with a 32
  78. bit result.
  79. */
  80. if bit != 0 {
  81. m.phaseQ16 += m.wOneQ16
  82. m.output <- multq15(m.amplitude, m.sinLutQ15[m.phaseQ16>>2])
  83. } else {
  84. m.phaseQ16 += m.wZeroQ16
  85. m.output <- multq15(m.amplitude, m.sinLutQ15[m.phaseQ16>>2])
  86. }
  87. }
  88. func (m *Modulator) SetAmplitude(amplitude int16) {
  89. m.amplitude = amplitude
  90. }
  91. func (m *Modulator) run(ctx context.Context) {
  92. var modState int // modulator state machine
  93. var nextState int // next state of state machine
  94. var c byte // current baudot char being modulated
  95. var modNbit int // num bits modulated so far in this char
  96. var modBit int // current bit in modBaudot being modulated
  97. var modSample int // current sample in bit being modulated
  98. var idleSamples int
  99. for {
  100. nextState = modState
  101. switch modState {
  102. case modStateReady:
  103. fallthrough
  104. case modStateIdle:
  105. select {
  106. case <-ctx.Done():
  107. return
  108. case c = <-m.input:
  109. modSample = 0
  110. nextState = modStateStart
  111. idleSamples = 0
  112. if m.callback != nil {
  113. m.callback(EventStartBit, 0)
  114. if modState == modStateIdle {
  115. m.callback(EventActive, 0)
  116. }
  117. }
  118. default:
  119. m.modulate(1)
  120. if modState == modStateReady {
  121. if idleSamples < m.idleDelay {
  122. idleSamples++
  123. } else {
  124. nextState = modStateIdle
  125. if m.callback != nil {
  126. m.callback(EventIdle, 0)
  127. }
  128. idleSamples++
  129. }
  130. }
  131. }
  132. case modStateStart:
  133. m.modulate(0)
  134. modSample++
  135. // after sending start bit send LSB data bit
  136. if modSample == m.samplesPerBit {
  137. modNbit = 0
  138. modBit = int(c & 0x1)
  139. modSample = 0
  140. nextState = modStateBit
  141. }
  142. case modStateBit:
  143. m.modulate(modBit)
  144. modSample++
  145. // when this data bit complete, send next data bit
  146. if modSample == m.samplesPerBit {
  147. modSample = 0
  148. modNbit++
  149. modBit = int((c >> uint(modNbit)) & 0x1)
  150. if modNbit == m.settings.DataBits {
  151. nextState = modStateStop
  152. // fmt.Println("modStateStop")
  153. }
  154. }
  155. case modStateStop:
  156. m.modulate(1)
  157. modSample++
  158. // when stop bit complete start transmission of next char, or enter idle state
  159. if modSample == m.numStopSamples {
  160. modSample = 0
  161. nextState = modStateReady
  162. if m.callback != nil {
  163. m.callback(EventStopBit, 0)
  164. }
  165. }
  166. // (obl.callback)(obl,OBL_EVENT_TX_STATE, OBL_TRANSMIT_STOP);
  167. }
  168. modState = nextState
  169. }
  170. }