Keelan Lightfoot 7 years ago
parent
commit
c0d45acc38
8 changed files with 263 additions and 465 deletions
  1. 11
    38
      code.go
  2. 24
    102
      common.go
  3. 16
    42
      decoder.go
  4. 73
    81
      demodulator.go
  5. 33
    59
      dsp.go
  6. 47
    71
      encoder.go
  7. 9
    4
      examples/main.go
  8. 50
    68
      modulator.go

+ 11
- 38
code.go View File

@@ -1,45 +1,18 @@
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
+
1 12
 package openbaudot
2 13
 
3 14
 import "unicode"
4 15
 
5
-/*
6
- * OBL openbaudot Library
7
- *
8
- * Copyright (C) 2017 Keelan Lightfoot
9
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
10
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
11
- * Copyright (C) 2007-2008 Omnitor AB
12
- * Copyright (C) 2007-2008 Voiceriver Inc
13
- *
14
- * This software was developed with support from the National Institute on
15
- * Disability and Rehabilitation Research, US Dept of Education under Grant
16
- * # H133E990006 and H133E040014
17
- *
18
- * This library is free software; you can redistribute it and/or modify it
19
- * under the terms of the GNU Lesser General Public License as published by
20
- * the Free Software Foundation; either version 2.1 of the License, or (at
21
- * your option) any later version.
22
- *
23
- * This library is distributed in the hope that it will be useful, but
24
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
26
- * License for more details.
27
- *
28
- * You should have received a copy of the GNU Lesser General Public License
29
- * along with this library; if not, write to the Free Software Foundation,
30
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31
- *
32
- * Please send a copy of any improved versions of the library to:
33
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
34
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
35
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
36
- *
37
- * file...: obl.go
38
- * original author.: Keelan Lightfoot
39
- * Created: 20 May 2017
40
- *
41
- */
42
-
43 16
 const (
44 17
 	shiftUnknown = iota
45 18
 	shiftLetter

+ 24
- 102
common.go View File

@@ -1,95 +1,21 @@
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
+
12
+// Package openbaudot provides a set of tools to encode, modulate, demodulate and
13
+// baudot/TTY/RTTY data streams
1 14
 package openbaudot
2 15
 
3 16
 import "math"
4 17
 
5
-/*
6
- * OBL openbaudot Library
7
- *
8
- * Copyright (C) 2017 Keelan Lightfoot
9
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
10
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
11
- * Copyright (C) 2007-2008 Omnitor AB
12
- * Copyright (C) 2007-2008 Voiceriver Inc
13
- *
14
- * This software was developed with support from the National Institute on
15
- * Disability and Rehabilitation Research, US Dept of Education under Grant
16
- * # H133E990006 and H133E040014
17
- *
18
- * This library is free software; you can redistribute it and/or modify it
19
- * under the terms of the GNU Lesser General Public License as published by
20
- * the Free Software Foundation; either version 2.1 of the License, or (at
21
- * your option) any later version.
22
- *
23
- * This library is distributed in the hope that it will be useful, but
24
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
26
- * License for more details.
27
- *
28
- * You should have received a copy of the GNU Lesser General Public License
29
- * along with this library; if not, write to the Free Software Foundation,
30
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31
- *
32
- * Please send a copy of any improved versions of the library to:
33
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
34
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
35
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
36
- *
37
- * file...: obl.go
38
- * original author.: Keelan Lightfoot
39
- * Created: 20 May 2017
40
- *
41
- */
42
-
43 18
 const (
44
-
45
-	// LETR  Letters Baudot code
46
-	LETR byte = 0x1f
47
-	// FIGR Figures Baudot code
48
-	FIGR byte = 0x1b
49
-	// CRLFThresh start looking for space
50
-	CRLFThresh = 60
51
-	// CRLFForce force CR-LF
52
-	CRLFForce = 72
53
-
54
-	// ModStateIdle no data in mod buffer, idling
55
-	ModStateIdle = 0
56
-	// ModStateStart modulating start bit
57
-	ModStateStart = 1
58
-	// ModStateBit modulating a baudot bit
59
-	ModStateBit = 2
60
-	// ModStateStop modulating stop bit
61
-	ModStateStop = 3
62
-	// ModStateHold modulating hold tone
63
-	ModStateHold = 4
64
-
65
-	// LPFOrder Low pass filter order
66
-	LPFOrder = 20 // 20
67
-
68
-	/* oblDemodulate() state machine states */
69
-
70
-	// DemodStateWaitStart wait for start bit
71
-	DemodStateWaitStart = 0 /**/
72
-	// DemodStateSample sampling demod bits
73
-	DemodStateSample = 1 /**/
74
-	// DemodStateWaitStop wait for stop bit
75
-	DemodStateWaitStop = 2 /**/
76
-
77
-	// MinThresh ratio for vaild signal
78
-	MinThresh = 3
79
-
80
-	/* auto baud detection state machine states */
81
-
82
-	// AutobaudStateWaitStart waiting for start bit
83
-	AutobaudStateWaitStart = 0
84
-	// AutobaudStateWaitZeroX waiting for zero crossing
85
-	AutobaudStateWaitZeroX = 1
86
-	// AutobaudStateWaitStop waiting for stop bit
87
-	AutobaudStateWaitStop = 2
88
-	// AutobaudStateDisabled disabled
89
-	AutobaudStateDisabled = 3
90
-
91
-	/* top level state machines states */
92
-
93 19
 	// EventDemodChar is fun
94 20
 	EventDemodChar = iota
95 21
 	// EventDemodAbort is fun
@@ -102,21 +28,21 @@ const (
102 28
 	EventIdle
103 29
 )
104 30
 
105
-/* precomputed constants for demodDsp */
31
+// Callback is func
32
+type Callback func(event int, data interface{})
106 33
 
107
-var (
108
-	// sampleRate Sample rate
109
-	sampleRate = 8000
110
-	// Beta filter bandwidth factor
111
-	Beta = 0.95 //.95
112
-)
34
+// ModemSettings is fun
35
+type ModemSettings struct {
36
+	Baud       float64
37
+	StopBits   float64
38
+	DataBits   int
39
+	SampleRate int
40
+}
113 41
 
114
-func multq(x, y int16) int16 {
42
+func multq15(x, y int16) int16 {
115 43
 	return int16((int(x) * int(y)) >> 15)
116
-
117 44
 }
118 45
 
119
-// abs16 returns the absolute value of x.
120 46
 func abs16(x int16) int16 {
121 47
 	if x < 0 {
122 48
 		return -x
@@ -124,7 +50,6 @@ func abs16(x int16) int16 {
124 50
 	return x
125 51
 }
126 52
 
127
-// absint returns the absolute value of x.
128 53
 func absint(x int) int {
129 54
 	if x < 0 {
130 55
 		return -x
@@ -132,11 +57,8 @@ func absint(x int) int {
132 57
 	return x
133 58
 }
134 59
 
135
-func calculateW(oneF int, zeroF int) (float64, float64) {
60
+func calculateW(oneF int, zeroF int, sampleRate int) (float64, float64) {
136 61
 	wOne := (2 * math.Pi * float64(oneF) / float64(sampleRate))   //1400 // WOne 1 freq in normalised rads
137 62
 	wZero := (2 * math.Pi * float64(zeroF) / float64(sampleRate)) //1800 // WZero 0 freq in normazlised rads
138 63
 	return wOne, wZero
139 64
 }
140
-
141
-// Callback is func
142
-type Callback func(event int, data interface{})

+ 16
- 42
decoder.go View File

@@ -1,51 +1,25 @@
1
-package openbaudot
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.
2 11
 
3
-/*
4
- * OBL openbaudot Library
5
- *
6
- * Copyright (C) 2017 Keelan Lightfoot
7
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
8
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
9
- * Copyright (C) 2007-2008 Omnitor AB
10
- * Copyright (C) 2007-2008 Voiceriver Inc
11
- *
12
- * This software was developed with support from the National Institute on
13
- * Disability and Rehabilitation Research, US Dept of Education under Grant
14
- * # H133E990006 and H133E040014
15
- *
16
- * This library is free software; you can redistribute it and/or modify it
17
- * under the terms of the GNU Lesser General Public License as published by
18
- * the Free Software Foundation; either version 2.1 of the License, or (at
19
- * your option) any later version.
20
- *
21
- * This library is distributed in the hope that it will be useful, but
22
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
24
- * License for more details.
25
- *
26
- * You should have received a copy of the GNU Lesser General Public License
27
- * along with this library; if not, write to the Free Software Foundation,
28
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
- *
30
- * Please send a copy of any improved versions of the library to:
31
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
32
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
33
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
34
- *
35
- * file...: obl.go
36
- * original author.: Keelan Lightfoot
37
- * Created: 20 May 2017
38
- *
39
- */
12
+package openbaudot
40 13
 
41
-// Decoder is fun
14
+// Decoder converts a stream of bytes representing baudot codes into a stream
15
+// of unicode runes.
42 16
 type Decoder struct {
43 17
 	input   chan byte
44 18
 	output  chan rune
45 19
 	charset *CodeSet
46 20
 }
47 21
 
48
-// NewDecoder is fun
22
+// NewDecoder creates a new decoder.
49 23
 func NewDecoder(input chan byte, output chan rune, charset *CodeSet) *Decoder {
50 24
 	d := new(Decoder)
51 25
 	d.input = input
@@ -60,10 +34,10 @@ func (d *Decoder) run() {
60 34
 	shift := shiftLetter
61 35
 	for c := range d.input {
62 36
 		switch c {
63
-		case LETR:
37
+		case d.charset.UnshiftCode:
64 38
 			shift = shiftLetter
65 39
 			//obl.callback(EventDemodCase, Letters)
66
-		case FIGR:
40
+		case d.charset.ShiftCode:
67 41
 			shift = shiftFigure
68 42
 		//	obl.callback(EventDemodCase, Figures)
69 43
 		default:

+ 73
- 81
demodulator.go View File

@@ -1,44 +1,28 @@
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
+
1 12
 package openbaudot
2 13
 
3 14
 import "math"
4 15
 
5
-/*
6
- * OBL openbaudot Library
7
- *
8
- * Copyright (C) 2017 Keelan Lightfoot
9
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
10
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
11
- * Copyright (C) 2007-2008 Omnitor AB
12
- * Copyright (C) 2007-2008 Voiceriver Inc
13
- *
14
- * This software was developed with support from the National Institute on
15
- * Disability and Rehabilitation Research, US Dept of Education under Grant
16
- * # H133E990006 and H133E040014
17
- *
18
- * This library is free software; you can redistribute it and/or modify it
19
- * under the terms of the GNU Lesser General Public License as published by
20
- * the Free Software Foundation; either version 2.1 of the License, or (at
21
- * your option) any later version.
22
- *
23
- * This library is distributed in the hope that it will be useful, but
24
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
26
- * License for more details.
27
- *
28
- * You should have received a copy of the GNU Lesser General Public License
29
- * along with this library; if not, write to the Free Software Foundation,
30
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31
- *
32
- * Please send a copy of any improved versions of the library to:
33
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
34
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
35
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
36
- *
37
- * file...: obl.go
38
- * original author.: Keelan Lightfoot
39
- * Created: 20 May 2017
40
- *
41
- */
16
+const (
17
+	demodStateWaitStart = iota
18
+	demodStateSample
19
+	demodStateWaitStop
20
+
21
+	autobaudStateWaitStart = iota
22
+	autobaudStateWaitZeroX
23
+	autobaudStateWaitStop
24
+	autobaudStateDisabled
25
+)
42 26
 
43 27
 // Demodulator is fun
44 28
 type Demodulator struct {
@@ -54,6 +38,7 @@ type Demodulator struct {
54 38
 	samplesPerBit int
55 39
 	dsp           *dsp
56 40
 	dataBits      int
41
+	sampleRate    int
57 42
 	autobaud      struct {
58 43
 		enabled  bool    // audio baud detection enable/disable flag
59 44
 		state    int     // auto buad detection state mach state
@@ -63,30 +48,37 @@ type Demodulator struct {
63 48
 }
64 49
 
65 50
 // NewDemodulator is fun
66
-func NewDemodulator(baud float64, stopBits float64, dataBits int, input chan int16, output chan byte) *Demodulator {
51
+func NewDemodulator(s ModemSettings, input chan int16, output chan byte) *Demodulator {
67 52
 
68 53
 	d := new(Demodulator)
69 54
 	d.input = input
70 55
 	d.output = output
71
-	d.state = DemodStateWaitStart
56
+	d.state = demodStateWaitStart
72 57
 	//d.lettersFigures = Letters
73
-	d.baud = baud
74
-	d.dataBits = dataBits
75
-	d.samplesPerBit = int(float64(sampleRate) / d.baud)
58
+	d.baud = s.Baud
59
+	d.dataBits = s.DataBits
60
+	d.sampleRate = s.SampleRate
61
+	d.samplesPerBit = int(float64(d.sampleRate) / d.baud)
62
+
63
+	wOne, wZero := calculateW(2125, 2295, d.sampleRate)
76 64
 
77
-	wOne, wZero := calculateW(2125, 2295)
65
+	lfpOrder := 20
66
+	beta := 0.95 //.95
78 67
 
79 68
 	d.dsp = &dsp{
80
-		c1: int16((2.0 * math.Cos(wOne) * Beta) * 32768),
81
-		c2: int16(Beta * Beta * 32768),
82
-		c3: int16((2.0 * math.Cos(wZero) * Beta) * 32768),
69
+		c1:         int16((2.0 * math.Cos(wOne) * beta) * 32768),
70
+		c2:         int16(beta * beta * 32768),
71
+		c3:         int16((2.0 * math.Cos(wZero) * beta) * 32768),
72
+		demLpfIn:   make([]int16, lfpOrder),
73
+		demTotalIn: make([]int16, lfpOrder),
74
+		lpfOrder:   lfpOrder,
83 75
 	}
84 76
 
85 77
 	d.autobaud.estimate = d.baud
86 78
 	if d.autobaud.enabled {
87
-		d.autobaud.state = AutobaudStateWaitStart
79
+		d.autobaud.state = autobaudStateWaitStart
88 80
 	} else {
89
-		d.autobaud.state = AutobaudStateDisabled
81
+		d.autobaud.state = autobaudStateDisabled
90 82
 	}
91 83
 	go d.run()
92 84
 	return d
@@ -111,21 +103,21 @@ func (d *Demodulator) run() {
111 103
 		nextState = d.state
112 104
 
113 105
 		switch d.state {
114
-		case DemodStateWaitStart:
106
+		case demodStateWaitStart:
115 107
 			/*
116 108
 			   The demodulator sits in this state when it
117
-			   is waiting for a start bit.  When a sampleRateK
109
+			   is waiting for a start bit.  When a d.sampleRateK
118 110
 			   "0" (1800 Hz) start-bit is detected that is
119 111
 			   above a minimum threshold it transitions
120 112
 			   out of this state.
121 113
 			*/
122 114
 			if d.dsp.signalPresent() {
123
-				d.sample = int(float64(sampleRate)/d.baud + float64(sampleRate)/(2*d.baud))
115
+				d.sample = int(float64(d.sampleRate)/d.baud + float64(d.sampleRate)/(2*d.baud))
124 116
 				d.baudot = 0
125 117
 				d.bit = 0
126
-				nextState = DemodStateSample
118
+				nextState = demodStateSample
127 119
 			}
128
-		case DemodStateSample:
120
+		case demodStateSample:
129 121
 
130 122
 			d.sample--
131 123
 			if d.sample == 0 {
@@ -140,15 +132,15 @@ func (d *Demodulator) run() {
140 132
 					d.output <- d.baudot
141 133
 					//fmt.Printf("Demodulator done %d\n", d.baudot)
142 134
 
143
-					d.sample = int(float64(sampleRate) / d.baud)
144
-					nextState = DemodStateWaitStop
135
+					d.sample = int(float64(d.sampleRate) / d.baud)
136
+					nextState = demodStateWaitStop
145 137
 				} else {
146 138
 					/* sample next bit 1 bit-period later */
147
-					d.sample = int(float64(sampleRate) / d.baud)
139
+					d.sample = int(float64(d.sampleRate) / d.baud)
148 140
 				}
149 141
 			}
150 142
 
151
-			/* check for sampleRateK signal drop out */
143
+			/* check for d.sampleRateK signal drop out */
152 144
 
153 145
 			//return d.demTotal != 0 && d.demLpf < -1*MinThresh*d.demTotal
154 146
 
@@ -156,21 +148,21 @@ func (d *Demodulator) run() {
156 148
 				d.minSigTimeout++
157 149
 
158 150
 				/* If signal drops out for approx one bit period
159
-				   assume we have lost sampleRateK signal */
151
+				   assume we have lost d.sampleRateK signal */
160 152
 				if d.minSigTimeout > d.samplesPerBit {
161
-					nextState = DemodStateWaitStart
153
+					nextState = demodStateWaitStart
162 154
 				}
163 155
 			} else {
164 156
 				d.minSigTimeout = 0
165 157
 			}
166 158
 
167
-		case DemodStateWaitStop:
159
+		case demodStateWaitStop:
168 160
 
169 161
 			/* wait until we are in the middle of stop bit */
170 162
 
171 163
 			d.sample--
172 164
 			if d.sample == 0 {
173
-				nextState = DemodStateWaitStart
165
+				nextState = demodStateWaitStart
174 166
 			}
175 167
 
176 168
 		}
@@ -195,13 +187,13 @@ func (d *Demodulator) run() {
195 187
 		nextState = d.autobaud.state
196 188
 
197 189
 		switch d.autobaud.state {
198
-		case AutobaudStateWaitStart:
190
+		case autobaudStateWaitStart:
199 191
 			/* start bit kicks off this state machine */
200
-			if d.state == DemodStateSample {
201
-				nextState = AutobaudStateWaitZeroX
192
+			if d.state == demodStateSample {
193
+				nextState = autobaudStateWaitZeroX
202 194
 				d.autobaud.zeroX = 0
203 195
 			}
204
-		case AutobaudStateWaitZeroX:
196
+		case autobaudStateWaitZeroX:
205 197
 
206 198
 			d.autobaud.zeroX++
207 199
 
@@ -210,50 +202,50 @@ func (d *Demodulator) run() {
210 202
 
211 203
 				/* determine distance to closest edge assuming 50 baud */
212 204
 
213
-				dist75 := sampleRate / 75
205
+				dist75 := d.sampleRate / 75
214 206
 				edge = 0
215 207
 				for i := 0; i < (d.dataBits + 1); i++ {
216 208
 					dist = absint(edge - d.autobaud.zeroX)
217 209
 					if dist < dist75 {
218 210
 						dist75 = dist
219 211
 					}
220
-					edge += sampleRate / 75
212
+					edge += d.sampleRate / 75
221 213
 				}
222 214
 
223 215
 				/* determine distance to closest edge assuming 50 baud */
224 216
 
225
-				dist50 := sampleRate / 50
217
+				dist50 := d.sampleRate / 50
226 218
 				edge = 0
227 219
 				for i := 0; i < (d.dataBits + 1); i++ {
228 220
 					dist = absint(edge - d.autobaud.zeroX)
229 221
 					if dist < dist50 {
230 222
 						dist50 = dist
231 223
 					}
232
-					edge += sampleRate / 50
224
+					edge += d.sampleRate / 50
233 225
 				}
234 226
 
235 227
 				/* determine distance to closest edge assuming 47 baud */
236 228
 
237
-				dist47 := sampleRate / 47
229
+				dist47 := d.sampleRate / 47
238 230
 				edge = 0
239 231
 				for i := 0; i < (d.dataBits + 1); i++ {
240 232
 					dist = absint(edge - d.autobaud.zeroX)
241 233
 					if dist < dist47 {
242 234
 						dist47 = dist
243 235
 					}
244
-					edge += sampleRate / 47
236
+					edge += d.sampleRate / 47
245 237
 				}
246 238
 
247 239
 				/* determine distance to closest edge assuming 45 baud */
248 240
 
249
-				dist45 := sampleRate / 45
241
+				dist45 := d.sampleRate / 45
250 242
 				edge = 0
251 243
 				for i := 0; i < (d.dataBits + 1); i++ {
252 244
 					dist = absint(edge - d.autobaud.zeroX)
253 245
 					if dist < dist45 {
254 246
 						dist45 = dist
255 247
 					}
256
-					edge += sampleRate / 45
248
+					edge += d.sampleRate / 45
257 249
 				}
258 250
 
259 251
 				/* update 3-point smoothed distance estimates */
@@ -291,22 +283,22 @@ func (d *Demodulator) run() {
291 283
 
292 284
 				//printf("obl.autobaud_zerox: %d dist50: %02d dist47: %02d dist45: %02d est: %d\n",
293 285
 				//       obl.autobaud_zerox, dist50Smooth, dist47Smooth, dist45Smooth, obl.dem_baud_est);
294
-				nextState = AutobaudStateWaitStop
286
+				nextState = autobaudStateWaitStop
295 287
 			}
296 288
 
297
-			/* reset autobaud state machine, e.g. if sampleRateK drops out before
289
+			/* reset autobaud state machine, e.g. if d.sampleRateK drops out before
298 290
 			   we get a zero crossing */
299 291
 
300
-			if d.state != DemodStateSample {
301
-				nextState = AutobaudStateWaitStop
292
+			if d.state != demodStateSample {
293
+				nextState = autobaudStateWaitStop
302 294
 			}
303 295
 
304
-		case AutobaudStateWaitStop:
305
-			if d.state == DemodStateWaitStop {
306
-				nextState = AutobaudStateWaitStart
296
+		case autobaudStateWaitStop:
297
+			if d.state == demodStateWaitStop {
298
+				nextState = autobaudStateWaitStart
307 299
 			}
308 300
 
309
-		case AutobaudStateDisabled:
301
+		case autobaudStateDisabled:
310 302
 
311 303
 		default:
312 304
 

+ 33
- 59
dsp.go View File

@@ -1,68 +1,42 @@
1
-package openbaudot
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.
2 11
 
3
-/*
4
- * OBL openbaudot Library
5
- *
6
- * Copyright (C) 2017 Keelan Lightfoot
7
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
8
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
9
- * Copyright (C) 2007-2008 Omnitor AB
10
- * Copyright (C) 2007-2008 Voiceriver Inc
11
- *
12
- * This software was developed with support from the National Institute on
13
- * Disability and Rehabilitation Research, US Dept of Education under Grant
14
- * # H133E990006 and H133E040014
15
- *
16
- * This library is free software; you can redistribute it and/or modify it
17
- * under the terms of the GNU Lesser General Public License as published by
18
- * the Free Software Foundation; either version 2.1 of the License, or (at
19
- * your option) any later version.
20
- *
21
- * This library is distributed in the hope that it will be useful, but
22
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
24
- * License for more details.
25
- *
26
- * You should have received a copy of the GNU Lesser General Public License
27
- * along with this library; if not, write to the Free Software Foundation,
28
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
- *
30
- * Please send a copy of any improved versions of the library to:
31
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
32
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
33
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
34
- *
35
- * file...: obl.go
36
- * original author.: Keelan Lightfoot
37
- * Created: 20 May 2017
38
- *
39
- */
12
+package openbaudot
40 13
 
41 14
 type dsp struct {
42
-	demOne      [2]float64      // previous 2 output samples of one filter
43
-	demOneQ0    [2]int16        // previous 2 output samples of one filter
44
-	demZero     [2]float64      // previous 2 output samples of zero filter
45
-	demZeroQ0   [2]int16        // previous 2 output samples of one filter
46
-	demLpfIn    [LPFOrder]int16 // previous LPFOrder LPF input samples
47
-	pdemLpfIn   int             // ptr to oldest LPF input sample
48
-	demLpf      int             // current LPF output value
49
-	demTotalIn  [LPFOrder]int16 // previous LPFOrder energy input samples
50
-	pdemTotalIn int             // ptr to oldest energy sample
51
-	demTotal    int             // current energy output value
52
-	c1, c2, c3  int16           // precomputed values for demod_dsp
53
-
15
+	demOne      [2]float64 // previous 2 output samples of one filter
16
+	demOneQ0    [2]int16   // previous 2 output samples of one filter
17
+	demZero     [2]float64 // previous 2 output samples of zero filter
18
+	demZeroQ0   [2]int16   // previous 2 output samples of one filter
19
+	demLpfIn    []int16    // previous LPFOrder LPF input samples
20
+	pdemLpfIn   int        // ptr to oldest LPF input sample
21
+	demLpf      int        // current LPF output value
22
+	demTotalIn  []int16    // previous LPFOrder energy input samples
23
+	pdemTotalIn int        // ptr to oldest energy sample
24
+	demTotal    int        // current energy output value
25
+	c1, c2, c3  int16      // precomputed values for demod_dsp
26
+	lpfOrder    int        // LPFOrder Low pass filter order
27
+	minThresh   int        // MinThresh ratio for vaild signal
54 28
 }
55 29
 
56 30
 func (d *dsp) edgeDetected() bool {
57
-	return d.demLpf > MinThresh*d.demTotal
31
+	return d.demLpf > d.minThresh*d.demTotal
58 32
 }
59 33
 
60 34
 func (d *dsp) dropout() bool {
61
-	return absint(d.demLpf) < MinThresh*d.demTotal || d.demTotal == 0
35
+	return absint(d.demLpf) < d.minThresh*d.demTotal || d.demTotal == 0
62 36
 }
63 37
 
64 38
 func (d *dsp) signalPresent() bool {
65
-	return d.demTotal != 0 && d.demLpf < -1*MinThresh*d.demTotal
39
+	return d.demTotal != 0 && d.demLpf < -1*d.minThresh*d.demTotal
66 40
 }
67 41
 
68 42
 func (d *dsp) onePresent() bool {
@@ -74,14 +48,14 @@ func (d *dsp) demod(sam int16) { //short *buffer, int samples)
74 48
 	sam >>= 5
75 49
 
76 50
 	oneQ0 := sam
77
-	oneQ0 += multq(d.c1, d.demOneQ0[0])
78
-	oneQ0 -= multq(d.c2, d.demOneQ0[1])
51
+	oneQ0 += multq15(d.c1, d.demOneQ0[0])
52
+	oneQ0 -= multq15(d.c2, d.demOneQ0[1])
79 53
 	d.demOneQ0[1] = d.demOneQ0[0]
80 54
 	d.demOneQ0[0] = oneQ0
81 55
 
82 56
 	zeroQ0 := sam
83
-	zeroQ0 += multq(d.c3, d.demZeroQ0[0])
84
-	zeroQ0 -= multq(d.c2, d.demZeroQ0[1])
57
+	zeroQ0 += multq15(d.c3, d.demZeroQ0[0])
58
+	zeroQ0 -= multq15(d.c2, d.demZeroQ0[1])
85 59
 	d.demZeroQ0[1] = d.demZeroQ0[0]
86 60
 	d.demZeroQ0[0] = zeroQ0
87 61
 
@@ -89,7 +63,7 @@ func (d *dsp) demod(sam int16) { //short *buffer, int samples)
89 63
 	d.demLpf -= int(d.demLpfIn[d.pdemLpfIn])
90 64
 	d.demLpf += int(x)
91 65
 	d.demLpfIn[d.pdemLpfIn] = x
92
-	d.pdemLpfIn = (d.pdemLpfIn + 1) % LPFOrder
66
+	d.pdemLpfIn = (d.pdemLpfIn + 1) % d.lpfOrder
93 67
 
94 68
 	/* now work out total energy estimate, this is used to
95 69
 	   determine if a valid signal is present by comparing
@@ -99,5 +73,5 @@ func (d *dsp) demod(sam int16) { //short *buffer, int samples)
99 73
 	d.demTotal -= int(d.demTotalIn[d.pdemTotalIn])
100 74
 	d.demTotal += int(x)
101 75
 	d.demTotalIn[d.pdemTotalIn] = x
102
-	d.pdemTotalIn = (d.pdemTotalIn + 1) % LPFOrder
76
+	d.pdemTotalIn = (d.pdemTotalIn + 1) % d.lpfOrder
103 77
 }

+ 47
- 71
encoder.go View File

@@ -1,50 +1,25 @@
1
-package openbaudot
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.
2 11
 
3
-/*
4
- * OBL openbaudot Library
5
- *
6
- * Copyright (C) 2017 Keelan Lightfoot
7
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
8
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
9
- * Copyright (C) 2007-2008 Omnitor AB
10
- * Copyright (C) 2007-2008 Voiceriver Inc
11
- *
12
- * This software was developed with support from the National Institute on
13
- * Disability and Rehabilitation Research, US Dept of Education under Grant
14
- * # H133E990006 and H133E040014
15
- *
16
- * This library is free software; you can redistribute it and/or modify it
17
- * under the terms of the GNU Lesser General Public License as published by
18
- * the Free Software Foundation; either version 2.1 of the License, or (at
19
- * your option) any later version.
20
- *
21
- * This library is distributed in the hope that it will be useful, but
22
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
24
- * License for more details.
25
- *
26
- * You should have received a copy of the GNU Lesser General Public License
27
- * along with this library; if not, write to the Free Software Foundation,
28
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
- *
30
- * Please send a copy of any improved versions of the library to:
31
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
32
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
33
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
34
- *
35
- * file...: obl.go
36
- * original author.: Keelan Lightfoot
37
- * Created: 20 May 2017
38
- *
39
- */
12
+package openbaudot
40 13
 
41 14
 // Encoder is fun
42 15
 type Encoder struct {
43
-	input    chan rune
44
-	output   chan byte
45
-	autoWrap bool // true for auto CRLF mode
46
-	autoCRLF bool
47
-	charset  *CodeSet
16
+	input           chan rune
17
+	output          chan byte
18
+	autoWrap        bool // true for auto CRLF mode
19
+	autoCRLF        bool
20
+	charset         *CodeSet
21
+	crlfThresh      int // start looking for a space to replace with a crlf at this threshold
22
+	crlfForceThresh int // force a crlf if it hasn't happend by this threshold
48 23
 }
49 24
 
50 25
 // NewEncoder is fun
@@ -53,27 +28,28 @@ func NewEncoder(input chan rune, output chan byte, charset *CodeSet) *Encoder {
53 28
 	e.input = input
54 29
 	e.output = output
55 30
 	e.charset = charset
56
-
31
+	e.crlfThresh = 60
32
+	e.crlfForceThresh = 72
57 33
 	go e.run()
58 34
 	return e
59 35
 }
60 36
 
61 37
 // EncodeString is fun
62
-func (t *Encoder) EncodeString(s string) {
38
+func (e *Encoder) EncodeString(s string) {
63 39
 	go func() {
64 40
 		for _, c := range s {
65
-			t.input <- c
41
+			e.input <- c
66 42
 		}
67 43
 	}()
68 44
 }
69 45
 
70
-func (t *Encoder) run() {
46
+func (e *Encoder) run() {
71 47
 
72 48
 	var modCase int           // current Letters/Figures state
73 49
 	var charsWithoutCRLF int  // number of chars we have handled without inserting a CR-LF
74 50
 	var charsWithoutShift int // number of chars we have handled without seeing a shift
75
-	for r := range t.input {
76
-		c := t.charset.toCode(r)
51
+	for r := range e.input {
52
+		c := e.charset.toCode(r)
77 53
 
78 54
 		/*this rune can either be rendered as a Figures character,
79 55
 		  a Letters character or WHITESPACE which can be rendered by
@@ -92,7 +68,7 @@ func (t *Encoder) run() {
92 68
 			we must send something, so we'll choose the more common
93 69
 			Letters case*/
94 70
 			if modCase == shiftUnknown {
95
-				t.output <- t.charset.unshift()
71
+				e.output <- e.charset.unshift()
96 72
 			}
97 73
 
98 74
 			modCase = shiftWhitespace
@@ -101,9 +77,9 @@ func (t *Encoder) run() {
101 77
 			  our modulator's current state, so add a new case char
102 78
 			  here*/
103 79
 			if c.shift == shiftLetter {
104
-				t.output <- t.charset.unshift()
80
+				e.output <- e.charset.unshift()
105 81
 			} else {
106
-				t.output <- t.charset.shift()
82
+				e.output <- e.charset.shift()
107 83
 			}
108 84
 
109 85
 			/*and save our current state*/
@@ -119,11 +95,11 @@ func (t *Encoder) run() {
119 95
 		   at least every 72 characters. */
120 96
 		if charsWithoutShift > 70 {
121 97
 			if modCase == shiftWhitespace {
122
-				t.output <- t.charset.unshift() /*doesn't matter which, so how 'bout LETR*/
98
+				e.output <- e.charset.unshift() /*doesn't matter which, so how 'bout LETR*/
123 99
 			} else if modCase == shiftLetter {
124
-				t.output <- t.charset.unshift()
100
+				e.output <- e.charset.unshift()
125 101
 			} else {
126
-				t.output <- t.charset.shift()
102
+				e.output <- e.charset.shift()
127 103
 			}
128 104
 			charsWithoutShift = 0
129 105
 		}
@@ -131,38 +107,38 @@ func (t *Encoder) run() {
131 107
 		/* we need to ensure that we send a carriage return/linefeed
132 108
 		 * at least every 72 characters, but we start looking for a
133 109
 		 * space character starting at 60 characters */
134
-		if !t.autoWrap {
110
+		if !e.autoWrap {
135 111
 			/*we just insert our regular character*/
136
-			t.output <- c.toByte()
112
+			e.output <- c.toByte()
137 113
 
138
-			if t.autoCRLF {
114
+			if e.autoCRLF {
139 115
 				if r == '\n' {
140
-					t.output <- t.charset.toByte('\r')
116
+					e.output <- e.charset.toByte('\r')
141 117
 				} else if r == '\r' {
142
-					t.output <- t.charset.toByte('\n')
118
+					e.output <- e.charset.toByte('\n')
143 119
 				}
144 120
 			}
145 121
 
146
-		} else if (charsWithoutCRLF > 59) && (modCase == shiftWhitespace) {
122
+		} else if (charsWithoutCRLF > e.crlfThresh) && (modCase == shiftWhitespace) {
147 123
 			/*insert the cr-lf instead of the space character*/
148
-			t.output <- t.charset.toByte('\r')
149
-			t.output <- t.charset.toByte('\n')
124
+			e.output <- e.charset.toByte('\r')
125
+			e.output <- e.charset.toByte('\n')
150 126
 			charsWithoutCRLF = 0
151
-		} else if charsWithoutCRLF > 70 {
127
+		} else if charsWithoutCRLF > e.crlfForceThresh {
152 128
 			/*insert the cr-lf followed by the character*/
153
-			t.output <- t.charset.toByte('\r')
154
-			t.output <- t.charset.toByte('\n')
155
-			t.output <- c.toByte()
129
+			e.output <- e.charset.toByte('\r')
130
+			e.output <- e.charset.toByte('\n')
131
+			e.output <- c.toByte()
156 132
 			charsWithoutCRLF = 0
157 133
 		} else {
158 134
 			/*we just insert our regular character*/
159
-			t.output <- c.toByte()
135
+			e.output <- c.toByte()
160 136
 
161
-			if t.autoCRLF {
137
+			if e.autoCRLF {
162 138
 				if r == '\n' {
163
-					t.output <- t.charset.toByte('\r')
139
+					e.output <- e.charset.toByte('\r')
164 140
 				} else if r == '\r' {
165
-					t.output <- t.charset.toByte('\n')
141
+					e.output <- e.charset.toByte('\n')
166 142
 				}
167 143
 			}
168 144
 

+ 9
- 4
examples/main.go View File

@@ -8,8 +8,13 @@ import (
8 8
 )
9 9
 
10 10
 func main() {
11
-	baud := 45.45
12
-	stopBits := 2.0
11
+
12
+	s := openbaudot.ModemSettings{
13
+		Baud:       45.45,
14
+		StopBits:   2,
15
+		DataBits:   5,
16
+		SampleRate: 8000,
17
+	}
13 18
 
14 19
 	charset := openbaudot.USTTY.Initialize()
15 20
 
@@ -23,7 +28,7 @@ func main() {
23 28
 	done := make(chan struct{})
24 29
 
25 30
 	encoder := openbaudot.NewEncoder(encoderIn, modulatorIn, charset)
26
-	modulator := openbaudot.NewModulator(baud, stopBits, 5, modulatorIn, modulatorOut)
31
+	modulator := openbaudot.NewModulator(s, modulatorIn, modulatorOut)
27 32
 
28 33
 	callback := func(event int, data interface{}) {
29 34
 		switch event {
@@ -44,7 +49,7 @@ func main() {
44 49
 		}
45 50
 	}()
46 51
 
47
-	openbaudot.NewDemodulator(baud, stopBits, 5, demodulatorIn, decoderIn)
52
+	openbaudot.NewDemodulator(s, demodulatorIn, decoderIn)
48 53
 	openbaudot.NewDecoder(decoderIn, decoderOut, charset)
49 54
 
50 55
 	running := true

+ 50
- 68
modulator.go View File

@@ -1,66 +1,47 @@
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
+
1 12
 package openbaudot
2 13
 
3 14
 import "math"
4 15
 
5
-/*
6
- * OBL openbaudot Library
7
- *
8
- * Copyright (C) 2017 Keelan Lightfoot
9
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
10
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
11
- * Copyright (C) 2007-2008 Omnitor AB
12
- * Copyright (C) 2007-2008 Voiceriver Inc
13
- *
14
- * This software was developed with support from the National Institute on
15
- * Disability and Rehabilitation Research, US Dept of Education under Grant
16
- * # H133E990006 and H133E040014
17
- *
18
- * This library is free software; you can redistribute it and/or modify it
19
- * under the terms of the GNU Lesser General Public License as published by
20
- * the Free Software Foundation; either version 2.1 of the License, or (at
21
- * your option) any later version.
22
- *
23
- * This library is distributed in the hope that it will be useful, but
24
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
26
- * License for more details.
27
- *
28
- * You should have received a copy of the GNU Lesser General Public License
29
- * along with this library; if not, write to the Free Software Foundation,
30
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31
- *
32
- * Please send a copy of any improved versions of the library to:
33
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
34
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
35
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
36
- *
37
- * file...: obl.go
38
- * original author.: Keelan Lightfoot
39
- * Created: 20 May 2017
40
- *
41
- */
16
+const (
17
+	modStateIdle = iota
18
+	modStateStart
19
+	modStateBit
20
+	modStateStop
21
+	modStateHold
22
+)
42 23
 
43 24
 // Modulator is fun
44 25
 type Modulator struct {
45 26
 	input  chan byte
46 27
 	output chan int16
47 28
 
48
-	baud           float64 // modulator baud rate
49
-	dataBits       int
50
-	samplesPerBit  int    // number of samples for one bit
51
-	phaseQ16       uint16 // phase acc 0..2math.Pi -> 0..65536
52
-	amplitude      int16  // peak modulator amplitude for one tone
53
-	numStopBits    int    // number of stop bits
54
-	numStopSamples int    // number of samples for stop bit
55
-	wOneQ16        uint16 // scaled one freq 0..2math.Pi -> 0..65536
56
-	wZeroQ16       uint16 // scaled zero freq 0..2math.Pi -> 0..65536
57
-	sinLutQ15      []int16
58
-
59
-	callback Callback
29
+	baud            float64 // modulator baud rate
30
+	dataBits        int
31
+	samplesPerBit   int     // number of samples for one bit
32
+	phaseQ16        uint16  // phase acc 0..2math.Pi -> 0..65536
33
+	amplitude       int16   // peak modulator amplitude for one tone
34
+	numStopHalfBits int     // number of stop bits
35
+	numStopSamples  int     // number of samples for stop bit
36
+	wOneQ16         uint16  // scaled one freq 0..2math.Pi -> 0..65536
37
+	wZeroQ16        uint16  // scaled zero freq 0..2math.Pi -> 0..65536
38
+	sinLutQ15       []int16 // sine lookup table
39
+	sampleRate      int     // sample rate
40
+	callback        Callback
60 41
 }
61 42
 
62 43
 // NewModulator is fun
63
-func NewModulator(baud float64, stopBits float64, dataBits int, input chan byte, output chan int16) *Modulator {
44
+func NewModulator(s ModemSettings, input chan byte, output chan int16) *Modulator {
64 45
 
65 46
 	m := new(Modulator)
66 47
 	// mod.input = make(chan code)
@@ -69,14 +50,15 @@ func NewModulator(baud float64, stopBits float64, dataBits int, input chan byte,
69 50
 	m.input = input
70 51
 	m.output = output
71 52
 
72
-	m.baud = baud
73
-	m.dataBits = dataBits
74
-	m.samplesPerBit = int(float64(sampleRate) / m.baud)
75
-	m.numStopBits = int(math.Floor(stopBits / .5))
76
-	m.numStopSamples = m.numStopBits * m.samplesPerBit / 2
53
+	m.baud = s.Baud
54
+	m.dataBits = s.DataBits
55
+	m.sampleRate = s.SampleRate
56
+	m.samplesPerBit = int(float64(m.sampleRate) / m.baud)
57
+	m.numStopHalfBits = int(math.Floor(s.StopBits / .5))
58
+	m.numStopSamples = m.numStopHalfBits * m.samplesPerBit / 2
77 59
 	m.amplitude = 16384
78 60
 
79
-	wOne, wZero := calculateW(2125, 2295)
61
+	wOne, wZero := calculateW(2125, 2295, m.sampleRate)
80 62
 
81 63
 	m.wOneQ16 = uint16((65536 / (2.0 * math.Pi)) * wOne)
82 64
 	m.wZeroQ16 = uint16((65536 / (2.0 * math.Pi)) * wZero)
@@ -106,11 +88,11 @@ func (m *Modulator) modulate(bit int) { //short *buffer, int samples)
106 88
 	*/
107 89
 	if bit != 0 {
108 90
 		m.phaseQ16 += m.wOneQ16
109
-		m.output <- multq(m.amplitude, m.sinLutQ15[m.phaseQ16>>2])
91
+		m.output <- multq15(m.amplitude, m.sinLutQ15[m.phaseQ16>>2])
110 92
 
111 93
 	} else {
112 94
 		m.phaseQ16 += m.wZeroQ16
113
-		m.output <- multq(m.amplitude, m.sinLutQ15[m.phaseQ16>>2])
95
+		m.output <- multq15(m.amplitude, m.sinLutQ15[m.phaseQ16>>2])
114 96
 	}
115 97
 }
116 98
 
@@ -127,26 +109,26 @@ func (m *Modulator) run() {
127 109
 	for {
128 110
 		nextState = modState
129 111
 		switch modState {
130
-		case ModStateIdle:
112
+		case modStateIdle:
131 113
 			select {
132 114
 			case c = <-m.input:
133 115
 				modSample = 0
134
-				nextState = ModStateStart
116
+				nextState = modStateStart
135 117
 				//obl.callback(EventTransmitState, TransmitStart)
136 118
 				idleSamples = 0
137 119
 			default:
138 120
 				m.modulate(0)
139 121
 
140
-				if idleSamples < sampleRate {
122
+				if idleSamples < m.sampleRate {
141 123
 					idleSamples++
142
-				} else if idleSamples == sampleRate {
124
+				} else if idleSamples == m.sampleRate {
143 125
 					if m.callback != nil {
144 126
 						m.callback(EventIdle, 0)
145 127
 					}
146 128
 					idleSamples++
147 129
 				}
148 130
 			}
149
-		case ModStateStart:
131
+		case modStateStart:
150 132
 			m.modulate(0)
151 133
 			modSample++
152 134
 			// after sending start bit send LSB data bit
@@ -154,9 +136,9 @@ func (m *Modulator) run() {
154 136
 				modNbit = 0
155 137
 				modBit = int(c & 0x1)
156 138
 				modSample = 0
157
-				nextState = ModStateBit
139
+				nextState = modStateBit
158 140
 			}
159
-		case ModStateBit:
141
+		case modStateBit:
160 142
 			m.modulate(modBit)
161 143
 			modSample++
162 144
 			// when this data bit complete, send next data bit
@@ -165,16 +147,16 @@ func (m *Modulator) run() {
165 147
 				modNbit++
166 148
 				modBit = int((c >> uint(modNbit)) & 0x1)
167 149
 				if modNbit == m.dataBits {
168
-					nextState = ModStateStop
150
+					nextState = modStateStop
169 151
 				}
170 152
 			}
171
-		case ModStateStop:
153
+		case modStateStop:
172 154
 			m.modulate(1)
173 155
 			modSample++
174 156
 			// when stop bit complete start transmission of next char, or enter idle state
175 157
 			if modSample == m.numStopSamples {
176 158
 				modSample = 0
177
-				nextState = ModStateIdle
159
+				nextState = modStateIdle
178 160
 			}
179 161
 			// 	(obl.callback)(obl,OBL_EVENT_TX_STATE, OBL_TRANSMIT_STOP);
180 162
 		}