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