--- cplay.orig 2006-06-24 22:27:28.000000000 +0200 +++ cplay-1.49.patched1 2006-06-23 15:17:28.000000000 +0200 @@ -1,12 +1,14 @@ #!/usr/bin/env python # -*- python -*- -__version__ = "cplay 1.49" +__version__ = "cplay 1.49 speed-control" """ cplay - A curses front-end for various audio players Copyright (C) 1998-2003 Ulf Betlehem +Patched by Daniel Michalik to use mplayer with speed-control + 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 @@ -64,6 +66,8 @@ # ------------------------------------------ XTERM = re.search("rxvt|xterm", os.environ["TERM"]) CONTROL_FIFO = "%s/cplay-control-%s" % (os.environ.get("TMPDIR", "/tmp"), os.environ["USER"]) +MPLAYER_FIFO = "%s/mplayer-control-%s" % (os.environ.get("TMPDIR", "/tmp"), os.environ["USER"]) +SPEED_OFF = 0.005 # ------------------------------------------ def which(program): @@ -290,7 +294,7 @@ keymap.bind([1, '^'], app.seek, (0, 0)) # C-a keymap.bind([5, '$'], app.seek, (-1, 0)) # C-e keymap.bind(range(48,58), app.key_volume) # 0123456789 - keymap.bind(['+', '='], app.inc_volume, ()) + keymap.bind(['+'], app.inc_volume, ()) keymap.bind('-', app.dec_volume, ()) keymap.bind('n', app.next_song, ()) keymap.bind('p', app.prev_song, ()) @@ -300,6 +304,9 @@ keymap.bind('Q', app.quit, ()) keymap.bind('q', self.command_quit, ()) keymap.bind('v', app.mixer, ("toggle",)) + keymap.bind('[', app.speed_decr, ()) + keymap.bind(']', app.speed_incr, ()) + keymap.bind('=', app.speed_reset, ()) def command_quit(self): app.do_input_hook = self.do_quit @@ -539,6 +546,7 @@ <, > : horizontal scrolling s, S : shuffle/Sort playlist C-l, l : refresh, list mode w, @ : write playlist, jump to active h, q, Q : help, quit?, Quit! X : stop playlist after each track + [, ], = : decr, incr, reset speed """), "\n") # ------------------------------------------ @@ -1190,12 +1198,13 @@ self.buf = '' self.tid = None - def setup(self, entry, offset): + def setup(self, entry, offset, speed): self.argv = string.split(self.commandline) self.argv[0] = which(self.argv[0]) for i in range(len(self.argv)): if self.argv[i] == "%s": self.argv[i] = entry.pathname if self.argv[i] == "%d": self.argv[i] = str(offset*self.fps) + if self.argv[i] == "%x": self.argv[i] = str(speed) self.entry = entry if offset == 0: app.progress(0) @@ -1312,6 +1321,37 @@ self.set_position(head, head+tail, [head, tail]) # ------------------------------------------ +class TimeOffsetPlayerMplayer(Player): + re_progress = re.compile("\((?: (?P

\d+):)?(?:(?P\d+):)?(?P\d+).\d\).*\((?: (?P

\d+):)?(?:(?P\d+):)?(?P\d+).\d\)") + + def parse_buf(self): + match = self.re_progress.search(self.buf) + if match: + if match.group('h1'): + h1 = string.atoi(match.group('h1')) + else: h1 = 0 + if match.group('h2'): + h2 = string.atoi(match.group('h2')) + else: h2 = 0 + if match.group('m1'): + m1 = string.atoi(match.group('m1')) + else: m1 = 0 + if match.group('m2'): + m2 = string.atoi(match.group('m2')) + else: m2 = 0 + if match.group('s1'): + s1 = string.atoi(match.group('s1')) + else: s1 = 0 + if match.group('s2'): + s2 = string.atoi(match.group('s2')) + else: s2 = 0 + + #h1, m1, s1, h2, m2, s2 = map(string.atoi, match.groups()) + head = h1*3600+m1*60+s1 + tail = h2*3600+m2*60+s2-head + self.set_position(head, head+tail, [head, tail]) + +# ------------------------------------------ class NoOffsetPlayer(Player): def parse_buf(self): @@ -1375,6 +1415,24 @@ def backward(self): app.seek(-1, 1) + +# ------------------------------------------ +class MPLAYERControl: + def __init__(self): + self.fd = None + self.unlinked = 0 + try: + if os.path.exists(MPLAYER_FIFO): + self.unlinked = 1 + os.unlink(MPLAYER_FIFO) + os.mkfifo(MPLAYER_FIFO, 0600) + self.fd = open(MPLAYER_FIFO, "wb+", 0) + except IOError: + # warn that we're disabling the fifo because someone raced us? + return + + def send(self, arg): + self.fd.write(arg + "\n") # ------------------------------------------ class Application: @@ -1395,6 +1453,7 @@ self.input_keymap.bind(['\a', 27], self.cancel_input, ()) self.input_keymap.bind(['\n', curses.KEY_ENTER], self.stop_input, ()) + self.speed = 1.0 def setup(self): if tty: @@ -1430,6 +1489,8 @@ self.kludge = 0 self.win_filelist.listdir() self.control = FIFOControl() + self.mplayercontrol = MPLAYERControl() + self.speed = 1.0 def cleanup(self): try: curses.endwin() @@ -1481,7 +1542,7 @@ self.player.stop(quiet=1) for self.player in PLAYERS: if self.player.re_files.search(entry.pathname): - if self.player.setup(entry, offset): break + if self.player.setup(entry, offset, self.speed): break else: app.status(_("Player not found!"), 1) self.player.stopped = 0 # keep going @@ -1525,6 +1586,25 @@ try: self._mixer(cmd, arg) except Exception, e: app.status(e, 2) + def speedchg(self, set, offset): + if set == 0: + self.speed += offset + self.mplayercontrol.send("speed_incr " + str(offset)) + if set != 0: + self.speed = set + self.mplayercontrol.send("speed_set " + str(set)) + app.status(_("Speed: %s%%") % (self.speed * 100), 1) + + def speed_incr(self): + self.speedchg(0, SPEED_OFF) + + def speed_decr(self): + self.speedchg(0, -SPEED_OFF) + + def speed_reset(self): + self.speedchg(1, 0) + + def _mixer(self, cmd, arg): try: import ossaudiodev @@ -1650,6 +1730,7 @@ # ------------------------------------------ PLAYERS = [ + TimeOffsetPlayerMplayer("mplayer -speed %x -ss %d -input file=" + MPLAYER_FIFO + " %s", "\.(m4a|ogg|mp3|wav|wma)$"), FrameOffsetPlayer("ogg123 -q -v -k %d %s", "\.(ogg|flac)$"), FrameOffsetPlayer("splay -f -k %d %s", "(^http://|\.mp[123]$)", 38.28), FrameOffsetPlayer("mpg123 -q -v -k %d %s", "(^http://|\.mp[123]$)", 38.28),