X-Git-Url: https://scm.cri.ensmp.fr/git/minwii.git/blobdiff_plain/f6e0db47250bd3666e1f46f22ed8153d77b46f2e..8a421d33328f7dd6d6bff38cc04f53cdf25de3a9:/src/app/logfilereader.py?ds=sidebyside diff --git a/src/app/logfilereader.py b/src/app/logfilereader.py index 502b332..64711c1 100755 --- a/src/app/logfilereader.py +++ b/src/app/logfilereader.py @@ -13,11 +13,17 @@ from synth import Synth from musicxml import musicXml2Song import pygame -SUPPORTED_FILE_HEADER = 'ENV winwii log format version : 1.0-alpha' +SUPPORTED_FILE_HEADER = 'ENV winwii log format version : 1.0' class LogFileReader(object) : + """ + classe utilitaire pour l'accès aux données d'un fichier de log MinWii. + """ def __init__(self, logfile) : + """ logfile : chemin d'accès au fichier de log MinWii. + le format supporté est actuellement la version 1.0 uniquement. + """ if isinstance(logfile, str) : self.logfile = open(logfile, 'r') else : @@ -28,6 +34,7 @@ class LogFileReader(object) : def getSongFile(self) : + "retourne le chemin d'accès au fichier musicxml de la chanson" f = self.logfile pos = f.tell() @@ -40,6 +47,7 @@ class LogFileReader(object) : return songfile def getSoundFontFile(self) : + "retourne le chemin d'accès au fichier de la soundfont (*.sf2)" f = self.logfile pos = f.tell() f.seek(0) @@ -47,9 +55,35 @@ class LogFileReader(object) : if l.startswith('ENV soundfont :') : break soundFontFile = l.split(':', 1)[1].strip() + f.seek(pos) return soundFontFile + def getBank(self) : + "retourne le paramètre bank du synthétiseur (entier)" + f = self.logfile + pos = f.tell() + f.seek(0) + for l in self : + if l.startswith('APP bank :') : + break + f.seek(pos) + bank = l.split(':', 1)[1].strip() + return int(bank) + + def getPreset(self) : + "retourne le paramètre preset du synthétiseur (entier)" + f = self.logfile + pos = f.tell() + f.seek(0) + for l in self : + if l.startswith('APP preset :') : + break + f.seek(pos) + preset = l.split(':', 1)[1].strip() + return int(preset) + def getScreenResolution(self) : + "retourne la résolution écran (tuple de deux entiers)" f = self.logfile pos = f.tell() f.seek(0) @@ -57,9 +91,11 @@ class LogFileReader(object) : if l.startswith('ENV résolution écran :') : break screenResolution = eval(l.split(':', 1)[1].strip()) + f.seek(pos) return screenResolution def getFirstEventTicks(self) : + "retourne le timecode du premier événement (entier)" f = self.logfile pos = f.tell() f.seek(0) @@ -67,6 +103,7 @@ class LogFileReader(object) : if l.startswith('EVT ') : break firstTicks = int(l.split(None, 2)[1]) + f.seek(pos) return firstTicks def __del__(self) : @@ -80,6 +117,12 @@ class LogFileReader(object) : return line def getEventsIterator(self) : + """ Retourne un itérateur sur les événements. + Chaque itération retourne un tuple de 3 éléments : + (timecode, nom_événement, données) avec le typage : + (entier, chaîne, chaîne) + """ + self.logfile.seek(0) while True : try : l = self.next() @@ -90,9 +133,11 @@ class LogFileReader(object) : continue try : ticks, eventName, message = l.split(None, 3)[1:] + ticks = int(ticks) yield ticks, eventName, message except ValueError : ticks, eventName = l.split(None, 3)[1:] + ticks = int(ticks) yield ticks, eventName, '' @@ -102,17 +147,20 @@ class LogFilePlayer(PlayingScreenBase) : """ 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) + lfr = self.lfr = LogFileReader(logfile) + songFile = lfr.getSongFile() + soundFontFile = lfr.getSoundFontFile() + sfPath = lfr.getSoundFontFile() + bank = lfr.getBank() + preset = lfr.getPreset() + synth = Synth(sfPath=sfPath) + synth.program_select(0, bank, preset) + 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 @@ -124,7 +172,7 @@ class LogFilePlayer(PlayingScreenBase) : eIter = self.lfr.getEventsIterator() for ticks, eventName, message in eIter : - ticks = int(ticks) + t0 = pygame.time.get_ticks() if eventName == 'COLSTATECHANGE' : parts = message.split(None, 4) if len(parts) == 4 : @@ -135,25 +183,32 @@ class LogFilePlayer(PlayingScreenBase) : state = state == 'True' col = self.columns[midi] col.update(state, syllabus=syllabus.decode('utf-8')) + + elif eventName == 'NOTEON': + chan, key, vel = [int(v) for v in message.split(None, 2)] + self.synth.noteon(chan, key, vel) + + elif eventName == 'NOTEOFF': + chan, key = [int(v) for v in message.split(None, 1)] + self.synth.noteoff(chan, key) + + elif eventName.startswith('COL') : + pos = [int(n) for n in message.split(None, 4)[-1].strip('()').split(',')] + self.cursor.setPosition(pos) + - pygame.event.clear() # à virer - #EventDispatcher.dispatchEvents() + pygame.event.clear() dirty = self.draw(pygame.display.get_surface()) pygame.display.update(dirty) - execTime = clock.tick() + execTime = pygame.time.get_ticks() - t0 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() + + self.stop() \ No newline at end of file