X-Git-Url: https://scm.cri.minesparis.psl.eu/git/minwii.git/blobdiff_plain/1146c6cc44b9dfde050dd218f343811661796ecc..f6e0db47250bd3666e1f46f22ed8153d77b46f2e:/src/app/logfilereader.py diff --git a/src/app/logfilereader.py b/src/app/logfilereader.py new file mode 100755 index 0000000..502b332 --- /dev/null +++ b/src/app/logfilereader.py @@ -0,0 +1,159 @@ +# -*- coding: utf-8 -*- +""" +Module de lecture des fichiers de log minwii + +$Id$ +$URL$ +""" + +from widgets.playingscreen import PlayingScreenBase +from eventutils import EventDispatcher +from events import eventCodes +from synth import Synth +from musicxml import musicXml2Song +import pygame + +SUPPORTED_FILE_HEADER = 'ENV winwii log format version : 1.0-alpha' + +class LogFileReader(object) : + + def __init__(self, logfile) : + if isinstance(logfile, str) : + self.logfile = open(logfile, 'r') + else : + self.logfile = logfile + + firstline = self.next() + assert firstline == SUPPORTED_FILE_HEADER + + + def getSongFile(self) : + f = self.logfile + pos = f.tell() + + f.seek(0) + for l in self : + if l.startswith('APP chanson :') : + break + songfile = l.split(':', 1)[1].strip() + f.seek(pos) + return songfile + + def getSoundFontFile(self) : + f = self.logfile + pos = f.tell() + f.seek(0) + for l in self : + if l.startswith('ENV soundfont :') : + break + soundFontFile = l.split(':', 1)[1].strip() + return soundFontFile + + def getScreenResolution(self) : + f = self.logfile + pos = f.tell() + f.seek(0) + for l in self : + if l.startswith('ENV résolution écran :') : + break + screenResolution = eval(l.split(':', 1)[1].strip()) + return screenResolution + + def getFirstEventTicks(self) : + f = self.logfile + pos = f.tell() + f.seek(0) + for l in self : + if l.startswith('EVT ') : + break + firstTicks = int(l.split(None, 2)[1]) + return firstTicks + + def __del__(self) : + self.logfile.close() + + def __iter__(self) : + return self + + def next(self) : + line = self.logfile.next().strip() + return line + + def getEventsIterator(self) : + while True : + try : + l = self.next() + except StopIteration : + break + + if not l.startswith('EVT ') : + continue + try : + ticks, eventName, message = l.split(None, 3)[1:] + yield ticks, eventName, message + except ValueError : + ticks, eventName = l.split(None, 3)[1:] + yield ticks, eventName, '' + + +class LogFilePlayer(PlayingScreenBase) : + """ + ré-exécution d'une chanson sur la base de son fichier de log. + """ + + def __init__(self, logfile) : + lfr = self.lfr = LogFileReader(logfile) + songFile = lfr.getSongFile() + soundFontFile = lfr.getSoundFontFile() + sfPath = lfr.getSoundFontFile() + synth = Synth(sfPath=sfPath) + self.song = musicXml2Song(songFile) + screenResolution = lfr.getScreenResolution() + + pygame.display.set_mode(screenResolution) + + super(LogFilePlayer, self).__init__(synth, self.song.distinctNotes) + + def run(self): + self._running = True + clock = pygame.time.Clock() + pygame.display.flip() + pygame.mouse.set_visible(False) + + previousTicks = self.lfr.getFirstEventTicks() + eIter = self.lfr.getEventsIterator() + + for ticks, eventName, message in eIter : + ticks = int(ticks) + if eventName == 'COLSTATECHANGE' : + parts = message.split(None, 4) + if len(parts) == 4 : + parts.append('') + index, state, midi, name, syllabus = parts + index = int(index) + midi = int(midi) + state = state == 'True' + col = self.columns[midi] + col.update(state, syllabus=syllabus.decode('utf-8')) + + pygame.event.clear() # à virer + #EventDispatcher.dispatchEvents() + + dirty = self.draw(pygame.display.get_surface()) + pygame.display.update(dirty) + execTime = clock.tick() + + delay = ticks - previousTicks - execTime + if delay > 0 : + pygame.time.wait(delay) + + previousTicks = ticks + #print ticks, eventName, message + + #while self._running : + # EventDispatcher.dispatchEvents() + # dirty = self.draw(pygame.display.get_surface()) + # pygame.display.update(dirty) + # clock.tick() + + \ No newline at end of file