Skip to content

Commit

Permalink
Add working test for DTMF.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben Titcomb committed Mar 3, 2016
1 parent 24dc992 commit 98d4b41
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 22 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ Goertzel.Utilities.doublePeakFilter(energies1,energies2,sensitivity)
doublePeakFilter does the same thing as the normal peak filter but with two arrays at the same time.
```javascript
Goertzel.Utilities.generateSineBuffer(frequencies=[], sampleRate, numberOfSamples)
```
generateSineBuffer lets you create an artificial buffer of any number of combined sine waves. Added for testing purposes, but could have any number of uses. If you needed to create an oscillator to generate DTMF or other tones without access to a browser's audio API, that's your function.
## conclusion
I hope this project will be useful for anyone who wants to understand the Goertzel algorithm or basic signal processing with the HTML5 Audio API.
Expand Down
2 changes: 1 addition & 1 deletion build/dtmf.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 16 additions & 10 deletions build/goertzel.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions spec/dtmf.spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
`Goertzel = require('../build/goertzel');`
DTMF = require('../build/dtmf')
require('jasmine-expect')

describe 'DTMF', ->

pairs = [
{low: 697, high: 1209, char: '1'}
{low: 697, high: 1336, char: '2'}
{low: 697, high: 1477, char: '3'}
{low: 697, high: 1633, char: 'A'}
{low: 770, high: 1209, char: '4'}
{low: 770, high: 1336, char: '5'}
{low: 770, high: 1477, char: '6'}
{low: 770, high: 1633, char: 'B'}
{low: 852, high: 1209, char: '7'}
{low: 852, high: 1336, char: '8'}
{low: 852, high: 1477, char: '9'}
{low: 852, high: 1633, char: 'C'}
{low: 941, high: 1209, char: '*'}
{low: 941, high: 1336, char: '0'}
{low: 941, high: 1477, char: '#'}
{low: 941, high: 1633, char: 'D'}
]

describe '#processSample', ->
it 'identifies all dial tones', ->
dtmf = new DTMF
sampleRate: 44100
peakFilterSensitivity: 1.4
repeatMin: 1
for pair in pairs
dualTone = Goertzel.Utilities.generateSineBuffer([pair.low, pair.high], 44100, 512)
buffer = Goertzel.Utilities.floatBufferToInt(dualTone)
dtmf.processBuffer(buffer)
expect(dtmf.processBuffer(buffer)).toContain(pair.char)
97 changes: 97 additions & 0 deletions spec/dtmf.spec.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion spec/goertzel.spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe 'Goertzel', ->

it 'biases towards the expected frequency', ->
for frequency in allFrequencies
buffer = Goertzel.Utilities.generateSine(frequency, 8000, 2000)
buffer = Goertzel.Utilities.generateSineBuffer([frequency], 8000, 2000)
for sample in buffer
goertzel.processSample sample
for f in allFrequencies
Expand Down
4 changes: 2 additions & 2 deletions spec/goertzel.spec.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 13 additions & 8 deletions src/goertzel.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,25 @@ class Goertzel
false

## useful for testing purposes
generateSine: (frequency, sampleRate, numberOfSamples) ->
buffer = []

generateSineBuffer: (frequencies, sampleRate, numberOfSamples) ->
buffer = new (Uint8ClampedArray or Array)(numberOfSamples)
volumePerSine = 1 / frequencies.length
i = 0
while i < numberOfSamples
v = Math.sin(Math.PI * 2 * (i / sampleRate) * frequency)
buffer.push v
val = 0
for frequency in frequencies
val += (Math.sin(Math.PI * 2 * (i / sampleRate) * frequency) * volumePerSine)
buffer[i] = val
i++
buffer
buffer

floatBufferToInt: (floatBuffer) ->
intBuffer = []
floatBufferLength = floatBuffer.length
intBuffer = new (Uint8ClampedArray or Array)(floatBufferLength)
i = 0
while i < floatBuffer.length
intBuffer.push Goertzel.Utilities.floatToIntSample(floatBuffer[i])
while i < floatBufferLength
intBuffer[i] = Goertzel.Utilities.floatToIntSample(floatBuffer[i])
i++
intBuffer

Expand Down

0 comments on commit 98d4b41

Please sign in to comment.