add some pyaudio test files
[scannr.git] / test2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
from os.path import exists
from array import array
from struct import unpack, pack
 
import pyaudio
import wave
 
THRESHOLD = 500
CHUNK_SIZE = 1024
FORMAT = pyaudio.paInt16
RATE = 44100
 
def is_silent(L):
    "Returns `True` if below the 'silent' threshold"
    return max(L) < THRESHOLD
 
def normalize(L):
    "Average the volume out"
    MAXIMUM = 16384
    times = float(MAXIMUM)/max(abs(i) for i in L)
 
    LRtn = array('h')
    for i in L:
        LRtn.append(int(i*times))
    return LRtn
 
def trim(L):
    "Trim the blank spots at the start and end"
    def _trim(L):
        snd_started = False
        LRtn = array('h')
 
        for i in L:
            if not snd_started and abs(i)>THRESHOLD:
                snd_started = True
                LRtn.append(i)
 
            elif snd_started:
                LRtn.append(i)
        return LRtn
 
    # Trim to the left
    L = _trim(L)
 
    # Trim to the right
    L.reverse()
    L = _trim(L)
    L.reverse()
    return L
 
def add_silence(L, seconds):
    "Add silence to the start and end of `L` of length `seconds` (float)"
    LRtn = array('h', [0 for i in xrange(int(seconds*RATE))])
    LRtn.extend(L)
    LRtn.extend([0 for i in xrange(int(seconds*RATE))])
    return LRtn
 
def record():
    """
    Record a word or words from the microphone and 
    return the data as an array of signed shorts.
 
    Normalizes the audio, trims silence from the 
    start and end, and pads with 0.5 seconds of 
    blank sound to make sure VLC et al can play 
    it without getting chopped off.
    """
    p = pyaudio.PyAudio()
    stream = p.open(format=FORMAT, channels=2, rate=RATE, 
                    input=True, 
                    frames_per_buffer=CHUNK_SIZE)
 
    num_silent = 0
    snd_started = False
 
    LRtn = array('h')
 
    while 1:
        data = stream.read(CHUNK_SIZE)
        L = unpack('<' + ('h'*(len(data)/2)), data) # little endian, signed short
        L = array('h', L)
        LRtn.extend(L)
 
        silent = is_silent(L)
        #print silent, num_silent, L[:10]
 
        if silent and snd_started:
            num_silent += 1
        elif not silent and not snd_started:
            snd_started = True
 
        if snd_started and num_silent > 30:
            break
 
    sample_width = p.get_sample_size(FORMAT)
    stream.stop_stream()
    stream.close()
    p.terminate()
 
    LRtn = normalize(LRtn)
    LRtn = trim(LRtn)
    LRtn = add_silence(LRtn, 0.5)
    return sample_width, LRtn
 
def record_to_file(path):
    "Records from the microphone and outputs the resulting data to `path`"
    sample_width, data = record()
    data = pack('<' + ('h'*len(data)), *data)
 
    wf = wave.open(path, 'wb')
    wf.setnchannels(2)
    wf.setsampwidth(sample_width)
    wf.setframerate(RATE)
    wf.writeframes(data)
    wf.close()
 
if __name__ == '__main__':
    print("please speak a word into the microphone")
    record_to_file('demo.wav')
    print("done - result written to demo.wav")