]> git.parisson.com Git - telemeta.git/commitdiff
- now depends on TimeSide for the web audio components
authoryomguy <>
Mon, 30 Aug 2010 01:13:13 +0000 (01:13 +0000)
committeryomguy <>
Mon, 30 Aug 2010 01:13:13 +0000 (01:13 +0000)
- removed old processors based on audiolab & subprocess pipes (bye bye)
- analyzers are working but removed *temporaly* from templates
- improve caching for image and audio media streaming
- fixed many bugs around timeside, BE CAREFUL, needed more tests for 0.5.2

47 files changed:
INSTALL
telemeta/__init__.py
telemeta/analysis/__init__.py [deleted file]
telemeta/analysis/api.py [deleted file]
telemeta/analysis/channels.py [deleted file]
telemeta/analysis/core.py [deleted file]
telemeta/analysis/dc.py [deleted file]
telemeta/analysis/duration.py [deleted file]
telemeta/analysis/encoding.py [deleted file]
telemeta/analysis/format.py [deleted file]
telemeta/analysis/max_level.py [deleted file]
telemeta/analysis/mean_level.py [deleted file]
telemeta/analysis/resolution.py [deleted file]
telemeta/analysis/samplerate.py [deleted file]
telemeta/analysis/vamp/__init__.py [deleted file]
telemeta/analysis/vamp/core.py [deleted file]
telemeta/export/__init__.py [deleted file]
telemeta/export/api.py [deleted file]
telemeta/export/core.py [deleted file]
telemeta/export/flac.py [deleted file]
telemeta/export/mp3.py [deleted file]
telemeta/export/ogg.py [deleted file]
telemeta/export/wav.py [deleted file]
telemeta/models/media.py
telemeta/templates/telemeta_default/index.html
telemeta/templates/telemeta_default/mediaitem_detail.html
telemeta/urls.py
telemeta/visualization/__init__.py [deleted file]
telemeta/visualization/api.py [deleted file]
telemeta/visualization/octave/jet.m [deleted file]
telemeta/visualization/octave/spectrogram.m [deleted file]
telemeta/visualization/octave/spectrogram2img.m [deleted file]
telemeta/visualization/octave/waveform2img.m [deleted file]
telemeta/visualization/octave_core.py [deleted file]
telemeta/visualization/old/spectrogram.py [deleted file]
telemeta/visualization/old/spectrogram3.py [deleted file]
telemeta/visualization/old/waveform.py [deleted file]
telemeta/visualization/old/waveform2.py [deleted file]
telemeta/visualization/old/waveform4.py [deleted file]
telemeta/visualization/snack_core.py [deleted file]
telemeta/visualization/spectrogram_audiolab.py [deleted file]
telemeta/visualization/spectrogram_octave.py [deleted file]
telemeta/visualization/tkSnack.py [deleted file]
telemeta/visualization/wav2png.py [deleted file]
telemeta/visualization/waveform_audiolab.py [deleted file]
telemeta/web/__init__.py
telemeta/web/base.py

diff --git a/INSTALL b/INSTALL
index 2e45ef4b05827c18a1f0d067e107abfaba2f698a..d327105b3516fb710e4a1f0284fd7f74d72f8bf4 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -10,11 +10,9 @@ The following third party applications or libraries are required:
 
 :dependencies: python (>= 2.3.5-7), python-xml, python-mutagen, python-django (>= 1.0-1),
                python-imaging (>= 1.1.6), sox (>= 14.2), vorbis-tools, flac, normalize-audio,
-               python-mysqldb, mysql-server, octave2.9, python-tk, libgd2-xpm,
-               libsndfile1 (>= 1.0.17), python-numpy, python-ctypes (>= 1.0.1),
-               python-scikits-audiolab (>= 0.10), python-setuptools (>= 0.6b3),
-               python-support (>= 0.3), python-scipy, lame (>= 3.98.2),
-               python-docutils (>= 0.5)
+               python-mysqldb, mysql-server, python-timeside (>= 0.2), python-numpy, python-scipy
+               python-ctypes (>= 1.0.1), python-setuptools (>= 0.6b3),
+               python-support (>= 0.3), python-docutils (>= 0.5)
 
 :optional:     ecasound, festival, par2
 
@@ -65,16 +63,22 @@ Install
     $ sudo python setup.py install
 
 
-1.2. Install audiolab
+1.2. Install TimeSide
 ---------------------
 
-This is ONLY needed if you did NOT install telemeta with Debian's apt-get.
+In order to get all the Web Audio Components from TimeSide,
+you have to download and install it from source.
 
-In order to get the wavforms of the audio files,
-python-audiolab have to be installed with the help of git::
+So, checkout the last archives at :
+http://code.google.com/p/timeside/downloads/list
+
+Install it like in the following example::
+
+$ tar xzf timeside-0.2.tar.gz
+$ cd timeside-0.2
+
+Read the README and INSTALL file, install dependencies and then::
 
-$ git clone git://github.com/cournape/audiolab.git
-$ cd audiolab/
 $ sudo python setup.py install
 
 
@@ -123,7 +127,7 @@ Modifiy the following variables:
     :DATABASE_*:        your database settings (don't forget to create the database if needed)
     :MEDIA_ROOT:        absolute path to the media directory you just created
     :INSTALLED_APPS:    add 'telemeta'
-    :TEMPLATE_CONTEXT_PROCESSORS: include 'django.core.context_processors.request' and 
+    :TEMPLATE_CONTEXT_PROCESSORS: include 'django.core.context_processors.request' and
                                   'django.core.context_processors.auth' in this tuple
 
 Add the following variables:
@@ -133,13 +137,14 @@ Add the following variables:
                             as "Ethnology", etc...
     :TELEMETA_CACHE_DIR:    absolute path to the cache directory that you just created
     :TELEMETA_GMAP_KEY:     your Google Map API key
-    :TELEMETA_DOWNLOAD_ENABLED: True to enable audio data download 
+    :TELEMETA_DOWNLOAD_ENABLED: True to enable audio data download
 
 Just paste the lines below::
 
     LOGIN_URL = '/login'
     LOGIN_REDIRECT_URL = '/'
     TELEMETA_EXPORT_CACHE_DIR = TELEMETA_CACHE_DIR + "/export"
+    TELEMETA_DATA_CACHE_DIR = TELEMETA_CACHE_DIR + "/data"
     CACHE_BACKEND = "file://" + TELEMETA_CACHE_DIR + "/data"
 
 
index f2462bde12d7ad82576c608ce16960448e4ae587..f95b46496693cd16867db991966143b8513c9af7 100644 (file)
@@ -2,7 +2,6 @@
 
 """
 Telemeta
-Parisson SARL
 
 U{http://telemeta.org}
 
diff --git a/telemeta/analysis/__init__.py b/telemeta/analysis/__init__.py
deleted file mode 100644 (file)
index 080b274..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-from telemeta.analysis.api import *
-from telemeta.analysis.core import *
-from telemeta.analysis.channels import *
-from telemeta.analysis.format import *
-from telemeta.analysis.encoding import *
-from telemeta.analysis.resolution import *
-from telemeta.analysis.samplerate import *
-from telemeta.analysis.duration import *
-from telemeta.analysis.max_level import *
-from telemeta.analysis.mean_level import *
-from telemeta.analysis.dc import *
-
-
diff --git a/telemeta/analysis/api.py b/telemeta/analysis/api.py
deleted file mode 100644 (file)
index 302506c..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from telemeta.core import *
-
-class IMediaItemAnalyzer(Interface):
-    """Media item analyzer driver interface"""
-
-    def get_id():
-        """Return a short id alphanumeric, lower-case string."""
-
-    def get_name():
-        """Return the analysis name, such as "Mean Level", "Max level",
-        "Total length, etc..
-        """
-
-    def get_unit():
-        """Return the unit of the data such as "dB", "seconds", etc...
-        """
-    
-    def render(media_item, options=None):
-        """Return the result data of the process"""
-            
diff --git a/telemeta/analysis/channels.py b/telemeta/analysis/channels.py
deleted file mode 100644 (file)
index 2e90582..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson SARL
-#
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from telemeta.analysis.core import *
-from telemeta.analysis.api import IMediaItemAnalyzer
-import numpy
-
-class ChannelAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IMediaItemAnalyzer)
-
-    def get_id(self):
-        return "nb_channels"
-
-    def get_name(self):
-        return "Channels"
-
-    def get_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/telemeta/analysis/core.py b/telemeta/analysis/core.py
deleted file mode 100644 (file)
index 9ecf85a..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-# -*- coding: utf-8 -*-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  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 django.conf import settings
-from telemeta.core import *
-import optparse, math, sys
-import numpy
-import scikits.audiolab as audiolab
-
-
-class AudioProcessor(Component):
-    
-    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.file.path
-        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/telemeta/analysis/dc.py b/telemeta/analysis/dc.py
deleted file mode 100644 (file)
index e9e9fa5..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson SARL
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from telemeta.analysis.core import *
-from telemeta.analysis.api import IMediaItemAnalyzer
-import numpy
-
-class MeanDCShiftAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IMediaItemAnalyzer)
-
-    def get_id(self):
-        return "dc"
-
-    def get_name(self):
-        return "Mean DC shift"
-
-    def get_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/telemeta/analysis/duration.py b/telemeta/analysis/duration.py
deleted file mode 100644 (file)
index cebdd6d..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson SARL
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from telemeta.analysis.core import *
-from telemeta.analysis.api import IMediaItemAnalyzer
-import numpy
-import datetime
-
-class DurationAnalyzer(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IMediaItemAnalyzer)
-
-    def get_id(self):
-        return "duration"
-
-    def get_name(self):
-        return "Duration"
-
-    def get_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/telemeta/analysis/encoding.py b/telemeta/analysis/encoding.py
deleted file mode 100644 (file)
index b06c04d..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson SARL
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from telemeta.analysis.core import *
-from telemeta.analysis.api import IMediaItemAnalyzer
-import numpy
-
-class EncodingAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IMediaItemAnalyzer)
-
-    def get_id(self):
-        return "encoding"
-
-    def get_name(self):
-        return "Encoding format"
-
-    def get_unit(self):
-        return ""
-
-    def render(self, media_item, options=None):
-        self.pre_process(media_item)
-        return self.encoding
diff --git a/telemeta/analysis/format.py b/telemeta/analysis/format.py
deleted file mode 100644 (file)
index b2019c4..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson SARL
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from telemeta.analysis.core import *
-from telemeta.analysis.api import IMediaItemAnalyzer
-import numpy
-
-class FormatAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IMediaItemAnalyzer)
-
-    def get_id(self):
-        return "format"
-
-    def get_name(self):
-        return "File format"
-
-    def get_unit(self):
-        return ""
-
-    def render(self, media_item, options=None):
-        self.pre_process(media_item)
-        return self.format
diff --git a/telemeta/analysis/max_level.py b/telemeta/analysis/max_level.py
deleted file mode 100644 (file)
index a33831d..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson SARL
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from telemeta.analysis.core import *
-from telemeta.analysis.api import IMediaItemAnalyzer
-import numpy
-
-class MaxLevelAnalyzer(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IMediaItemAnalyzer)
-
-    def get_id(self):
-        return "max_level"
-
-    def get_name(self):
-        return "Maximum peak level"
-
-    def get_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)
\ No newline at end of file
diff --git a/telemeta/analysis/mean_level.py b/telemeta/analysis/mean_level.py
deleted file mode 100644 (file)
index 8f3aba8..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson SARL
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from telemeta.analysis.core import *
-from telemeta.analysis.api import IMediaItemAnalyzer
-import numpy
-
-class MeanLevelAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IMediaItemAnalyzer)
-
-    def get_id(self):
-        return "mean_level"
-
-    def get_name(self):
-        return "Mean RMS level"
-
-    def get_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/telemeta/analysis/resolution.py b/telemeta/analysis/resolution.py
deleted file mode 100644 (file)
index 1d375fc..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson SARL
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from telemeta.analysis.core import *
-from telemeta.analysis.api import IMediaItemAnalyzer
-import numpy
-
-class ResolutionAnalyser(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IMediaItemAnalyzer)
-
-    def get_id(self):
-        return "resolution"
-
-    def get_name(self):
-        return "Resolution"
-
-    def get_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 ''
\ No newline at end of file
diff --git a/telemeta/analysis/samplerate.py b/telemeta/analysis/samplerate.py
deleted file mode 100644 (file)
index 6daae7f..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson SARL
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <yomguy@parisson.com>
-
-from telemeta.analysis.core import *
-from telemeta.analysis.api import IMediaItemAnalyzer
-import numpy
-
-class SampleRateAnalyzer(AudioProcessor):
-    """Media item analyzer driver interface"""
-
-    implements(IMediaItemAnalyzer)
-
-    def get_id(self):
-        return "samplerate"
-
-    def get_name(self):
-        return "Samplerate"
-
-    def get_unit(self):
-        return "Hz"
-
-    def render(self, media_item, options=None):
-        self.pre_process(media_item)
-        return self.samplerate
diff --git a/telemeta/analysis/vamp/__init__.py b/telemeta/analysis/vamp/__init__.py
deleted file mode 100644 (file)
index 8098876..0000000
+++ /dev/null
@@ -1 +0,0 @@
-from telemeta.analysis.vamp.core import *
diff --git a/telemeta/analysis/vamp/core.py b/telemeta/analysis/vamp/core.py
deleted file mode 100644 (file)
index 242e49b..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-
-from telemeta.core import *
-from django.conf import settings
-from tempfile import NamedTemporaryFile
-from telemeta.analysis.api import IMediaItemAnalyzer
-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 get_id(self):
-        return "vamp_plugins"
-
-    def get_name(self):
-        return "Vamp plugins"
-
-    def get_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 VampProcessError('Command failure:', command, proc)
-            
-        # Core processing
-        while True:
-            __chunk = proc.stdout.read(buffer_size)
-            status = proc.poll()
-            if status != None and status != 0:
-                raise VampProcessError('Command failure:', command, proc)
-            if len(__chunk) == 0:
-                break
-            yield __chunk
-        
-
-class VampProcessError(TelemetaError):
-
-    def __init__(self, message, command, subprocess):
-        self.message = message
-        self.command = str(command)
-        self.subprocess = subprocess
-
-    def __str__(self):
-        if self.subprocess.stderr != None:
-            error = self.subprocess.stderr.read()
-        else:
-            error = ''
-        return "%s ; command: %s; error: %s" % (self.message,
-                                                self.command,
-                                                error)
diff --git a/telemeta/export/__init__.py b/telemeta/export/__init__.py
deleted file mode 100644 (file)
index 6ba2ef1..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-from telemeta.export.api import *
-from telemeta.export.core import *
-from telemeta.export.ogg import *
-from telemeta.export.flac import *
-from telemeta.export.wav import *
-from telemeta.export.mp3 import *
\ No newline at end of file
diff --git a/telemeta/export/api.py b/telemeta/export/api.py
deleted file mode 100644 (file)
index 8e8b77e..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2007-2009 Parisson
-# Copyright (c) 2007 Olivier Guilyardi <olivier@samalyse.com>
-# Copyright (c) 2007-2009 Guillaume Pellerin <pellerin@parisson.com>
-#
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-
-from telemeta.core import Interface, TelemetaError
-
-
-class IExporter(Interface):
-    """Export driver interface"""
-
-    # Remark: the method prototypes do not include any self or cls argument 
-    # because an interface is meant to show what methods a class must expose 
-    # from the caller's point of view. However, when implementing the class 
-    # you'll obviously want to include this extra argument.
-
-    def get_format():
-        """Return the export/encoding format as a short string 
-        Example: "MP3", "OGG", "AVI", ...
-        """
-   
-    def get_description():
-        """Return a string describing what this export format provides, is good 
-        for, etc... The description is meant to help the end user decide what 
-        format is good for him/her
-        """
-
-    def get_file_extension():
-        """Return the filename extension corresponding to this export format"""
-
-    def get_mime_type():
-        """Return the mime type corresponding to this export format"""
-
-    def set_cache_dir(path):
-        """Set the directory where cached files should be stored. Does nothing
-        if the exporter doesn't support caching. 
-       
-        The driver shouldn't assume that this method will always get called. A
-        temporary directory should be used if that's not the case.
-        """
-
-    def process(item_id, source, metadata, options=None):
-        """Perform the exporting process and return the absolute path 
-        to the resulting file.
-
-        item_id is the media item id that uniquely identifies this audio/video
-        resource
-
-        source is the audio/video source file absolute path. For audio that
-        should be a WAV file
-
-        metadata is a tuple containing tuples for each descriptor return by
-        the dc.Ressource of the item, in the model order :
-        ((name1, value1),(name2, value2),(name1, value3), ...)
-
-        The returned file path is not meant to be permanent in any way, it 
-        should be considered temporary/volatile by the caller.
-
-        It is highly recommended that export drivers implement some sort of
-        cache instead of re-encoding each time process() is called.
-
-        It should be possible to make subsequent calls to process() with
-        different items, using the same driver instance.
-        """
-
-class ExportProcessError(TelemetaError):
-
-    def __init__(self, message, command, subprocess):
-        self.message = message
-        self.command = str(command)
-        self.subprocess = subprocess
-
-    def __str__(self):
-        if self.subprocess.stderr != None:
-            error = self.subprocess.stderr.read()
-        else:
-            error = ''
-        return "%s ; command: %s; error: %s" % (self.message,
-                                                self.command,
-                                                error)
diff --git a/telemeta/export/core.py b/telemeta/export/core.py
deleted file mode 100644 (file)
index 2b08ff4..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-
-import os
-import re
-import md5
-import string
-import subprocess
-import mutagen
-
-import telemeta.export
-from telemeta.export import *
-from telemeta.core import *
-import xml.dom.minidom
-import xml.dom.ext
-
-class ExporterCore(Component):
-    """Defines the main parts of the exporting tools :
-    paths, metadata parsing, data streaming thru system command"""
-
-    def __init__(self):
-        self.source = ''
-        self.collection = ''
-        self.verbose = ''
-        self.dest = ''
-        self.metadata = []
-        self.cache_dir = 'cache'
-        self.buffer_size = 0xFFFF
-
-    def set_cache_dir(self,path):
-        self.cache_dir = path
-
-    def normalize(self):
-        """ Normalize the source and return its path """
-        args = ''
-        if self.verbose == '0':
-            args = '-q'
-        try:
-            os.system('normalize-audio '+args+' "'+self.source+'"')
-            return self.source
-        except:
-            raise IOError('ExporterError: cannot normalize, path does not exist.')
-
-    def check_md5_key(self):
-        """ Check if the md5 key is OK and return a boolean """
-        try:
-            md5_log = os.popen4('md5sum -c "'+self.dest+ \
-                                '" "'+self.dest+'.md5"')
-            return 'OK' in md5_log.split(':')
-        except IOError:
-            raise IOError('ExporterError: cannot check the md5 key.')
-    
-    def get_file_info(self):
-        """ Return the list of informations of the dest """
-        return self.export.get_file_info()
-
-    def get_wav_length_sec(self) :
-        """ Return the length of the audio source file in seconds """
-        try:
-            file1, file2 = os.popen4('wavinfo "'+self.source+ \
-                                     '" | grep wavDataSize')
-            for line in file2.readlines():
-                line_split = line.split(':')
-                value = int(int(line_split[1])/(4*44100))
-                return value
-        except:
-            raise IOError('ExporterError: cannot get the wav length.')
-
-    def compare_md5_key(self, source, dest):
-        """ Compare source and dest files wih md5 method """
-        f_source = open(source).read()
-        f_dest = open(dest).read()
-        return md5.new(f_source).digest() == md5.new(f_dest).digest()
-
-    def write_metadata_xml(self,path):
-        doc = xml.dom.minidom.Document()
-        root = doc.createElement('telemeta')
-        doc.appendChild(root)
-        for tag in self.metadata.keys() :
-            value = self.metadata[tag]
-            node = doc.createElement(tag)
-            node.setAttribute('value', str(value))
-            #node.setAttribute('type', get_type(value))
-            root.appendChild(node)
-        xml_file = open(path, "w")
-        xml.dom.ext.PrettyPrint(doc, xml_file)
-        xml_file.close()
-
-    def pre_process(self, item_id, source, metadata, ext,
-                    cache_dir, options=None):
-        """ Pre processing : prepare the export path and return it"""
-        self.item_id = str(item_id)
-        self.source = source
-        file_name = get_file_name(self.source)
-        file_name_wo_ext, file_ext = split_file_name(file_name)
-        self.cache_dir = cache_dir
-        self.metadata = metadata
-        #self.collection = self.metadata['Collection']
-        #self.artist = self.metadata['Artist']
-        #self.title = self.metadata['Title']
-
-        # Normalize if demanded
-        if not options is None:
-            self.options = options
-            if 'normalize' in self.options and \
-                self.options['normalize'] == True:
-                self.normalize()
-
-        # Define the export directory
-        self.ext = self.get_file_extension()
-        export_dir = os.path.join(self.cache_dir,self.ext)
-
-        if not os.path.exists(export_dir):
-            export_dir_split = export_dir.split(os.sep)
-            path = os.sep + export_dir_split[0]
-            for _dir in export_dir_split[1:]:
-                path = os.path.join(path,_dir)
-                if not os.path.exists(path):
-                    os.mkdir(path)
-        else:
-            path = export_dir
-
-        # Set the target file
-        target_file = self.item_id+'.'+self.ext
-        dest = os.path.join(path,target_file)
-        return dest
-
-    def core_process(self, command, buffer_size, dest):
-        """Encode and stream audio data through a generator"""
-
-        __chunk = 0
-        file_out = open(dest,'w')
-
-        proc = subprocess.Popen(command.encode('utf-8'),
-                    shell = True,
-                    bufsize = buffer_size,
-                    stdin = subprocess.PIPE,
-                    stdout = subprocess.PIPE,
-                    close_fds = True)
-
-        # Core processing
-        while True:
-            __chunk = proc.stdout.read(buffer_size)
-            status = proc.poll()
-            if status != None and status != 0:
-                raise ExportProcessError('Command failure:', command, proc)
-            if len(__chunk) == 0:
-                break
-            yield __chunk
-            file_out.write(__chunk)
-
-        file_out.close()
-
-    def post_process(self, item_id, source, metadata, ext, 
-                     cache_dir, options=None):
-        """ Post processing : write tags, print infos, etc..."""
-        #self.write_tags()
-        if not options is None:
-            if 'verbose' in self.options and self.options['verbose'] != '0':
-                print self.dest
-                print self.get_file_info()
-
-
-# External functions
-
-def get_type(value):
-    """ Return a String with the type of value """
-    types = {bool : 'bool', int : 'int', str : 'str'}
-    # 'bool' type must be placed *before* 'int' type, otherwise booleans are
-    # detected as integers
-    for type in types.keys():
-        if isinstance(value, type) :
-            return types[type]
-    raise TypeError(str(value) + ' has an unsupported type')
-
-def get_cast(value, type) :
-    """ Return value, casted into type """
-    if type == 'bool' :
-        if value == 'True' :
-            return True
-        return False
-    elif type == 'int' :
-        return int(value)
-    elif type == 'str' :
-        return str(value)
-    raise TypeError(type + ' is an unsupported type')
-
-def get_file_mime_type(path):
-    """ Return the mime type of a file """
-    try:
-        file_out1, file_out2 = os.popen4('file -i "'+path+'"')
-        for line in file_out2.readlines():
-            line_split = line.split(': ')
-            mime = line_split[len(line_split)-1]
-            return mime[:len(mime)-1]
-    except:
-        raise IOError('ExporterError: path does not exist.')
-
-def get_file_type_desc(path):
-    """ Return the type of a file given by the 'file' command """
-    try:
-        file_out1, file_out2 = os.popen4('file "'+path+'"')
-        for line in file_out2.readlines():
-            description = line.split(': ')
-            description = description[1].split(', ')
-            return description
-    except:
-        raise IOError('ExporterError: path does not exist.')
-
-def iswav(path):
-    """ Tell if path is a WAV """
-    try:
-        mime = get_file_mime_type(path)
-        return mime == 'audio/x-wav'
-    except:
-        raise IOError('ExporterError: path does not exist.')
-
-def iswav16(path):
-    """ Tell if path is a 16 bit WAV """
-    try:
-        file_type_desc = get_file_type_desc(path)
-        return iswav(path) and '16 bit' in file_type_desc
-    except:
-        raise IOError('ExporterError: path does not exist.')
-
-def get_file_name(path):
-    """ Return the file name targeted in the path """
-    return os.path.split(path)[1]
-
-def split_file_name(file):
-    """ Return main file name and its extension """
-    try:
-        return os.path.splitext(file)
-    except:
-        raise IOError('ExporterError: path does not exist.')
-
-def clean_word(word) :
-    """ Return the word without excessive blank spaces, underscores and
-    characters causing problem to exporters"""
-    word = re.sub("^[^\w]+","",word)    #trim the beginning
-    word = re.sub("[^\w]+$","",word)    #trim the end
-    word = re.sub("_+","_",word)        #squeeze continuous _ to one _
-    word = re.sub("^[^\w]+","",word)    #trim the beginning _
-    #word = string.replace(word,' ','_')
-    #word = string.capitalize(word)
-    dict = '&[];"*:,'
-    for letter in dict:
-        word = string.replace(word,letter,'_')
-    return word
-
-def recover_par_key(path):
-    """ Recover a file with par2 key """
-    os.system('par2 r "'+path+'"')
-
-def verify_par_key(path):
-    """ Verify a par2 key """
-    os.system('par2 v "'+path+'.par2"')
-
-
diff --git a/telemeta/export/flac.py b/telemeta/export/flac.py
deleted file mode 100644 (file)
index 6282d05..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-
-# Author: Guillaume Pellerin <pellerin@parisson.com>
-
-import os
-import string
-import subprocess
-
-from telemeta.export.core import *
-from telemeta.export.api import IExporter
-from mutagen.flac import FLAC
-from tempfile import NamedTemporaryFile
-
-class FlacExporter(ExporterCore):
-    """Defines methods to export to FLAC"""
-
-    implements(IExporter)
-
-    def __init__(self):
-        self.item_id = ''
-        self.source = ''
-        self.metadata = {}
-        self.options = {}
-        self.description = ''
-        self.dest = ''
-        self.quality_default = '-5'
-        self.info = []
-        self.buffer_size = 0xFFFF
-
-    def get_format(self):
-        return 'FLAC'
-
-    def get_file_extension(self):
-        return 'flac'
-
-    def get_mime_type(self):
-        return 'application/flac'
-
-    def get_description(self):
-        return 'FIXME'
-
-    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('ExporterError: metaflac is not installed or ' + \
-                           'file does not exist.')
-
-    def set_cache_dir(self,path):
-        """Set the directory where cached files should be stored. Does nothing
-        if the exporter doesn't support caching.
-
-        The driver shouldn't assume that this method will always get called. A
-        temporary directory should be used if that's not the case.
-        """
-        self.cache_dir = path
-
-    def decode(self):
-        try:
-            file_name, ext = get_file_name(self.source)
-            dest = self.cache_dir+os.sep+file_name+'.wav'
-            os.system('flac -d -o "'+dest+'" "'+self.source+'"')
-            self.source = dest
-            return dest
-        except:
-            raise IOError('ExporterError: decoder is not compatible.')
-
-    def write_tags(self, file):
-        media = FLAC(file)
-        for tag in self.metadata:
-            name = tag[0]
-            value = clean_word(tag[1])
-            if name == 'COMMENT':
-                media['DESCRIPTION'] = unicode(value)
-            else:
-                media[name] = unicode(value)
-        try:
-            media.save()
-        except:
-            raise IOError('ExporterError: 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, item_id, source, metadata, options=None):
-        self.item_id = item_id
-        self.source = source
-        self.metadata = metadata
-        self.args = self.get_args(options)
-        self.ext = self.get_file_extension()
-        self.args = ' '.join(self.args)
-        self.command = 'sox "%s"  --single-threaded -q -b 16 -t wav -c2 - | flac -c %s - ' % (self.source, self.args)
-
-        # Pre-proccessing
-        self.dest = self.pre_process(self.item_id,
-                                         self.source,
-                                         self.metadata,
-                                         self.ext,
-                                         self.cache_dir,
-                                         self.options)
-
-        # Processing (streaming + cache writing)
-        stream = self.core_process(self.command, self.buffer_size, self.dest)
-
-        for chunk in stream:
-            pass
-
-        self.write_tags(self.dest)
-        file = open(self.dest,'r')
-
-        while True:
-            chunk = file.read(self.buffer_size)
-            if len(chunk) == 0:
-                break
-            yield chunk
-
-        file.close()
-
-        # Post-proccessing
-        #self.post_process(self.item_id,
-                         #self.source,
-                         #self.metadata,
-                         #self.ext,
-                         #self.cache_dir,
-                         #self.options)
-
diff --git a/telemeta/export/mp3.py b/telemeta/export/mp3.py
deleted file mode 100644 (file)
index e5317be..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2007 Parisson SARL
-# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-
-import os
-import string
-import subprocess
-
-from telemeta.export.core import *
-from telemeta.export.api import IExporter
-#from mutagen.id3 import *
-
-
-class Mp3Exporter(ExporterCore):
-    """Defines methods to export to MP3"""
-
-    implements(IExporter)
-
-    def __init__(self):
-        self.item_id = ''
-        self.metadata = {}
-        self.description = ''
-        self.info = []
-        self.source = ''
-        self.dest = ''
-        self.options = {}
-        self.bitrate_default = '192'
-        self.buffer_size = 0xFFFF
-        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
-                             }
-    def get_format(self):
-        return 'MP3'
-
-    def get_file_extension(self):
-        return 'mp3'
-
-    def get_mime_type(self):
-        return 'audio/mpeg'
-
-    def get_description(self):
-        return "FIXME"
-
-    def set_cache_dir(self,path):
-       self.cache_dir = path
-
-    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('ExporterError: file does not exist.')
-
-    def decode(self):
-        try:
-            os.system('sox "'+self.source+'" -s -q -r 44100 -t wav "' \
-                        +self.cache_dir+os.sep+self.item_id+'"')
-            return self.cache_dir+os.sep+self.item_id+'.wav'
-        except:
-            raise IOError('ExporterError: decoder is not compatible.')
-
-    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('ExporterError: cannot tag "'+tag+'"')
-        try:
-            id3.save()
-        except:
-            raise IOError('ExporterError: 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 '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 -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, item_id, source, metadata, options=None):
-        self.item_id = item_id
-        self.source = source
-        self.metadata = metadata
-        self.args = self.get_args(options)
-        self.ext = self.get_file_extension()
-        self.args = ' '.join(self.args)
-        self.command = 'sox "%s" --single-threaded -q -b 16 -t wav - | lame %s -' % (self.source, self.args)
-        #self.command = 'lame %s "%s" -' % (self.args, self.source)
-
-        # Pre-proccessing
-        self.dest = self.pre_process(self.item_id,
-                                         self.source,
-                                         self.metadata,
-                                         self.ext,
-                                         self.cache_dir,
-                                         self.options)
-
-        # Processing (streaming + cache writing)
-        stream = self.core_process(self.command, self.buffer_size, self.dest)
-        for chunk in stream:
-            yield chunk
-
-        # Post-proccessing
-        #self.post_process(self.item_id,
-                         #self.source,
-                         #self.metadata,
-                         #self.ext,
-                         #self.cache_dir,
-                         #self.options)
-
diff --git a/telemeta/export/ogg.py b/telemeta/export/ogg.py
deleted file mode 100644 (file)
index d2328fc..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2007 Parisson
-# Copyright (c) 2006-2009 Guillaume Pellerin <pellerin@parisson.com>
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-
-import os
-import string
-import subprocess
-
-from telemeta.export.core import *
-from telemeta.export.api import IExporter
-from mutagen.oggvorbis import OggVorbis
-
-class OggExporter(ExporterCore):
-    """Defines methods to export to OGG Vorbis"""
-
-    implements(IExporter)
-
-    def __init__(self):
-        self.item_id = ''
-        self.metadata = {}
-        self.description = ''
-        self.info = []
-        self.source = ''
-        self.dest = ''
-        self.options = {}
-        self.bitrate_default = '192'
-        self.buffer_size = 0xFFFF
-        self.dub2args_dict = {'creator': 'artist',
-                             'relation': 'album'
-                             }
-
-    def get_format(self):
-        return 'OGG'
-
-    def get_file_extension(self):
-        return 'ogg'
-
-    def get_mime_type(self):
-        return 'application/ogg'
-
-    def get_description(self):
-        return 'FIXME'
-
-    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('ExporterError: file does not exist.')
-
-    def set_cache_dir(self,path):
-       self.cache_dir = path
-
-    def decode(self):
-        try:
-            os.system('oggdec -o "'+self.cache_dir+os.sep+self.item_id+
-                      '.wav" "'+self.source+'"')
-            return self.cache_dir+os.sep+self.item_id+'.wav'
-        except:
-            raise IOError('ExporterError: decoder is not compatible.')
-
-    def write_tags(self):
-        media = OggVorbis(self.dest)
-        for tag in self.metadata.keys():
-            media[tag] = str(self.metadata[tag])
-        media.save()
-
-    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('-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, item_id, source, metadata, options=None):
-        self.item_id = item_id
-        self.source = source
-        self.metadata = metadata
-        self.args = self.get_args(options)
-        self.ext = self.get_file_extension()
-        self.args = ' '.join(self.args)
-        self.command = 'sox "%s"  --single-threaded -q -b 16 -t wav -c2 - | oggenc %s -' % (self.source, self.args)
-
-        # Pre-proccessing
-        self.dest = self.pre_process(self.item_id,
-                                        self.source,
-                                        self.metadata,
-                                        self.ext,
-                                        self.cache_dir,
-                                        self.options)
-
-        # Processing (streaming + cache writing)
-        stream = self.core_process(self.command, self.buffer_size, self.dest)
-        for chunk in stream:
-            yield chunk
-
-        # Post-proccessing
-        #self.post_process(self.item_id,
-                        #self.source,
-                        #self.metadata,
-                        #self.ext,
-                        #self.cache_dir,
-                        #self.options)
-
diff --git a/telemeta/export/wav.py b/telemeta/export/wav.py
deleted file mode 100644 (file)
index bfad553..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright Guillaume Pellerin, (2006-2009)
-# <yomguy@parisson.com>
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-
-import os
-import string
-
-from telemeta.export.core import *
-from telemeta.export.api import IExporter
-
-class WavExporter(ExporterCore):
-    """Defines methods to export to WAV"""
-
-    implements(IExporter)
-    
-    def __init__(self):
-        self.item_id = ''
-        self.metadata = {}
-        self.description = ''
-        self.info = []
-        self.source = ''
-        self.dest = ''
-        self.options = {}
-        self.buffer_size = 0xFFFF
-
-    def get_format(self):
-        return 'WAV'
-    
-    def get_file_extension(self):
-        return 'wav'
-
-    def get_mime_type(self):
-        return 'audio/x-wav'
-
-    def get_description(self):
-        return 'FIXME'
-
-    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('ExporterError: wavinfo id not installed or file does not exist.')
-
-    def set_cache_dir(self,path):
-        self.cache_dir = path
-
-    def decode(self):
-        try:
-            file_name, ext = get_file_name(self.source)
-            dest = self.cache_dir+os.sep+file_name+'.wav'
-            os.system('sox "'+self.source+'" -s -r 44100 -t wav -c2 "'+ \
-                      dest+'.wav"')
-            self.source = dest
-            return dest
-        except:
-            raise IOError('ExporterError: decoder is not compatible.')
-
-    def write_tags(self):
-        # Create metadata XML file !
-        self.write_metadata_xml(self.dest+'.xml')
-    
-    def create_md5_key(self):
-        """ Create the md5 keys of the dest """
-        try:
-            os.system('md5sum -b "'+self.dest+'" >"'+self.dest+'.md5"')
-        except:
-            raise IOError('ExporterError: cannot create the md5 key.')
-    
-    def create_par_key(self):
-        """ Create the par2 keys of the dest """
-        args = 'c -n1 '
-        if 'verbose' in self.options and self.options['verbose'] != '0':
-            args = args
-        else:
-            args = args + '-q -q '
-
-        try:
-            os.system('par2 '+args+' "'+self.dest+'"')
-        except:
-            raise IOError('ExporterError: cannot create the par2 key.')
-
-    def process(self, item_id, source, metadata, options=None):
-        self.item_id = item_id
-        self.source = source
-        self.metadata = metadata
-        self.options = {}
-
-        if not options is None:
-            self.options = options
-
-        # Pre-proccessing
-        self.ext = self.get_file_extension()
-        self.dest = self.pre_process(self.item_id,
-                                        self.source,
-                                        self.metadata,
-                                        self.ext,
-                                        self.cache_dir,
-                                        self.options)
-
-        # Initializing
-        file_in = open(self.source,'rb')
-        file_out = open(self.dest,'w')
-
-        # Core Processing
-        while True:
-            chunk = file_in.read(self.buffer_size)
-            if len(chunk) == 0:
-                break
-            yield chunk
-            file_out.write(chunk)
-
-        file_in.close()
-        file_out.close()
-
-        # Create the md5 key
-        #if 'md5' in self.metadata and self.metadata['md5']:
-        self.create_md5_key()
-
-        # Create the par2 key
-        #if 'par2' in self.metadata and self.metadata['par2']:
-        #self.create_par_key()
-
-        # Pre-proccessing
-        self.post_process(self.item_id,
-                        self.source,
-                        self.metadata,
-                        self.ext,
-                        self.cache_dir,
-                        self.options)
-
-
-
-            #if self.compare_md5_key():
-            #os.system('cp -a "'+self.source+'" "'+ self.dest+'"')
-            #print 'COPIED'
-
index a86f87827a5dd712d75b0e4f6f8eb9533670e51e..a33c519d9cc7dba1c5e3cb01f12f622e287781bf 100644 (file)
@@ -282,15 +282,7 @@ class MediaItem(MediaResource):
 
     def computed_duration(self):
         "Tell the length in seconds of this item media data"
-        # FIXME: use TimeSide?
-        seconds = 0
-        if self.file:
-            import wave
-            media = wave.open(self.file.path, "rb")
-            seconds = media.getnframes() / media.getframerate()
-            media.close()
-
-        return Duration(seconds=seconds)
+        return self.approx_duration
 
     computed_duration.verbose_name = _('computed duration')        
 
index ea9f7caaf07f5abf643297df3d350b292ae6b1a2..0fb65cb093708cbf54a189df585b481ca56db9ee 100644 (file)
     <li>
         <a href="{% url telemeta-item-detail item.public_id %}"><b>{{item}}</b></a>
         <br />
-        <span class="info">{{item.computed_duration}} {{item.apparent_collector|prepend:' - '}} - {{item.country_or_continent}}</span>
+        <span class="info">{{item.apparent_collector|prepend:' - '}} - {{item.country_or_continent}}</span>
     </li>
     {% endfor %}
     </ul>
-</div>    
+</div>
 {% endblock %}
 
 </div>
index 2e3bb841a3ff3481bba30aa302f8d09bc6d2360e..6249c488ae42fdec054be6c555c4fae8f16447ed 100644 (file)
@@ -22,7 +22,7 @@ soundManager.url = '{% url telemeta-swf "./" %}';
 soundManager.flashVersion = 9;\r
 soundManager.debugMode = false;\r
 set_player_image_url('{% url telemeta-item-visualize item.public_id,visualizer_id,"WIDTH","HEIGHT" %}');\r
-load_player({{ item.computed_duration.as_seconds }});\r
+load_player({{ item.approx_duration.as_seconds }});\r
 </script>\r
 \r
 {% endblock %}\r
@@ -52,10 +52,10 @@ load_player({{ item.computed_duration.as_seconds }});
                 <div class="ts-wave">\r
                     <div class="ts-image-container">\r
                         <a href="{% url telemeta-item-export item.public_id,"mp3" %}">\r
-                        <img class="ts-image" src="{% url telemeta-item-visualize item.public_id,visualizer_id,360,130 %}" \r
+                        <img class="ts-image" src="{% url telemeta-item-visualize item.public_id,visualizer_id,360,130 %}"\r
                           alt="" /></a>\r
                     </div>\r
-                </div>  \r
+                </div>\r
             </div>\r
         </div>\r
         </div>\r
@@ -79,7 +79,7 @@ load_player({{ item.computed_duration.as_seconds }});
                 <input type="submit" value="Set" />\r
             </form>\r
 \r
-          <div class="analyzer">\r
+<!--          <div class="analyzer">\r
             <table width="100%">\r
              <tr class="analyzer-title">\r
               <td>Property</td>\r
@@ -91,7 +91,7 @@ load_player({{ item.computed_duration.as_seconds }});
               <td>\r
                 {{ analyser.name }}\r
               </td>\r
-              <td> \r
+              <td>\r
                 {{ analyser.value }}\r
               </td>\r
               <td>\r
@@ -100,8 +100,8 @@ load_player({{ item.computed_duration.as_seconds }});
             </tr>\r
             {% endfor %}\r
            </table>\r
-         </div>\r
-\r
+         </div>-->\r
+<!--\r
         <form method="get" action="#">\r
             <p>&nbsp;Vamp plugin analysis</p>\r
             <select name="vamp_id">\r
@@ -112,7 +112,7 @@ load_player({{ item.computed_duration.as_seconds }});
             </select>\r
             <input type="submit" value="Get" />\r
         </form>\r
-        \r
+-->\r
         </div>\r
 \r
         {% if audio_export_enabled %}\r
@@ -230,7 +230,6 @@ load_player({{ item.computed_duration.as_seconds }});
                 <dl class="listing">\r
                     <dt>{% trans "Media type" %}</dt><dd>{% trans "Audio" %}</dd>\r
                     {% dl_field item "approx_duration" %}\r
-                    {% dl_field item "computed_duration" %}\r
                 </dl>\r
             </div>\r
         </div>\r
index 336205cd5878d0af612d15189d1ed980b5f540c8..3fc26b3949ccf811ddbe12ded38a6eb288eed1ec 100644 (file)
@@ -36,7 +36,7 @@
 
 from django.conf.urls.defaults import *
 from telemeta.models import MediaItem, MediaCollection
-from telemeta.core import ComponentManager
+#from telemeta.core import ComponentManager
 from telemeta.web import WebView
 import os.path
 import telemeta.config
@@ -44,8 +44,8 @@ import telemeta.config
 telemeta.config.check()
 
 # initialization
-comp_mgr = ComponentManager()
-web_view = WebView(comp_mgr)
+#comp_mgr = ComponentManager()
+web_view = WebView()
 
 # query sets for Django generic views
 all_items = { 'queryset': MediaItem.objects.enriched(), }
diff --git a/telemeta/visualization/__init__.py b/telemeta/visualization/__init__.py
deleted file mode 100644 (file)
index 7b46c19..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-from telemeta.visualization.api import *
-from telemeta.visualization.waveform_audiolab import *
-from telemeta.visualization.spectrogram_audiolab import *
-from telemeta.visualization.spectrogram_octave import *
diff --git a/telemeta/visualization/api.py b/telemeta/visualization/api.py
deleted file mode 100644 (file)
index aa7b4e9..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2007 Samalyse SARL
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Olivier Guilyardi <olivier@samalyse.com>
-
-from telemeta.core import *
-
-class IMediaItemVisualizer(Interface):
-    """Media item visualizer driver interface"""
-
-    def get_id():
-        """Return a short id alphanumeric, lower-case string."""
-
-    def get_name():
-        """Return the visualization name, such as "Waveform", "Spectral view",
-        etc..
-        """
-
-    def set_colors(self, background=None, scheme=None):
-        """Set the colors used for image generation. background is a RGB tuple, 
-        and scheme a a predefined color theme name"""
-        pass
-
-    def render(media_item, width=None, height=None, options=None):
-        """Generator that streams the visualization output as a PNG image"""
diff --git a/telemeta/visualization/octave/jet.m b/telemeta/visualization/octave/jet.m
deleted file mode 100644 (file)
index ba9f742..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-function J = jet(m)
-%JET    Variant of HSV
-%   JET(M), a variant of HSV(M), is an M-by-3 matrix containing
-%   the default colormap used by CONTOUR, SURF and PCOLOR.
-%   The colors begin with dark blue, range through shades of
-%   blue, cyan, green, yellow and red, and end with dark red.
-%   JET, by itself, is the same length as the current figure's
-%   colormap. If no figure exists, MATLAB creates one.
-%
-%   See also HSV, HOT, PINK, FLAG, COLORMAP, RGBPLOT.
-
-%   Copyright 1984-2004 The MathWorks, Inc.
-%   $Revision: 5.7.4.2 $  $Date: 2005/06/21 19:31:40 $
-
-if nargin < 1
-   m = size(get(gcf,'colormap'),1);
-end
-n = ceil(m/4);
-u = [(1:1:n)/n ones(1,n-1) (n:-1:1)/n]';
-g = ceil(n/2) - (mod(m,4)==1) + (1:length(u))';
-r = g + n;
-b = g - n;
-g(g>m) = [];
-r(r>m) = [];
-b(b<1) = [];
-J = zeros(m,3);
-J(r,1) = u(1:length(r));
-J(g,2) = u(1:length(g));
-J(b,3) = u(end-length(b)+1:end);
\ No newline at end of file
diff --git a/telemeta/visualization/octave/spectrogram.m b/telemeta/visualization/octave/spectrogram.m
deleted file mode 100644 (file)
index 3b9e071..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-## Copyright (C) 2000 Paul Kienzle
-##
-## This program is free software and may be used for any purpose.  This
-## copyright notice must be maintained. Paul Kienzle is not responsible
-## for the consequences of using this software.
-
-## usage: [S, f, t] = spectrogram(x, Fs, window, step, maxF, shape, minE)
-##
-## Generate a spectrogram for the signal. This chops the signal into
-## overlapping slices, windows each slice and applies a Fourier
-## transform to determine the frequency components at that slice. 
-##
-## x:      signal to analyse
-## Fs:     sampling rate for the signal
-## window: analysis window length (default 30 msec)
-## step:   time between windows, start to start (default 5 ms)
-## maxF:   maximum frequency to display (default 4000 Hz)
-##    Alternatively, use [maxF, nF], where nF is the minimum
-##    of frequency points to display.  If nF is greater than
-##    what it would normally be for the given window size and
-##    maximum displayed frequency, the FFT is zero-padded until
-##    it at least nF points are displayed on the y axis.
-## shape:  window analysis function (default 'hanning')
-##    Shape is any function which takes an integer n and returns
-##    a vector of length n.  If shape contains %d and ends with
-##    ')', as for example '(1:%d)' or 'kaiser(%d,0.5)' do, then 
-##    %d is replaced with the desired window length, and the
-##    expression is evaluated.
-## minE:   noise floor (default -40dB)
-##    Any value less than the noise floor is clipped before the
-##    spectrogram is displayed.  This limits the dynamic range
-##    that your spectrogram must accomodate.  Alternatively,
-##    use [minE, maxE], where maxE is the clipping ceiling, also
-##    in decibels.
-##
-## Return values
-##    S is the spectrogram in S with linear magnitude normalized to 1.
-##    f is the frequency indices corresponding to the rows of S.
-##    t is the time indices corresponding to the columns of S.
-##    If no return value is requested, the spectrogram is displayed instead.
-##
-## Global variables
-##    spectrogram_{window,step,maxF,nF,shape,minE,maxE} can override
-##    the default values with your own.
-##
-## To make a good spectrogram, generating spectral slices is only half
-## the problem.  Before you generate them, you must first choose your
-## window size, step size and FFT size.  A wide window shows more
-## harmonic detail, a narrow window shows more formant structure.  This
-## defines your time-frequency resolution. Step size controls the
-## horizontal scale of the spectrogram. Decrease it to stretch, or
-## increase it to compress. Certainly, increasing step size will reduce
-## time resolution, but decreasing it will not improve it much beyond
-## the limits imposed by the window size (you do gain a little bit,
-## depending on the shape of your window, as the peak of the window
-## slides over peaks in the signal energy).  The range 1-5 msec is good
-## for speech. Finally, FFT length controls the vertical scale, with
-## larger values stretching the frequency range.  Clearly, padding with
-## zeros does not add any information to the spectrum, but it is a
-## cheap, easy and good way to interpolate between frequency points, and
-## can make for prettier spectrograms.
-##
-## After you have generated the spectral slices, there are a number of
-## decisions for displaying them.  Firstly, the entire frequency range
-## does not need to be displayed.  The frequency range of the FFT is
-## determined by sampling rate.  If most of your signal is below 4 kHz
-## (in speech for example), there is no reason to display up to the
-## Nyquist frequency of 10 kHz for a 20 kHz sampling rate.  Next, there
-## is the dynamic range of the signal.  Since the information in speech
-## is well above the noise floor, it makes sense to eliminate any
-## dynamic range at the bottom end.  This is done by taking the max of
-## the normalized magnitude and some lower limit such as -40 dB.
-## Similarly, there is not much information in the very top of the
-## range, so clipping to -3 dB makes sense there. Finally, there is the
-## choice of colormap.  A brightness varying colormap such as copper or
-## bone gives good shape to the ridges and valleys.  A hue varying
-## colormap such as jet or hsv gives an indication of the steepness of
-## the slopes.
-
-## TODO: Accept vector of frequencies at which to sample the signal.
-## TODO: Consider accepting maxF (values > 0), shape (value is string)
-## TODO:    and dynamic range (values <= 0) in any order.
-## TODO: Consider defaulting step and maxF so that the spectrogram is
-## TODO:    an appropriate size for the screen (eg, 600x100).
-## TODO: Consider drawing in frequency/time grid; 
-## TODO:    (necessary with automatic sizing as suggested above)
-## TODO: Consider using step vs. [nT, nF] rather than maxF vs [maxF, nF]
-## TODO: Figure out why exist() is so slow: 50 ms vs 1 ms for lookup. 
-
-function [S_r, f_r, t_r] = spectrogram(x, Fs, window, step, maxF, shape, minE)
-  global spectrogram_window=30;
-  global spectrogram_step=5;
-  global spectrogram_maxF=4000;
-  global spectrogram_shape="hanning";
-  global spectrogram_minE=-40;
-  global spectrogram_maxE=0;
-  global spectrogram_nF=[];
-
-  if nargin < 2 || nargin > 7
-    usage ("[S, f, t] = spectrogram(x, fs, window, step, maxF, shape, minE)");
-  end
-
-  if nargin<3 || isempty(window), 
-    window=spectrogram_window; 
-  endif
-  if nargin<4 || isempty(step), 
-    step=spectrogram_step; 
-  endif
-  if nargin<5 || isempty(maxF), 
-    maxF=spectrogram_maxF; 
-  endif
-  if nargin<6 || isempty(shape), 
-    shape=spectrogram_shape;
-  endif
-  if nargin<7 || isempty(minE), 
-    minE=spectrogram_minE; 
-  endif
-  if any(minE>0)
-    error ("spectrogram clipping range must use values less than 0 dB");
-  endif
-  if length(minE)>1,
-    maxE=minE(2); 
-    minE=minE(1); 
-  else
-    maxE = spectrogram_maxE;
-  endif
-  if length(maxF)>1,
-    min_nF=maxF(2);
-    maxF=maxF(1);
-  else
-    min_nF=spectrogram_nF;
-  endif
-
-  ## make sure x is a column vector
-  if size(x,2) != 1 && size(x,1) != 1
-    error ("spectrogram data must be a vector");
-  end
-  if size(x,2) != 1, x = x'; end
-
-  if (maxF>Fs/2)
-    ## warning("spectrogram: cannot display frequencies greater than Fs/2");
-    maxF = Fs/2;
-  endif
-
-  step_n = fix(step*Fs/1000);    # one spectral slice every step ms
-
-  ## generate window from duration and shape function name
-  win_n = fix(window*Fs/1000);
-  if shape(length(shape)) == ')' 
-    shape = sprintf(shape, win_n);
-  else
-    shape = sprintf("%s(%d)", shape, win_n);
-  endif
-  win_vec = eval(strcat(shape,";"));
-  if size(win_vec,2) != 1, win_vec = win_vec'; endif
-  if size(win_vec,2) != 1 || size(win_vec,1) != win_n,
-    error("spectrogram %s did not return a window of length %d", \
-         shape, win_n);
-  endif
-         
-  ## FFT length from size of window and number of freq. pts requested
-  fft_n = 2^nextpow2(win_n);    # next highest power of 2
-  dF = Fs/fft_n;                # freq. step with current fft_n
-  nF = ceil(maxF(1)/dF);        # freq. pts with current fft_n,maxF
-  if !isempty(min_nF)           # make sure there are at least n freq. pts
-    if min_nF > nF,             # if not enough
-      dF = maxF/min_nF;            # figure out what freq. step we need
-      fft_n = 2^nextpow2(Fs/dF);   # figure out what fft_n this requires
-      dF = Fs/fft_n;               # freq. step with new fft_n
-      nF = ceil(maxF/dF);          # freq. pts with new fft_n,maxF
-    endif
-  endif
-
-  ## build matrix of windowed data slices
-  offset = 1:step_n:length(x)-win_n;
-  S = zeros (fft_n, length(offset));
-  for i=1:length(offset)
-    S(1:win_n, i) = x(offset(i):offset(i)+win_n-1) .* win_vec;
-  endfor
-
-  ## compute fourier transform
-  S = fft (S);
-  S = abs(S(1:nF,:));        # select the desired frequencies
-  S = S/max(S(:));           # normalize magnitude so that max is 0 dB.
-  S = max(S, 10^(minE/10));  # clip below minF dB.
-  S = min(S, 10^(maxE/10));  # clip above maxF dB.
-
-  f = [0:nF-1]*Fs/fft_n;
-  t = offset/Fs;
-  if nargout==0
-    imagesc(f,t,20*log10(flipud(S)));
-  else
-    S_r = S;
-    f_r = f;
-    t_r = t;
-  endif
-
-endfunction
\ No newline at end of file
diff --git a/telemeta/visualization/octave/spectrogram2img.m b/telemeta/visualization/octave/spectrogram2img.m
deleted file mode 100644 (file)
index 74b1309..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-# Author: Guillaume Pellerin <pellerin@parisson.com>
-#
-# SpectrogramVisualizer2.m
-#
-# Depends: octave2.9, octave2.9-forge, spectrogram.m, xloadimage, imagemagick
-
-clear all;
-close all;
-
-dest_image = $IMGFILE;
-wav_file = $WAVFILE;
-octave_path = $OCTAVEPATH;
-
-cd(octave_path);
-ncmap = 128; % number of points for colormap
-step = 6;   % spectral slice period (ms)
-% step_length = fix(5*Fs/1000);
-window = 30;   % filter window (ms)
-% window = fix(40*Fs/1000);
-time_limit = 30; % length limit of the displayed sample (s)
-
-[x, Fs] = wavread(wav_file);
-x = x(:,1);  % mono
-lx = length(x);
-
-% LIMITING time
-lx_lim = Fs.*time_limit;
-if lx > lx_lim;
- x = x(1:lx_lim);
-end
-    
-%fftn = 2^nextpow2(window); % next highest power of 2
-[S, f, t] = spectrogram(x, Fs, window, step, 8000, 'hanning', -30);
-S = flipud(20*log10(S));
-%  
-%  cmap = [0:1:ncmap-1];
-%  map_cos = cos(cmap*3.141/(2*ncmap));
-%  map_lin = cmap./ncmap;
-%  map_one = ones(1,ncmap);
-%
-%  cmap = [ [map_cos]' [map_cos]' [fliplr(map_cos)]' ];
-%  colormap(jet(ncmap));
-cmap = colormap(jet(ncmap));
-
-img = imagesc(t, f, S);
-saveimage(dest_image, img, 'ppm', cmap);
-
-quit;
-
diff --git a/telemeta/visualization/octave/waveform2img.m b/telemeta/visualization/octave/waveform2img.m
deleted file mode 100644 (file)
index 936dee3..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <pellerin@parisson.com>
-#
-# SpectrogramVisualizer2.m
-#
-# Depends: octave2.9, octave2.9-forge
-
-clear all;
-close all;
-
-dest_image = $IMGFILE;
-wav_file = $WAVFILE;
-octave_path = $OCTAVEPATH;
-
-cd(octave_path);
-ncmap = 128; % number of points for colormap
-step = 6;   % spectral slice period (ms)
-% step_length = fix(5*Fs/1000);
-window = 30;   % filter window (ms)
-% window = fix(40*Fs/1000);
-time_limit = 300; % length limit of the displayed sample (s)
-% Downsampling factor
-D = 100;
-
-% Read audio data
-[x, Fs] = wavread(wav_file);
-x = x(:,1);  % mono
-lx = length(x);
-
-% LIMITING time
-lx_lim = Fs.*time_limit;
-if lx > lx_lim;
- x = x(1:lx_lim);
-end
-N = length(x);
-
-% Downsampling by D
-t = 1:1:lx;
-t = (t-1)./Fs;
-x2(1:ceil(N/D)) = x(1:D:N);
-t2(1:ceil(N/D)) = t(1:D:N);
-%x(ceil(N/D)+1:N) = zeros(1,N-ceil(N/D));
-
-img = plot(t2,x2);
-print(dest_image, '-dpng');
-
-quit;
-
diff --git a/telemeta/visualization/octave_core.py b/telemeta/visualization/octave_core.py
deleted file mode 100644 (file)
index 788860f..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-from telemeta.core import *
-#from telemeta.visualization.api import IMediaItemVisualizer
-from django.conf import settings
-from tempfile import NamedTemporaryFile
-import os
-import random
-import subprocess
-import signal
-import time
-
-class OctaveCoreVisualizer(Component):
-    """Parent class for Octave visualization drivers"""
-
-    def get_mFile_line(self):
-        octave_path = os.path.dirname(__file__) + '/octave/'
-        mFile_path = os.path.dirname(__file__) + '/octave/' + self.mFile
-        mFile = open(mFile_path,'r')
-        
-        for line in mFile.readlines():
-            if '$OCTAVEPATH' in line:
-                line = line.replace('$OCTAVEPATH','"'+octave_path+'"')
-            if '$WAVFILE' in line:
-                line = line.replace('$WAVFILE','"'+self.wavFile_path+'"')
-            if '$IMGFILE' in line:
-                line = line.replace('$IMGFILE','"'+self.ppmFile.name+'"')
-            yield line
-            
-        mFile.close()
-
-    def set_m_file(self,mFile):
-        self.mFile = mFile
-
-    def get_wav_path(self, media_item):
-        self.wavFile_path = media_item.file.path
-        
-    def octave_to_png_stream(self, media_item):
-        self.buffer_size = 0xFFFF
-        self.trans_type = 'ppm'
-        self.mat_type = 'm'
-        self.ppmFile = NamedTemporaryFile(suffix='.'+self.trans_type)
-        self.wavFile = self.get_wav_path(media_item)
-        mFile_tmp = NamedTemporaryFile(suffix='.'+self.mat_type)
-        mFile_name = mFile_tmp.name
-        mFile_tmp.close()
-        mFile_tmp = open(mFile_name,'w')
-        self.pngFile = NamedTemporaryFile(suffix='.png')
-        command = ['octave', mFile_name]
-
-        for line in self.get_mFile_line():
-            mFile_tmp.write(line)
-        mFile_tmp.close()
-
-        # Compute
-        proc = subprocess.Popen(command, stdout = subprocess.PIPE)               
-        proc.wait()
-        
-        # Convert
-        os.system('convert ' + self.ppmFile.name + \
-                  ' -scale x250 ' + self.pngFile.name)
-        
-        # Stream
-        while True:
-            buffer = self.pngFile.read(self.buffer_size)
-            if len(buffer) == 0:
-                break
-            yield buffer
-
-        self.ppmFile.close()
-        self.pngFile.close()
-        os.remove(mFile_name)
-        
-        
diff --git a/telemeta/visualization/old/spectrogram.py b/telemeta/visualization/old/spectrogram.py
deleted file mode 100644 (file)
index f4f0bfc..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2007 Samalyse SARL
-# All rights reserved.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution. The terms
-# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
-#
-# Author: Olivier Guilyardi <olivier@samalyse.com>
-
-from telemeta.core import *
-from telemeta.visualization.api import IMediaItemVisualizer
-from telemeta.visualization.snack_core import SnackCoreVisualizer
-
-class SpectrogramVisualizer(SnackCoreVisualizer):
-    """Spectral view visualization driver"""
-
-    implements(IMediaItemVisualizer)
-
-    # possible alternative:
-    # http://jokosher.python-hosting.com/file/jokosher-extra/Waveform.py
-
-    def get_id(self):
-        return "spectrogram"
-
-    def get_name(self):
-        return "Spectrogram 1"
-    
-    def set_colors(self, background=None, scheme=None):
-        pass
-
-    def render(self, media_item, options=None):
-        """Generator that streams the spectral view as a PNG image"""
-
-        canvas = self.get_snack_canvas()
-        snd = self.get_snack_sound(media_item)
-
-        canvas.create_spectrogram(0, 10, sound=snd, height=180, width=300 ,
-            windowtype="hamming", fftlength=1024, topfrequency=5000, channel="all", winlength=64)
-
-        stream = self.canvas_to_png_stream(canvas)
-
-        return stream
-        
-
-
-
-
-        
-
-            
diff --git a/telemeta/visualization/old/spectrogram3.py b/telemeta/visualization/old/spectrogram3.py
deleted file mode 100644 (file)
index f970e47..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (C) 2008 Parisson SARL
-# All rights reserved.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution. The terms
-# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
-#
-# Author: Guillaume Pellerin <pellerin@parisson.com>
-
-from telemeta.core import *
-from telemeta.visualization.api import IMediaItemVisualizer
-from django.conf import settings
-from tempfile import NamedTemporaryFile
-from telemeta.visualization.wav2png import *
-
-class SpectrogramVisualizer3(Component):
-    """Spectrogram visualization driver (python style)"""
-
-    implements(IMediaItemVisualizer)
-
-    bg_color = None
-    color_scheme = None
-
-    def get_id(self):
-        return "spectrogram3"
-
-    def get_name(self):
-        return "Spectrogram (audiolab)"
-    
-    def set_colors(self, background=None, scheme=None):
-        self.bg_color = background
-        self.color_scheme = scheme
-
-    def render(self, media_item, width=None, height=None, options=None):
-        """Generator that streams the spectrogram as a PNG image with a python method"""
-
-        wav_file = media_item.file.path
-        pngFile = NamedTemporaryFile(suffix='.png')
-
-        if not width == None:
-            image_width = width
-        else:
-            image_width = 305
-        if not height == None:
-            image_height = height
-        else:
-            image_height = 150
-            
-        fft_size = 2048
-        args = (wav_file, pngFile.name, image_width, image_height, fft_size, 
-                self.bg_color, self.color_scheme)
-        create_spectrogram_png(*args)
-
-        buffer = pngFile.read(0xFFFF)
-        while buffer:
-            yield buffer
-            buffer = pngFile.read(0xFFFF)
-
-        pngFile.close()
diff --git a/telemeta/visualization/old/waveform.py b/telemeta/visualization/old/waveform.py
deleted file mode 100644 (file)
index c645c5e..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright (C) 2007 Samalyse SARL
-# All rights reserved.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution. The terms
-# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
-#
-# Author: Olivier Guilyardi <olivier@samalyse.com>
-
-from telemeta.core import *
-from telemeta.visualization.api import IMediaItemVisualizer
-from django.conf import settings
-from tempfile import NamedTemporaryFile
-import os
-import os.path
-
-class WaveFormVisualizer(Component):
-    """WaveForm visualization driver"""
-
-    implements(IMediaItemVisualizer)
-
-    # possible alternative:
-    # http://jokosher.python-hosting.com/file/jokosher-extra/Waveform.py
-
-    def get_id(self):
-        return "waveform_first"
-
-    def get_name(self):
-        return "Waveform (wav2png.c)"
-    
-    def set_colors(self, background=None, scheme=None):
-        pass
-
-    def render(self, media_item, options=None):
-        """Generator that streams the waveform as a PNG image"""
-
-        pngFile = NamedTemporaryFile(suffix='.png')
-        wav2png = os.path.dirname(__file__) + '/wav2png/wav2png'
-        args  = "-i " + media_item.file.path + " "
-        args += "-o " + pngFile.name + " "
-        args += "-b ffffff "
-        args += "-l 000088 "
-        args += "-z 990000 "
-        args += "-w 300 "
-        args += "-h 151 "
-       
-        os.system(wav2png + " " + args)
-
-        buffer = pngFile.read(0xFFFF)
-        while buffer:
-            yield buffer
-            buffer = pngFile.read(0xFFFF)
-
-        pngFile.close()            
-
diff --git a/telemeta/visualization/old/waveform2.py b/telemeta/visualization/old/waveform2.py
deleted file mode 100644 (file)
index 83a67aa..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2007 Samalyse SARL
-# All rights reserved.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution. The terms
-# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
-#
-# Authors: Olivier Guilyardi <olivier@samalyse.com>
-#          Guillaume Pellerin <pellerin@parisson.com>
-
-from telemeta.core import *
-from telemeta.visualization.api import IMediaItemVisualizer
-from telemeta.visualization.octave_core import OctaveCoreVisualizer
-
-class WaveformVisualizer2(OctaveCoreVisualizer):
-    """Octave temporal view visualization driver"""
-    
-    implements(IMediaItemVisualizer)
-
-    def __init__(self):
-        self.set_m_file('waveform2img.m')
-        self.buffer_size = 0xFFFF
-        self.trans_type = 'png'
-        
-    def get_id(self):
-        return "waveform_octave"
-
-    def get_name(self):
-        return "Waveform (octave)"
-    
-    def set_colors(self, background=None, scheme=None):
-        pass
-
-    def render(self, media_item, options=None):
-        """Generator that streams the temporal view as a PNG image"""
-
-        stream = self.octave_to_png_stream(media_item)
-        for chunk in stream:
-            yield chunk
-            
-        
diff --git a/telemeta/visualization/old/waveform4.py b/telemeta/visualization/old/waveform4.py
deleted file mode 100644 (file)
index 93d9b57..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (C) 2008 Parisson SARL
-# All rights reserved.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution. The terms
-# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
-#
-# Author: Guillaume Pellerin <pellerin@parisson.com>
-
-from telemeta.core import *
-from telemeta.visualization.api import IMediaItemVisualizer
-from django.conf import settings
-from tempfile import NamedTemporaryFile
-from telemeta.visualization.wav2png import *
-
-class WaveFormVisualizer(Component):
-    """WaveForm visualization driver (python style)"""
-
-    implements(IMediaItemVisualizer)
-
-    bg_color = None
-    color_scheme = None
-
-    def get_id(self):
-        return "waveform4"
-
-    def get_name(self):
-        return "Waveform (audiolab large)"
-
-    def set_colors(self, background=None, scheme=None):
-        self.bg_color = background
-        self.color_scheme = scheme
-
-    def render(self, media_item, width=None, height=None, options=None):
-        """Generator that streams the waveform as a PNG image with a python method"""
-
-        wav_file = media_item.file.path
-        pngFile = NamedTemporaryFile(suffix='.png')
-
-        if not width == None:
-            image_width = width
-        else:
-            image_width = 1800
-        if not height == None:
-            image_height = height
-        else:
-            image_height = 300
-
-        fft_size = 2048
-        args = (wav_file, pngFile.name, image_width, image_height, fft_size, self.bg_color, self.color_scheme)
-        create_wavform_png(*args)
-
-        buffer = pngFile.read(0xFFFF)
-        while buffer:
-            yield buffer
-            buffer = pngFile.read(0xFFFF)
-
-        pngFile.close()
-
diff --git a/telemeta/visualization/snack_core.py b/telemeta/visualization/snack_core.py
deleted file mode 100644 (file)
index 1232d88..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-
-from telemeta.core import *
-from telemeta.visualization.api import IMediaItemVisualizer
-from django.conf import settings
-from Tkinter import Tk
-import tkSnack
-from tempfile import NamedTemporaryFile
-import os
-import random
-
-class SnackCoreVisualizer(Component):
-    """Parent class for tkSnack-based visualization drivers"""
-
-    def get_snack_canvas(self):
-        #id = "telemeta" + str(random.randrange(0,1000000))
-        #self.tk_root = Tk(baseName=id)
-        self.tk_root = Tk()
-        tkSnack.initializeSnack(self.tk_root)
-        canvas = tkSnack.SnackCanvas(height=200)
-        canvas.pack()
-        return canvas
-
-    def get_snack_sound(self, media_item):        
-        self.snd = tkSnack.Sound()
-        self.snd.read(media_item.file.path)
-        return self.snd
-        
-    def canvas_to_png_stream(self, canvas):
-
-        psFile = NamedTemporaryFile(suffix='.ps')
-        canvas.postscript({'file': psFile.name, 'height': 200, 'width': 300})
-        pngFile = NamedTemporaryFile(suffix='.png')
-        os.system('convert -resize 300x200 ' + psFile.name + ' ' + pngFile.name)
-        psFile.close()
-
-        buffer = pngFile.read(0xFFFF)
-        while buffer:
-            yield buffer
-            buffer = pngFile.read(0xFFFF)
-
-        pngFile.close()            
-        self.cleanup()
-
-    def cleanup(self): 
-        self.snd.destroy()
-        self.tk_root.destroy()
-
diff --git a/telemeta/visualization/spectrogram_audiolab.py b/telemeta/visualization/spectrogram_audiolab.py
deleted file mode 100644 (file)
index 0b07b47..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson SARL
-
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <pellerin@parisson.com>
-
-from telemeta.core import *
-from telemeta.visualization.api import IMediaItemVisualizer
-from django.conf import settings
-from tempfile import NamedTemporaryFile
-from telemeta.visualization.wav2png import *
-
-class SpectrogramVisualizerAudiolab(Component):
-    """Spectrogram visualization driver (python style thanks to wav2png.py and scikits.audiolab)"""
-
-    implements(IMediaItemVisualizer)
-
-    bg_color = None
-    color_scheme = None
-
-    def get_id(self):
-        return "spectrogram_audiolab"
-
-    def get_name(self):
-        return "Spectrogram (audiolab)"
-    
-    def set_colors(self, background=None, scheme=None):
-        self.bg_color = background
-        self.color_scheme = scheme
-
-    def render(self, media_item, width=None, height=None, options=None):
-        """Generator that streams the spectrogram as a PNG image with a python method"""
-
-        wav_file = media_item.file.path
-        pngFile = NamedTemporaryFile(suffix='.png')
-
-        if not width == None:
-            image_width = width
-        else:
-            image_width = 1500
-        if not height == None:
-            image_height = height
-        else:
-            image_height = 200
-            
-        fft_size = 2048
-        args = (wav_file, pngFile.name, image_width, image_height, fft_size, 
-                self.bg_color, self.color_scheme)
-        create_spectrogram_png(*args)
-
-        buffer = pngFile.read(0xFFFF)
-        while buffer:
-            yield buffer
-            buffer = pngFile.read(0xFFFF)
-
-        pngFile.close()
diff --git a/telemeta/visualization/spectrogram_octave.py b/telemeta/visualization/spectrogram_octave.py
deleted file mode 100644 (file)
index 8a5c24b..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2007 Samalyse SARL
-# Copyright (c) 2007-2009 Guillaume Pellerin <yomguy@parisson.com>
-#
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Authors: Olivier Guilyardi <olivier@samalyse.com>
-#          Guillaume Pellerin <pellerin@parisson.com>
-
-from telemeta.core import *
-from telemeta.visualization.api import IMediaItemVisualizer
-from telemeta.visualization.octave_core import OctaveCoreVisualizer
-
-class SpectrogramVisualizerOctave(OctaveCoreVisualizer):
-    """Octave spectral view visualization driver"""
-    
-    implements(IMediaItemVisualizer)
-
-    def __init__(self):
-        self.set_m_file('spectrogram2img.m')
-        
-    def get_id(self):
-        return "spectrogram_octave"
-
-    def get_name(self):
-        return "Spectrogram (octave)"
-
-    def set_colors(self, background=None, scheme=None):
-        pass
-    
-    def render(self, media_item, width=None, height=None, options=None):
-        """Generator that streams the spectral view as a PNG image"""
-
-        stream = self.octave_to_png_stream(media_item)
-        for chunk in stream:
-            yield chunk
-
diff --git a/telemeta/visualization/tkSnack.py b/telemeta/visualization/tkSnack.py
deleted file mode 100755 (executable)
index 5fde35a..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-"""
-tkSnack
-An interface to Kare Sjolander's Snack Tcl extension
-http://www.speech.kth.se/snack/index.html
-
-by Kevin Russell and Kare Sjolander
-last modified: Mar 28, 2003
-"""
-
-import Tkinter
-import types
-import string
-
-Tkroot = None
-audio = None
-mixer = None
-
-def initializeSnack(newroot):
-    global Tkroot, audio, mixer
-    Tkroot = newroot
-    Tkroot.tk.call('eval', 'package require snack')
-    Tkroot.tk.call('snack::createIcons')
-    Tkroot.tk.call('snack::setUseOldObjAPI')
-    audio = AudioControllerSingleton()
-    mixer = MixerControllerSingleton()
-
-
-def _cast(astring):
-    """This function tries to convert a string returned by a Tcl call
-    to a Python integer or float, if possible, and otherwise passes on the
-    raw string (or None instead of an empty string)."""
-    try:
-        return int(astring)
-    except ValueError:
-        try:
-            return float(astring)
-        except ValueError:
-            if astring:
-                return astring
-            else:
-                return None
-
-
-class NotImplementedException(Exception):
-    pass
-
-
-class TkObject:
-    """A mixin class for various Python/Tk communication functions,
-    such as reading and setting the object's configuration options.
-    We put them in a mixin class so we don't have to keep repeating
-    them for sounds, filters, and spectrograms.
-    These are mostly copied from the Tkinter.Misc class."""
-
-    def _getboolean(self, astring):
-        if astring:
-            return self.tk.getboolean(astring)
-
-    def _getints(self, astring):
-        if astring:
-            return tuple(map(int, self.tk.splitlist(astring)))
-
-    def _getdoubles(self, astring):
-        if astring:
-            return tuple(map(float, self.tk.splitlist(astring)))
-
-    def _options(self, cnf, kw=None):
-        if kw:
-            cnf = Tkinter._cnfmerge((cnf, kw))
-        else:
-            cnf = Tkinter._cnfmerge(cnf)
-        res = ()
-        for k,v in cnf.items():
-            if v is not None:
-                if k[-1] == '_': k = k[:-1]
-                #if callable(v):
-                #    v = self._register(v)
-                res = res + ('-'+k, v)
-        return res
-
-    def configure(self, cnf=None, **kw):
-        self._configure(cnf, kw)
-
-    def _configure(self, cnf=None, kw={}):
-        if kw:
-            cnf = Tkinter._cnfmerge((cnf, kw))
-        elif cnf:
-            cnf = Tkinter._cnfmerge(cnf)
-        if cnf is None:
-            cnf = {}
-            for x in self.tk.split(
-                self.tk.call(self.name, 'configure')):
-                cnf[x[0][1:]] = (x[0][1:],) + x[1:]
-                return cnf
-        if type(cnf) is types.StringType:
-            x = self.tk.split(self.tk.call(self.name, 'configure', '-'+cnf))
-            return (x[0][1:],) + x[1:]
-        self.tk.call((self.name, 'configure') + self._options(cnf))
-    config = configure
-
-    def cget(self, key):
-        return _cast(self.tk.call(self.name, 'cget' , '-'+key))    
-    
-    # Set "cget" as the method to handle dictionary-like attribute access
-    __getitem__ = cget
-
-    def __setitem__(self, key, value):
-        self.configure({key: value})
-
-    def keys(self):
-        return map(lambda x: x[0][1:],
-                   self.tk.split(self.tk.call(self.name, 'configure')))
-
-    def __str__(self):
-        return self.name
-
-
-
-class Sound (TkObject):
-    
-    def __init__(self, name=None, master=None, **kw):
-        self.name = None
-        if not master:
-            if Tkroot:
-                master = Tkroot
-            else:
-                raise RuntimeError, \
-                      'Tk not intialized or not registered with Snack'
-        self.tk = master.tk
-        if not name:
-            self.name = self.tk.call(('sound',) + self._options(kw))
-        else:
-            self.name = self.tk.call(('sound', name) + self._options(kw))
-        #self._configure(cnf, kw)
-        
-    def append(self, binarydata, **kw):
-        """Appends binary string data to the end of the sound."""
-        self.tk.call((self.name, 'append', binarydata) + self._options(kw))
-     
-    def concatenate(self, othersound):
-        """Concatenates the sample data from othersound to the end of
-        this sound.  Both sounds must be of the same type."""
-        self.tk.call(self.name, 'concatenate', othersound.name)
-        
-    def configure(self, **kw):
-        """The configure command is used to set options for a sound."""
-        self.tk.call((self.name, 'configure') + self._options(kw))
-
-    def copy(self, sound, **kw):
-        """Copies sample data from another sound into self."""
-        self.tk.call((self.name, 'copy', sound.name) + self._options(kw))
-
-    def changed(self, flag):
-        """This command is used to inform Snack that the sound object has been
-        modified. Normally Snack tracks changes to sound objects automatically,
-        but in a few cases this must be performed explicitly. For example,
-        if individual samples are changed using the sample command these
-        will not be tracked for performance reasons."""
-        self.tk.call((self.name, 'changed', flag))
-
-    def convert(self, **kw):
-        """Convert a sound to a different sample encoding, sample rate,
-        or number of channels."""
-        self.tk.call((self.name, 'convert') + self._options(kw))
-
-    def crop(self, start=1, end=None, **kw):
-        """Removes all samples outside of the range [start..end]."""
-        if end is None:
-            end = self.length()
-        self.tk.call((self.name, 'crop', start, end) + self._options(kw))
-
-    def cut(self, start=1, end=None, **kw):
-        """Removes all samples inside the range [start..end]."""
-        if end is None:
-            end = self.length()
-        self.tk.call((self.name, 'cut', start, end) + self._options(kw))
-        
-    def data(self, binarydata=None, **kw):
-        """Loads sound data from, or writes to, a binary string."""
-        if binarydata: # copy data to sound
-            self.tk.call((self.name, 'data', binarydata) + self._options(kw))
-        else: # return sound data
-            return self.tk.call((self.name, 'data') + self._options(kw))
-                          
-    def destroy(self):
-        """Removes the Tcl command for this sound and frees the storage
-        associated with it."""
-        self.tk.call(self.name, 'destroy')
-        
-    def dBPowerSpectrum(self, **kw):
-        """Computes the log FFT power spectrum of the sound (at the time
-        given by the start option) and returns a list of dB values."""
-        result = self.tk.call((self.name, 'dBPowerSpectrum')
-                              + self._options(kw))
-        return self._getdoubles(result)        
-
-    def powerSpectrum(self, **kw):
-        """Computes the FFT power spectrum of the sound (at the time
-        given by the start option) and returns a list of magnitude values."""
-        result = self.tk.call((self.name, 'powerSpectrum')
-                              + self._options(kw))
-        return self._getdoubles(result)        
-
-    def filter(self, filter, **kw):
-        """Applies the given filter to the sound."""
-        return self.tk.call((self.name, 'filter', filter.name) +
-                            self._options(kw))
-        
-    def formant(self, **kw):
-        """Returns a list of formant trajectories."""
-        result = self.tk.call((self.name, 'formant') + self._options(kw))
-        return map(self._getdoubles, self.tk.splitlist(result))
-    
-    def flush(self):
-        """Removes all audio data from the sound."""
-        self.tk.call(self.name, 'flush')
-
-    def info(self, format='string'):
-        """Returns a list with information about the sound.  The entries are
-        [length, rate, max, min, encoding, channels, fileFormat, headerSize]
-        """
-        result = self.tk.call(self.name, 'info')
-        if format == 'list':
-            return map(self._cast, string.split(result))
-        else:
-            return result
-        
-    def insert(self, sound, position, **kw):
-        """Inserts sound at position."""
-        self.tk.call((self.name, 'insert', sound.name, position) + self._options(kw))
-    
-    def length(self, n=None, **kw):
-        """Gets/sets the length of the sound in number of samples (default)
-        or seconds, as determined by the 'units' option."""
-        if n is not None:
-            result = self.tk.call((self.name, 'length', n) + self._options(kw))
-        else:
-            result = self.tk.call((self.name, 'length') + self._options(kw))
-        return _cast(result)
-
-    def load(self, filename, **kw):
-        """Reads new sound data from a file.  Synonym for "read"."""
-        self.tk.call((self.name, 'read', filename) + self._options(kw))
-    
-    def max(self, **kw):
-        """Returns the largest positive sample value of the sound."""
-        return _cast(self.tk.call((self.name, 'max') + self._options(kw)))
-
-    def min(self, **kw):
-        """Returns the largest negative sample value of the sound."""
-        return _cast(self.tk.call((self.name, 'min') + self._options(kw)))
-
-    def mix(self, sound, **kw):
-        """Mixes sample data from another sound into self."""
-        self.tk.call((self.name, 'mix', sound.name) + self._options(kw))
-
-    def pause(self):
-        """Pause current record/play operation.  Next pause invocation
-        resumes play/record."""
-        self.tk.call(self.name, 'pause')
-        
-    def pitch(self, method=None, **kw):
-        """Returns a list of pitch values."""
-        if method is None or method is "amdf" or method is "AMDF":
-            result = self.tk.call((self.name, 'pitch') + self._options(kw))
-            return self._getdoubles(result)
-        else:
-            result = self.tk.call((self.name, 'pitch', '-method', method) + 
-                                  self._options(kw))
-            return map(self._getdoubles, self.tk.splitlist(result))
-
-    def play(self, **kw):
-        """Plays the sound."""
-        self.tk.call((self.name, 'play') + self._options(kw))
-
-    def power(self, **kw):
-        """Computes the FFT power spectrum of the sound (at the time
-        given by the start option) and returns a list of power values."""
-        result = self.tk.call((self.name, 'power')
-                              + self._options(kw))
-        return self._getdoubles(result)        
-
-    def read(self, filename, **kw):
-        """Reads new sound data from a file."""
-        self.tk.call((self.name, 'read', filename) + self._options(kw))
-
-    def record(self, **kw):
-        """Starts recording data from the audio device into the sound object."""
-        self.tk.call((self.name, 'record') + self._options(kw))
-
-    def reverse(self, **kw):
-        """Reverses a sound."""
-        self.tk.call((self.name, 'reverse') + self._options(kw))
-
-    def sample(self, index, left=None, right=None):
-        """Without left/right, this gets the sample value at index.
-        With left/right, it sets the sample value at index in the left
-        and/or right channels."""
-        if right is not None:
-            if left is None:
-                left = '?'
-            opts = (left, right)
-        elif left is not None:
-            opts = (left,)
-        else:
-            opts = ()
-        return _cast(self.tk.call((self.name, 'sample', index) + opts))
-        
-    def stop(self):
-        """Stops current play or record operation."""
-        self.tk.call(self.name, 'stop')
-
-    def stretch(self, **kw):
-        self.tk.call((self.name, 'stretch') + self._options(kw))
-
-    def write(self, filename, **kw):
-        """Writes sound data to a file."""
-        self.tk.call((self.name, 'write', filename) + self._options(kw))
-
-
-class AudioControllerSingleton(TkObject):
-    """This class offers functions that control various aspects of the
-    audio devices.
-    It is written as a class instead of as a set of module-level functions
-    so that we can piggy-back on the Tcl-interface functions in TkObject,
-    and so that the user can invoke the functions in a way more similar to
-    how they're invoked in Tcl, e.g., snack.audio.rates().
-    It is intended that there only be once instance of this class, the
-    one created in snack.initialize.
-    """
-    
-    def __init__(self):
-        self.tk = Tkroot.tk
-    
-    def encodings(self):
-        """Returns a list of supported sample encoding formats for the
-        currently selected device."""
-        result = self.tk.call('snack::audio', 'encodings')
-        return self.tk.splitlist(result)
-        
-    def rates(self):
-        """Returns a list of supported sample rates for the currently
-        selected device."""
-        result = self.tk.call('snack::audio', 'frequencies')
-        return self._getints(result)
-
-    def frequencies(self):
-        """Returns a list of supported sample rates for the currently
-        selected device."""
-        result = self.tk.call('snack::audio', 'frequencies')
-        return self._getints(result)
-        
-    def inputDevices(self):
-        """Returns a list of available audio input devices"""
-        result = self.tk.call('snack::audio', 'inputDevices')
-        return self.tk.splitlist(result)
-        
-    def playLatency(self, latency=None):
-        """Sets/queries (in ms) how much sound will be queued up at any
-        time to the audio device to play back."""
-        if latency is not None:
-            return _cast(self.tk.call('snack::audio', 'playLatency', latency))
-        else:
-            return _cast(self.tk.call('snack::audio', 'playLatency'))
-            
-    def pause(self):
-        """Toggles between play/pause for all playback on the audio device."""
-        self.tk.call('snack::audio', 'pause')
-        
-    def play(self):
-        """Resumes paused playback on the audio device."""
-        self.tk.call('snack::audio', 'play')
-        
-    def play_gain(self, gain=None):
-        """Returns/sets the current play gain.  Valid values are integers
-        in the range 0-100."""
-        if gain is not None:
-            return _cast(self.tk.call('snack::audio', 'play_gain', gain))
-        else:
-            return _cast(self.tk.call('snack::audio', 'play_gain'))
-            
-    def outputDevices(self):
-        """Returns a list of available audio output devices."""
-        result = self.tk.call('snack::audio', 'outputDevices')
-        return self.tk.splitlist(result)
-        
-    def selectOutput(self, device):
-        """Selects an audio output device to be used as default."""
-        self.tk.call('snack::audio', 'selectOutput', device)
-        
-    def selectInput(self, device):
-        """Selects an audio input device to be used as default."""
-        self.tk.call('snack::audio', 'selectInput', device)
-        
-    def stop(self):
-        """Stops all playback on the audio device."""
-        self.tk.call('snack::audio', 'stop')
-
-    def elapsedTime(self):
-        """Return the time since the audio device started playback."""
-        result = self.tk.call('snack::audio', 'elapsedTime')
-        return self.tk.getdouble(result)
-
-class Filter(TkObject):
-
-    def __init__(self, name, *args, **kw):
-        global Tkroot
-        self.name = None
-        if Tkroot:
-            master = Tkroot
-        else:
-            raise RuntimeError, \
-                 'Tk not intialized or not registered with Snack'
-        self.tk = master.tk
-        self.name = self.tk.call(('snack::filter', name) + args +
-                                 self._options(kw))
-
-    def configure(self, *args):
-        """Configures the filter."""
-        self.tk.call((self.name, 'configure') + args)
-        
-    def destroy(self):
-        """Removes the Tcl command for the filter and frees its storage."""
-        self.tk.call(self.name, 'destroy')
-        
-        
-class MixerControllerSingleton(TkObject):
-
-    """Like AudioControllerSingleton, this class is intended to have only
-    a single instance object, which will control various aspects of the
-    mixers."""
-    
-    def __init__(self):
-        self.tk = Tkroot.tk
-        
-    def channels(self, line):
-        """Returns a list with the names of the channels for the
-        specified line."""
-        result = self.tk.call('snack::mixer', 'channels', line)
-        return self.tk.splitlist(result)
-        
-    def devices(self):
-        """Returns a list of the available mixer devices."""
-        result = self.tk.call('snack::mixer', 'devices')
-        return self.tk.splitlist(result)
-        
-    def input(self, jack=None, tclVar=None):
-        """Gets/sets the current input jack.  Optionally link a boolean
-        Tcl variable."""
-        opts = ()
-        if jack is not None:
-            opts = opts + jack
-        if tclVar is not None:
-            opts = opts + tclVar
-        return self.tk.call(('snack::mixer', 'input') + opts)
-
-    def inputs(self):
-        """Returns a list of available input ports."""
-        result = self.tk.call('snack::mixer', 'inputs')
-        return self.tk.splitlist(result)
-        
-    def lines(self):
-        """Returns a list with the names of the lines of the mixer device."""
-        result = self.tk.call('snack::mixer', 'lines')
-        return self.tk.splitlist(result)
-        
-    def output(self, jack=None, tclVar=None):
-        """Gets/sets the current output jack.  Optionally link a boolean
-        Tcl variable."""
-        opts = ()
-        if jack is not None:
-            opts = opts + jack
-        if tclVar is not None:
-            opts = opts + tclVar
-        return self.tk.call(('snack::mixer', 'output') + opts)
-
-    def outputs(self):
-        """Returns a list of available output ports."""
-        result = self.tk.call('snack::mixer', 'outputs')
-        return self.tk.splitlist(result)
-        
-    def update(self):
-        """Updates all linked variables to reflect the status of the
-        mixer device."""
-        self.tk.call('snack::mixer', 'update')
-        
-    def volume(self, line, leftVar=None, rightVar=None):
-        if self.channels(line)[0] == 'Mono':
-            return self.tk.call('snack::mixer', 'volume', line, rightVar)
-        else:
-            return self.tk.call('snack::mixer', 'volume', line, leftVar, rightVar)
-        
-    def select(self, device):
-        """Selects a device to be used as default."""
-        self.tk.call('snack::mixer', 'select', device)
-        
-
-
-class SoundFrame(Tkinter.Frame):
-    
-    """A simple "tape recorder" widget."""
-    
-    def __init__(self, parent=None, sound=None, *args, **kw):
-        Tkinter.Frame.__init__(self)
-        if sound:
-            self.sound = sound
-        else:
-            self.sound = Sound()
-        self.canvas = SnackCanvas(self, height=100)
-        kw['sound'] = self.sound.name
-        self.canvas.create_waveform(0, 0, kw)
-        self.canvas.pack(side='top')
-        bbar = Tkinter.Frame(self)
-        bbar.pack(side='left')
-        Tkinter.Button(bbar, image='snackOpen', command=self.load
-                       ).pack(side='left')
-        Tkinter.Button(bbar, bitmap='snackPlay', command=self.play
-                       ).pack(side='left')
-        Tkinter.Button(bbar, bitmap='snackRecord', fg='red',
-                       command=self.record).pack(side='left')
-        Tkinter.Button(bbar, bitmap='snackStop', command=self.stop
-                       ).pack(side='left')
-        Tkinter.Button(bbar, text='Info', command=self.info).pack(side='left')
-
-        
-    def load(self):
-        file = Tkroot.tk.call('eval', 'snack::getOpenFile')
-        self.sound.read(file, progress='snack::progressCallback')
-        
-    def play(self):
-        self.sound.play()
-        
-    def stop(self):
-        self.sound.stop()        
-        
-    def record(self):
-        self.sound.record()
-        
-    def info(self):
-        print self.sound.info()
-        
-def createSpectrogram(canvas, *args, **kw):
-    """Draws a spectrogram of a sound on canvas."""
-    return canvas._create('spectrogram', args, kw)
-
-def createSection(canvas, *args, **kw):
-    """Draws and FFT log power spectrum section on canvas."""
-    return canvas._create('section', args, kw)
-
-def createWaveform(canvas, *args, **kw):
-    """Draws a waveform on canvas."""
-    return canvas._create('waveform', args, kw)
-
-
-class SnackCanvas(Tkinter.Canvas):
-    
-    def __init__(self, master=None, cnf={}, **kw):
-        Tkinter.Widget.__init__(self, master, 'canvas', cnf, kw)
-    
-    def create_spectrogram(self, *args, **kw):
-        """Draws a spectrogram of a sound on the canvas."""
-        return self._create('spectrogram', args, kw)
-
-    def create_section(self, *args, **kw):
-        """Draws an FFT log power spectrum section."""
-        return self._create('section', args, kw)
-
-    def create_waveform(self, *args, **kw):
-        """Draws a waveform."""
-        return self._create('waveform', args, kw)
-
-
-if __name__ == '__main__':
-    # Create a test SoundFrame if the module is called as the main program
-    root = Tkinter.Tk()
-    initializeSnack(root)
-    frame = SoundFrame(root)
-    frame.pack(expand=0)
-    root.mainloop()
diff --git a/telemeta/visualization/wav2png.py b/telemeta/visualization/wav2png.py
deleted file mode 100755 (executable)
index 0525e00..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-#!/usr/bin/env python
-
-# wav2png.py -- converts wave files to wave file and spectrogram images
-# Copyright (C) 2008 MUSIC TECHNOLOGY GROUP (MTG)
-#                    UNIVERSITAT POMPEU FABRA
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Authors:
-#   Bram de Jong <bram.dejong at domain.com where domain in gmail>
-# Contributors:
-#   Guillaume Pellerin <pellerin@parisson.com>
-
-
-import optparse, math, sys
-import ImageFilter, ImageChops, Image, ImageDraw, ImageColor
-import numpy
-import scikits.audiolab as audiolab
-
-color_schemes = {
-    'default': {
-        'waveform': [(50,0,200), (0,220,80), (255,224,0), (255,0,0)],
-        'spectrogram': [(0, 0, 0), (58/4,68/4,65/4), (80/2,100/2,153/2), (90,180,100),
-                      (224,224,44), (255,60,30), (255,255,255)]
-    },
-    'iso': {
-        'waveform': [(0,0,255), (0,255,255), (255,255,0), (255,0,0)],
-        'spectrogram': [(0, 0, 0), (58/4,68/4,65/4), (80/2,100/2,153/2), (90,180,100),
-                      (224,224,44), (255,60,30), (255,255,255)]
-    },
-    'purple': {
-        'waveform': [(173,173,173), (147,149,196), (77,80,138), (108,66,0)],
-        'spectrogram': [(0, 0, 0), (58/4,68/4,65/4), (80/2,100/2,153/2), (90,180,100),
-                      (224,224,44), (255,60,30), (255,255,255)]
-    }
-}
-
-class TestAudioFile(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
-        self.has_broken_header = has_broken_header
-
-    def seek(self, seekpoint):
-        self.seekpoint = seekpoint
-
-    def get_nframes(self):
-        return self.num_frames
-
-    def get_samplerate(self):
-        return 44100
-
-    def get_channels(self):
-        return 1
-
-    def read_frames(self, frames_to_read):
-        if self.has_broken_header and self.seekpoint + frames_to_read > self.num_frames / 2:
-            raise IOError()
-
-        num_frames_left = self.num_frames - self.seekpoint
-        if num_frames_left < frames_to_read:
-            will_read = num_frames_left
-        else:
-            will_read = frames_to_read
-        self.seekpoint += will_read
-        return numpy.random.random(will_read)*2 - 1 
-
-
-class AudioProcessor(object):
-    def __init__(self, audio_file, fft_size, window_function=numpy.ones):
-        self.fft_size = fft_size
-        self.window = window_function(self.fft_size)
-        self.audio_file = audio_file
-        self.frames = audio_file.get_nframes()
-        self.samplerate = audio_file.get_samplerate()
-        self.channels = audio_file.get_channels()
-        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 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)
-
-
-def interpolate_colors(colors, flat=False, num_colors=256):
-    """ 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 """
-    
-    palette = []
-    
-    for i in range(num_colors):
-        index = (i * (len(colors) - 1))/(num_colors - 1.0)
-        index_int = int(index)
-        alpha = index - float(index_int)
-        
-        if alpha > 0:
-            r = (1.0 - alpha) * colors[index_int][0] + alpha * colors[index_int + 1][0]
-            g = (1.0 - alpha) * colors[index_int][1] + alpha * colors[index_int + 1][1]
-            b = (1.0 - alpha) * colors[index_int][2] + alpha * colors[index_int + 1][2]
-        else:
-            r = (1.0 - alpha) * colors[index_int][0]
-            g = (1.0 - alpha) * colors[index_int][1]
-            b = (1.0 - alpha) * colors[index_int][2]
-        
-        if flat:
-            palette.extend((int(r), int(g), int(b)))
-        else:
-            palette.append((int(r), int(g), int(b)))
-        
-    return palette
-    
-
-class WaveformImage(object):
-    def __init__(self, image_width, image_height, bg_color = None, color_scheme = None):
-        if not bg_color:
-            bg_color = (0,0,0)
-        if not color_scheme: 
-            color_scheme = 'default'
-
-        self.image = Image.new("RGB", (image_width, image_height), bg_color)
-        
-        self.image_width = image_width
-        self.image_height = image_height
-        
-        self.draw = ImageDraw.Draw(self.image)
-        self.previous_x, self.previous_y = None, None
-        
-        colors = color_schemes[color_scheme]['waveform']
-        
-        # this line gets the old "screaming" colors back...
-        # colors = [self.color_from_value(value/29.0) for value in range(0,30)]
-        
-        self.color_lookup = interpolate_colors(colors)
-        self.pix = self.image.load()
-
-    def color_from_value(self, value):
-        """ given a value between 0 and 1, return an (r,g,b) tuple """
-
-        return ImageColor.getrgb("hsl(%d,%d%%,%d%%)" % (int( (1.0 - value) * 360 ), 80, 50))
-        
-    def draw_peaks(self, x, peaks, spectral_centroid):
-        """ draw 2 peaks at x using the spectral_centroid for color """
-
-        y1 = self.image_height * 0.5 - peaks[0] * (self.image_height - 4) * 0.5
-        y2 = self.image_height * 0.5 - peaks[1] * (self.image_height - 4) * 0.5
-        
-        line_color = self.color_lookup[int(spectral_centroid*255.0)]
-        
-        if self.previous_y != None:
-            self.draw.line([self.previous_x, self.previous_y, x, y1, x, y2], line_color)
-        else:
-            self.draw.line([x, y1, x, y2], line_color)
-    
-        self.previous_x, self.previous_y = x, y2
-        
-        self.draw_anti_aliased_pixels(x, y1, y2, line_color)
-    
-    def draw_anti_aliased_pixels(self, x, y1, y2, color):
-        """ vertical anti-aliasing at y1 and y2 """
-
-        y_max = max(y1, y2)
-        y_max_int = int(y_max)
-        alpha = y_max - y_max_int
-        
-        if alpha > 0.0 and alpha < 1.0 and y_max_int + 1 < self.image_height:
-            current_pix = self.pix[x, y_max_int + 1]
-            
-            r = int((1-alpha)*current_pix[0] + alpha*color[0])
-            g = int((1-alpha)*current_pix[1] + alpha*color[1])
-            b = int((1-alpha)*current_pix[2] + alpha*color[2])
-            
-            self.pix[x, y_max_int + 1] = (r,g,b)
-            
-        y_min = min(y1, y2)
-        y_min_int = int(y_min)
-        alpha = 1.0 - (y_min - y_min_int)
-        
-        if alpha > 0.0 and alpha < 1.0 and y_min_int - 1 >= 0:
-            current_pix = self.pix[x, y_min_int - 1]
-                
-            r = int((1-alpha)*current_pix[0] + alpha*color[0])
-            g = int((1-alpha)*current_pix[1] + alpha*color[1])
-            b = int((1-alpha)*current_pix[2] + alpha*color[2])
-            
-            self.pix[x, y_min_int - 1] = (r,g,b)
-            
-    def save(self, filename):
-        # draw a zero "zero" line
-        a = 25
-        for x in range(self.image_width):
-            self.pix[x, self.image_height/2] = tuple(map(lambda p: p+a, self.pix[x, self.image_height/2]))
-        
-        self.image.save(filename)
-        
-        
-class SpectrogramImage(object):
-    def __init__(self, image_width, image_height, fft_size, bg_color = None, color_scheme = None):
-
-        #FIXME: bg_color is ignored
-
-        if not color_scheme: 
-            color_scheme = 'default'
-
-        self.image = Image.new("P", (image_height, image_width))
-        
-        self.image_width = image_width
-        self.image_height = image_height
-        self.fft_size = fft_size
-        
-        colors = color_schemes[color_scheme]['spectrogram']
-        
-        self.image.putpalette(interpolate_colors(colors, True))
-
-        # generate the lookup which translates y-coordinate to fft-bin
-        self.y_to_bin = []
-        f_min = 100.0
-        f_max = 22050.0
-        y_min = math.log10(f_min)
-        y_max = math.log10(f_max)
-        for y in range(self.image_height):
-            freq = math.pow(10.0, y_min + y / (image_height - 1.0) *(y_max - y_min))
-            bin = freq / 22050.0 * (self.fft_size/2 + 1)
-
-            if bin < self.fft_size/2:
-                alpha = bin - int(bin)
-                
-                self.y_to_bin.append((int(bin), alpha * 255))
-           
-        # this is a bit strange, but using image.load()[x,y] = ... is
-        # a lot slower than using image.putadata and then rotating the image
-        # so we store all the pixels in an array and then create the image when saving
-        self.pixels = []
-            
-    def draw_spectrum(self, x, spectrum):
-        for (index, alpha) in self.y_to_bin:
-            self.pixels.append( int( ((255.0-alpha) * spectrum[index] + alpha * spectrum[index + 1] )) )
-            
-        for y in range(len(self.y_to_bin), self.image_height):
-            self.pixels.append(0)
-
-    def save(self, filename):
-        self.image.putdata(self.pixels)
-        self.image.transpose(Image.ROTATE_90).save(filename)
-
-
-def create_wavform_png(input_filename, output_filename_w, image_width, image_height, fft_size,
-                       bg_color = None, color_scheme = None):
-    audio_file = audiolab.sndfile(input_filename, 'read')
-
-    samples_per_pixel = audio_file.get_nframes() / float(image_width)
-    processor = AudioProcessor(audio_file, fft_size, numpy.hanning)
-    
-    waveform = WaveformImage(image_width, image_height, bg_color, color_scheme)
-    
-    for x in range(image_width):
-        
-        seek_point = int(x * samples_per_pixel)
-        next_seek_point = int((x + 1) * samples_per_pixel)
-        
-        (spectral_centroid, db_spectrum) = processor.spectral_centroid(seek_point)
-        peaks = processor.peaks(seek_point, next_seek_point)
-        
-        waveform.draw_peaks(x, peaks, spectral_centroid)
-    
-    waveform.save(output_filename_w)
-
-def create_spectrogram_png(input_filename, output_filename_s, image_width, image_height, fft_size,
-                           bg_color = None, color_scheme = None):
-    audio_file = audiolab.sndfile(input_filename, 'read')
-
-    samples_per_pixel = audio_file.get_nframes() / float(image_width)
-    processor = AudioProcessor(audio_file, fft_size, numpy.hanning)
-    
-    spectrogram = SpectrogramImage(image_width, image_height, fft_size, bg_color, color_scheme)
-    
-    for x in range(image_width):
-   
-        seek_point = int(x * samples_per_pixel)
-        next_seek_point = int((x + 1) * samples_per_pixel)  
-        (spectral_centroid, db_spectrum) = processor.spectral_centroid(seek_point) 
-        spectrogram.draw_spectrum(x, db_spectrum)
-    
-    spectrogram.save(output_filename_s)
-    
-
diff --git a/telemeta/visualization/waveform_audiolab.py b/telemeta/visualization/waveform_audiolab.py
deleted file mode 100644 (file)
index c042864..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008 Parisson SARL
-# All rights reserved.
-#
-# This software is a computer program whose purpose is to backup, analyse,
-# transcode and stream any audio content with its metadata over a web frontend.
-
-# This software is governed by the CeCILL  license under French law and
-# abiding by the rules of distribution of free software.  You can  use,
-# modify and/ or redistribute the software under the terms of the CeCILL
-# license as circulated by CEA, CNRS and INRIA at the following URL
-# "http://www.cecill.info".
-
-# As a counterpart to the access to the source code and  rights to copy,
-# modify and redistribute granted by the license, users are provided only
-# with a limited warranty  and the software's author,  the holder of the
-# economic rights,  and the successive licensors  have only  limited
-# liability.
-
-# In this respect, the user's attention is drawn to the risks associated
-# with loading,  using,  modifying and/or developing or reproducing the
-# software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate,  and  that  also
-# therefore means  that it is reserved for developers  and  experienced
-# professionals having in-depth computer knowledge. Users are therefore
-# encouraged to load and test the software's suitability as regards their
-# requirements in conditions enabling the security of their systems and/or
-# data to be ensured and,  more generally, to use and operate it in the
-# same conditions as regards security.
-
-# The fact that you are presently reading this means that you have had
-# knowledge of the CeCILL license and that you accept its terms.
-#
-# Author: Guillaume Pellerin <pellerin@parisson.com>
-
-from telemeta.core import *
-from telemeta.visualization.api import IMediaItemVisualizer
-from django.conf import settings
-from tempfile import NamedTemporaryFile
-from telemeta.visualization.wav2png import *
-
-class WaveFormVisualizerAudiolab(Component):
-    """WaveForm visualization driver (python style thanks to wav2png.py and scikits.audiolab)"""
-
-    implements(IMediaItemVisualizer)
-
-    bg_color = None
-    color_scheme = None
-
-    def get_id(self):
-        return "waveform_audiolab"
-
-    def get_name(self):
-        return "Waveform (audiolab)"
-
-    def set_colors(self, background=None, scheme=None):
-        self.bg_color = background
-        self.color_scheme = scheme
-
-    def render(self, media_item, width=None, height=None, options=None):
-        """Generator that streams the waveform as a PNG image with a python method"""
-
-        wav_file = media_item.file.path
-        pngFile = NamedTemporaryFile(suffix='.png')
-
-        if not width == None:
-            image_width = width
-        else:
-            image_width = 1500
-        if not height == None:
-            image_height = height
-        else:
-            image_height = 200
-
-        fft_size = 2048
-        args = (wav_file, pngFile.name, image_width, image_height, fft_size, 
-                self.bg_color, self.color_scheme)
-        create_wavform_png(*args)
-
-        buffer = pngFile.read(0xFFFF)
-        while buffer:
-            yield buffer
-            buffer = pngFile.read(0xFFFF)
-
-        pngFile.close()
-
index dce752c1a1e9da45720216803021a043c3f129ae..22d21398130b83ec63c6898ccf973d2358c5b9a2 100644 (file)
@@ -1 +1,2 @@
 from telemeta.web.base import WebView
+from pages import *
index 8be7cc9bce0dbdcee44eaa46d044ecef4a1d8de8..d185309319363d2b5a8ede3f822ad1055624c023 100644 (file)
@@ -35,6 +35,7 @@
 import re
 import os
 import sys
+import datetime
 
 from django.template import RequestContext, loader
 from django import template
@@ -46,33 +47,46 @@ from django.conf import settings
 from django.contrib import auth
 from django.contrib.auth.decorators import login_required
 
-import telemeta
 from telemeta.models import MediaItem, Location, MediaCollection, EthnicGroup
 from telemeta.models import dublincore, Enumeration
-from telemeta.core import Component, ExtensionPoint
-from telemeta.export import *
-from telemeta.visualization import *
-from telemeta.analysis import *
-from telemeta.analysis.vamp import *
+#from telemeta.core import Component, ExtensionPoint
+#from telemeta.export import *
+#from telemeta.visualization import *
+#from telemeta.analysis import *
+#from telemeta.analysis.vamp import *
 import telemeta.interop.oai as oai
 from telemeta.interop.oaidatasource import TelemetaOAIDataSource
 from django.core.exceptions import ObjectDoesNotExist
 from telemeta.util.unaccent import unaccent
 from telemeta.web import pages
-import datetime
 from telemeta.util.unaccent import unaccent_icmp
 
+import timeside
+
+
 def render(request, template, data = None, mimetype = None):
     return render_to_response(template, data, context_instance=RequestContext(request), 
-                              mimetype=mimetype) 
+                              mimetype=mimetype)
+
+def stream(file):
+    chunk_size = 0x10000
+    f = open(file,  'r')
+    while True:
+        _chunk = f.read(chunk_size)
+        if not len(_chunk):
+            break
+        yield _chunk
+    f.close()
 
-class WebView(Component):
-    """Provide web UI methods"""
 
-    exporters = ExtensionPoint(IExporter)
-    visualizers = ExtensionPoint(IMediaItemVisualizer)
-    analyzers = ExtensionPoint(IMediaItemAnalyzer)
+class WebView:
+    """Provide web UI methods"""
 
+    graphers = timeside.processors(timeside.api.IGrapher)
+    decoders = timeside.processors(timeside.api.IDecoder)
+    encoders= timeside.processors(timeside.api.IEncoder)
+    analyzers = timeside.processors(timeside.api.IAnalyzer)
+    
     def index(self, request):
         """Render the homepage"""
 
@@ -95,63 +109,88 @@ class WebView(Component):
         item = MediaItem.objects.get(public_id=public_id)
         
         formats = []
-        for exporter in self.exporters:
-            formats.append({'name': exporter.get_format(), 'extension': exporter.get_file_extension()})
-
-        visualizers = []
-        for visualizer in self.visualizers:
-            visualizers.append({'name':visualizer.get_name(), 'id':
-                visualizer.get_id()})
-        if request.REQUEST.has_key('visualizer_id'):
-            visualizer_id = request.REQUEST['visualizer_id']
+        for encoder in self.encoders:
+            formats.append({'name': encoder.format(), 'extension': encoder.file_extension()})
+
+        graphers = []
+        for grapher in self.graphers:
+            graphers.append({'name':grapher.name(), 'id': grapher.id()})
+        if request.REQUEST.has_key('grapher_id'):
+            grapher_id = request.REQUEST['grapher_id']
         else:
-            visualizer_id = 'waveform_audiolab'
-
-        analyzers = []
-        for analyzer in self.analyzers:
+            grapher_id = 'waveform'
+        
+        analyzers = [{'name':'','id':'','unit':'','value':''}]
+        # TODO: override timeside analyzer process when caching
+        self.analyzer_mode = 0
+        
+        if self.analyzer_mode:
+            analyzers_sub = []
             if item.file:
-                value = analyzer.render(item)
-            else:
-                value = 'N/A'
-
-            analyzers.append({'name':analyzer.get_name(),
-                              'id':analyzer.get_id(),
-                              'unit':analyzer.get_unit(),
-                              'value':str(value)})
-
-        vamp = VampCoreAnalyzer()
-        vamp_plugins = vamp.get_plugins_list()
-        vamp_plugin_list = []
-        for plugin in vamp_plugins:
-            vamp_plugin_list.append(':'.join(plugin[1:]))
-          
+                audio = os.path.join(os.path.dirname(__file__), item.file.path)
+                decoder  = timeside.decoder.FileDecoder(audio)
+                self.pipe = decoder
+                for analyzer in self.analyzers:
+                    subpipe = analyzer()
+                    analyzers_sub.append(subpipe)
+                    self.pipe = self.pipe | subpipe
+                self.pipe.run()
+                
+            for analyzer in analyzers_sub:
+                if item.file:
+                    value = analyzer.result()
+                    if analyzer.id() == 'duration':
+                        approx_value = int(round(value))
+                        item.approx_duration = approx_value
+                        item.save()
+                        value = datetime.timedelta(0,value)
+                else:
+                    value = 'N/A'
+
+                analyzers.append({'name':analyzer.name(),
+                                  'id':analyzer.id(),
+                                  'unit':analyzer.unit(),
+                                  'value':str(value)})
+
+#        vamp = VampCoreAnalyzer()
+#        vamp_plugins = vamp.get_plugins_list()
+#        vamp_plugin_list = []
+#        for plugin in vamp_plugins:
+#            vamp_plugin_list.append(':'.join(plugin[1:]))
+                    
         return render(request, template, 
                     {'item': item, 'export_formats': formats, 
-                    'visualizers': visualizers, 'visualizer_id': visualizer_id,
-                    'analysers': analyzers, 'vamp_plugins': vamp_plugin_list,
+                    'visualizers': graphers, 'visualizer_id': grapher_id,'analysers': analyzers,
                     'audio_export_enabled': getattr(settings, 'TELEMETA_DOWNLOAD_ENABLED', False)
                     })
-                    
+
     def item_visualize(self, request, public_id, visualizer_id, width, height):
-        for visualizer in self.visualizers:
-            if visualizer.get_id() == visualizer_id:
+        grapher_id = visualizer_id
+        for grapher in self.graphers:
+            if grapher.id() == grapher_id:
                 break
 
-        if visualizer.get_id() != visualizer_id:
+        if grapher.id() != grapher_id:
             raise Http404
-        
-        item = MediaItem.objects.get(public_id=public_id)
 
-        visualizer.set_colors((255,255,255), 'purple')
-        stream = visualizer.render(item, width=int(width), height=int(height))
-        response = HttpResponse(stream, mimetype = 'image/png')
+        media = settings.TELEMETA_EXPORT_DATA_DIR + os.sep + public_id + '_' + grapher_id + '_' + width + '_' + height + '.png'
+        #graph.set_colors((255,255,255), 'purple')
+        
+        if not os.path.exists(media):
+            item = MediaItem.objects.get(public_id=public_id)
+            audio = os.path.join(os.path.dirname(__file__), item.file.path)
+            decoder  = timeside.decoder.FileDecoder(audio)
+            graph = grapher(width=int(width), height=int(height), output=media)
+            (decoder | graph).run()
+            graph.render()
+        response = HttpResponse(stream(media), mimetype = 'image/png')
         return response
 
     def list_export_extensions(self):
         "Return the recognized item export file extensions, as a list"
         list = []
-        for exporter in self.exporters:
-            list.append(exporter.get_file_extension())
+        for encoder in self.encoders:
+            list.append(encoder.file_extension())
         return list
 
     def item_export(self, request, public_id, extension):                    
@@ -160,24 +199,34 @@ class WebView(Component):
         if extension != 'mp3' and not getattr(settings, 'TELEMETA_DOWNLOAD_ENABLED', False):
             raise Http404 # FIXME: should be some sort of permissions denied error
 
-        for exporter in self.exporters:
-            if exporter.get_file_extension() == extension:
+        for encoder in self.encoders:
+            if encoder.file_extension() == extension:
                 break
 
-        if exporter.get_file_extension() != extension:
+        if encoder.file_extension() != extension:
             raise Http404('Unknown export file extension: %s' % extension)
 
-        mime_type = exporter.get_mime_type()
-
-        exporter.set_cache_dir(settings.TELEMETA_EXPORT_CACHE_DIR)
-
+        mime_type = encoder.mime_type()
+        cache_dir = settings.TELEMETA_EXPORT_CACHE_DIR
+        media = cache_dir + os.sep + public_id + '.' + encoder.file_extension()
+        
         item = MediaItem.objects.get(public_id=public_id)
-
-        infile = item.file.path
-        metadata = dublincore.express_item(item).to_list()
-        stream = exporter.process(item.id, infile, metadata)
-
-        response = HttpResponse(stream, mimetype = mime_type)
+        audio = os.path.join(os.path.dirname(__file__), item.file.path)
+        decoder  = timeside.decoder.FileDecoder(audio)
+        print decoder.format(),  mime_type
+        if decoder.format() == mime_type:
+            # source > stream
+            media = audio
+        else:        
+            if not os.path.exists(media):
+                # source > encoder > stream
+                decoder  = timeside.decoder.FileDecoder(audio)
+                enc = encoder(media)
+                metadata = dublincore.express_item(item).to_list()
+                #enc.set_metadata(metadata)
+                (decoder | enc).run()
+            
+        response = HttpResponse(stream(media), mimetype = mime_type)
         response['Content-Disposition'] = 'attachment'
         return response