# GNU Solfege - free ear training software # Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Tom Cato Amundsen # # 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., 51 Franklin ST, Fifth Floor, Boston, MA 02110-1301 USA import sys, os, tempfile, signal import textwrap from synth_common import SynthCommon from mpd.track import MidiEventStream def ms_win_kill(pid): import win32api handle = win32api.OpenProcess(1, 0, pid) return (0 != win32api.TerminateProcess(handle, 0)) class MidiFileSynth(SynthCommon): NUM_CHANNELS = 16 def __init__(self, cmd, verbose_init): SynthCommon.__init__(self) self.m_type_major = "Midifile" self.m_cmd = cmd self.m_tmpfilename = tempfile.mkstemp(".mid")[1] self.error_report_cb = None self.m_pidfile = tempfile.mkstemp()[1] if sys.platform == 'win32': self.play_midieventstream = self._play_midieventstream_system else: self.play_midieventstream = self._play_midieventstream_fork_execl if verbose_init: print "Solfege will use an external midiplayer program." print "cmdline:", self.m_cmd print "tmpfile:", self.m_tmpfilename self.__child_pid = None def close(self): try: if os.path.exists(self.m_tmpfilename): os.remove(self.m_tmpfilename) except OSError: pass # We ignore this error because it seems to be easiest right now. # FIXME def join_cmd_and_filename(self, cmd, filename): if "%s" in cmd: return cmd % filename else: return " ".join((cmd, filename)) def play_track(self, *tracks): self.play_midieventstream(MidiEventStream(*tracks)) def play_midieventstream(self, midieventstream): if sys.platform == 'win32': self._play_midieventstream_system(*midieventstream) else: self._play_midieventstream_fork_execl(*midieventstream) def _play_midieventstream_system(self, midieventstream): midieventstream.create_midifile(self.m_tmpfilename) os.system(self.join_cmd_and_filename(self.m_cmd, self.m_tmpfilename)) # spawnl(os.P_DETACH, 'c:\\python20\\python', 'python', 'script.py') # #P_DETACH'ed can be killed def _play_midieventstream_fork_execl(self, midieventstream): midieventstream.create_midifile(self.m_tmpfilename) if not os.path.isfile(self.m_cmd.split()[0]): msg = _("""Failed to play music because the selected midi player program '%s' does not exist. You have to change the sound setup from the preferences window (Ctrl-F12).""") % self.m_cmd.split()[0] if self.error_report_cb: self.error_report_cb(msg) else: print >> sys.stderr, "\n".join(textwrap.wrap(msg)) return if self.__child_pid: try: os.kill(self.__child_pid, signal.SIGKILL) except OSError: pass os.wait() self.__child_pid = None pid = os.fork() if pid == 0: v = self.join_cmd_and_filename(self.m_cmd, self.m_tmpfilename).split(" ") v = v[:1] + [""] + v[1:] try: os.execlp(*v) except OSError, x: print "OSError while trying to invoke external midiplayer:", x print "Please check your sound setup!" os._exit(-1) else: self.__child_pid = pid def stop(self): if sys.platform != 'win32': if self.__child_pid: try: os.kill(self.__child_pid, signal.SIGKILL) except OSError: pass os.wait() self.__child_pid = None def test(): synth = MidiFileSynth("/usr/bin/timidity %s", True) sys.path.insert(0, ".") import mpd from mpd.track import track from mpd.rat import Rat import src.i18n src.i18n.setup(".") t1 = track.Track() t1.set_bpm(520, 4) for i in range(70, 90): t1.start_note(i, 127) t1.notelen_time(Rat(1, 4)) t1.stop_note(i, 127) t2 = track.Track() for i in reversed(range(80, 100)): t2.start_note(i, 127) t2.notelen_time(Rat(1, 4)) t2.stop_note(i, 127) synth.play_track(track.MidiEventStream(t1, t2)) if __name__ == '__main__': test()