recording & noise profile support on linux

This commit is contained in:
Damien Elmes 2009-01-17 01:05:39 +09:00
parent f515a6c5f9
commit 334d126237
6 changed files with 107 additions and 22 deletions

View file

@ -1453,8 +1453,8 @@ where id = :id""", pending)
# Progress info # Progress info
########################################################################## ##########################################################################
def startProgress(self, title, min, max): def startProgress(self, max=100, min=0, title=None):
runHook("startProgress", title, min, max) runHook("startProgress", max, min, title)
def updateProgress(self, label=None, value=None): def updateProgress(self, label=None, value=None):
runHook("updateProgress", label, value) runHook("updateProgress", label, value)
@ -1641,7 +1641,7 @@ Return new path, relative to media dir."""
def fixIntegrity(self): def fixIntegrity(self):
"Responsibility of caller to call rebuildQueue()" "Responsibility of caller to call rebuildQueue()"
self.startProgress(_("Check DB"), 0, 11) self.startProgress(11)
self.updateProgress(_("Checking integrity...")) self.updateProgress(_("Checking integrity..."))
if self.s.scalar("pragma integrity_check") != "ok": if self.s.scalar("pragma integrity_check") != "ok":
return _("Database file damaged. Restore from backup.") return _("Database file damaged. Restore from backup.")
@ -1873,8 +1873,8 @@ select sql from undoLog where
seq > :s and seq <= :e order by seq desc""", s=start, e=end) seq > :s and seq <= :e order by seq desc""", s=start, e=end)
mod = len(sql) / 35 mod = len(sql) / 35
if mod: if mod:
self.startProgress(_("Undo/Redo"), 0, 36) self.startProgress(36)
self.updateProgress(_("Applying changes...")) self.updateProgress(_("Processing..."))
newstart = self._latestUndoRow() newstart = self._latestUndoRow()
for c, s in enumerate(sql): for c, s in enumerate(sql):
if mod and not c % mod: if mod and not c % mod:

View file

@ -59,11 +59,11 @@ class AnkiExporter(Exporter):
self.includeSchedulingInfo = False self.includeSchedulingInfo = False
def exportInto(self, path): def exportInto(self, path):
n = 4 n = 3
if not self.includeSchedulingInfo: if not self.includeSchedulingInfo:
n += 1 n += 1
self.deck.startProgress(_("Export"), 0, n) self.deck.startProgress(n)
self.deck.updateProgress(_("Determining items...")) self.deck.updateProgress(_("Exporting..."))
self.newDeck = DeckStorage.Deck(path) self.newDeck = DeckStorage.Deck(path)
client = SyncClient(self.deck) client = SyncClient(self.deck)
server = SyncServer(self.newDeck) server = SyncServer(self.newDeck)
@ -74,12 +74,12 @@ class AnkiExporter(Exporter):
# set up a custom change list and sync # set up a custom change list and sync
lsum = self.localSummary() lsum = self.localSummary()
rsum = server.summary(0) rsum = server.summary(0)
self.deck.updateProgress(_("Copying...")) self.deck.updateProgress()
payload = client.genPayload((lsum, rsum)) payload = client.genPayload((lsum, rsum))
self.deck.updateProgress(_("Applying...")) self.deck.updateProgress()
res = server.applyPayload(payload) res = server.applyPayload(payload)
if not self.includeSchedulingInfo: if not self.includeSchedulingInfo:
self.deck.updateProgress(_("Updating schedule...")) self.deck.updateProgress()
self.newDeck.s.statement(""" self.newDeck.s.statement("""
delete from reviewHistory""") delete from reviewHistory""")
self.newDeck.s.statement(""" self.newDeck.s.statement("""
@ -121,7 +121,6 @@ delete from stats""")
bulkClient.server = bulkServer bulkClient.server = bulkServer
bulkClient.sync() bulkClient.sync()
# need to save manually # need to save manually
self.deck.updateProgress(_("Finalizing..."))
self.newDeck.rebuildCounts() self.newDeck.rebuildCounts()
self.exportedCards = self.newDeck.cardCount self.exportedCards = self.newDeck.cardCount
self.newDeck.s.commit() self.newDeck.s.commit()

View file

@ -46,11 +46,11 @@ class Importer(object):
def doImport(self): def doImport(self):
"Import." "Import."
self.deck.startProgress(_("Import"), 0, 6) self.deck.startProgress(6)
self.deck.updateProgress(_("Reading source...")) self.deck.updateProgress(_("Importing..."))
c = self.foreignCards() c = self.foreignCards()
self.importCards(c) self.importCards(c)
self.deck.updateProgress(_("Updating priorities...")) self.deck.updateProgress()
self.deck.updateAllPriorities() self.deck.updateAllPriorities()
self.deck.finishProgress() self.deck.finishProgress()
if c: if c:
@ -123,7 +123,7 @@ all but one card template."""))
def addCards(self, cards): def addCards(self, cards):
"Add facts in bulk from foreign cards." "Add facts in bulk from foreign cards."
# add facts # add facts
self.deck.updateProgress(_("Adding facts...")) self.deck.updateProgress()
factIds = [genID() for n in range(len(cards))] factIds = [genID() for n in range(len(cards))]
self.deck.s.execute(factsTable.insert(), self.deck.s.execute(factsTable.insert(),
[{'modelId': self.model.id, [{'modelId': self.model.id,
@ -134,7 +134,7 @@ all but one card template."""))
delete from factsDeleted delete from factsDeleted
where factId in (%s)""" % ",".join([str(s) for s in factIds])) where factId in (%s)""" % ",".join([str(s) for s in factIds]))
# add all the fields # add all the fields
self.deck.updateProgress(_("Adding fields...")) self.deck.updateProgress()
for fm in self.model.fieldModels: for fm in self.model.fieldModels:
try: try:
index = self.mapping.index(fm) index = self.mapping.index(fm)
@ -150,7 +150,7 @@ where factId in (%s)""" % ",".join([str(s) for s in factIds]))
self.deck.s.execute(fieldsTable.insert(), self.deck.s.execute(fieldsTable.insert(),
data) data)
# and cards # and cards
self.deck.updateProgress(_("Adding cards...")) self.deck.updateProgress()
now = time.time() now = time.time()
for cm in self.model.cardModels: for cm in self.model.cardModels:
self._now = now self._now = now
@ -165,7 +165,7 @@ where factId in (%s)""" % ",".join([str(s) for s in factIds]))
'type': 2},cards[m]) for m in range(len(cards))] 'type': 2},cards[m]) for m in range(len(cards))]
self.deck.s.execute(cardsTable.insert(), self.deck.s.execute(cardsTable.insert(),
data) data)
self.deck.updateProgress(_("Caching QA...")) self.deck.updateProgress()
self.deck.updateCardsFromModel(self.model) self.deck.updateCardsFromModel(self.model)
self.deck.cardCount += len(cards) self.deck.cardCount += len(cards)
self.total = len(factIds) self.total = len(factIds)

View file

@ -18,7 +18,7 @@ class Anki10Importer(Importer):
def doImport(self): def doImport(self):
"Import." "Import."
self.deck.startProgress(_("Import"), 0, 4) self.deck.startProgress(4)
self.deck.updateProgress(_("Importing...")) self.deck.updateProgress(_("Importing..."))
src = DeckStorage.Deck(self.file) src = DeckStorage.Deck(self.file)
client = SyncClient(self.deck) client = SyncClient(self.deck)

View file

@ -119,7 +119,7 @@ def rebuildMediaDir(deck, deleteRefs=False, dirty=True):
unusedFileCount = 0 unusedFileCount = 0
missingFileCount = 0 missingFileCount = 0
deck.mediaDir(create=True) deck.mediaDir(create=True)
deck.startProgress(_("Check Media DB"), 0, 16) deck.startProgress(16, 0, _("Check Media DB"))
# rename all files to checksum versions, note non-renamed ones # rename all files to checksum versions, note non-renamed ones
deck.updateProgress(_("Checksum files...")) deck.updateProgress(_("Checksum files..."))
files = os.listdir(unicode(deck.mediaDir())) files = os.listdir(unicode(deck.mediaDir()))

View file

@ -8,7 +8,7 @@ Sound support
""" """
__docformat__ = 'restructuredtext' __docformat__ = 'restructuredtext'
import re, sys, threading, time, subprocess, os import re, sys, threading, time, subprocess, os, signal
# Shared utils # Shared utils
########################################################################## ##########################################################################
@ -26,6 +26,30 @@ def hasSound(text):
# External audio # External audio
########################################################################## ##########################################################################
# the amount of noise to cancel
NOISE_AMOUNT = "0.1"
# the amount of amplification
NORM_AMOUNT = "-3"
# the amount of bass
BASS_AMOUNT = "+0"
# the amount to fade at end
FADE_AMOUNT = "0.2"
noiseProfile = ""
processingSrc = "tmp.wav"
processingDst = "tmp.mp3"
processingChain = []
tmpFiles = ["tmp2.wav", "tmp3.wav"]
cmd = ["sox", processingSrc, "tmp2.wav"]
processingChain = [
None, # placeholder
["sox", "tmp2.wav", "tmp3.wav", "norm", NORM_AMOUNT,
"bass", BASS_AMOUNT, "fade", FADE_AMOUNT, "0"],
["lame", "tmp3.wav", processingDst, "--noreplaygain"],
]
queue = [] queue = []
manager = None manager = None
@ -33,8 +57,11 @@ if sys.platform.startswith("win32"):
base = os.path.join(os.path.dirname(sys.argv[0]), "mplayer.exe") base = os.path.join(os.path.dirname(sys.argv[0]), "mplayer.exe")
#base = "C:\mplayer.exe" #base = "C:\mplayer.exe"
externalPlayer = [base, "-ao", "win32", "-really-quiet"] externalPlayer = [base, "-ao", "win32", "-really-quiet"]
externalRecorder = ["rec", processingSrc]
else: else:
externalPlayer = ["mplayer", "-really-quiet"] externalPlayer = ["mplayer", "-really-quiet"]
externalRecorder = ["ecasound", "-x", "-f:16,1,44100", "-i",
"alsahw,1,0", "-o", processingSrc]
# don't show box on windows # don't show box on windows
if sys.platform == "win32": if sys.platform == "win32":
@ -43,6 +70,29 @@ if sys.platform == "win32":
else: else:
si = None si = None
# noise profiles
##########################################################################
def checkForNoiseProfile():
cmd = ["sox", processingSrc, "tmp2.wav"]
if os.path.exists(noiseProfile):
cmd = cmd + ["noisered", noiseProfile, NOISE_AMOUNT]
processingChain[0] = cmd
def generateNoiseProfile(file):
try:
os.unlink(noiseProfile)
except OSError:
pass
subprocess.Popen(["sox", processingSrc, tmpFiles[0], "trim", "1.5", "1.5"])
subprocess.Popen(["sox", tmpFiles[0], tmpFiles[1],
"noiseprof", noiseProfile]).wait()
processingChain[0] = ["sox", processingSrc, "tmp2.wav",
"noisered", noiseProfile, NOISE_AMOUNT]
# External playing
##########################################################################
class QueueMonitor(threading.Thread): class QueueMonitor(threading.Thread):
def run(self): def run(self):
@ -68,6 +118,37 @@ def clearQueueExternal():
global queue global queue
queue = [] queue = []
# External recording
##########################################################################
class _Recorder(object):
def postprocess(self):
for c in processingChain:
print c
if subprocess.Popen(c, startupinfo=si).wait():
raise Exception("problem with" + str(c))
class ExternalUnixRecorder(_Recorder):
def __init__(self):
for t in tmpFiles + [processingSrc, processingDst]:
try:
os.unlink(t)
except OSError:
pass
def start(self):
self.proc = subprocess.Popen(
externalRecorder, startupinfo=si)
def stop(self):
os.kill(self.proc.pid, signal.SIGINT)
self.proc.wait()
def file(self):
return processingDst
# Mac audio support # Mac audio support
########################################################################## ##########################################################################
@ -124,6 +205,11 @@ except ImportError:
if sys.platform.startswith("darwin"): if sys.platform.startswith("darwin"):
play = playOSX play = playOSX
clearAudioQueue = clearQueueOSX clearAudioQueue = clearQueueOSX
Recorder = None
else: else:
play = playExternal play = playExternal
clearAudioQueue = clearQueueExternal clearAudioQueue = clearQueueExternal
if sys.platform.startswith("win32"):
Recorder = None
else:
Recorder = ExternalUnixRecorder