diff options
author | Martin Michlmayr <tbm@cyrius.com> | 2006-02-05 20:24:07 +0100 |
---|---|---|
committer | Martin Michlmayr <tbm@cyrius.com> | 2006-02-05 20:24:07 +0100 |
commit | 97d87e1fa0808cf747bf0a4fe3b39d1cbdb5efc8 (patch) | |
tree | c817c2371ea765b6fd6f9e47f4985209dd1937dd /jack_workers.py |
Import jack_3.1.1+cvs20050801.orig.tar.gz
[dgit import orig jack_3.1.1+cvs20050801.orig.tar.gz]
Diffstat (limited to 'jack_workers.py')
-rwxr-xr-x | jack_workers.py | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/jack_workers.py b/jack_workers.py new file mode 100755 index 0000000..b341745 --- /dev/null +++ b/jack_workers.py @@ -0,0 +1,372 @@ +### jack_workers: worker functions for +### jack - extract audio from a CD and encode it using 3rd party software +### Copyright (C) 1999-2004 Arne Zellentin <zarne@users.sf.net> + +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. + +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. + +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software +### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import sndhdr +import signal +import string +import posix +import array +import fcntl +import wave +import time +import pty +import sys +import os + +import jack_functions +import jack_ripstuff +import jack_helpers +import jack_targets +import jack_utils +import jack_tag + +from jack_globals import * +from jack_helpers import helpers +from jack_init import F_SETFL, O_NONBLOCK + +def default_signals(): + signal.signal(signal.SIGTERM, signal.SIG_DFL) + signal.signal(signal.SIGINT, signal.SIG_DFL) + signal.signal(signal.SIGQUIT, signal.SIG_DFL) + signal.signal(signal.SIGHUP, signal.SIG_DFL) + signal.signal(signal.SIGWINCH, signal.SIG_DFL) + +def start_new_process(args, nice_value = 0): + "start a new process in a pty and renice it" + data = {} + data['start_time'] = time.time() + pid, master_fd = pty.fork() + if pid == CHILD: + default_signals() + if nice_value: + os.nice(nice_value) + os.execvp(args[0], [a.encode(cf['_charset'], "replace") for a in args]) + else: + data['pid'] = pid + if os.uname()[0] == "Linux": + fcntl.fcntl(master_fd, F_SETFL, O_NONBLOCK) + data['fd'] = master_fd + data['file'] = os.fdopen(master_fd) + data['cmd'] = args + data['buf'] = "" + data['otf'] = 0 + data['percent'] = 0 + data['elapsed'] = 0 + return data + +def start_new_ripper(track, ripper): + "start a new DAE process" + helper = helpers[cf['_ripper']] + cmd = string.split(helper['cmd']) + args = [] + for i in cmd: + if i == "%n": args.append(`track[NUM]`) + elif i == "%o": args.append(track[NAME].decode(cf['_charset'], "replace") + ".wav") + elif i == "%d": args.append(cf['_cd_device']) + elif i == "%D": args.append(cf['_gen_device']) + else: args.append(i) + data = start_new_process(args) + data['type'] = "ripper" + data['prog'] = cf['_ripper'] + data['track'] = track + return data + +def start_new_encoder(track, encoder): + "start a new encoder process" + helper = helpers[cf['_encoder']] + if cf['_vbr']: + cmd = string.split(helper['vbr-cmd']) + else: + cmd = string.split(helper['cmd']) + + args = [] + for i in cmd: + if i == "%r": + args.append(`track[RATE] * helper['bitrate_factor']`) + elif i == "%q": + if helper.has_key('inverse-quality') and helper['inverse-quality']: + quality = min(9, 10 - cf['_vbr_quality']) + else: + quality = cf['_vbr_quality'] + args.append("%.3f" % quality) + elif i == "%i": + args.append(track[NAME].decode(cf['_charset'], "replace") + ".wav") + elif i == "%o": + args.append(track[NAME].decode(cf['_charset'], "replace") + jack_targets.targets[jack_helpers.helpers[cf['_encoder']]['target']]['file_extension']) + else: + if jack_targets.targets[helper['target']]['can_pretag']: + if i == "%t": + if jack_tag.track_names: + args.append(jack_tag.track_names[track[NUM]][1]) + else: + args.append("") + elif i == "%a": + if jack_tag.track_names: + if jack_tag.track_names[track[NUM]][0]: + args.append(jack_tag.track_names[track[NUM]][0]) + else: + args.append(jack_tag.track_names[0][0]) + else: + args.append("") + elif i == "%n": + args.append(`track[NUM]`) + elif i == "%l": + if jack_tag.track_names: + args.append(jack_tag.track_names[0][1]) + else: + args.append("") + elif i == "%G": + if cf['_id3_genre'] >= 0: args.append(cf['_id3_genre']) + else: args.append('255') + elif i == "%g": + if cf['_id3_genre'] >= 0: args.append(jack_tag.genretxt) + else: args.append('Unknown') + elif i == "%y": + if cf['_id3_year'] > 0: + args.append(`cf['_id3_year']`) + else: + args.append('0') + else: + args.append(i) + else: + args.append(i) + data = start_new_process(args, cf['_nice_value']) + data['type'] = "encoder" + data['prog'] = cf['_encoder'] + data['track'] = track + return data + +def start_new_otf(track, ripper, encoder): + "start a new ripper/encoder pair for on-the-fly encoding" + data = {} + data['rip'] = {} + data['enc'] = {} + data['rip']['otf'] = 1 + data['enc']['otf'] = 1 + enc_in, rip_out = os.pipe() + data['rip']['fd'], rip_err = os.pipe() + data['enc']['fd'], enc_err = os.pipe() + args = [] + for i in string.split(helpers[ripper]['otf-cmd']): + if i == "%n": args.append(`track[NUM]`) + elif i == "%d": args.append(cf['_cd_device']) + elif i == "%D": args.append(cf['_gen_device']) + else: args.append(i) + data['rip']['start_time'] = time.time() + pid = os.fork() + if pid == CHILD: + default_signals() + os.dup2(rip_out, STDOUT_FILENO) + os.dup2(rip_err, STDERR_FILENO) + os.close(rip_out) + os.close(rip_err) + os.execvp(args[0], args) + # child won't see anything below... + os.close(rip_out) + os.close(rip_err) + data['rip']['pid'] = pid + data['rip']['cmd'] = helpers[cf['_ripper']]['otf-cmd'] + data['rip']['buf'] = "" + data['rip']['percent'] = 0 + data['rip']['elapsed'] = 0 + data['rip']['type'] = "ripper" + data['rip']['prog'] = cf['_ripper'] + data['rip']['track'] = track + if cf['_vbr']: + cmd = string.split(helpers[cf['_encoder']]['vbr-otf-cmd']) + else: + cmd = string.split(helpers[cf['_encoder']]['otf-cmd']) + args = [] + for i in cmd: + if i == "%r": + args.append(`track[RATE] * helpers[cf['_encoder']]['bitrate_factor']`) + elif i == "%q": + if helper.has_key('inverse-quality') and helper['inverse-quality']: + quality = min(9, 10 - cf['_vbr_quality']) + else: + quality = cf['_vbr_quality'] + args.append("%.3f" % quality) + elif i == "%o": + args.append(track[NAME].decode(cf['_charset'], "replace") + jack_targets.targets[jack_helpers.helpers[cf['_encoder']]['target']]['file_extension']) + elif i == "%d": + args.append(cf['_cd_device']) + elif i == "%D": + args.append(cf['_gen_device']) + else: + args.append(i) + data['enc']['start_time'] = time.time() + pid = os.fork() + if pid == CHILD: + default_signals() + if cf['_nice_value']: + os.nice(cf['_nice_value']) + os.dup2(enc_in, STDIN_FILENO) + os.dup2(enc_err, STDERR_FILENO) + os.close(enc_in) + os.close(enc_err) + os.execvp(args[0], args) + # child won't see anything below... + os.close(enc_in) + os.close(enc_err) + data['enc']['pid'] = pid + data['enc']['otf-pid'] = data['rip']['pid'] + data['enc']['cmd'] = cmd + data['enc']['buf'] = "" + data['enc']['percent'] = 0 + data['enc']['elapsed'] = 0 + data['enc']['type'] = "encoder" + data['enc']['prog'] = cf['_encoder'] + data['enc']['track'] = track + data['rip']['otf-pid'] = data['enc']['pid'] + + if os.uname()[0] == "Linux": + fcntl.fcntl(data['rip']['fd'], F_SETFL, O_NONBLOCK) + fcntl.fcntl(data['enc']['fd'], F_SETFL, O_NONBLOCK) + data['rip']['file'] = os.fdopen(data['rip']['fd']) + data['enc']['file'] = os.fdopen(data['enc']['fd']) + return data + +def ripread(track, offset = 0): + "rip one track from an image file." + data = {} + start_time = time.time() + pid, master_fd = pty.fork() # this could also be done with a pipe, anyone? + if pid == CHILD: + #debug: + #so=open("/tmp/stdout", "w") + #sys.stdout = so + #se=open("/tmp/stderr", "w+") + #sys.stderr = se + default_signals() + +# FIXME: all this offset stuff has to go, track 0 support has to come. + + print ":fAE: waiting for status report..." + sys.stdout.flush() + hdr = sndhdr.whathdr(cf['_image_file']) + my_swap_byteorder = cf['_swap_byteorder'] + my_offset = offset + if hdr: + +## I guess most people use cdparanoia 1- (instead of 0- if applicable) +## for image creation, so for a wav file use: + + image_offset = -offset + + else: + if string.upper(cf['_image_file'])[-4:] == ".CDR": + hdr = ('cdr', 44100, 2, -1, 16) # Unknown header, assuming cdr +# +## assume old cdrdao which started at track 1, not at block 0 + image_offset = -offset + + elif string.upper(cf['_image_file'])[-4:] == ".BIN": + hdr = ('bin', 44100, 2, -1, 16) # Unknown header, assuming bin +# +## assume new cdrdao which starts at block 0, byteorder is reversed. + my_swap_byteorder = not my_swap_byteorder + image_offset = 0 + + elif string.upper(cf['_image_file'])[-4:] == ".RAW": + hdr = ('bin', 44100, 2, -1, 16) # Unknown header, assuming raw + image_offset = 0 + + else: + debug("unsupported image file " + cf['_image_file']) + posix._exit(4) + + expected_filesize = jack_functions.tracksize(jack_ripstuff.all_tracks)[CDR] + CDDA_BLOCKSIZE * offset +# +## WAVE header is 44 Bytes for normal PCM files... +# + if hdr[0] == 'wav': + expected_filesize = expected_filesize + 44 + + if abs(jack_utils.filesize(cf['_image_file']) - expected_filesize) > CDDA_BLOCKSIZE: + # we *do* allow a difference of one frame + debug("image file size mismatch, aborted. %d != %d" % (jack_utils.filesize(cf['_image_file']), expected_filesize)) + posix._exit(1) + + elif hdr[0] == 'wav' and (hdr[1], hdr[2], hdr[4]) != (44100, 2, 16): + debug("unsupported WAV, need CDDA_fmt, aborted.") + posix._exit(2) + + elif hdr[0] not in ('wav', 'cdr', 'bin'): + debug("unsupported: " + hdr[0] + ", aborted.") + posix._exit(3) + + else: + f = open(cf['_image_file'], 'r') +# +## set up output wav file: +# + wav = wave.open(track[NAME].decode(cf['_charset'], "replace") + ".wav", 'w') + wav.setnchannels(2) + wav.setsampwidth(2) + wav.setframerate(44100) + wav.setnframes(0) + wav.setcomptype('NONE', 'not compressed') +# +## calculate (and seek to) position in image file +# + track_start = (track[START] + image_offset) * CDDA_BLOCKSIZE + if hdr[0] == 'wav': + track_start = track_start + 44 + f.seek(track_start) +# +## copy / convert the stuff +# + for i in range(0, track[LEN]): + buf = array.array("h") + buf.fromfile(f, 1176) # CDDA_BLOCKSIZE / 2 + if not my_swap_byteorder: # this is inverted as WAVE swabs them anyway. + buf.byteswap() + wav.writeframesraw(buf.tostring()) + if i % 1000 == 0: + print ":fAE: Block " + `i` + "/" + `track[LEN]` + (" (%2i%%)" % (i * 100 / track[LEN])) + sys.stdout.flush() + wav.close() + f.close() + + stop_time = time.time() + read_speed = track[LEN] / CDDA_BLOCKS_PER_SECOND / ( stop_time - start_time ) + if read_speed < 100: + print "[%2.0fx]" % read_speed, + else: + print "[99x]", + if hdr[0] in ('bin', 'wav'): + print "[ - read from image - ]" + else: + print "[cdr-WARNING, check byteorder !]" + sys.stdout.flush() + posix._exit(0) + else: # we are not the child + data['start_time'] = start_time + data['pid'] = pid + data['fd'] = master_fd + data['file'] = os.fdopen(master_fd) + data['cmd'] = "" + data['buf'] = "" + data['type'] = "image_reader" + data['prog'] = "builtin" + data['track'] = track + data['percent'] = 0 + data['otf'] = 0 + data['elapsed'] = 0 + return data + |