~ubuntu-branches/ubuntu/lucid/anki/lucid-updates

« back to all changes in this revision

Viewing changes to libanki/anki/sound.py

  • Committer: Bazaar Package Importer
  • Author(s): Mackenzie Morgan
  • Date: 2010-05-31 15:55:50 UTC
  • mfrom: (7.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100531155550-wj3tag8bvp6fwhpo
Tags: 0.9.9.8.6-2~lucid1
Backport from maverick to fix FTBFS (LP: #550145)

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
"""
9
9
__docformat__ = 'restructuredtext'
10
10
 
11
 
import re, sys, threading, time, subprocess, os, signal
 
11
import re, sys, threading, time, subprocess, os, signal, atexit, errno
 
12
from anki.hooks import addHook, runHook
12
13
 
13
14
# Shared utils
14
15
##########################################################################
49
50
    ["lame", "tmp3.wav", processingDst, "--noreplaygain", "--quiet"],
50
51
    ]
51
52
 
52
 
queue = []
53
 
manager = None
54
 
 
55
 
if sys.platform.startswith("win32"):
56
 
    externalPlayer = ["mplayer.exe", "-ao", "win32", "-really-quiet", "-noconsolecontrols"]
57
 
    dir = os.path.dirname(os.path.abspath(sys.argv[0]))
58
 
    os.environ['PATH'] += ";" + dir
59
 
    os.environ['PATH'] += ";" + dir + "\\..\\dist" # for testing
60
 
else:
61
 
    externalPlayer = ["mplayer", "-really-quiet", "-noconsolecontrols"]
62
 
 
63
53
# don't show box on windows
64
54
if sys.platform == "win32":
65
55
    si = subprocess.STARTUPINFO()
111
101
    processingChain[0] = ["sox", processingSrc, "tmp2.wav",
112
102
                          "noisered", noiseProfile, NOISE_AMOUNT]
113
103
 
114
 
# External playing
115
 
##########################################################################
116
 
 
117
 
class QueueMonitor(threading.Thread):
118
 
 
119
 
    def run(self):
120
 
        while 1:
121
 
            time.sleep(0.1)
122
 
            if queue:
123
 
                path = queue.pop(0)
124
 
                try:
125
 
                    retryWait(subprocess.Popen(
126
 
                        externalPlayer + [path], startupinfo=si))
127
 
                except OSError:
128
 
                    raise Exception("Audio player not found")
129
 
            else:
130
 
                return
131
 
 
132
 
def playExternal(path):
133
 
    global manager
 
104
# Mplayer settings
 
105
##########################################################################
 
106
 
 
107
if sys.platform.startswith("win32"):
 
108
    mplayerCmd = ["mplayer.exe", "-ao", "win32", "-really-quiet"]
 
109
    dir = os.path.dirname(os.path.abspath(sys.argv[0]))
 
110
    os.environ['PATH'] += ";" + dir
 
111
    os.environ['PATH'] += ";" + dir + "\\..\\dist" # for testing
 
112
else:
 
113
    mplayerCmd = ["mplayer", "-really-quiet"]
 
114
 
 
115
# Mplayer in slave mode
 
116
##########################################################################
 
117
 
 
118
mplayerQueue = []
 
119
mplayerManager = None
 
120
mplayerReader = None
 
121
mplayerCond = threading.Condition()
 
122
 
 
123
class MplayerReader(threading.Thread):
 
124
    "Read any debugging info to prevent mplayer from blocking."
 
125
 
 
126
    def run(self):
 
127
        while 1:
 
128
            mplayerCond.acquire()
 
129
            mplayerCond.wait()
 
130
            mplayerCond.release()
 
131
            try:
 
132
                mplayerManager.mplayer.stdout.read()
 
133
            except:
 
134
                pass
 
135
 
 
136
class MplayerMonitor(threading.Thread):
 
137
 
 
138
    def run(self):
 
139
        self.mplayer = None
 
140
        while 1:
 
141
            mplayerCond.acquire()
 
142
            while not mplayerQueue:
 
143
                if not mplayerCond:
 
144
                    return
 
145
                mplayerCond.wait()
 
146
            if not self.mplayer:
 
147
                self.startProcess()
 
148
            if self.mplayer != -1 and self.mplayer.poll() is not None:
 
149
                self.mplayer.wait()
 
150
                self.startProcess()
 
151
            nextClears = False
 
152
            while mplayerQueue:
 
153
                item = mplayerQueue.pop(0)
 
154
                if item is None:
 
155
                    nextClears = True
 
156
                    continue
 
157
                if nextClears:
 
158
                    nextClears = False
 
159
                    extra = ""
 
160
                else:
 
161
                    extra = " 1"
 
162
                cmd = 'loadfile "%s"%s\n' % (item, extra)
 
163
                self.mplayer.stdin.write(cmd)
 
164
            mplayerCond.release()
 
165
 
 
166
    def startProcess(self):
 
167
        try:
 
168
            cmd = mplayerCmd + ["-slave", "-idle"]
 
169
            self.mplayer = subprocess.Popen(
 
170
                cmd, startupinfo=si, stdin=subprocess.PIPE,
 
171
                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
 
172
        except OSError:
 
173
            mplayerCond.release()
 
174
            raise Exception("Audio player not found")
 
175
 
 
176
def queueMplayer(path):
 
177
    ensureMplayerThreads()
134
178
    path = path.encode(sys.getfilesystemencoding())
135
 
    queue.append(path)
136
 
    if not manager or not manager.isAlive():
137
 
        manager = QueueMonitor()
138
 
        manager.start()
139
 
 
140
 
def clearQueueExternal():
141
 
    global queue
142
 
    queue = []
 
179
    mplayerCond.acquire()
 
180
    mplayerQueue.append(path)
 
181
    mplayerCond.notifyAll()
 
182
    mplayerCond.release()
 
183
    runHook("soundQueued")
 
184
 
 
185
def clearMplayerQueue():
 
186
    mplayerCond.acquire()
 
187
    mplayerQueue.append(None)
 
188
    mplayerCond.release()
 
189
 
 
190
def ensureMplayerThreads():
 
191
    global mplayerManager, mplayerReader
 
192
    if not mplayerManager:
 
193
        mplayerManager = MplayerMonitor()
 
194
        mplayerManager.daemon = True
 
195
        mplayerManager.start()
 
196
        mplayerReader = MplayerReader()
 
197
        mplayerReader.daemon = True
 
198
        mplayerReader.start()
 
199
        atexit.register(stopMplayer)
 
200
 
 
201
def stopMplayer(restart=False):
 
202
    if not mplayerManager:
 
203
        return
 
204
    mplayerCond.acquire()
 
205
    if mplayerManager.mplayer:
 
206
        while 1:
 
207
            try:
 
208
                mplayerManager.mplayer.stdin.write("quit\n")
 
209
                break
 
210
            except OSError, e:
 
211
                if e.errno != errno.EINTR:
 
212
                    # osx throws interrupt errors regularly, but we want to
 
213
                    # ignore other errors on shutdown
 
214
                    break
 
215
            except IOError:
 
216
                # already closed
 
217
                break
 
218
            except ValueError:
 
219
                # already closed
 
220
                break
 
221
    if not restart:
 
222
        mplayerManager.mplayer = -1
 
223
    mplayerCond.notifyAll()
 
224
    mplayerCond.release()
 
225
 
 
226
def stopMplayerOnce():
 
227
    stopMplayer(restart=True)
 
228
 
 
229
addHook("deckClosed", stopMplayerOnce)
143
230
 
144
231
# PyAudio recording
145
232
##########################################################################
157
244
 
158
245
class _Recorder(object):
159
246
 
160
 
    def postprocess(self):
 
247
    def postprocess(self, encode=True):
 
248
        self.encode = encode
161
249
        for c in processingChain:
162
250
            #print c
 
251
            if not self.encode and c[0] == 'lame':
 
252
                continue
163
253
            ret = retryWait(subprocess.Popen(c, startupinfo=si))
164
254
            if ret:
165
255
                raise Exception(_("""
181
271
        try:
182
272
            p = pyaudio.PyAudio()
183
273
        except NameError:
184
 
            raise Exception("Recording not supported on OSX10.3.")
 
274
            raise Exception(
 
275
                "Pyaudio not installed (recording not supported on OSX10.3)")
185
276
        stream = p.open(format=PYAU_FORMAT,
186
277
                        channels=PYAU_CHANNELS,
187
278
                        rate=PYAU_RATE,
217
308
                os.unlink(t)
218
309
            except OSError:
219
310
                pass
 
311
        self.encode = False
220
312
 
221
313
    def start(self):
222
314
        self.thread = PyAudioThreadedRecorder()
227
319
        self.thread.join()
228
320
 
229
321
    def file(self):
230
 
        return processingDst
 
322
        if self.encode:
 
323
            return processingDst
 
324
        else:
 
325
            return tmpFiles[1]
231
326
 
232
 
# Default audio player
 
327
# Audio interface
233
328
##########################################################################
234
329
 
235
 
play = playExternal
236
 
clearAudioQueue = clearQueueExternal
 
330
_player = queueMplayer
 
331
_queueEraser = clearMplayerQueue
 
332
 
 
333
def play(path):
 
334
    _player(path)
 
335
 
 
336
def clearAudioQueue():
 
337
    _queueEraser()
237
338
 
238
339
Recorder = PyAudioRecorder