1
2
3
4 """Interface to audio card via pygame
5
6 """
7
8 import sys
9 import pygame
10 import numpy as np
11
12 try:
13 from guitools import Logger
14 except ImportError:
17
19 _doinit = 1
20 _disabled = None
21 _dafreq = None
22 _bits = None
23 _chans = None
24
26 if _Beeper._disabled: return
27
28 if _Beeper._doinit:
29 if pygame.mixer.get_init() is None:
30 try:
31 pygame.mixer.init()
32 except pygame.error:
33 Logger('beep: no audio device available -- check perms\n')
34 _Beeper._doinit = 0
35 _Beeper._disabled = 1
36 return
37 pygame.sndarray.use_arraytype('numpy')
38 (_Beeper._dafreq,
39 _Beeper._bits, _Beeper._chans) = pygame.mixer.get_init()
40 _Beeper.cache = {}
41 _Beeper._doinit = 0
42
43 - def _beep(self, freq, msdur, vol, risefall, wait, play):
44 if _Beeper._disabled: return
45
46 try:
47 s = _Beeper.cache[freq, msdur, vol, risefall]
48 except KeyError:
49 s = self._synth(freq, msdur, vol, risefall)
50 _Beeper.cache[freq, msdur, vol, risefall] = s
51
52 if play:
53
54
55
56
57 s.play()
58 while wait and pygame.mixer.get_busy():
59 pass
60
61 - def _synth(self, freq, msdur, vol, risefall):
62 t = np.arange(0, msdur / 1000.0, 1.0 / _Beeper._dafreq)
63 s = np.zeros((t.shape[0], 2))
64
65 if msdur < 40:
66 risefall = msdur / 2.0
67 env = -abs((t - (t[-1] / 2)) / (risefall/1000.0))
68 env = env - min(env)
69 env = np.where(np.less(env, 1.0), env, 1.0)
70
71 bits = _Beeper._bits
72 if bits < 0:
73 bits = -bits
74 signed = 1
75 else:
76 signed = 0
77
78 fullrange = np.power(2, bits-1)
79
80 if freq is None:
81 y = env * vol * fullrange * np.random.random(t.shape)
82 else:
83 y = env * vol * fullrange * np.sin(2.0 * np.pi * t * freq)
84 y = y.astype(np.int16)
85
86 if _Beeper._chans == 2:
87 y = np.transpose(np.array([y,y]))
88 s = pygame.sndarray.make_sound(y)
89 return s
90
91 -def beep(freq=-1, msdur=-1, vol=0.5, risefall=20, wait=1, play=1, disable=None):
92 """Beep the speaker using sound card.
93
94 :param freq: (Hz/None) tone frequency (None for noise)
95
96 :param msdur: (ms) tone duration
97
98 :param vol: (0-1) volume
99
100 :param risefall: (ms) envelope rise and fall
101
102 :param wait: (bool) block until sound has been played
103
104 :param play: (bool) true: play now; false: synthesize and cache for later
105
106 :return: nothing
107 """
108
109 if disable:
110
111 _Beeper._disabled = 1
112 elif freq and freq < 0:
113 _Beeper()
114 else:
115 _Beeper()._beep(freq, msdur, vol=vol, risefall=risefall,
116 wait=wait, play=play)
117
118
119
120 -def warble(base, t, volume=1, fmper=25, driver=None):
121 """Make a nice warbling sound - cheapo FM
122
123 :param base: (Hz) base frequency
124
125 :param t: (ms) duration
126
127 :param volume: (0-1) volume
128
129 :param fmper: (ms) period of modulation frequency
130
131 :return: nothing
132
133 """
134
135 et = 0
136 while et < t:
137 beep(base, fmper, volume, wait=0)
138 beep(1.10*base, fmper, volume, wait=0)
139 et = et + (2 * fmper)
140
141
142 if __name__ == '__main__':
143 print "start"
144 beep(1000, 50)
145 beep(500, 50)
146 print "quitting"
147 while pygame.mixer.get_busy():
148 pygame.mixer.quit()
149 print "done."
150