mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 06:52:21 -04:00
recording & noise profile support on linux
This commit is contained in:
parent
f515a6c5f9
commit
334d126237
6 changed files with 107 additions and 22 deletions
10
anki/deck.py
10
anki/deck.py
|
@ -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:
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()))
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue