]> git.parisson.com Git - timeside.git/commitdiff
- move id() into to IProcessor, all processors are required to implement this static...
authorOlivier Guilyardi <olivier@samalyse.com>
Fri, 27 Nov 2009 17:32:05 +0000 (17:32 +0000)
committerOlivier Guilyardi <olivier@samalyse.com>
Fri, 27 Nov 2009 17:32:05 +0000 (17:32 +0000)
- MetaProcessor now ensures that all id's are wellformed and unique and raise an exception otherwise
- add id() to all encoders and decoders, and make it static in analyzers and graphers
- remove underscores and shorten a couple of id's, see the doc of IProcessor.id()

25 files changed:
analyze/api.py
analyze/channels.py
analyze/dc.py
analyze/duration.py
analyze/encoding.py
analyze/format.py
analyze/max_level.py
analyze/mean_level.py
analyze/resolution.py
analyze/samplerate.py
api.py
core.py
decode/core.py
decode/flac.py
decode/mp3.py
decode/ogg.py
decode/wav.py
encode/flac.py
encode/mp3.py
encode/ogg.py
encode/wav.py
graph/api.py
graph/spectrogram_audiolab.py
graph/waveform_audiolab.py
tests/listprocessors.py

index 46d4ab9353f12383ba66e775709f5c252fcd885e..187dc29db833b120e0c1a7bb443605d3cb9f0164 100644 (file)
@@ -24,10 +24,6 @@ from timeside.api import IProcessor
 class IAnalyzer(IProcessor):
     """Media item analyzer driver interface"""
 
-    @staticmethod
-    def id():
-        """Return a short id alphanumeric, lower-case string."""
-
     @staticmethod
     def name():
         """Return the analyzer name, such as "Mean Level", "Max level",
index cb7e0fba288d7cebaa2fcc9623ac7e2a2c444391..e09c6abddfb856eb71ed4c1ffadbd0eb26ad1414 100644 (file)
@@ -28,8 +28,9 @@ class ChannelAnalyser(AudioProcessor):
 
     implements(IAnalyzer)
 
-    def id(self):
-        return "nb_channels"
+    @staticmethod
+    def id():
+        return "nchannels"
 
     def name(self):
         return "Channels"
index 050980946f3b7c7e6e059574ce8a24b7578e8992..28d0a68708f00f7b49593f27c53234465cbf8052 100644 (file)
@@ -28,7 +28,8 @@ class MeanDCShiftAnalyser(AudioProcessor):
 
     implements(IAnalyzer)
 
-    def id(self):
+    @staticmethod
+    def id():
         return "dc"
 
     def name(self):
index e69d31d0d1d3de3082ee2b677a59ae8e0c31aaab..4ea94011cb1dd805fff305b7066060b8904a1bee 100644 (file)
@@ -29,7 +29,8 @@ class DurationAnalyzer(AudioProcessor):
 
     implements(IAnalyzer)
 
-    def id(self):
+    @staticmethod
+    def id():
         return "duration"
 
     def name(self):
index e6ba192978796f6a5b81bda83e2d73f361bf2ac3..3ca3b927dacc67006234a0a767049d7f00e2c549 100644 (file)
@@ -28,7 +28,8 @@ class EncodingAnalyser(AudioProcessor):
 
     implements(IAnalyzer)
 
-    def id(self):
+    @staticmethod
+    def id():
         return "encoding"
 
     def name(self):
index b86c1cf1a72bdf4498fadca42cf8109bdb2557da..681afc381c429ed087b4dd478a994066c54b9e65 100644 (file)
@@ -28,7 +28,8 @@ class FormatAnalyser(AudioProcessor):
 
     implements(IAnalyzer)
 
-    def id(self):
+    @staticmethod
+    def id():
         return "format"
 
     def name(self):
index 8768d7632304127c7a0ed622e78a0f23aa7673fc..95c2303ea299f5c537a643566ad2ca61390887f9 100644 (file)
@@ -28,8 +28,9 @@ class MaxLevelAnalyzer(AudioProcessor):
 
     implements(IAnalyzer)
 
-    def id(self):
-        return "max_level"
+    @staticmethod
+    def id():
+        return "maxlevel"
 
     def name(self):
         return "Maximum peak level"
@@ -40,4 +41,4 @@ class MaxLevelAnalyzer(AudioProcessor):
     def render(self, media_item, options=None):
         self.pre_process(media_item)
         samples = self.get_samples()
-        return numpy.round(20*numpy.log10(numpy.max(samples)),2)
\ No newline at end of file
+        return numpy.round(20*numpy.log10(numpy.max(samples)),2)
index 3443c9ae3058201684d186cdfef46828b9b2272c..ae9424d957371fdb90892084f47603db62697757 100644 (file)
@@ -28,8 +28,9 @@ class MeanLevelAnalyser(AudioProcessor):
 
     implements(IAnalyzer)
 
-    def id(self):
-        return "mean_level"
+    @staticmethod
+    def id():
+        return "meanlevel"
 
     def name(self):
         return "Mean RMS level"
index 60a17a04b1dd902197aa4ec4a1d6a8bca71740fc..b13820501e5b62688fa9ca7c5fa404e84065935a 100644 (file)
@@ -28,7 +28,8 @@ class ResolutionAnalyser(AudioProcessor):
 
     implements(IAnalyzer)
 
-    def id(self):
+    @staticmethod
+    def id():
         return "resolution"
 
     def name(self):
@@ -48,4 +49,4 @@ class ResolutionAnalyser(AudioProcessor):
         if '32' in self.encoding:
             return 32
         else:
-            return ''
\ No newline at end of file
+            return ''
index 638e9f8b24caa47a9e522f7566766859b1f0f302..8093537edf1f3de0fe4789fc7c14249eea5a436d 100644 (file)
@@ -28,7 +28,8 @@ class SampleRateAnalyzer(AudioProcessor):
 
     implements(IAnalyzer)
 
-    def id(self):
+    @staticmethod
+    def id():
         return "samplerate"
 
     def name(self):
diff --git a/api.py b/api.py
index e2f62b9d0a6811a7bfa936d816ed19da4fdb5fab..48a7cf5c9613a07d9c01e0d978fe23b148fa0b48 100644 (file)
--- a/api.py
+++ b/api.py
 from timeside.component import Interface
 
 class IProcessor(Interface):
-    pass
+
+    @staticmethod
+    def id():
+        """Return a short alphanumeric, lower-case string which uniquely
+        identify this processor. Only letters and digits are allowed.
+        An exception will be raised by MetaProcessor if the id is malformed or
+        not unique amongst registered processors.
+        
+        Typically this identifier is likely to be used during HTTP requests
+        and be passed as a GET parameter. Thus it should be as short as possible."""
 
diff --git a/core.py b/core.py
index 94e636c6ac7011a4526592b5035f506a09327943..c797db401d05646058a230343d0a2b582ff9bf0e 100644 (file)
--- a/core.py
+++ b/core.py
@@ -19,6 +19,7 @@
 
 from timeside.component import *
 from timeside.api import IProcessor
+import re
 
 __all__ = ['Processor', 'Component', 'implements', 'processors', 'TimeSideError']
 
@@ -26,15 +27,28 @@ class TimeSideError(Exception):
     """Exception base class for errors in TimeSide."""
     # FIXME: is this redundant with Django's error handling ?
 
-_processors = []
+_processors = {}
 
 class MetaProcessor(MetaComponent):
-    """Metaclass of the Processor class, used mainly for ensuring uniqueness of 
-    processor id's"""
+    """Metaclass of the Processor class, used mainly for ensuring that processor
+    id's are wellformed and unique"""
+
+    valid_id = re.compile("^[a-z][a-z0-9]*$")
+
     def __new__(cls, name, bases, d):
         new_class = MetaComponent.__new__(cls, name, bases, d)
-        id = "fixme"
-        _processors.append((id, new_class))
+        if new_class in implementations(IProcessor):
+            id = str(new_class.id())
+            if _processors.has_key(id):
+                raise TimeSideError("%s and %s have the same id: '%s'"
+                    % (new_class.__name__, _processors[id].__name__, id))
+            if not MetaProcessor.valid_id.match(id):
+                raise TimeSideError("%s has a malformed id: '%s'"
+                    % (new_class.__name__, id))
+                
+
+            _processors[id] = new_class
+
         return new_class
 
 class Processor(Component):
index abbe37c3f1b41b9a3d683c72678d6ac57736e989..c7a5afebb765924da41191d750e1af4438a4ea37 100644 (file)
@@ -55,7 +55,7 @@ class SubProcessPipe:
         self.output = self.proc.stdout
 
 
-class DecoderCore(Component):
+class DecoderCore(Processor):
     """Defines the main parts of the decoding tools :
     paths, metadata parsing, data streaming thru system command"""
 
index 44733d747707f27f389c4ec25739606c2214d82d..b9b02c2afa67ac7a4cf5860f1753a17095fde7db 100644 (file)
@@ -33,6 +33,10 @@ class FlacDecoder(DecoderCore):
 
     implements(IDecoder)
 
+    @staticmethod
+    def id():
+        return "flacdec"
+    
     def format(self):
         return 'FLAC'
 
index 8f1f1e51e0f1c35049dc74ee6fba5a274ae116bd..dc2c968ae4c3e831d89e860c2dc1d1603ed4103c 100644 (file)
@@ -36,6 +36,10 @@ class Mp3Decoder(DecoderCore):
     def __init__(self):
         self.command = 'sox -t mp3 "%s" -q -b 16 -r 44100 -t wav -c2 - '
 
+    @staticmethod
+    def id():
+        return "mp3dec"
+    
     def format(self):
         return 'MP3'
 
index 280b3c73cdca1e2149243bd79dc81f7f23fd9ab3..3e22af0fd46fee391197a601388ca51c2d5c1c96 100644 (file)
@@ -32,6 +32,10 @@ class OggDecoder(DecoderCore):
 
     implements(IDecoder)
 
+    @staticmethod
+    def id():
+        return "oggdec"
+    
     def format(self):
         return 'OggVorbis'
 
index 8012f2826215380a4d001b9dbad1acf4394144e0..be23402dd0bc75d7d2b6f1c49e3806ff92ce159b 100644 (file)
@@ -31,6 +31,10 @@ class WavDecoder(DecoderCore):
 
     implements(IDecoder)
 
+    @staticmethod
+    def id():
+        return "wavdec"
+    
     def format(self):
         return 'WAV'
 
index 8312e900d4f00771af1a3c40026ca3f1cae02ceb..3f43dbe9a84e0201dc586def8ca53fa4d8aa8eb9 100644 (file)
@@ -38,6 +38,10 @@ class FlacEncoder(EncoderCore):
                              'relation': 'album'
                              }
 
+    @staticmethod
+    def id():
+        return "flacenc"
+    
     def format(self):
         return 'FLAC'
 
index e38f5b87bba067ad4f7a88744457d4ed27779c03..51fdf87d5396310746c2acab57dadd85e624a7df 100644 (file)
@@ -51,6 +51,11 @@ class Mp3Encoder(EncoderCore):
                              'publisher': 'tc', #comment
                              'date': 'ty', #year
                              }
+
+    @staticmethod
+    def id():
+        return "mp3enc"
+    
     def format(self):
         return 'MP3'
 
index 84dd8c7d25cc6dfb710d88f5d2cd33b71bb1a2de..ef1986301a2ac4673016eef207cc59c76fbf7fac 100644 (file)
@@ -37,6 +37,10 @@ class OggVorbisEncoder(EncoderCore):
                              'relation': 'album'
                              }
 
+    @staticmethod
+    def id():
+        return "oggenc"
+
     def format(self):
         return 'OggVorbis'
 
index f1b8017e89ace8a7cd8ef46a5674014f7830dbea..54b8199ca0c8643361d29a1ed86126dbf2e4f3cc 100644 (file)
@@ -33,6 +33,10 @@ class WavEncoder(EncoderCore):
     def __init__(self):
         pass
 
+    @staticmethod
+    def id():
+        return "wavenc"
+
     def format(self):
         return 'WAV'
 
index af1ed7a1c408cf858e491d8595c70e679b361f5f..fa1e941b9a064d7115064986b46ac8af348b4495 100644 (file)
@@ -25,10 +25,6 @@ from timeside.api import IProcessor
 class IGrapher(IProcessor):
     """Media item visualizer driver interface"""
 
-    @staticmethod
-    def id():
-        """Return a short id alphanumeric, lower-case string."""
-
     @staticmethod
     def name():
         """Return the graph name, such as "Waveform", "Spectral view",
index dc14fe1f23a1325700a7e9d0889ae9973b676686..b731fa6d7ccac740cbd2f1345772053071fccfd4 100644 (file)
@@ -32,8 +32,10 @@ class SpectrogramGrapherAudiolab(Processor):
     bg_color = None
     color_scheme = None
 
-    def id(self):
-        return "spectrogram_audiolab"
+    @staticmethod
+    def id():
+        #FIXME: too long + underscore discouraged
+        return "spectrogram"
 
     def name(self):
         return "Spectrogram (audiolab)"
index 4aeefc39934731a0dc95c60517b28e042fb1b1c5..62de0302b18d38853287989465cb54ecbe1faf81 100644 (file)
@@ -32,8 +32,10 @@ class WaveFormGrapherAudiolab(Processor):
     bg_color = None
     color_scheme = None
 
-    def id(self):
-        return "waveform_audiolab"
+    @staticmethod
+    def id():
+        #FIXME: too long + underscore discouraged
+        return "waveform"
 
     def name(self):
         return "Waveform (audiolab)"
index bf12c42c82445a741a0d5df8006cbacacbd66e48..840c087d8c2669e6758f33b54806b78a8f45d4b5 100644 (file)
@@ -7,6 +7,6 @@ def list_processors(interface, prefix=""):
         list_processors(i, prefix + "  ")
     processors = timeside.processors(interface, False)
     for p in processors:
-        print prefix + "  " + p.__name__
+        print prefix + "  %s [%s]" % (p.__name__, p.id())
 
 list_processors(timeside.api.IProcessor)