|
|
@@ -13,15 +13,15 @@ import (
|
|
|
const sampleRate = 8000 // Hz
|
|
|
|
|
|
var (
|
|
|
- // Length of the longest number sound
|
|
|
- longestNumSndLen int
|
|
|
+ // Length of the longest digit sound.
|
|
|
+ longestDigitSndLen int
|
|
|
endingBeepSound []byte
|
|
|
)
|
|
|
|
|
|
func init() {
|
|
|
- for _, v := range numberSounds {
|
|
|
- if longestNumSndLen < len(v) {
|
|
|
- longestNumSndLen = len(v)
|
|
|
+ for _, v := range digitSounds {
|
|
|
+ if longestDigitSndLen < len(v) {
|
|
|
+ longestDigitSndLen = len(v)
|
|
|
}
|
|
|
}
|
|
|
endingBeepSound = changeSpeed(beepSound, 1.4)
|
|
|
@@ -31,56 +31,55 @@ type Audio struct {
|
|
|
body *bytes.Buffer
|
|
|
}
|
|
|
|
|
|
-// NewImage returns a new audio captcha with the given slice of numbers, where
|
|
|
-// each number must be in range 0-9.
|
|
|
-func NewAudio(numbers []byte) *Audio {
|
|
|
- numsnd := make([][]byte, len(numbers))
|
|
|
+// NewImage returns a new audio captcha with the given digits, where each digit
|
|
|
+// must be in range 0-9.
|
|
|
+func NewAudio(digits []byte) *Audio {
|
|
|
+ numsnd := make([][]byte, len(digits))
|
|
|
nsdur := 0
|
|
|
- for i, n := range numbers {
|
|
|
- snd := randomizedNumSound(n)
|
|
|
+ for i, n := range digits {
|
|
|
+ snd := randomizedDigitSound(n)
|
|
|
nsdur += len(snd)
|
|
|
numsnd[i] = snd
|
|
|
}
|
|
|
- // Intervals between numbers (including beginning)
|
|
|
- intervals := make([]int, len(numbers)+1)
|
|
|
+ // Random intervals between digits (including beginning).
|
|
|
+ intervals := make([]int, len(digits)+1)
|
|
|
intdur := 0
|
|
|
for i := range intervals {
|
|
|
- // 1 to 3 seconds
|
|
|
- dur := rnd(sampleRate, sampleRate*3)
|
|
|
+ dur := rnd(sampleRate, sampleRate*3) // 1 to 3 seconds
|
|
|
intdur += dur
|
|
|
intervals[i] = dur
|
|
|
}
|
|
|
- // Background noise
|
|
|
- bg := makeBackgroundSound(longestNumSndLen*len(numbers) + intdur)
|
|
|
- // --
|
|
|
+ // Generate background sound.
|
|
|
+ bg := makeBackgroundSound(longestDigitSndLen*len(digits) + intdur)
|
|
|
+ // Create buffer and write audio to it.
|
|
|
a := new(Audio)
|
|
|
sil := makeSilence(sampleRate / 5)
|
|
|
bufcap := 3*len(beepSound) + 2*len(sil) + len(bg) + len(endingBeepSound)
|
|
|
a.body = bytes.NewBuffer(make([]byte, 0, bufcap))
|
|
|
- // Prelude, three beeps
|
|
|
+ // Write prelude, three beeps.
|
|
|
a.body.Write(beepSound)
|
|
|
a.body.Write(sil)
|
|
|
a.body.Write(beepSound)
|
|
|
a.body.Write(sil)
|
|
|
a.body.Write(beepSound)
|
|
|
- // Numbers
|
|
|
+ // Write digits.
|
|
|
pos := intervals[0]
|
|
|
for i, v := range numsnd {
|
|
|
mixSound(bg[pos:], v)
|
|
|
pos += len(v) + intervals[i+1]
|
|
|
}
|
|
|
a.body.Write(bg)
|
|
|
- // Ending
|
|
|
+ // Write ending (one beep).
|
|
|
a.body.Write(endingBeepSound)
|
|
|
return a
|
|
|
}
|
|
|
|
|
|
-// NewRandomAudio generates a sequence of random numbers with the given length,
|
|
|
-// and returns a new audio captcha with this numbers, and the sequence of
|
|
|
-// numbers itself.
|
|
|
-func NewRandomAudio(length int) (a *Audio, numbers []byte) {
|
|
|
- numbers = randomNumbers(length)
|
|
|
- a = NewAudio(numbers)
|
|
|
+// NewRandomAudio generates a sequence of random digits with the given length,
|
|
|
+// and returns a new audio captcha with these digits, and the sequence of
|
|
|
+// digits itself.
|
|
|
+func NewRandomAudio(length int) (a *Audio, digits []byte) {
|
|
|
+ digits = randomDigits(length)
|
|
|
+ a = NewAudio(digits)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
@@ -137,25 +136,25 @@ func setSoundLevel(a []byte, level float64) {
|
|
|
|
|
|
// changeSpeed returns new PCM bytes from the bytes with the speed and pitch
|
|
|
// changed to the given value that must be in range [0, x].
|
|
|
-func changeSpeed(a []byte, pitch float64) []byte {
|
|
|
- b := make([]byte, int(math.Floor(float64(len(a))*pitch)))
|
|
|
+func changeSpeed(a []byte, speed float64) []byte {
|
|
|
+ b := make([]byte, int(math.Floor(float64(len(a))*speed)))
|
|
|
var p float64
|
|
|
for _, v := range a {
|
|
|
- for i := int(p); i < int(p+pitch); i++ {
|
|
|
+ for i := int(p); i < int(p+speed); i++ {
|
|
|
b[i] = v
|
|
|
}
|
|
|
- p += pitch
|
|
|
+ p += speed
|
|
|
}
|
|
|
return b
|
|
|
}
|
|
|
|
|
|
-// rndFloat64n returns a random float64 number in range [from, to].
|
|
|
-func rndFloat64n(from, to float64) float64 {
|
|
|
+// rndf returns a random float64 number in range [from, to].
|
|
|
+func rndf(from, to float64) float64 {
|
|
|
return (to-from)*rand.Float64() + from
|
|
|
}
|
|
|
|
|
|
func randomSpeed(a []byte) []byte {
|
|
|
- pitch := rndFloat64n(0.9, 1.2)
|
|
|
+ pitch := rndf(0.9, 1.2)
|
|
|
return changeSpeed(a, pitch)
|
|
|
}
|
|
|
|
|
|
@@ -192,18 +191,18 @@ func reversedSound(a []byte) []byte {
|
|
|
func makeBackgroundSound(length int) []byte {
|
|
|
b := makeWhiteNoise(length, 8)
|
|
|
for i := 0; i < length/(sampleRate/10); i++ {
|
|
|
- snd := numberSounds[rand.Intn(10)]
|
|
|
- snd = changeSpeed(reversedSound(snd), rndFloat64n(0.8, 1.4))
|
|
|
+ snd := digitSounds[rand.Intn(10)]
|
|
|
+ snd = changeSpeed(reversedSound(snd), rndf(0.8, 1.4))
|
|
|
place := rand.Intn(len(b) - len(snd))
|
|
|
- setSoundLevel(snd, rndFloat64n(0.5, 1.2))
|
|
|
+ setSoundLevel(snd, rndf(0.5, 1.2))
|
|
|
mixSound(b[place:], snd)
|
|
|
}
|
|
|
- setSoundLevel(b, rndFloat64n(0.2, 0.3))
|
|
|
+ setSoundLevel(b, rndf(0.2, 0.3))
|
|
|
return b
|
|
|
}
|
|
|
|
|
|
-func randomizedNumSound(n byte) []byte {
|
|
|
- s := randomSpeed(numberSounds[n])
|
|
|
- setSoundLevel(s, rndFloat64n(0.7, 1.3))
|
|
|
+func randomizedDigitSound(n byte) []byte {
|
|
|
+ s := randomSpeed(digitSounds[n])
|
|
|
+ setSoundLevel(s, rndf(0.7, 1.3))
|
|
|
return s
|
|
|
}
|