Switch distutils -> setuptools.
[minwii.git] / src / minwii / logfilereader.py
index a08855a..57cdc60 100755 (executable)
@@ -6,20 +6,23 @@ $Id$
 $URL$
 """
 
 $URL$
 """
 
+from types import StringTypes
 from widgets.playingscreen import PlayingScreenBase
 from eventutils import EventDispatcher
 from events import eventCodes
 from synth import Synth
 from musicxml import musicXml2Song
 import pygame
 from widgets.playingscreen import PlayingScreenBase
 from eventutils import EventDispatcher
 from events import eventCodes
 from synth import Synth
 from musicxml import musicXml2Song
 import pygame
+from backwardsfilereader import BackwardsReader
 
 SUPPORTED_FILE_HEADER = 'ENV winwii log format version : 1.0'
 
 def inplaceread(m) :
     def readinplace(self, *args, **kw) :
 
 SUPPORTED_FILE_HEADER = 'ENV winwii log format version : 1.0'
 
 def inplaceread(m) :
     def readinplace(self, *args, **kw) :
-        self.savePos()
+        pos = self.logfile.tell()
+        self.logfile.seek(0)
         ret = m(self, *args, **kw)
         ret = m(self, *args, **kw)
-        self.recallPos()
+        self.logfile.seek(pos)
         return ret
     return readinplace
 
         return ret
     return readinplace
 
@@ -28,27 +31,19 @@ class LogFileReader(object) :
     classe utilitaire pour l'accès aux données d'un fichier de log MinWii.
     """
     
     classe utilitaire pour l'accès aux données d'un fichier de log MinWii.
     """
     
-    def __init__(self, logfile) :
+    def __init__(self, logfile, mode='r') :
         """ logfile : chemin d'accès au fichier de log MinWii.
             le format supporté est actuellement la version 1.0 uniquement.
         """
         """ 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')
+        if isinstance(logfile, StringTypes) :
+            self.logfile = open(logfile, mode)
         else :
             self.logfile = logfile
         
         else :
             self.logfile = logfile
         
-        self.__pos = 0
-        
         firstline = self.next()
         assert firstline == SUPPORTED_FILE_HEADER
     
         firstline = self.next()
         assert firstline == SUPPORTED_FILE_HEADER
     
-    def savePos(self) :
-        self.__pos = self.logfile.tell()
-        self.logfile.seek(0)
-    
-    def recallPos(self) :
-        self.logfile.seek(self.__pos)
-    
+        
     @inplaceread
     def getSongFile(self) :
         "retourne le chemin d'accès au fichier musicxml de la chanson"
     @inplaceread
     def getSongFile(self) :
         "retourne le chemin d'accès au fichier musicxml de la chanson"
@@ -104,6 +99,16 @@ class LogFileReader(object) :
         mode = l.split(':', 1)[1].strip()
         return mode
     
         mode = l.split(':', 1)[1].strip()
         return mode
     
+    @inplaceread
+    def getHID(self) :
+        "retourne l'interface homme-machine utilisée"
+        for l in self :
+            if l.startswith('APP HID :') :
+                break
+            
+        mode = l.split(':', 1)[1].strip()
+        return mode
+    
     @inplaceread
     def getFirstEventTicks(self) :
         "retourne le timecode du premier événement (entier)"
     @inplaceread
     def getFirstEventTicks(self) :
         "retourne le timecode du premier événement (entier)"
@@ -113,8 +118,20 @@ class LogFileReader(object) :
         firstTicks = int(l.split(None, 2)[1])
         return firstTicks
     
         firstTicks = int(l.split(None, 2)[1])
         return firstTicks
     
+    @inplaceread
+    def getLastEventTicks(self) :
+        "retourne le timecode du dernier événement (entier)"
+        for l in self.getBackwardLineIterator() :
+            if l.startswith('EVT ') :
+                break
+        else :
+            return None
+        
+        lastTicks = int(l.split(None, 2)[1])
+        return lastTicks
+    
     def __del__(self) :
     def __del__(self) :
-        self.logfile.close()
+        self.close()
     
     def __iter__(self) :
         return self
     
     def __iter__(self) :
         return self
@@ -146,6 +163,47 @@ class LogFileReader(object) :
                 ticks, eventName = l.split(None, 3)[1:]
                 ticks = int(ticks)
                 yield ticks, eventName, ''
                 ticks, eventName = l.split(None, 3)[1:]
                 ticks = int(ticks)
                 yield ticks, eventName, ''
+    
+    def getBackwardLineIterator(self) :
+        br = BackwardsReader(self.logfile, BLKSIZE=128)
+        line = br.readline()
+        while line :
+            yield line.strip()
+            line = br.readline()
+    
+    @inplaceread
+    def getMetadata(self) :
+        metadata = {}
+        self.next() # skip identification line.
+        line = self.next()
+        while line.startswith('METADATA ') :
+            line = line.split(None, 1)[1]
+            name, value = [v.strip() for v in line.split(':', 1)]
+            metadata[name] = value
+            line = self.next()
+        return metadata
+    
+    def setMetadata(self, metadata) :
+        f = self.logfile
+        f.seek(0)
+        before = f.readline()
+        line = f.readline()
+        while line.startswith('METADATA ') :
+            line = f.readline()
+        after = line + f.read()
+        
+        lines = []
+        for name, value in metadata :
+            lines.append('METADATA %s : %s' % (name, value.encode('utf-8')))
+        metadata = '\n'.join(lines)
+        f.seek(0)
+        f.write(before)
+        f.write(metadata)
+        f.write(after)
+    
+    def close(self) :
+        self.logfile.close()
+        
                 
 
 class LogFilePlayer(PlayingScreenBase) :
                 
 
 class LogFilePlayer(PlayingScreenBase) :
@@ -217,5 +275,4 @@ class LogFilePlayer(PlayingScreenBase) :
             previousTicks = ticks
         
         self.stop()
             previousTicks = ticks
         
         self.stop()
-        
     
\ No newline at end of file
     
\ No newline at end of file