tone-stream 1.4.4 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.editorconfig ADDED
@@ -0,0 +1,9 @@
1
+ root = true
2
+
3
+
4
+ [Makefile]
5
+ indent_style = tab
6
+
7
+ [*]
8
+ indent_style = space
9
+ indent_size = 2
@@ -1,51 +1,28 @@
1
1
  const { ToneStream } = require('../index.js')
2
- const goertzel = require('goertzel-stream')
3
-
4
- const {PassThrough} = require('stream')
5
-
6
- const sampleRate = 8000
2
+ const DtmfDetectionStream = require('dtmf-detection-stream')
7
3
 
8
4
  const format = {
9
- sampleRate: sampleRate,
10
- bitDepth: 16,
11
- channels: 1,
5
+ sampleRate: 8000,
6
+ bitDepth: 16,
7
+ channels: 1,
12
8
  }
13
9
 
14
10
  const ts = new ToneStream(format)
15
-
16
- var notes = [
17
- //[2000, 'DTMF:#'],
18
- [2000, 697],
19
- [1000, 's'],
20
- /*
21
- [2000, 770],
22
- [1000, 's'],
23
- [2000, 852],
24
- [1000, 's'],
25
- */
26
- ]
27
-
28
- ts.concat(notes)
29
-
30
- var detector = goertzel([697, 770, 852, 941, 1209, 1336, 1477, 1633], {
31
- sampleRate: sampleRate,
32
- })
33
-
34
- // adding PassThrough stream to check data in the pipe
35
- const pt = new PassThrough()
36
-
37
- pt.on('data', data => {
38
- console.log(data.length, data)
39
- })
40
-
41
- ts.pipe(pt)
42
- pt.pipe(detector)
43
-
44
- detector.on('toneStart', function (tones) {
45
- console.log('start', tones)
11
+ ts.add([800, 's']) // silence
12
+ ts.add([800, 'DTMF:1'])
13
+ ts.add([800, 's']) // silence
14
+ ts.add([800, 'DTMF:2'])
15
+ ts.add([800, 's']) // silence
16
+ ts.add([800, 'DTMF:3'])
17
+ ts.add([800, 's']) // silence
18
+
19
+ const dds = new DtmfDetectionStream(format)
20
+
21
+ dds.on('dtmf', data => {
22
+ console.log('Got', data)
46
23
  })
47
24
 
48
- detector.on('toneEnd', function (tones) {
49
- console.log('end', tones)
25
+ ts.on('data', data => {
26
+ dds.write(data)
50
27
  })
51
28
 
@@ -10,9 +10,11 @@ const format = {
10
10
  channels: 1
11
11
  }
12
12
 
13
- const filler = 0 // silence
13
+ const opts = {
14
+ stay_alive: true,
15
+ }
14
16
 
15
- const ts = new ToneStream(format, filler)
17
+ const ts = new ToneStream(format, opts)
16
18
 
17
19
  const s = new Speaker(format)
18
20
 
@@ -44,7 +46,7 @@ assert(b.length == 140)
44
46
  s.write(b)
45
47
 
46
48
  b = ts.read(12000)
47
- assert(b.length == 12000) // this will be filled with zeros after all items are consumed.
49
+ assert(b.length == 12000) // this will be filled with silence (zero) after all items are consumed.
48
50
  s.write(b)
49
51
 
50
52
  setTimeout(() => {}, 2000)
package/index.js CHANGED
@@ -1,159 +1,169 @@
1
- const { Readable } = require('stream')
1
+ const { Readable } = require("stream");
2
2
 
3
- const SpecReadStream = require('spec-read-stream')
3
+ const SpecReadStream = require("spec-read-stream");
4
4
 
5
- const DTMF = require('./lib/dtmf')
5
+ const DTMF = require("./lib/dtmf");
6
6
 
7
7
  class ToneStream extends Readable {
8
- constructor(format, filler) {
9
- super()
10
-
11
- if(format) {
12
- this.sampleRate = format.sampleRate
13
- this.bitDepth = format.bitDepth
14
- this.channels = format.channels
15
- } else {
16
- // default
17
- this.sampleRate = 8000
18
- this.bitDepth = 16
19
- this.channels = 1
20
- }
21
-
22
- this.filler = filler
23
-
24
- this.amplitude = (2**this.bitDepth)/2 - 1
25
-
26
- this.specReadStream = new SpecReadStream()
27
-
28
- this.currentSample = 0
29
- }
30
-
31
- add(spec) {
32
- this.specReadStream.add(spec)
33
- }
34
-
35
- concat(specs) {
36
- specs.forEach(spec => {
37
- this.specReadStream.add(spec)
38
- })
39
- }
40
-
41
- on(evt, cb) {
42
- super.on(evt, cb)
43
-
44
- if(evt == 'empty') {
45
- this.specReadStream.on(evt, cb)
46
- }
47
- }
48
-
49
- _read(n) {
50
- //console.log(`_read(${n})`)
51
-
52
- let sampleSize = this.bitDepth / 8
53
- let blockAlign = sampleSize * this.channels
54
-
55
- let numSamples = Math.floor(n / blockAlign)
56
-
57
- let end = this.currentSample + numSamples
58
-
59
- let buf = Buffer.alloc(numSamples * blockAlign)
60
-
61
- let setter = (buf['writeInt' + this.bitDepth + 'LE']).bind(buf)
62
-
63
- var specs = this.specReadStream.read(numSamples)
64
- //console.log(`specs=${specs}`)
65
-
66
- var buf_idx = 0;
67
-
68
- if(!specs) {
69
- //console.log(`no specs filler=${this.filler}`)
70
- if(typeof this.filler == 'number') {
71
- for(var j=0 ; j<numSamples * this.channels; j++) {
72
- let offset = (j * sampleSize * this.channels)
73
- setter(this.filler, offset)
74
- }
75
- return buf
76
- } else {
77
- return null
78
- }
79
- }
80
-
81
- let actualSamples = specs.reduce((total, spec) => { return total + spec[0] }, 0)
82
- //console.log(`actualSamples=${actualSamples}`)
83
-
84
- for(var i=0 ; i<specs.length ; i++) {
85
- var spec = specs[i]
86
- //console.log(`spec=${spec}`)
87
-
88
- var nSamples = spec[0]
89
- var spec_val = spec[1]
90
-
91
- var val_calculator = (() => {
92
- if(spec_val == 's') {
93
- // silence
94
- return () => { return 0 }
95
- } else if(typeof spec_val == 'number') {
96
- var freq = spec_val
97
- let t = (Math.PI * 2 * freq) / this.sampleRate
98
-
99
- return (amplitude, currentSample) => {
100
- return Math.round(amplitude * Math.sin(t * currentSample)) // sine wave
101
- }
102
- } else if(typeof spec_val == 'string' && spec_val.startsWith("DTMF:")) {
103
- var tone = DTMF[spec_val.split(":")[1]]
104
- var lo = tone[0]
105
- var hi = tone[1]
106
-
107
- let t_lo = (Math.PI * 2 * lo) / this.sampleRate
108
- let t_hi = (Math.PI * 2 * hi) / this.sampleRate
109
-
110
- return (amplitude, currentSample) => {
111
- return (
112
- Math.round(amplitude * Math.sin(t_lo * currentSample)) +
113
- Math.round(amplitude * Math.sin(t_hi * currentSample))
114
- ) / 2
115
- }
116
- } else {
117
- throw `invalid spec ${spec}`
118
- }
119
- })()
120
-
121
- for(var j=0 ; j<nSamples ; j++) {
122
- for (let channel = 0; channel < this.channels; channel++) {
123
- let val = val_calculator(this.amplitude, this.currentSample) / 2 // halve amplitude
124
- let offset = (buf_idx * sampleSize * this.channels) + (channel * sampleSize)
125
- setter(val, offset)
126
- buf_idx++
127
- this.currentSample++
128
- }
129
- }
130
- }
131
-
132
- if(typeof this.filler == 'number') {
133
- while(numSamples > actualSamples) {
134
- //console.log("adding filler")
135
- for (let channel = 0; channel < this.channels; channel++) {
136
- let offset = (actualSamples-1) * sampleSize * this.channels
137
- setter(this.filler, offset)
138
- this.currentSample++
139
- actualSamples++
140
- }
141
- }
142
- }
143
-
144
- if(numSamples > actualSamples) {
145
- //console.log(`slicing buf from ${numSamples} to ${actualSamples}`)
146
- //console.log(`${actualSamples * sampleSize * this.channels}`)
147
- buf = buf.slice(0, actualSamples * sampleSize * this.channels)
148
- }
149
-
150
- //console.log("pushing")
151
- //console.log(buf.length)
152
- this.push(buf)
153
- }
8
+ constructor(format, opts) {
9
+ super();
10
+
11
+ if (format) {
12
+ this.sampleRate = format.sampleRate;
13
+ this.bitDepth = format.bitDepth;
14
+ this.channels = format.channels;
15
+ } else {
16
+ // default
17
+ this.sampleRate = 8000;
18
+ this.bitDepth = 16;
19
+ this.channels = 1;
20
+ }
21
+
22
+ this.opts = opts;
23
+
24
+ this.amplitude = 2 ** this.bitDepth / 2 - 1;
25
+
26
+ this.specReadStream = new SpecReadStream();
27
+
28
+ this.currentSample = 0;
29
+ }
30
+
31
+ add(spec) {
32
+ this.specReadStream.add(spec);
33
+ }
34
+
35
+ concat(specs) {
36
+ specs.forEach((spec) => {
37
+ this.specReadStream.add(spec);
38
+ });
39
+ }
40
+
41
+ on(evt, cb) {
42
+ super.on(evt, cb);
43
+
44
+ if (evt == "empty") {
45
+ this.specReadStream.on(evt, cb);
46
+ }
47
+ }
48
+
49
+ _read(n) {
50
+ //console.log(`_read(${n})`)
51
+
52
+ let sampleSize = this.bitDepth / 8;
53
+ let blockAlign = sampleSize * this.channels;
54
+
55
+ let numSamples = Math.floor(n / blockAlign);
56
+
57
+ let end = this.currentSample + numSamples;
58
+
59
+ let buf = Buffer.alloc(numSamples * blockAlign);
60
+
61
+ let setter = buf["writeInt" + this.bitDepth + "LE"].bind(buf);
62
+
63
+ var specs = this.specReadStream.read(numSamples);
64
+ //console.log(`specs=${specs}`)
65
+
66
+ var buf_idx = 0;
67
+
68
+ if (!specs) {
69
+ if (this.opts && this.opts.stay_alive) {
70
+ for (var j = 0; j < numSamples * this.channels; j++) {
71
+ let offset = j * sampleSize * this.channels;
72
+ setter(0, offset);
73
+ }
74
+
75
+ this.push(buf);
76
+ return;
77
+ } else {
78
+ return null;
79
+ }
80
+ }
81
+
82
+ let actualSamples = specs.reduce((total, spec) => {
83
+ return total + spec[0];
84
+ }, 0);
85
+ //console.log(`actualSamples=${actualSamples}`)
86
+
87
+ for (var i = 0; i < specs.length; i++) {
88
+ var spec = specs[i];
89
+ //console.log(`spec=${spec}`)
90
+
91
+ var nSamples = spec[0];
92
+ var spec_val = spec[1];
93
+
94
+ var val_calculator = (() => {
95
+ if (spec_val == "s") {
96
+ // silence
97
+ return () => {
98
+ return 0;
99
+ };
100
+ } else if (typeof spec_val == "number") {
101
+ var freq = spec_val;
102
+ let t = (Math.PI * 2 * freq) / this.sampleRate;
103
+
104
+ return (amplitude, currentSample) => {
105
+ return Math.round(amplitude * Math.sin(t * currentSample)); // sine wave
106
+ };
107
+ } else if (
108
+ typeof spec_val == "string" &&
109
+ spec_val.startsWith("DTMF:")
110
+ ) {
111
+ var tone = DTMF[spec_val.split(":")[1]];
112
+ var lo = tone[0];
113
+ var hi = tone[1];
114
+
115
+ let t_lo = (Math.PI * 2 * lo) / this.sampleRate;
116
+ let t_hi = (Math.PI * 2 * hi) / this.sampleRate;
117
+
118
+ return (amplitude, currentSample) => {
119
+ return (
120
+ (Math.round(amplitude * Math.sin(t_lo * currentSample)) +
121
+ Math.round(amplitude * Math.sin(t_hi * currentSample))) /
122
+ 2
123
+ );
124
+ };
125
+ } else {
126
+ throw `invalid spec ${spec}`;
127
+ }
128
+ })();
129
+
130
+ for (var j = 0; j < nSamples; j++) {
131
+ for (let channel = 0; channel < this.channels; channel++) {
132
+ let val = val_calculator(this.amplitude, this.currentSample) / 2; // halve amplitude
133
+ let offset =
134
+ buf_idx * sampleSize * this.channels + channel * sampleSize;
135
+ setter(val, offset);
136
+ buf_idx++;
137
+ this.currentSample++;
138
+ }
139
+ }
140
+ }
141
+
142
+ if (typeof this.filler == "number") {
143
+ while (numSamples > actualSamples) {
144
+ //console.log("adding filler")
145
+ for (let channel = 0; channel < this.channels; channel++) {
146
+ let offset = (actualSamples - 1) * sampleSize * this.channels;
147
+ setter(this.filler, offset);
148
+ this.currentSample++;
149
+ actualSamples++;
150
+ }
151
+ }
152
+ }
153
+
154
+ if (numSamples > actualSamples) {
155
+ //console.log(`slicing buf from ${numSamples} to ${actualSamples}`)
156
+ //console.log(`${actualSamples * sampleSize * this.channels}`)
157
+ buf = buf.slice(0, actualSamples * sampleSize * this.channels);
158
+ }
159
+
160
+ //console.log("pushing")
161
+ //console.log(buf.length)
162
+ this.push(buf);
163
+ }
154
164
  }
155
165
 
156
166
  module.exports = {
157
- ToneStream,
158
- utils: require('./lib/utils.js'),
159
- }
167
+ ToneStream,
168
+ utils: require("./lib/utils.js"),
169
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tone-stream",
3
- "version": "1.4.4",
3
+ "version": "1.6.0",
4
4
  "description": "A simple audio tone stream library",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -21,11 +21,11 @@
21
21
  "author": "MayamaTakeshi",
22
22
  "license": "MIT",
23
23
  "devDependencies": {
24
- "goertzel-stream": "git+https://github.com/MayamaTakeshi/goertzel-stream.git",
25
24
  "lodash": "^4.17.21",
26
25
  "speaker": "^0.5.1"
27
26
  },
28
27
  "dependencies": {
28
+ "dtmf-detection-stream": "^1.10.0",
29
29
  "morse-node": "^0.1.1",
30
30
  "note-to-frequency": "^1.4.1",
31
31
  "spec-read-stream": "^1.2.0",