]> git.parisson.com Git - timeside.git/commitdiff
change processor module title, remove obsolete processors, cleanup
authoryomguy <yomguy@parisson.com>
Thu, 1 Apr 2010 21:04:31 +0000 (21:04 +0000)
committeryomguy <yomguy@parisson.com>
Thu, 1 Apr 2010 21:04:31 +0000 (21:04 +0000)
44 files changed:
__init__.py
analyze/__init__.py [deleted file]
analyze/channels.py [deleted file]
analyze/core.py [deleted file]
analyze/dc.py [deleted file]
analyze/duration.py [deleted file]
analyze/encoding.py [deleted file]
analyze/format.py [deleted file]
analyze/max_level.py [deleted file]
analyze/mean_level.py [deleted file]
analyze/resolution.py [deleted file]
analyze/samplerate.py [deleted file]
analyze/vamp/__init__.py [deleted file]
analyze/vamp/core.py [deleted file]
analyzer/__init__.py [new file with mode: 0644]
analyzer/core.py [new file with mode: 0644]
analyzer/dc.py [new file with mode: 0644]
analyzer/duration.py [new file with mode: 0644]
analyzer/max_level.py [new file with mode: 0644]
analyzer/mean_level.py [new file with mode: 0644]
analyzer/vamp/__init__.py [new file with mode: 0644]
analyzer/vamp/core.py [new file with mode: 0644]
decode/__init__.py [deleted file]
decode/core.py [deleted file]
decode/flac.py [deleted file]
decode/mp3.py [deleted file]
decode/ogg.py [deleted file]
decode/wav.py [deleted file]
decoder/__init__.py [new file with mode: 0644]
decoder/core.py [new file with mode: 0644]
encode/__init__.py [deleted file]
encode/core.py [deleted file]
encode/flac.py [deleted file]
encode/mp3.py [deleted file]
encode/ogg.py [deleted file]
encode/wav.py [deleted file]
encoder/__init__.py [new file with mode: 0644]
encoder/core.py [new file with mode: 0644]
encoder/flac.py [new file with mode: 0644]
encoder/mp3.py [new file with mode: 0644]
encoder/ogg.py [new file with mode: 0644]
encoder/wav.py [new file with mode: 0644]
grapher/core.py
tests/test.py

index f0212039040ec3521cec18db66911141b9ddf039..81ad004632f0385b7a38c9208e184562fe18de9a 100644 (file)
@@ -2,7 +2,7 @@
 
 from core import *
 from metadata import Metadata
-import decode
-import encode
-import analyze
+import decoder
+import encoder
+import analyzer
 import grapher
diff --git a/analyze/__init__.py b/analyze/__init__.py
deleted file mode 100644 (file)
index 307016e..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- coding: utf-8 -*-
-from timeside.analyze.core import *
-from timeside.analyze.channels import *
-from timeside.analyze.format import *
-from timeside.analyze.encoding import *
-from timeside.analyze.resolution import *
-from timeside.analyze.samplerate import *
-from timeside.analyze.duration import *
-from timeside.analyze.max_level import *
-from timeside.analyze.mean_level import *
-from timeside.analyze.dc import *
-
-
diff --git a/analyze/channels.py b/analyze/channels.py
deleted file mode 100644 (file)
index 6ad202d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from timeside.analyze.core import *
-from timeside.api import IAnalyzer
-import numpy
-
-class ChannelAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IAnalyzer)
-
-    @staticmethod
-    def id():
-        return "nchannels"
-
-    def name(self):
-        return "Channels"
-
-    def unit(self):
-        return ""
-
-    def render(self, media_item, options=None):
-        self.pre_process(media_item)
-        if self.channels == 1:
-            return 'mono'
-        if self.channels == 2:
-            return 'stereo'
-        else:
-            return self.channels
diff --git a/analyze/core.py b/analyze/core.py
deleted file mode 100644 (file)
index c2371d2..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Authors:
-#   Bram de Jong <bram.dejong at domain.com where domain in gmail>
-#   Guillaume Pellerin <yomguy at parisson.com>
-
-from timeside.core import *
-import optparse, math, sys
-import numpy
-import scikits.audiolab as audiolab
-
-# FIXME: AudioProcessor: wrong name, should be Analyzer or AnalyzerCore
-class AudioProcessor(Processor):
-
-    def __init__(self):
-        self.fft_size = 2048
-        self.window_function = numpy.ones
-        self.window = self.window_function(self.fft_size)
-        self.spectrum_range = None
-        self.lower = 100
-        self.higher = 22050
-        self.lower_log = math.log10(self.lower)
-        self.higher_log = math.log10(self.higher)
-        self.clip = lambda val, low, high: min(high, max(low, val))
-
-    def pre_process(self, media_item):
-        wav_file = media_item
-        self.audio_file = audiolab.sndfile(wav_file, 'read')
-        self.frames = self.audio_file.get_nframes()
-        self.samplerate = self.audio_file.get_samplerate()
-        self.channels = self.audio_file.get_channels()
-        self.format = self.audio_file.get_file_format()
-        self.encoding = self.audio_file.get_encoding()
-
-    def get_samples(self):
-        samples = self.audio_file.read_frames(self.frames)
-        return samples
-
-    def get_mono_samples(self):
-        # convert to mono by selecting left channel only
-        samples = self.get_samples()
-        if self.channels > 1:
-            return samples[:,0]
-        else:
-            return samples
-
-    def read(self, start, size, resize_if_less=False):
-        """ read size samples starting at start, if resize_if_less is True and less than size
-        samples are read, resize the array to size and fill with zeros """
-
-        # number of zeros to add to start and end of the buffer
-        add_to_start = 0
-        add_to_end = 0
-
-        if start < 0:
-            # the first FFT window starts centered around zero
-            if size + start <= 0:
-                if resize_if_less:
-                    return numpy.zeros(size)
-                else:
-                    return numpy.array([])
-            else:
-                self.audio_file.seek(0)
-
-                add_to_start = -start # remember: start is negative!
-                to_read = size + start
-
-                if to_read > self.frames:
-                    add_to_end = to_read - self.frames
-                    to_read = self.frames
-        else:
-            self.audio_file.seek(start)
-
-            to_read = size
-            if start + to_read >= self.frames:
-                to_read = self.frames - start
-                add_to_end = size - to_read
-
-        try:
-            samples = self.audio_file.read_frames(to_read)
-        except IOError:
-            # this can happen for wave files with broken headers...
-            if resize_if_less:
-                return numpy.zeros(size)
-            else:
-                return numpy.zeros(2)
-
-        # convert to mono by selecting left channel only
-        if self.channels > 1:
-            samples = samples[:,0]
-
-        if resize_if_less and (add_to_start > 0 or add_to_end > 0):
-            if add_to_start > 0:
-                samples = numpy.concatenate((numpy.zeros(add_to_start), samples), axis=1)
-
-            if add_to_end > 0:
-                samples = numpy.resize(samples, size)
-                samples[size - add_to_end:] = 0
-
-        return samples
-
-
-    def spectral_centroid(self, seek_point, spec_range=120.0):
-        """ starting at seek_point read fft_size samples, and calculate the spectral centroid """
-
-        samples = self.read(seek_point - self.fft_size/2, self.fft_size, True)
-
-        samples *= self.window
-        fft = numpy.fft.fft(samples)
-        spectrum = numpy.abs(fft[:fft.shape[0] / 2 + 1]) / float(self.fft_size) # normalized abs(FFT) between 0 and 1
-        length = numpy.float64(spectrum.shape[0])
-
-        # scale the db spectrum from [- spec_range db ... 0 db] > [0..1]
-        db_spectrum = ((20*(numpy.log10(spectrum + 1e-30))).clip(-spec_range, 0.0) + spec_range)/spec_range
-
-        energy = spectrum.sum()
-        spectral_centroid = 0
-
-        if energy > 1e-20:
-            # calculate the spectral centroid
-
-            if self.spectrum_range == None:
-                self.spectrum_range = numpy.arange(length)
-
-            spectral_centroid = (spectrum * self.spectrum_range).sum() / (energy * (length - 1)) * self.samplerate * 0.5
-
-            # clip > log10 > scale between 0 and 1
-            spectral_centroid = (math.log10(self.clip(spectral_centroid, self.lower, self.higher)) - self.lower_log) / (self.higher_log - self.lower_log)
-
-        return (spectral_centroid, db_spectrum)
-
-
-    def peaks(self, start_seek, end_seek):
-        """ read all samples between start_seek and end_seek, then find the minimum and maximum peak
-        in that range. Returns that pair in the order they were found. So if min was found first,
-        it returns (min, max) else the other way around. """
-
-        # larger blocksizes are faster but take more mem...
-        # Aha, Watson, a clue, a tradeof!
-        block_size = 4096
-
-        max_index = -1
-        max_value = -1
-        min_index = -1
-        min_value = 1
-
-        if end_seek > self.frames:
-            end_seek = self.frames
-
-        if block_size > end_seek - start_seek:
-            block_size = end_seek - start_seek
-
-        if block_size <= 1:
-            samples = self.read(start_seek, 1)
-            return samples[0], samples[0]
-        elif block_size == 2:
-            samples = self.read(start_seek, True)
-            return samples[0], samples[1]
-
-        for i in range(start_seek, end_seek, block_size):
-            samples = self.read(i, block_size)
-
-            local_max_index = numpy.argmax(samples)
-            local_max_value = samples[local_max_index]
-
-            if local_max_value > max_value:
-                max_value = local_max_value
-                max_index = local_max_index
-
-            local_min_index = numpy.argmin(samples)
-            local_min_value = samples[local_min_index]
-
-            if local_min_value < min_value:
-                min_value = local_min_value
-                min_index = local_min_index
-
-        if min_index < max_index:
-            return (min_value, max_value)
-        else:
-            return (max_value, min_value)
-
-
-
diff --git a/analyze/dc.py b/analyze/dc.py
deleted file mode 100644 (file)
index ac31e6f..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from timeside.analyze.core import *
-from timeside.api import IValueAnalyzer
-import numpy
-
-class MeanDCShiftAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IValueAnalyzer)
-
-    @staticmethod
-    def id():
-        return "dc"
-
-    def name(self):
-        return "Mean DC shift"
-
-    def unit(self):
-        return "%"
-
-    def render(self, media_item, options=None):
-        self.pre_process(media_item)
-        samples = self.get_mono_samples()
-        return numpy.round(100*numpy.mean(samples),4)
diff --git a/analyze/duration.py b/analyze/duration.py
deleted file mode 100644 (file)
index 64546d0..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from timeside.analyze.core import *
-from timeside.api import IAnalyzer
-import numpy
-import datetime
-
-class DurationAnalyzer(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IAnalyzer)
-
-    @staticmethod
-    def id():
-        return "duration"
-
-    def name(self):
-        return "Duration"
-
-    def unit(self):
-        return "h:m:s"
-
-    def render(self, media_item, options=None):
-        self.pre_process(media_item)
-        media_time = numpy.round(float(self.frames)/float(self.samplerate),0)
-        return datetime.timedelta(0,media_time)
diff --git a/analyze/encoding.py b/analyze/encoding.py
deleted file mode 100644 (file)
index 0448f47..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from timeside.analyze.core import *
-from timeside.api import IAnalyzer
-import numpy
-
-class EncodingAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IAnalyzer)
-
-    @staticmethod
-    def id():
-        return "encoding"
-
-    def name(self):
-        return "Encoding format"
-
-    def unit(self):
-        return ""
-
-    def render(self, media_item, options=None):
-        self.pre_process(media_item)
-        return self.encoding
diff --git a/analyze/format.py b/analyze/format.py
deleted file mode 100644 (file)
index 2c7fdf3..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from timeside.analyze.core import *
-from timeside.api import IAnalyzer
-import numpy
-
-class FormatAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IAnalyzer)
-
-    @staticmethod
-    def id():
-        return "format"
-
-    def name(self):
-        return "File format"
-
-    def unit(self):
-        return ""
-
-    def render(self, media_item, options=None):
-        self.pre_process(media_item)
-        return self.format
diff --git a/analyze/max_level.py b/analyze/max_level.py
deleted file mode 100644 (file)
index af6c4a0..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from timeside.analyze.core import *
-from timeside.api import IValueAnalyzer
-import numpy
-
-class MaxLevelAnalyzer(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IValueAnalyzer)
-
-    @staticmethod
-    def id():
-        return "max_level"
-
-    @staticmethod
-    def name():
-        return "Maximum peak level"
-
-    def unit(self):
-        return "dB"
-
-    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)
diff --git a/analyze/mean_level.py b/analyze/mean_level.py
deleted file mode 100644 (file)
index 0ab38ff..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from timeside.analyze.core import *
-from timeside.api import IValueAnalyzer
-import numpy
-
-class MeanLevelAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IValueAnalyzer)
-
-    @staticmethod
-    def id():
-        return "meanlevel"
-
-    def name(self):
-        return "Mean RMS level"
-
-    def unit(self):
-        return "dB"
-
-    def render(self, media_item, options=None):
-        self.pre_process(media_item)
-        samples = self.get_mono_samples()
-        return numpy.round(20*numpy.log10(numpy.mean(numpy.sqrt(numpy.square(samples)))),2)
diff --git a/analyze/resolution.py b/analyze/resolution.py
deleted file mode 100644 (file)
index 6040fec..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from timeside.analyze.core import *
-from timeside.api import IAnalyzer
-import numpy
-
-class ResolutionAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IAnalyzer)
-
-    @staticmethod
-    def id():
-        return "resolution"
-
-    def name(self):
-        return "Resolution"
-
-    def unit(self):
-        return "bits"
-
-    def render(self, media_item, options=None):
-        self.pre_process(media_item)
-        if '8' in self.encoding:
-            return 8
-        if '16' in self.encoding:
-            return 16
-        if '24' in self.encoding:
-            return 24
-        if '32' in self.encoding:
-            return 32
-        else:
-            return ''
diff --git a/analyze/samplerate.py b/analyze/samplerate.py
deleted file mode 100644 (file)
index d235ebd..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from timeside.analyze.core import *
-from timeside.api import IAnalyzer
-import numpy
-
-class SampleRateAnalyzer(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IAnalyzer)
-
-    @staticmethod
-    def id():
-        return "samplerate"
-
-    def name(self):
-        return "Samplerate"
-
-    def unit(self):
-        return "Hz"
-
-    def render(self, media_item, options=None):
-        self.pre_process(media_item)
-        return self.samplerate
diff --git a/analyze/vamp/__init__.py b/analyze/vamp/__init__.py
deleted file mode 100644 (file)
index d889d34..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from timeside.analyze.vamp.core import *
diff --git a/analyze/vamp/core.py b/analyze/vamp/core.py
deleted file mode 100644 (file)
index 6248508..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from timeside.core import *
-from tempfile import NamedTemporaryFile
-from timeside.exceptions import SubProcessError
-import os
-import random
-import subprocess
-import signal
-import time
-
-class VampCoreAnalyzer:
-    """Parent class for Vamp plugin drivers"""
-
-    def __init__(self):
-        self.vamp_path = '/usr/lib/vamp/'
-        # needs vamp-examples package
-        self.host = 'vamp-simple-host'
-        self.buffer_size = 0xFFFF
-               
-    def id(self):
-        return "vamp_plugins"
-
-    def name(self):
-        return "Vamp plugins"
-
-    def unit(self):
-        return ""
-
-    def get_plugins_list(self):
-        if os.path.exists(self.vamp_path):
-            args = ' --list-outputs'
-            command = self.host + args
-            #tmp_file = NamedTemporaryFile()
-            data = self.core_process(command, self.buffer_size)
-            text = ''
-            plugins = []
-            for chunk in data:
-                text = text + chunk
-            lines = text.split('\n')
-            for line in lines:
-                if line != '':
-                    struct = line.split(':')
-                    struct = struct[1:]
-                    plugins.append(struct)
-            return plugins
-        else:
-            return []
-
-    def get_wav_path(self, media_item):
-        return settings.MEDIA_ROOT + '/' + media_item.file
-        #return media_item
-        
-    def render(self, plugin, media_item):
-        self.wavFile = self.get_wav_path(media_item)
-        args = ' -s ' + ':'.join(plugin) + ' ' + str(self.wavFile)
-        command = command = self.host + args
-        data = self.core_process(command, self.buffer_size)
-        string = ''
-        values = {}
-        for chunk in data:
-            string = string + chunk
-        lines = string.split('\n')
-        for line in lines:
-            if line != '':
-                struct = line.split(':')
-                values[struct[0]] = struct[1]
-        return values
-
-    def core_process(self, command, buffer_size):
-        """Encode and stream audio data through a generator"""
-        
-        __chunk = 0
-
-        try:
-            proc = subprocess.Popen(command,
-                    shell = True,
-                    bufsize = buffer_size,
-                    stdin = subprocess.PIPE,
-                    stdout = subprocess.PIPE,
-                    close_fds = True)
-        except:
-            raise SubProcessError('Command failure:', command, proc)
-            
-        # Core processing
-        while True:
-            __chunk = proc.stdout.read(buffer_size)
-            status = proc.poll()
-            if status != None and status != 0:
-                raise SubProcessError('Command failure:', command, proc)
-            if len(__chunk) == 0:
-                break
-            yield __chunk
-        
-
diff --git a/analyzer/__init__.py b/analyzer/__init__.py
new file mode 100644 (file)
index 0000000..f0af279
--- /dev/null
@@ -0,0 +1,6 @@
+# -*- coding: utf-8 -*-
+from timeside.analyzer.core import *
+from timeside.analyzer.duration import *
+from timeside.analyzer.max_level import *
+from timeside.analyzer.mean_level import *
+from timeside.analyzer.dc import *
diff --git a/analyzer/core.py b/analyzer/core.py
new file mode 100644 (file)
index 0000000..17cbfa1
--- /dev/null
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Authors:
+#   Guillaume Pellerin <yomguy at parisson.com>
+
+from timeside.core import *
+from timeside.grapher.core import *
+import numpy
+
diff --git a/analyzer/dc.py b/analyzer/dc.py
new file mode 100644 (file)
index 0000000..e92cfd5
--- /dev/null
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+from timeside.analyzer.core import *
+from timeside.api import IValueAnalyzer
+import numpy
+
+
+class MeanDCShift(Processor):
+    implements(IValueAnalyzer)
+
+    @interfacedoc
+    def setup(self, channels=None, samplerate=None, nframes=None):
+        super(MeanDCShift, self).setup(channels, samplerate, nframes)
+        self.value = 0
+
+    @staticmethod
+    @interfacedoc
+    def id():
+        return "dc"
+
+    @staticmethod
+    @interfacedoc
+    def name():
+        return "Mean DC shift"
+
+    @staticmethod
+    @interfacedoc
+    def unit():
+        return "%"
+
+    def __str__(self):
+        return "%s %s" % (str(self.value), unit())
+
+    def process(self, frames, eod=False):
+        self.value = numpy.round(100*numpy.mean(samples),4)
+        return frames, eod
+
+    def result(self):
+        return self.value
+
diff --git a/analyzer/duration.py b/analyzer/duration.py
new file mode 100644 (file)
index 0000000..456a527
--- /dev/null
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+from timeside.analyzer.core import *
+from timeside.api import IValueAnalyzer
+import datetime
+
+
+class Duration(Processor):
+    implements(IValueAnalyzer)
+
+    @interfacedoc
+    def setup(self, channels=None, samplerate=None, nframes=None):
+        super(Duration, self).setup(channels, samplerate, nframes)
+        self.value = 0
+
+    @staticmethod
+    @interfacedoc
+    def id():
+        return "duration"
+
+    @staticmethod
+    @interfacedoc
+    def name():
+        return "Duration"
+
+    @staticmethod
+    @interfacedoc
+    def unit():
+        return "h:m:s"
+
+    def __str__(self):
+        return "%s %s" % (str(self.value), unit())
+
+    def process(self, frames, eod=False):
+        return frames, eod
+
+    def result(self):
+        return datetime.timedelta(0,numpy.round(self.nframes / float(self.samplerate), 0))
+
diff --git a/analyzer/max_level.py b/analyzer/max_level.py
new file mode 100644 (file)
index 0000000..93ff3ec
--- /dev/null
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
+# Copyright (c) 2009 Olivier Guilyardi <olivier@samalyse.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+from timeside.analyzer.core import *
+from timeside.api import IValueAnalyzer
+import numpy
+
+
+class MaxLevel(Processor):
+    implements(IValueAnalyzer)
+
+    @interfacedoc
+    def setup(self, channels=None, samplerate=None, nframes=None):
+        super(MaxLevel, self).setup(channels, samplerate, nframes)
+        self.value = -140
+
+    @staticmethod
+    @interfacedoc
+    def id():
+        return "maxlevel"
+
+    @staticmethod
+    @interfacedoc
+    def name():
+        return "Max level"
+
+    @staticmethod
+    @interfacedoc
+    def unit():
+        return "dB"
+
+    def __str__(self):
+        return "%s %s" % (str(self.value), unit())
+
+    def process(self, frames, eod=False):
+        max = numpy.round(20*numpy.log10(frames.max()), 2)
+        if max > self.value:
+            self.value = max
+
+        return frames, eod
+
+    def result(self):
+        return self.value
+
diff --git a/analyzer/mean_level.py b/analyzer/mean_level.py
new file mode 100644 (file)
index 0000000..8b68324
--- /dev/null
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+from timeside.analyzer.core import *
+from timeside.api import IValueAnalyzer
+import numpy
+
+
+class MeanLevel(Processor):
+    implements(IValueAnalyzer)
+
+    @interfacedoc
+    def setup(self, channels=None, samplerate=None, nframes=None):
+        super(MeanLevel, self).setup(channels, samplerate, nframes)
+        self.value = -140
+
+    @staticmethod
+    @interfacedoc
+    def id():
+        return "meanlevel"
+
+    @staticmethod
+    @interfacedoc
+    def name():
+        return "Mean RMS level"
+
+    @staticmethod
+    @interfacedoc
+    def unit():
+        return "dB"
+
+    def __str__(self):
+        return "%s %s" % (str(self.value), unit())
+
+    def process(self, frames, eod=False):
+        max = numpy.round(20*numpy.log10(numpy.mean(numpy.sqrt(numpy.square(frames.max())))), 2)
+        if max > self.value:
+            self.value = max
+
+        return frames, eod
+
+    def result(self):
+        return self.value
+
diff --git a/analyzer/vamp/__init__.py b/analyzer/vamp/__init__.py
new file mode 100644 (file)
index 0000000..1ded83d
--- /dev/null
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+from timeside.analyzer.vamp.core import *
diff --git a/analyzer/vamp/core.py b/analyzer/vamp/core.py
new file mode 100644 (file)
index 0000000..49ae9a0
--- /dev/null
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+from timeside.core import *
+from tempfile import NamedTemporaryFile
+from timeside.exceptions import SubProcessError
+import os
+import random
+import subprocess
+import signal
+import time
+
+class VampCoreAnalyzer:
+    """Parent class for Vamp plugin drivers"""
+
+    def __init__(self):
+        self.vamp_path = '/usr/lib/vamp/'
+        # needs vamp-examples package
+        self.host = 'vamp-simple-host'
+        self.buffer_size = 0xFFFF
+
+    def id(self):
+        return "vamp_plugins"
+
+    def name(self):
+        return "Vamp plugins"
+
+    def unit(self):
+        return ""
+
+    def get_plugins_list(self):
+        if os.path.exists(self.vamp_path):
+            args = ' --list-outputs'
+            command = self.host + args
+            #tmp_file = NamedTemporaryFile()
+            data = self.core_process(command, self.buffer_size)
+            text = ''
+            plugins = []
+            for chunk in data:
+                text = text + chunk
+            lines = text.split('\n')
+            for line in lines:
+                if line != '':
+                    struct = line.split(':')
+                    struct = struct[1:]
+                    plugins.append(struct)
+            return plugins
+        else:
+            return []
+
+    def get_wav_path(self, media_item):
+        return settings.MEDIA_ROOT + '/' + media_item.file
+        #return media_item
+
+    def render(self, plugin, media_item):
+        self.wavFile = self.get_wav_path(media_item)
+        args = ' -s ' + ':'.join(plugin) + ' ' + str(self.wavFile)
+        command = command = self.host + args
+        data = self.core_process(command, self.buffer_size)
+        string = ''
+        values = {}
+        for chunk in data:
+            string = string + chunk
+        lines = string.split('\n')
+        for line in lines:
+            if line != '':
+                struct = line.split(':')
+                values[struct[0]] = struct[1]
+        return values
+
+    def core_process(self, command, buffer_size):
+        """Encode and stream audio data through a generator"""
+
+        __chunk = 0
+
+        try:
+            proc = subprocess.Popen(command,
+                    shell = True,
+                    bufsize = buffer_size,
+                    stdin = subprocess.PIPE,
+                    stdout = subprocess.PIPE,
+                    close_fds = True)
+        except:
+            raise SubProcessError('Command failure:', command, proc)
+
+        # Core processing
+        while True:
+            __chunk = proc.stdout.read(buffer_size)
+            status = proc.poll()
+            if status != None and status != 0:
+                raise SubProcessError('Command failure:', command, proc)
+            if len(__chunk) == 0:
+                break
+            yield __chunk
+
+
diff --git a/decode/__init__.py b/decode/__init__.py
deleted file mode 100644 (file)
index d04cfce..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from timeside.decode.core import *
-from timeside.decode.ogg import *
-from timeside.decode.flac import *
-from timeside.decode.wav import *
-from timeside.decode.mp3 import *
diff --git a/decode/core.py b/decode/core.py
deleted file mode 100644 (file)
index b3c5b15..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from timeside.decode import *
-from timeside.core import *
-import subprocess
-
-class SubProcessPipe:
-
-    def __init__(self, command, stdin=None):
-        """Read media and stream data through a generator.
-        Taken from Telemeta (see http://telemeta.org)"""
-
-        self.buffer_size = 0xFFFF
-
-        if not stdin:
-            stdin =  subprocess.PIPE
-
-        self.proc = subprocess.Popen(command.encode('utf-8'),
-                    shell = True,
-                    bufsize = self.buffer_size,
-                    stdin = stdin,
-                    stdout = subprocess.PIPE,
-                    close_fds = True)
-
-        self.input = self.proc.stdin
-        self.output = self.proc.stdout
-
-
-class DecoderCore(Processor):
-    """Defines the main parts of the decoding tools :
-    paths, metadata parsing, data streaming thru system command"""
-
-    def __init__(self):
-        self.command = 'ffmpeg -i "%s" -f wav - '
-
-    def process(self, source, options=None):
-        """Encode and stream audio data through a generator"""
-
-        command = self.command % source
-        proc = SubProcessPipe(command)
-        return proc.output
-
-        #while True:
-            #__chunk = proc.output.read(self.proc.buffer_size)
-            #status = proc.poll()
-            #if status != None and status != 0:
-                #raise ExportProcessError('Command failure:', command, proc)
-            #if len(__chunk) == 0:
-                #break
-            #yield __chunk
-
-
-
diff --git a/decode/flac.py b/decode/flac.py
deleted file mode 100644 (file)
index 5289713..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-import os
-import string
-import subprocess
-
-from timeside.decode.core import *
-from timeside.api import IDecoder
-from mutagen.flac import FLAC
-from tempfile import NamedTemporaryFile
-
-class FlacDecoder(DecoderCore):
-    """Defines methods to decode from FLAC"""
-
-    implements(IDecoder)
-
-    @staticmethod
-    def id():
-        return "flacdec"
-    
-    def format(self):
-        return 'FLAC'
-
-    def file_extension(self):
-        return 'flac'
-
-    def mime_type(self):
-        return 'audio/x-flac'
-
-    def description(self):
-        return """
-        Free Lossless Audio Codec (FLAC) is a file format for lossless audio
-        data compression. During compression, FLAC does not lose quality from
-        the audio stream, as lossy compression formats such as MP3, AAC, and
-        Vorbis do. Josh Coalson is the primary author of FLAC.
-        (source Wikipedia)
-        """
-
-    def get_file_info(self):
-        try:
-            file1, file2 = os.popen4('metaflac --list "'+self.dest+'"')
-            info = []
-            for line in file2.readlines():
-                info.append(clean_word(line[:-1]))
-            self.info = info
-            return self.info
-        except:
-            raise IOError('DecoderError: metaflac is not installed or ' + \
-                           'file does not exist.')
-
diff --git a/decode/mp3.py b/decode/mp3.py
deleted file mode 100644 (file)
index f4f1973..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2007 Parisson SARL
-# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-import os
-import string
-import subprocess
-
-from timeside.decode.core import *
-from timeside.api import IDecoder
-
-
-class Mp3Decoder(DecoderCore):
-    """Defines methods to decode from MP3"""
-
-    implements(IDecoder)
-
-    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'
-
-    def file_extension(self):
-        return 'mp3'
-
-    def mime_type(self):
-        return 'audio/mpeg'
-
-    def description(self):
-        return """
-        MPEG-1 Audio Layer 3, more commonly referred to as MP3, is a patented
-        digital audio encoding format using a form of lossy data compression.
-        It is a common audio format for consumer audio storage, as well as a
-        de facto standard of digital audio compression for the transfer and
-        playback of music on digital audio players. MP3 is an audio-specific
-        format that was designed by the Moving Picture Experts Group as part
-        of its MPEG-1 standard. (source Wikipedia)
-        """
-
-    def get_file_info(self):
-        try:
-            file_out1, file_out2 = os.popen4('mp3info "'+self.dest+'"')
-            info = []
-            for line in file_out2.readlines():
-                info.append(clean_word(line[:-1]))
-            self.info = info
-            return self.info
-        except:
-            raise IOError('DecoderError: file does not exist.')
-
diff --git a/decode/ogg.py b/decode/ogg.py
deleted file mode 100644 (file)
index ffd6903..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-import os
-import string
-import subprocess
-
-from timeside.decode.core import *
-from timeside.api import IDecoder
-from mutagen.oggvorbis import OggVorbis
-
-class OggDecoder(DecoderCore):
-    """Defines methods to decode from OGG Vorbis"""
-
-    implements(IDecoder)
-
-    @staticmethod
-    def id():
-        return "oggdec"
-    
-    def format(self):
-        return 'OggVorbis'
-
-    def file_extension(self):
-        return 'ogg'
-
-    def mime_type(self):
-        return 'application/ogg'
-
-    def description(self):
-        return """
-        Vorbis is a free software / open source project headed by the Xiph.Org
-        Foundation (formerly Xiphophorus company). The project produces an audio
-        format specification and software implementation (codec) for lossy audio
-        compression. Vorbis is most commonly used in conjunction with the Ogg
-        container format and it is therefore often referred to as Ogg Vorbis.
-        (source Wikipedia)
-        """
-
-    def get_file_info(self):
-        try:
-            file_out1, file_out2 = os.popen4('ogginfo "'+self.dest+'"')
-            info = []
-            for line in file_out2.readlines():
-                info.append(clean_word(line[:-1]))
-            self.info = info
-            return self.info
-        except:
-            raise IOError('DecoderError: file does not exist.')
-
diff --git a/decode/wav.py b/decode/wav.py
deleted file mode 100644 (file)
index 08bca88..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-import os
-import string
-import subprocess
-
-from timeside.decode.core import *
-from timeside.api import IDecoder
-
-class WavDecoder(DecoderCore):
-    """Defines methods to decode from WAV"""
-
-    implements(IDecoder)
-
-    @staticmethod
-    def id():
-        return "wavdec"
-    
-    def format(self):
-        return 'WAV'
-
-    def file_extension(self):
-        return 'wav'
-
-    def mime_type(self):
-        return 'audio/x-wav'
-
-    def description(self):
-        return """
-        WAV (or WAVE), short for Waveform audio format, also known as Audio for
-        Windows, is a Microsoft and IBM audio file format standard for storing
-        an audio bitstream on PCs. It is an application of the RIFF bitstream
-        format method for storing data in “chunks”, and thus is also close to
-        the 8SVX and the AIFF format used on Amiga and Macintosh computers,
-        respectively. It is the main format used on Windows systems for raw and
-        typically uncompressed audio. The usual bitstream encoding is the Pulse
-        Code Modulation (PCM) format.
-        """
-
-    def get_file_info(self):
-        try:
-            file1, file2 = os.popen4('wavinfo "'+self.dest+'"')
-            info = []
-            for line in file2.readlines():
-                info.append(clean_word(line[:-1]))
-            self.info = info
-            return self.info
-        except:
-            raise IOError('DecoderError: wavinfo id not installed or file does not exist.')
-
diff --git a/decoder/__init__.py b/decoder/__init__.py
new file mode 100644 (file)
index 0000000..9f37f75
--- /dev/null
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+from timeside.decoder.core import *
diff --git a/decoder/core.py b/decoder/core.py
new file mode 100644 (file)
index 0000000..85d818e
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+from timeside.core import *
+import subprocess
+
+class SubProcessPipe:
+
+    def __init__(self, command, stdin=None):
+        """Read media and stream data through a generator.
+        Taken from Telemeta (see http://telemeta.org)"""
+
+        self.buffer_size = 0xFFFF
+
+        if not stdin:
+            stdin =  subprocess.PIPE
+
+        self.proc = subprocess.Popen(command.encode('utf-8'),
+                    shell = True,
+                    bufsize = self.buffer_size,
+                    stdin = stdin,
+                    stdout = subprocess.PIPE,
+                    close_fds = True)
+
+        self.input = self.proc.stdin
+        self.output = self.proc.stdout
+
+
+class DecoderCore(Processor):
+    """Defines the main parts of the decoding tools :
+    paths, metadata parsing, data streaming thru system command"""
+
+    def __init__(self):
+        self.command = 'ffmpeg -i "%s" -f wav - '
+
+    def process(self, source, options=None):
+        """Encode and stream audio data through a generator"""
+
+        command = self.command % source
+        proc = SubProcessPipe(command)
+        return proc.output
+
+        #while True:
+            #__chunk = proc.output.read(self.proc.buffer_size)
+            #status = proc.poll()
+            #if status != None and status != 0:
+                #raise ExportProcessError('Command failure:', command, proc)
+            #if len(__chunk) == 0:
+                #break
+            #yield __chunk
+
+
+
diff --git a/encode/__init__.py b/encode/__init__.py
deleted file mode 100644 (file)
index a3dd62f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from timeside.encode.core import *
-from timeside.encode.ogg import *
-from timeside.encode.wav import *
-from timeside.encode.mp3 import *
-from timeside.encode.flac import *
diff --git a/encode/core.py b/encode/core.py
deleted file mode 100644 (file)
index f7284b6..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-
-from timeside.encode import *
-from timeside.core import *
-
-import subprocess
-
-class SubProcessPipe:
-    """Read media and stream data through a generator.
-    Taken from Telemeta (see http://telemeta.org)"""
-
-    def __init__(self, command, stdin=None):
-        self.buffer_size = 0xFFFF
-        if not stdin:
-            stdin =  subprocess.PIPE
-
-        self.proc = subprocess.Popen(command.encode('utf-8'),
-                    shell = True,
-                    bufsize = self.buffer_size,
-                    stdin = stdin,
-                    stdout = subprocess.PIPE,
-                    close_fds = True)
-
-        self.input = self.proc.stdin
-        self.output = self.proc.stdout
-
-class EncoderCore(Processor):
-    """Defines the main parts of the encoding tools :
-    paths, metadata parsing, data streaming thru system command"""
-
-    def core_process(self, command, stdin):
-        """Encode and stream audio data through a generator"""
-
-        proc = SubProcessPipe(command, stdin)
-
-        while True:
-            __chunk = proc.output.read(proc.buffer_size)
-            #status = proc.poll()
-            #if status != None and status != 0:
-                #raise EncodeProcessError('Command failure:', command, proc)
-            if len(__chunk) == 0:
-                break
-            yield __chunk
-
-
-
diff --git a/encode/flac.py b/encode/flac.py
deleted file mode 100644 (file)
index 256c7a7..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-import os
-import string
-import subprocess
-
-from timeside.encode.core import *
-from timeside.api import IEncoder
-from tempfile import NamedTemporaryFile
-
-class FlacEncoder(EncoderCore):
-    """Defines methods to encode to FLAC"""
-
-    implements(IEncoder)
-
-    def __init__(self):
-        self.quality_default = '-5'
-        self.dub2args_dict = {'creator': 'artist',
-                             'relation': 'album'
-                             }
-
-    @staticmethod
-    def id():
-        return "flacenc"
-    
-    def format(self):
-        return 'FLAC'
-
-    def file_extension(self):
-        return 'flac'
-
-    def mime_type(self):
-        return 'audio/x-flac'
-
-    def description(self):
-        return """
-        Free Lossless Audio Codec (FLAC) is a file format for lossless audio
-        data compression.
-        """
-
-    def get_file_info(self):
-        try:
-            file1, file2 = os.popen4('metaflac --list "'+self.dest+'"')
-            info = []
-            for line in file2.readlines():
-                info.append(clean_word(line[:-1]))
-            self.info = info
-            return self.info
-        except:
-            raise IOError('EncoderError: metaflac is not installed or ' + \
-                           'file does not exist.')
-
-    def write_tags(self, file):
-        from mutagen.flac import FLAC
-        media = FLAC(file)
-        for tag in self.metadata:
-            name = tag[0]
-            value = clean_word(tag[1])
-            if name in self.dub2args_dict.keys():
-                name = self.dub2args_dict[name]
-            if name == 'comment':
-                media['DESCRIPTION'] = unicode(value)
-            else:
-                media[name] = unicode(value)
-        try:
-            media.save()
-        except:
-            raise IOError('EncoderError: cannot write tags.')
-
-
-    def get_args(self,options=None):
-        """Get process options and return arguments for the encoder"""
-        args = []
-        if not options is None:
-            self.options = options
-            if not ('verbose' in self.options and self.options['verbose'] != '0'):
-                args.append('-s')
-            if 'flac_quality' in self.options:
-                args.append('-f ' + self.options['flac_quality'])
-            else:
-                args.append('-f ' + self.quality_default)
-        else:
-            args.append('-s -f ' + self.quality_default)
-
-        #for tag in self.metadata.keys():
-            #value = clean_word(self.metadata[tag])
-            #args.append('-c %s="%s"' % (tag, value))
-            #if tag in self.dub2args_dict.keys():
-                #arg = self.dub2args_dict[tag]
-                #args.append('-c %s="%s"' % (arg, value))
-
-        return args
-
-    def process(self, source, metadata, options=None):
-        buffer_size = 0xFFFF
-        self.metadata= metadata
-        self.options = options
-        args = self.get_args()
-        args = ' '.join(args)
-        ext = self.file_extension()
-        temp_file = NamedTemporaryFile()
-        command = 'flac %s - -o %s ' % (args, temp_file.name)
-
-        stream = self.core_process(command, source)
-        
-        for __chunk in stream:
-            #temp_file.write(__chunk)
-            #temp_file.flush()
-            pass
-
-        #self.write_tags(temp_file.name)
-
-        while True:
-            __chunk = temp_file.read(buffer_size)
-            if len(__chunk) == 0:
-                break
-            yield __chunk
-
-        temp_file.close()
-
-
diff --git a/encode/mp3.py b/encode/mp3.py
deleted file mode 100644 (file)
index a29d369..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2007 Parisson SARL
-# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-import os
-import string
-import subprocess
-
-from timeside.encode.core import *
-from timeside.api import IEncoder
-
-
-class Mp3Encoder(EncoderCore):
-    """Defines methods to encode to MP3"""
-
-    implements(IEncoder)
-
-    def __init__(self):
-        self.bitrate_default = '192'
-        self.dub2id3_dict = {'title': 'TIT2', #title2
-                             'creator': 'TCOM', #composer
-                             'creator': 'TPE1', #lead
-                             'identifier': 'UFID', #Unique ID...
-                             'identifier': 'TALB', #album
-                             'type': 'TCON', #genre
-                             'publisher': 'TPUB', #comment
-                             #'date': 'TYER', #year
-                             }
-        self.dub2args_dict = {'title': 'tt', #title2
-                             'creator': 'ta', #composerS
-                             'relation': 'tl', #album
-                             #'type': 'tg', #genre
-                             'publisher': 'tc', #comment
-                             'date': 'ty', #year
-                             }
-
-    @staticmethod
-    def id():
-        return "mp3enc"
-    
-    def format(self):
-        return 'MP3'
-
-    def file_extension(self):
-        return 'mp3'
-
-    def mime_type(self):
-        return 'audio/mpeg'
-
-    def description(self):
-        return """
-        MPEG-1 Audio Layer 3, more commonly referred to as MP3, is a patented
-        digital audio encoding format using a form of lossy data compression.
-        """
-
-    def get_file_info(self):
-        try:
-            file_out1, file_out2 = os.popen4('mp3info "'+self.dest+'"')
-            info = []
-            for line in file_out2.readlines():
-                info.append(clean_word(line[:-1]))
-            self.info = info
-            return self.info
-        except:
-            raise IOError('EncoderError: file does not exist.')
-
-    def write_tags(self):
-        """Write all ID3v2.4 tags by mapping dub2id3_dict dictionnary with the
-            respect of mutagen classes and methods"""
-        from mutagen import id3
-        id3 = id3.ID3(self.dest)
-        for tag in self.metadata.keys():
-            if tag in self.dub2id3_dict.keys():
-                frame_text = self.dub2id3_dict[tag]
-                value = self.metadata[tag]
-                frame = mutagen.id3.Frames[frame_text](3,value)
-                try:
-                    id3.add(frame)
-                except:
-                    raise IOError('EncoderError: cannot tag "'+tag+'"')
-        try:
-            id3.save()
-        except:
-            raise IOError('EncoderError: cannot write tags')
-
-    def get_args(self):
-        """Get process options and return arguments for the encoder"""
-        args = []
-        if not self.options is None:
-            if not ( 'verbose' in self.options and self.options['verbose'] != '0' ):
-                args.append('-S')
-            if 'mp3_bitrate' in self.options:
-                args.append('-b ' + self.options['mp3_bitrate'])
-            else:
-                args.append('-b '+self.bitrate_default)
-            #Copyrights, etc..
-            args.append('-c -o')
-        else:
-            args.append('-S -c --tt "unknown" -o')
-
-        for tag in self.metadata:
-            name = tag[0]
-            value = clean_word(tag[1])
-            if name in self.dub2args_dict.keys():
-                arg = self.dub2args_dict[name]
-                args.append('--' + arg + ' "' + value + '"')
-        return args
-
-    def process(self, source, metadata, options=None):
-        self.metadata = metadata
-        self.options = options
-        args = self.get_args()
-        args = ' '.join(args)
-        command = 'lame %s - -' % args
-
-        stream = self.core_process(command, source)
-        for __chunk in stream:
-            yield __chunk
-
diff --git a/encode/ogg.py b/encode/ogg.py
deleted file mode 100644 (file)
index c0855f9..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-import os
-import string
-import subprocess
-
-from timeside.encode.core import *
-from timeside.api import IEncoder
-
-class OggVorbisEncoder(EncoderCore):
-    """Defines methods to encode to OGG Vorbis"""
-
-    implements(IEncoder)
-
-    def __init__(self):
-        self.bitrate_default = '192'
-        self.dub2args_dict = {'creator': 'artist',
-                             'relation': 'album'
-                             }
-
-    @staticmethod
-    def id():
-        return "oggenc"
-
-    def format(self):
-        return 'OggVorbis'
-
-    def file_extension(self):
-        return 'ogg'
-
-    def mime_type(self):
-        return 'application/ogg'
-
-    def description(self):
-        return """
-        Vorbis is a free software / open source project headed by the Xiph.Org
-        Foundation (formerly Xiphophorus company). The project produces an audio
-        format specification and software implementation (codec) for lossy audio
-        compression. Vorbis is most commonly used in conjunction with the Ogg
-        container format and it is therefore often referred to as Ogg Vorbis.
-        (source Wikipedia)
-        """
-
-    def get_file_info(self, file):
-        try:
-            file_out1, file_out2 = os.popen4('ogginfo "' + file + '"')
-            info = []
-            for line in file_out2.readlines():
-                info.append(clean_word(line[:-1]))
-            self.info = info
-            return self.info
-        except:
-            raise IOError('EncoderError: file does not exist.')
-
-    def write_tags(self, file):
-        from mutagen.oggvorbis import OggVorbis
-        media = OggVorbis(file)
-        for tag in self.metadata.keys():
-            media[tag] = str(self.metadata[tag])
-        media.save()
-
-    def get_args(self):
-        """Get process options and return arguments for the encoder"""
-        args = []
-        if not self.options is None:
-            if not ('verbose' in self.options and self.options['verbose'] != '0'):
-                args.append('-Q ')
-            if 'ogg_bitrate' in self.options:
-                args.append('-b '+self.options['ogg_bitrate'])
-            elif 'ogg_quality' in self.options:
-                args.append('-q '+self.options['ogg_quality'])
-            else:
-                args.append('-b '+self.bitrate_default)
-        else:
-            args.append('-Q -b '+self.bitrate_default)
-
-        for tag in self.metadata:
-            name = tag[0]
-            value = clean_word(tag[1])
-            args.append('-c %s="%s"' % (name, value))
-            if name in self.dub2args_dict.keys():
-                arg = self.dub2args_dict[name]
-                args.append('-c %s="%s"' % (arg, value))
-        return args
-
-    def process(self, source, metadata, options=None):
-        self.metadata = metadata
-        self.options = options
-        args = self.get_args()
-        args = ' '.join(args)
-        command = 'oggenc %s -' % args
-
-        stream = self.core_process(command, source)
-        for __chunk in stream:
-            yield __chunk
-
-
diff --git a/encode/wav.py b/encode/wav.py
deleted file mode 100644 (file)
index 1903050..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide 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.
-
-# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-import os
-import string
-
-from timeside.encode.core import *
-from timeside.api import IEncoder
-
-class WavEncoder(EncoderCore):
-    """Defines methods to encode to WAV"""
-
-    implements(IEncoder)
-
-    def __init__(self):
-        pass
-
-    @staticmethod
-    def id():
-        return "wavenc"
-
-    def format(self):
-        return 'WAV'
-
-    def file_extension(self):
-        return 'wav'
-
-    def mime_type(self):
-        return 'audio/x-wav'
-
-    def description(self):
-        return """
-        WAV (or WAVE), short for Waveform audio format, also known as Audio for
-        Windows, is a Microsoft and IBM audio file format standard for storing
-        an audio bitstream on PCs. It is an application of the RIFF bitstream
-        format method for storing data in “chunks”, and thus is also close to
-        the 8SVX and the AIFF format used on Amiga and Macintosh computers,
-        respectively. It is the main format used on Windows systems for raw and
-        typically uncompressed audio. The usual bitstream encoding is the Pulse
-        Code Modulation (PCM) format.
-        """
-
-    def get_file_info(self):
-        try:
-            file1, file2 = os.popen4('wavinfo "'+self.dest+'"')
-            info = []
-            for line in file2.readlines():
-                info.append(clean_word(line[:-1]))
-            self.info = info
-            return self.info
-        except:
-            raise IOError('EncoderError: wavinfo id not installed or file does not exist.')
-
-    def process(self, source, metadata, options=None):
-        self.metadata = metadata
-        self.options = options
-        command = 'sox -t wav - -s -q -b 16 -r 44100 -t wav -c2 -'
-
-        stream = self.core_process(command, source)
-        for __chunk in stream:
-            yield __chunk
diff --git a/encoder/__init__.py b/encoder/__init__.py
new file mode 100644 (file)
index 0000000..2818f2d
--- /dev/null
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+
+from timeside.encoder.core import *
+from timeside.encoder.ogg import *
+from timeside.encoder.wav import *
+from timeside.encoder.mp3 import *
+from timeside.encoder.flac import *
diff --git a/encoder/core.py b/encoder/core.py
new file mode 100644 (file)
index 0000000..3053165
--- /dev/null
@@ -0,0 +1,65 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+from timeside.core import *
+
+import subprocess
+
+class SubProcessPipe:
+    """Read media and stream data through a generator.
+    Taken from Telemeta (see http://telemeta.org)"""
+
+    def __init__(self, command, stdin=None):
+        self.buffer_size = 0xFFFF
+        if not stdin:
+            stdin =  subprocess.PIPE
+
+        self.proc = subprocess.Popen(command.encode('utf-8'),
+                    shell = True,
+                    bufsize = self.buffer_size,
+                    stdin = stdin,
+                    stdout = subprocess.PIPE,
+                    close_fds = True)
+
+        self.input = self.proc.stdin
+        self.output = self.proc.stdout
+
+class EncoderCore(Processor):
+    """Defines the main parts of the encoding tools :
+    paths, metadata parsing, data streaming thru system command"""
+
+    def core_process(self, command, stdin):
+        """Encode and stream audio data through a generator"""
+
+        proc = SubProcessPipe(command, stdin)
+
+        while True:
+            __chunk = proc.output.read(proc.buffer_size)
+            #status = proc.poll()
+            #if status != None and status != 0:
+                #raise EncodeProcessError('Command failure:', command, proc)
+            if len(__chunk) == 0:
+                break
+            yield __chunk
+
+
+
diff --git a/encoder/flac.py b/encoder/flac.py
new file mode 100644 (file)
index 0000000..0753441
--- /dev/null
@@ -0,0 +1,140 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+import os
+import string
+import subprocess
+
+from timeside.encoder.core import *
+from timeside.api import IEncoder
+from tempfile import NamedTemporaryFile
+
+class FlacEncoder(EncoderCore):
+    """Defines methods to encode to FLAC"""
+
+    implements(IEncoder)
+
+    def __init__(self):
+        self.quality_default = '-5'
+        self.dub2args_dict = {'creator': 'artist',
+                             'relation': 'album'
+                             }
+
+    @staticmethod
+    def id():
+        return "flacenc"
+
+    def format(self):
+        return 'FLAC'
+
+    def file_extension(self):
+        return 'flac'
+
+    def mime_type(self):
+        return 'audio/x-flac'
+
+    def description(self):
+        return """
+        Free Lossless Audio Codec (FLAC) is a file format for lossless audio
+        data compression.
+        """
+
+    def get_file_info(self):
+        try:
+            file1, file2 = os.popen4('metaflac --list "'+self.dest+'"')
+            info = []
+            for line in file2.readlines():
+                info.append(clean_word(line[:-1]))
+            self.info = info
+            return self.info
+        except:
+            raise IOError('EncoderError: metaflac is not installed or ' + \
+                           'file does not exist.')
+
+    def write_tags(self, file):
+        from mutagen.flac import FLAC
+        media = FLAC(file)
+        for tag in self.metadata:
+            name = tag[0]
+            value = clean_word(tag[1])
+            if name in self.dub2args_dict.keys():
+                name = self.dub2args_dict[name]
+            if name == 'comment':
+                media['DESCRIPTION'] = unicode(value)
+            else:
+                media[name] = unicode(value)
+        try:
+            media.save()
+        except:
+            raise IOError('EncoderError: cannot write tags.')
+
+
+    def get_args(self,options=None):
+        """Get process options and return arguments for the encoder"""
+        args = []
+        if not options is None:
+            self.options = options
+            if not ('verbose' in self.options and self.options['verbose'] != '0'):
+                args.append('-s')
+            if 'flac_quality' in self.options:
+                args.append('-f ' + self.options['flac_quality'])
+            else:
+                args.append('-f ' + self.quality_default)
+        else:
+            args.append('-s -f ' + self.quality_default)
+
+        #for tag in self.metadata.keys():
+            #value = clean_word(self.metadata[tag])
+            #args.append('-c %s="%s"' % (tag, value))
+            #if tag in self.dub2args_dict.keys():
+                #arg = self.dub2args_dict[tag]
+                #args.append('-c %s="%s"' % (arg, value))
+
+        return args
+
+    def process(self, source, metadata, options=None):
+        buffer_size = 0xFFFF
+        self.metadata= metadata
+        self.options = options
+        args = self.get_args()
+        args = ' '.join(args)
+        ext = self.file_extension()
+        temp_file = NamedTemporaryFile()
+        command = 'flac %s - -o %s ' % (args, temp_file.name)
+
+        stream = self.core_process(command, source)
+
+        for __chunk in stream:
+            #temp_file.write(__chunk)
+            #temp_file.flush()
+            pass
+
+        #self.write_tags(temp_file.name)
+
+        while True:
+            __chunk = temp_file.read(buffer_size)
+            if len(__chunk) == 0:
+                break
+            yield __chunk
+
+        temp_file.close()
+
+
diff --git a/encoder/mp3.py b/encoder/mp3.py
new file mode 100644 (file)
index 0000000..70f6dfb
--- /dev/null
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Parisson SARL
+# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+import os
+import string
+import subprocess
+
+from timeside.encoder.core import *
+from timeside.api import IEncoder
+
+
+class Mp3Encoder(EncoderCore):
+    """Defines methods to encode to MP3"""
+
+    implements(IEncoder)
+
+    def __init__(self):
+        self.bitrate_default = '192'
+        self.dub2id3_dict = {'title': 'TIT2', #title2
+                             'creator': 'TCOM', #composer
+                             'creator': 'TPE1', #lead
+                             'identifier': 'UFID', #Unique ID...
+                             'identifier': 'TALB', #album
+                             'type': 'TCON', #genre
+                             'publisher': 'TPUB', #comment
+                             #'date': 'TYER', #year
+                             }
+        self.dub2args_dict = {'title': 'tt', #title2
+                             'creator': 'ta', #composerS
+                             'relation': 'tl', #album
+                             #'type': 'tg', #genre
+                             'publisher': 'tc', #comment
+                             'date': 'ty', #year
+                             }
+
+    @staticmethod
+    def id():
+        return "mp3enc"
+
+    def format(self):
+        return 'MP3'
+
+    def file_extension(self):
+        return 'mp3'
+
+    def mime_type(self):
+        return 'audio/mpeg'
+
+    def description(self):
+        return """
+        MPEG-1 Audio Layer 3, more commonly referred to as MP3, is a patented
+        digital audio encoding format using a form of lossy data compression.
+        """
+
+    def get_file_info(self):
+        try:
+            file_out1, file_out2 = os.popen4('mp3info "'+self.dest+'"')
+            info = []
+            for line in file_out2.readlines():
+                info.append(clean_word(line[:-1]))
+            self.info = info
+            return self.info
+        except:
+            raise IOError('EncoderError: file does not exist.')
+
+    def write_tags(self):
+        """Write all ID3v2.4 tags by mapping dub2id3_dict dictionnary with the
+            respect of mutagen classes and methods"""
+        from mutagen import id3
+        id3 = id3.ID3(self.dest)
+        for tag in self.metadata.keys():
+            if tag in self.dub2id3_dict.keys():
+                frame_text = self.dub2id3_dict[tag]
+                value = self.metadata[tag]
+                frame = mutagen.id3.Frames[frame_text](3,value)
+                try:
+                    id3.add(frame)
+                except:
+                    raise IOError('EncoderError: cannot tag "'+tag+'"')
+        try:
+            id3.save()
+        except:
+            raise IOError('EncoderError: cannot write tags')
+
+    def get_args(self):
+        """Get process options and return arguments for the encoder"""
+        args = []
+        if not self.options is None:
+            if not ( 'verbose' in self.options and self.options['verbose'] != '0' ):
+                args.append('-S')
+            if 'mp3_bitrate' in self.options:
+                args.append('-b ' + self.options['mp3_bitrate'])
+            else:
+                args.append('-b '+self.bitrate_default)
+            #Copyrights, etc..
+            args.append('-c -o')
+        else:
+            args.append('-S -c --tt "unknown" -o')
+
+        for tag in self.metadata:
+            name = tag[0]
+            value = clean_word(tag[1])
+            if name in self.dub2args_dict.keys():
+                arg = self.dub2args_dict[name]
+                args.append('--' + arg + ' "' + value + '"')
+        return args
+
+    def process(self, source, metadata, options=None):
+        self.metadata = metadata
+        self.options = options
+        args = self.get_args()
+        args = ' '.join(args)
+        command = 'lame %s - -' % args
+
+        stream = self.core_process(command, source)
+        for __chunk in stream:
+            yield __chunk
+
diff --git a/encoder/ogg.py b/encoder/ogg.py
new file mode 100644 (file)
index 0000000..566c529
--- /dev/null
@@ -0,0 +1,116 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+import os
+import string
+import subprocess
+
+from timeside.encoder.core import *
+from timeside.api import IEncoder
+
+class OggVorbisEncoder(EncoderCore):
+    """Defines methods to encode to OGG Vorbis"""
+
+    implements(IEncoder)
+
+    def __init__(self):
+        self.bitrate_default = '192'
+        self.dub2args_dict = {'creator': 'artist',
+                             'relation': 'album'
+                             }
+
+    @staticmethod
+    def id():
+        return "oggenc"
+
+    def format(self):
+        return 'OggVorbis'
+
+    def file_extension(self):
+        return 'ogg'
+
+    def mime_type(self):
+        return 'application/ogg'
+
+    def description(self):
+        return """
+        Vorbis is a free software / open source project headed by the Xiph.Org
+        Foundation (formerly Xiphophorus company). The project produces an audio
+        format specification and software implementation (codec) for lossy audio
+        compression. Vorbis is most commonly used in conjunction with the Ogg
+        container format and it is therefore often referred to as Ogg Vorbis.
+        (source Wikipedia)
+        """
+
+    def get_file_info(self, file):
+        try:
+            file_out1, file_out2 = os.popen4('ogginfo "' + file + '"')
+            info = []
+            for line in file_out2.readlines():
+                info.append(clean_word(line[:-1]))
+            self.info = info
+            return self.info
+        except:
+            raise IOError('EncoderError: file does not exist.')
+
+    def write_tags(self, file):
+        from mutagen.oggvorbis import OggVorbis
+        media = OggVorbis(file)
+        for tag in self.metadata.keys():
+            media[tag] = str(self.metadata[tag])
+        media.save()
+
+    def get_args(self):
+        """Get process options and return arguments for the encoder"""
+        args = []
+        if not self.options is None:
+            if not ('verbose' in self.options and self.options['verbose'] != '0'):
+                args.append('-Q ')
+            if 'ogg_bitrate' in self.options:
+                args.append('-b '+self.options['ogg_bitrate'])
+            elif 'ogg_quality' in self.options:
+                args.append('-q '+self.options['ogg_quality'])
+            else:
+                args.append('-b '+self.bitrate_default)
+        else:
+            args.append('-Q -b '+self.bitrate_default)
+
+        for tag in self.metadata:
+            name = tag[0]
+            value = clean_word(tag[1])
+            args.append('-c %s="%s"' % (name, value))
+            if name in self.dub2args_dict.keys():
+                arg = self.dub2args_dict[name]
+                args.append('-c %s="%s"' % (arg, value))
+        return args
+
+    def process(self, source, metadata, options=None):
+        self.metadata = metadata
+        self.options = options
+        args = self.get_args()
+        args = ' '.join(args)
+        command = 'oggenc %s -' % args
+
+        stream = self.core_process(command, source)
+        for __chunk in stream:
+            yield __chunk
+
+
diff --git a/encoder/wav.py b/encoder/wav.py
new file mode 100644 (file)
index 0000000..4a7a90c
--- /dev/null
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide 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.
+
+# TimeSide 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 TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+import os
+import string
+
+from timeside.encoder.core import *
+from timeside.api import IEncoder
+
+class WavEncoder(EncoderCore):
+    """Defines methods to encode to WAV"""
+
+    implements(IEncoder)
+
+    def __init__(self):
+        pass
+
+    @staticmethod
+    def id():
+        return "wavenc"
+
+    def format(self):
+        return 'WAV'
+
+    def file_extension(self):
+        return 'wav'
+
+    def mime_type(self):
+        return 'audio/x-wav'
+
+    def description(self):
+        return """
+        WAV (or WAVE), short for Waveform audio format, also known as Audio for
+        Windows, is a Microsoft and IBM audio file format standard for storing
+        an audio bitstream on PCs. It is an application of the RIFF bitstream
+        format method for storing data in “chunks”, and thus is also close to
+        the 8SVX and the AIFF format used on Amiga and Macintosh computers,
+        respectively. It is the main format used on Windows systems for raw and
+        typically uncompressed audio. The usual bitstream encoding is the Pulse
+        Code Modulation (PCM) format.
+        """
+
+    def get_file_info(self):
+        try:
+            file1, file2 = os.popen4('wavinfo "'+self.dest+'"')
+            info = []
+            for line in file2.readlines():
+                info.append(clean_word(line[:-1]))
+            self.info = info
+            return self.info
+        except:
+            raise IOError('EncoderError: wavinfo id not installed or file does not exist.')
+
+    def process(self, source, metadata, options=None):
+        self.metadata = metadata
+        self.options = options
+        command = 'sox -t wav - -s -q -b 16 -r 44100 -t wav -c2 -'
+
+        stream = self.core_process(command, source)
+        for __chunk in stream:
+            yield __chunk
index f90d71e16b7c6d6152b417e43e814d6af5a6d672..0c3ff70cdb12782c09ab817bd6590033a0e70647 100644 (file)
@@ -48,7 +48,8 @@ color_schemes = {
 }
 
 
-class SpectralCentroid(object):
+class Spectrum(object):
+    """ FFT based frequency analysis of audio frames."""
 
     def __init__(self, fft_size, nframes, samplerate, lower, higher, window_function=numpy.ones):
         self.fft_size = fft_size
@@ -64,6 +65,8 @@ class SpectralCentroid(object):
         self.spectrum_adapter = FixedSizeInputAdapter(self.fft_size, 1, pad=True)
 
     def process(self, frames, eod, spec_range=120.0):
+        """ Returns a tuple containing the spectral centroid and the spectrum (dB scales) of the input audio frames.
+            An adapter is used to fix the buffer length and then provide fixed FFT window sizes."""
 
         for buffer, end in self.spectrum_adapter.process(frames, True):
             samples = buffer[:,0].copy()
@@ -92,7 +95,7 @@ class SpectralCentroid(object):
 
 
 def interpolate_colors(colors, flat=False, num_colors=256):
-    """ given a list of colors, create a larger list of colors interpolating
+    """ Given a list of colors, create a larger list of colors interpolating
     the first one. If flatten is True a list of numers will be returned. If
     False, a list of (r,g,b) tuples. num_colors is the number of colors wanted
     in the final list """
@@ -122,9 +125,11 @@ def interpolate_colors(colors, flat=False, num_colors=256):
 
 
 class WaveformImage(object):
+    """ Builds a PIL image representing a waveform of the audio stream.
+    Adds pixels iteratively thanks to the adapter providing fixed size frame buffers.
+    Peaks are colored relative to the spectral centroids of each frame packet. """
 
     def __init__(self, image_width, image_height, nframes, samplerate, fft_size, bg_color=None, color_scheme=None, filename=None):
-
         self.image_width = image_width
         self.image_height = image_height
         self.nframes = nframes
@@ -148,7 +153,7 @@ class WaveformImage(object):
 
         self.lower = 500
         self.higher = 16000
-        self.spectral_centroid = SpectralCentroid(self.fft_size, self.nframes, self.samplerate, self.lower, self.higher, numpy.hanning)
+        self.spectrum = Spectrum(self.fft_size, self.nframes, self.samplerate, self.lower, self.higher, numpy.hanning)
 
         self.image = Image.new("RGB", (self.image_width, self.image_height), self.bg_color)
         self.pixel = self.image.load()
@@ -158,9 +163,9 @@ class WaveformImage(object):
         self.pixel_cursor = 0
 
     def peaks(self, samples):
-        """ read all samples between start_seek and end_seek, then find the minimum and maximum peak
-        in that range. Returns that pair in the order they were found. So if min was found first,
-        it returns (min, max) else the other way around. """
+        """ Find the minimum and maximum peak of the samples.
+        Returns that pair in the order they were found.
+        So if min was found first, it returns (min, max) else the other way around. """
 
         max_index = numpy.argmax(samples)
         max_value = samples[max_index]
@@ -232,7 +237,7 @@ class WaveformImage(object):
             buffer = frames[:,0].copy()
             buffer.shape = (len(frames),1)
 
-        (spectral_centroid, db_spectrum) = self.spectral_centroid.process(buffer, True)
+        (spectral_centroid, db_spectrum) = self.spectrum.process(buffer, True)
         for samples, end in self.pixels_adapter.process(buffer, eod):
             if self.pixel_cursor < self.image_width:
                 peaks = self.peaks(samples)
@@ -240,6 +245,7 @@ class WaveformImage(object):
                 self.pixel_cursor += 1
 
     def save(self):
+        """ Apply last 2D transforms and write all pixels to the file. """
         a = 25
         for x in range(self.image_width):
             self.pixel[x, self.image_height/2] = tuple(map(lambda p: p+a, self.pixel[x, self.image_height/2]))
@@ -247,6 +253,8 @@ class WaveformImage(object):
 
 
 class SpectrogramImage(object):
+    """ Builds a PIL image representing a spectrogram of the audio stream (level vs. frequency vs. time).
+    Adds pixels iteratively thanks to the adapter providing fixed size frame buffers."""
 
     def __init__(self, image_width, image_height, nframes, samplerate, fft_size, bg_color=None, color_scheme='default', filename=None):
         self.image_width = image_width
@@ -268,7 +276,7 @@ class SpectrogramImage(object):
 
         self.lower = 20
         self.higher = 16000
-        self.spectral_centroid = SpectralCentroid(self.fft_size, self.nframes, self.samplerate, self.lower, self.higher, numpy.hanning)
+        self.spectrum = Spectrum(self.fft_size, self.nframes, self.samplerate, self.lower, self.higher, numpy.hanning)
 
         # generate the lookup which translates y-coordinate to fft-bin
         self.y_to_bin = []
@@ -309,11 +317,12 @@ class SpectrogramImage(object):
         # FIXME : breaks spectrum linearity
         for samples, end in self.pixels_adapter.process(buffer, eod):
             if self.pixel_cursor < self.image_width:
-                (spectral_centroid, db_spectrum) = self.spectral_centroid.process(samples, False)
+                (spectral_centroid, db_spectrum) = self.spectrum.process(samples, False)
                 self.draw_spectrum(self.pixel_cursor, db_spectrum)
                 self.pixel_cursor += 1
 
     def save(self):
+        """ Apply last 2D transforms and write all pixels to the file. """
         self.image.putdata(self.pixels)
         self.image.transpose(Image.ROTATE_90).save(self.filename)
 
@@ -322,6 +331,7 @@ class Noise(object):
     """A class that mimics audiolab.sndfile but generates noise instead of reading
     a wave file. Additionally it can be told to have a "broken" header and thus crashing
     in the middle of the file. Also useful for testing ultra-short files of 20 samples."""
+
     def __init__(self, num_frames, has_broken_header=False):
         self.seekpoint = 0
         self.num_frames = num_frames
index 6e762edc073715e74bb011b8e29217d74e980816..c2b007b1bbe2bb86009e69e26b0322d0b165c38d 100755 (executable)
@@ -12,13 +12,7 @@ class TestAnalyzers:
 
     def list(self):
         analyzers = []
-        for analyzer_class in self.analyzers:
-            # FIXME: should access the name, id and unit member statically
-            # there should be no need to instantiate analyzer_class
-            # eg: access directly analyzer_class.name(), etc...
-            #
-            # This remark is true at many places in this file
-            analyzer = analyzer_class()
+        for analyzer in self.analyzers:
             analyzers.append({'name':analyzer.name(),
                             'id':analyzer.id(),
                             'unit':analyzer.unit(),
@@ -27,8 +21,7 @@ class TestAnalyzers:
 
     def run(self, media):
         print '\n=== Analyzer testing ===\n'
-        for analyzer_class in self.analyzers:
-            analyzer = analyzer_class()
+        for analyzer in self.analyzers:
             id = analyzer.id()
             value = analyzer.render(media)
             print id + ' = ' + str(value) + ' ' + analyzer.unit()
@@ -39,8 +32,7 @@ class TestDecoders:
 
     def list(self):
         decoders_list = []
-        for decoder_class in self.decoders:
-            decoder = decoder_class()
+        for decoder in self.decoders:
             decoders_list.append({'format': decoder.format(),
                             'mime_type': decoder.mime_type(),
                             'file_extension': decoder.file_extension(),
@@ -48,8 +40,7 @@ class TestDecoders:
         print decoders_list
 
     def get_decoder(self, mime_type):
-        for decoder_class in self.decoders:
-            decoder = decoder_class()
+        for decoder in self.decoders:
             if decoder.mime_type() == mime_type:
                 return decoder
 
@@ -76,24 +67,21 @@ class TestEncoders:
 
     def list(self):
         encoders = []
-        for encoder_class in self.encoders:
-            encoder = encoder_class()
+        for encoder in self.encoders:
             encoders.append({'format': encoder.format(),
                             'mime_type': encoder.mime_type(),
                             })
         print encoders
 
     def get_encoder(self, mime_type):
-        for encoder_class in self.encoders:
-            encoder = encoder_class()
+        for encoder in self.encoders:
             if encoder.mime_type() == mime_type:
                 return encoder
 
     def run(self, source, metadata):
         print '\n=== Encoder testing ===\n'
-        for encoder_class in self.encoders:
+        for encoder in self.encoders:
             print '=================================='
-            encoder = encoder_class()
             mime = mimetype(source)
             format = encoder.format()
             decoders = TestDecoders()
@@ -115,8 +103,7 @@ class TestGraphers:
 
     def list(self):
         graphers = []
-        for grapher_class in self.graphers:
-            grapher = grapher_class()
+        for grapher in self.graphers:
             graphers.append({'id':grapher.id(),
                             'name':grapher.name(),
                             })
@@ -124,8 +111,7 @@ class TestGraphers:
 
     def run(self, media):
         print '\n=== Grapher testing ===\n'
-        for grapher_class in self.graphers:
-            grapher = grapher_class()
+        for grapher in self.graphers:
             id = grapher.id()
             image = grapher.render(media)
             file_path = 'results/'+id+'.png'
@@ -135,6 +121,7 @@ class TestGraphers:
             print 'Image exported to :' + file_path
             file.close()
 
+
 def mimetype(path):
     if hasattr(magic, "Magic"):
         if not hasattr(mimetype, "magic"):
@@ -155,13 +142,13 @@ if __name__ == '__main__':
     a = TestAnalyzers()
     d = TestDecoders()
     e = TestEncoders()
-    #g = TestGraphers()
+    g = TestGraphers()
     a.list()
     d.list()
     e.list()
-    #g.list()
+    g.list()
     a.run(sample)
-    #g.run(sample)
+    g.run(sample)
     e.run(sample, metadata)
     d.export('samples/')