Update abcplay.sh -> abcplay.py and improve signal handling.
authorW. Trevor King <wking@drexel.edu>
Sat, 13 Nov 2010 18:55:48 +0000 (13:55 -0500)
committerW. Trevor King <wking@drexel.edu>
Sat, 13 Nov 2010 19:00:18 +0000 (14:00 -0500)
I hadn't looked at abcplay.sh for a while, and I like Python more now
than I did whenever I'd written the Bash version, so I rewrote the
script in Python.  On ^C, the new version skips to the next refnum
(the old version skipped to the next file).

posts/abcplay.mdwn
posts/abcplay/abcplay.py [new file with mode: 0755]
posts/abcplay/abcplay.sh [deleted file]

index 3873260253c8d7776c3ce2a30598af93c9107a81..6df247c610f3644954a6833f60edccdd340cacf4 100644 (file)
@@ -19,7 +19,7 @@ search tools and repositories listed on the [ABC homepage][ABC] and
 [JC's page][JC].
 
 To make playing ABC files as easy as possible, I've written a little
-script, [[abcplay.sh]], which uses `abc2midi` to generate a MIDI file
+script, [[abcplay.py]], which uses `abc2midi` to generate a MIDI file
 for each tune and then plays them with [timidity++][].
 
 [Bill Whipple]: http://www.wiplstix.com/
@@ -33,4 +33,5 @@ for each tune and then plays them with [timidity++][].
 [timidity++]: http://timidity.sourceforge.net/
 
 [[!tag tags/fun]]
+[[!tag tags/python]]
 [[!tag tags/tools]]
diff --git a/posts/abcplay/abcplay.py b/posts/abcplay/abcplay.py
new file mode 100755 (executable)
index 0000000..a3cd6c7
--- /dev/null
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+# 
+# Copyright (C) 2009-2010 W. Trevor King <wking@drexel.edu>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation, either version 3 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program.  If not, see
+# <http://www.gnu.org/licenses/>.
+
+from subprocess import Popen
+from tempfile import mkstemp
+from time import time
+from os import remove
+
+
+class ABCPlayer (object):
+    def __init__(self):
+        f,self._tempfile = mkstemp(prefix='abcplay-', suffix='.midi')
+        self._last_interrupt = 0
+        self._p = None
+
+    def cleanup(self):
+        remove(self._tempfile)
+
+    def play_files(self, filenames):
+        for filename in filenames:
+            refnums = list(self._refnums(filename))
+            while len(refnums) > 0:
+                refnum = refnums.pop(0)
+                try:
+                    self.play(filename, refnum)
+                except KeyboardInterrupt:
+                    self._kill_p()
+                    if self._return_after_interrupt():
+                        return
+
+    def _return_after_interrupt(self):
+        t = time()
+        ret = t-self._last_interrupt < 1
+        self._last_interrupt = t
+        return ret
+
+    def _refnums(self, filename):
+        with open(filename, 'r') as f:
+            for line in f:
+                if line.startswith('X:'):
+                    yield int(line[len('X:'):])
+
+    def play(self, filename, refnum):
+        self._convert_to_midi(filename, refnum)
+        self._play_midi()
+
+    def _convert_to_midi(self, filename, refnum):
+        self._p = Popen(
+            ['abc2midi', filename, str(refnum), '-o', self._tempfile])
+        self._p.wait()
+        self._p = None
+
+    def _play_midi(self):
+        self._p = Popen(['timidity', self._tempfile])
+        self._p.wait()
+        self._p = None
+
+    def _kill_p(self):
+        if self._p != None:
+            self._p.terminate()
+            self._p.wait()
+            self._p = None
+
+
+if __name__ == '__main__':
+    import sys
+
+    p = ABCPlayer()
+    try:
+        p.play_files(sys.argv[1:])
+    finally:
+        p.cleanup()
diff --git a/posts/abcplay/abcplay.sh b/posts/abcplay/abcplay.sh
deleted file mode 100755 (executable)
index ccc01e0..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/bash
-# 
-# Copyright (C) 2009-2010 W. Trevor King <wking@drexel.edu>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as
-# published by the Free Software Foundation, either version 3 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program.  If not, see
-# <http://www.gnu.org/licenses/>.
-
-
-MIDI_FILE=`mktemp --tmpdir abcmidi-XXXXXX`
-
-USER_INTERRUPT=13
-LAST_SIGINT=0
-# Clean up and exit on SIGTERM (default signal from kill command)
-trap 'rm -f "$MIDI_FILE"; exit $USER_INTERRUPT' TERM HUP
-# Clean up and continue to next song on SIGINT (^C)
-# If two SIGINTS come in the same second, exit.
-trap 'rm -f "$MIDI_FILE"; TIME=`date +%s`;
-  let "DELAY = TIME - LAST_SIGINT";
-  if [ "$DELAY" -eq 0 ] || [ "$DELAY" -eq 1 ]; then exit $USER_INTERRUPT; fi
-  LAST_SIGINT="$TIME";' INT
-
-for ABC_FILE in $*; do
-    grep '^X:' "$ABC_FILE" | cut -d: -f2 | while read REFNUM
-    do
-        abc2midi "$ABC_FILE" "$REFNUM" -o "$MIDI_FILE"
-        timidity "$MIDI_FILE"
-        rm -f "$MIDI_FILE"
-    done
-done