From: yomguy Date: Wed, 19 Sep 2012 11:22:01 +0000 (+0200) Subject: Full update of README, make ts-waveforms script X-Git-Tag: 0.3.3^2~6 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=f21fa5694a63ec59c7b92bff1c3c62bd23d3aa86;p=timeside.git Full update of README, make ts-waveforms script --- diff --git a/INSTALL.rst b/INSTALL.rst index 53502e9..bd56d86 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -5,46 +5,24 @@ Howto Install TimeSide This file describe how to install the TimeSide python package from source. -1. Install dependencies -======================= - -TimeSide needs some other python modules to run. -See README for the full dependency list. - -The following methods explain how to install all dependencies on a Debian based system -and espacially on Debian Squeeze 6.0 (stable). Is it now considered you have install this system correctly. - -Become root. In a terminal or console, run:: - - $ su +INSTALL +======= -Write your root password. -Note : you can paste the full command but without the shell character '$'. -Then:: +TimeSide needs some other python modules to run. The following methods explain how to install all dependencies on a Debian based system like Debian, Ubuntu, etc.. On Fedora and Red-Hat you might replace 'apt-get by 'yum', on Gentoo by 'emerge', or any other package manager you like:: - $ aptitude update - $ aptitude install python python-gobject gobject-introspection python-setuptools python-xml python-mutagen \ - python-imaging python-numpy python-scipy python-gst0.10 gstreamer0.10-plugins-base gir1.0-gstreamer-0.10 \ - gstreamer0.10-fluendo-mp3 gstreamer0.10-plugins-good gstreamer0.10-plugins-bad + $ sudo apt-get update + $ sudo apt-get install python python-pip python-setuptools python-gobject \ + python-gst0.10 gstreamer0.10-plugins-base gir1.0-gstreamer-0.10 \ + gstreamer0.10-plugins-good gstreamer0.10-plugins-bad \ + gobject-introspection -Add Debian multimedia repository to the apt sources.list and install Gstreamer MP3 modules:: - - $ echo "deb deb http://www.debian-multimedia.org stable main" | tee -a /etc/apt/sources.list - $ aptitude update - $ aptitude install gstreamer0.10-fluendo-mp3 gstreamer0.10-lame - - -2. Install TimeSide -=================== - -Go into the module directory and then install:: - - $ cd timeside - $ python setup.py install + $ sudo pip install timeside -Or, directly from python package directory:: +To get non-free MP3, MP4 or AAC decoding and encoding features, add Debian Multimedia repository and install the modules:: - $ sudo pip install timeside + $ echo "deb http://www.deb-multimedia.org stable main non-free" | sudo tee -a /etc/apt/sources.list + $ sudo apt-get update + $ apt-get install gstreamer0.10-lame gstreamer0.10-plugins-really-bad 3. Use TimeSide diff --git a/README.rst b/README.rst index 3914575..5aac764 100644 --- a/README.rst +++ b/README.rst @@ -2,11 +2,11 @@ TimeSide : open and fast web audio components ============================================== -TimeSide is a set of client and server side components for audio-enabling web sites and applications. +TimeSide is a set of python components enabling easy audio processing, transcoding, imaging and streaming. Its simple architecture and high-level API have been design to process serial pipelines -It includes a powerful DHTML-based interactive player, with support for time-marking. -The server side components provide generic APIs for easy transcoding, metadata embedding, -sound visualization and audio analysis. +It includes a powerfull HTM5 interactive player which can be embedded in any web application to provide fancy waveforms, various analyzer results, synced time metadata display during playback and remote indexing. + +The engine (server side) is fully written in Python, the player (client side) in HTML, CSS and JavaScript. News ===== @@ -20,85 +20,109 @@ News * bugfixes -Platforms -========= +Dive in +======== -TimeSide is intended to work on all Unix / Linux platforms. -MacOS X and Windows versions will soon be explorated. +Define some processors:: -It is mostly written in Python and JavaScript / CSS / HTML + >>> import timeside + >>> decoder = timeside.decoder.FileDecoder('source.wav') + >>> grapher = timeside.grapher.Waveform() + >>> analyzer = timeside.analyzer.MaxLevel() + >>> encoder = timeside.encoder.Mp3Encoder('output.mp3') +then, the *magic* pipeline:: -Install and usage -================== + >>> (decoder | grapher | analyzer | encoder).run() -See INSTALL.rst +get the results:: + >>> grapher.render(output='image.png') + >>> print 'Level:', analyzer.result() -Dependencies -============ +finally see image.png and play output.mp3 ;) - * python (>= 2.4) - * python-xml - * python-mutagen - * python-imaging (>= 1.1.6) - * python-numpy - * python-setuptools - * python-gst0.10 - * gstreamer0.10-plugins-base, - * gstreamer0.10-plugins-fluendo-mp3 - * gstreamer0.10-plugins-good +More examples +============= -Provides -========== + * http://code.google.com/p/timeside/ + * http://code.google.com/p/timeside/wiki/PythonApi + * https://github.com/yomguy/TimeSide/tree/master/scripts/batch/ + * http://archives.crem-cnrs.fr/items/CNRSMH_I_1956_002_001_01/ (player embedded in a Telemeta session) - * SoundManager 2 >= 2.91 (http://www.schillmania.com/projects/soundmanager2) - * jQuery => 1.2.6 (http://www.jquery.com) - * jsGraphics => 3.03 (http://www.walterzorn.com/jsgraphics/jsgraphics_e.htm) +Related projects +================= -High level process example -=========================== +TimeSide has emerged in 2010 from the `Telemeta project `_ which develop a free and open-source web audio CMS. -For example:: +The time decoder depends on the `GStreamer framework`_. - >>> import timeside - >>> decoder = timeside.decoder.FileDecoder('source.wav') - >>> grapher = timeside.grapher.Waveform() - >>> analyzer = timeside.analyzer.MaxLevel() - >>> encoder = timeside.encoder.Mp3Encoder('output.mp3') - >>> (decoder | grapher | analyzer | encoder).run() - >>> grapher.render(output='image.png') - >>> print 'Level:', analyzer.result() +APIs +==== -UI Integration -=============== +Engine API : http://code.google.com/p/timeside/source/browse/trunk/timeside/api.py -See TimeSide UI integration guide: http://code.google.com/p/timeside/wiki/UiGuide +Player API and guide : http://code.google.com/p/timeside/wiki/UiGuide -More examples -============== +Platforms +========= - * http://code.google.com/p/timeside/ - * http://archives.crem-cnrs.fr/items/CNRSMH_I_1956_002_001_01/ - * http://demo.telemeta.org (login: demo , pass: demo) +The TimeSide engine is intended to work on all Unix / Linux platforms, but MacOS X and Windows versions will soon be explorated. +The player should work on any modern HTML5 enabled browser. Flash is needed for MP3 if the browser doesn't support it. -Related projects -================= -Telemeta : open web audio CMS (http://telemeta.org) +Install +======= +TimeSide needs some other python modules to run. The following methods explain how to install all dependencies on a Debian based system like Debian, Ubuntu, etc.. On Fedora and Red-Hat you might replace 'apt-get by 'yum', on Gentoo by 'emerge', or any other package manager you like:: -Copyrights -========== + $ sudo apt-get update + $ sudo apt-get install python python-pip python-setuptools python-gobject \ + python-gst0.10 gstreamer0.10-plugins-base gir1.0-gstreamer-0.10 \ + gstreamer0.10-plugins-good gstreamer0.10-plugins-bad \ + gobject-introspection + + $ sudo pip install timeside + +To get non-free MP3, MP4 or AAC decoding and encoding features, add Debian Multimedia repository and install the modules:: + + $ echo "deb http://www.deb-multimedia.org stable main non-free" | sudo tee -a /etc/apt/sources.list + $ sudo apt-get update + $ apt-get install gstreamer0.10-lame gstreamer0.10-plugins-really-bad + + +Batching +========= + +TimeSide provides ts-waveforms : a waveform redering batch script. + +Usage:: + + $ ts-waveforms /path/to/media_dir /path/to/img_dir + +Please use absolute paths. For example:: + + $ ts-waveforms /home/$user/music/mp3/ /home/$USER/images/ + +To change the color scheme or the size of the waveforms, edit the script from the source and change the variables of the GrapherScheme object:: -Copyright (c) 2006, 2011 Parisson SARL. All rights reserved. -Copyright (c) 2006, 2010 Samalyse SARL. -Copyright (c) 2010, 2012, Paul Brossier. + $ git clone git://github.com/yomguy/TimeSide.git + $ cd timeside/scripts/ + $ vi ts-waveforms + $ ./ts-waveforms /home/$user/music/mp3/ /home/$USER/images/ + + +Packages included +================= + + * SoundManager 2 >= 2.91 (http://www.schillmania.com/projects/soundmanager2) + * jQuery => 1.2.6 (http://www.jquery.com) + * jsGraphics => 3.03 (http://www.walterzorn.com/jsgraphics/jsgraphics_e.htm) License @@ -117,7 +141,19 @@ GNU General Public License for more details. See LICENSE for more details. -Contact and Informations -======================== +Development +=========== + + * http://code.google.com/p/timeside/ + * https://github.com/yomguy/TimeSide + + +Copyrights +========== + + * Copyright (c) 2006, 2012 Parisson SARL + * Copyright (c) 2006, 2012 Guillaume Pellerin + * Copyright (c) 2010, 2012 Paul Brossier + * Copyright (c) 2006, 2010 Samalyse SARL + -See http://code.google.com/p/timeside/ diff --git a/scripts/old/telemeta_preprocess_batch.py b/scripts/old/telemeta_preprocess_batch.py new file mode 100644 index 0000000..81986a2 --- /dev/null +++ b/scripts/old/telemeta_preprocess_batch.py @@ -0,0 +1,200 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2009-2010 Guillaume Pellerin + +# 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 . + +# Author: Guillaume Pellerin + +version = '0.4' + +import os +import sys +import time +import datetime +import timeside +from logger import Logger +import Queue +from threading import Thread +from cache import Cache +from django.core.management import setup_environ +from django.core.files.base import ContentFile + + +class GrapherScheme: + + def __init__(self): + self.color = 255 + self.color_scheme = { + 'waveform': [ # Four (R,G,B) tuples for three main color channels for the spectral centroid method + (self.color,self.color,self.color) +# (0, 0, 0), (0, 0, 0), (0, 0, 0), (0,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) + ]} + + # Grapher id + self.id = 'waveform_awdio' + + # Width of the image + self.width = 1800 + + # Height of the image + self.height = 233 + + # Background color + self.bg_color = None + + # Force computation. By default, the class doesn't overwrite existing image files. + self.force = False + + # Nb of threads + # FIXME: memory leak for > 1 ! + self.threads = 1 + + +class TelemetaPreprocessImport(object): + + def __init__(self, media_dir, dest_dir, log_file): + self.root_dir = media_dir + self.dest_dir = dest_dir + self.threads = 1 + self.logger = Logger(log_file) + self.counter = 0 + self.force = 0 + self.cache = Cache(self.dest_dir) + + self.scheme = GrapherScheme() + self.width = self.scheme.width + self.height = self.scheme.height + self.bg_color = self.scheme.bg_color + self.color_scheme = self.scheme.color_scheme + self.force = self.scheme.force + self.threads = self.scheme.threads + self.logger = Logger(log_file) + self.counter = 0 + + self.analyzers = timeside.core.processors(timeside.api.IAnalyzer) + self.grapher = timeside.grapher.WaveformAwdio(width=self.width, + height=self.height, + bg_color=self.bg_color, + color_scheme=self.color_scheme) + + self.media_list = self.get_media_list() + if not os.path.exists(self.dest_dir): + os.makedirs(self.dest_dir) + + def get_media_list(self): + media_list = [] + for root, dirs, files in os.walk(self.root_dir): + if root: + for file in files: + if file[0] != '.': + ext = file.split('.')[-1] + media_list.append(root+os.sep+file) + return media_list + + def process(self): + for media in self.media_list: + filename = media.split(os.sep)[-1] + name, ext = os.path.splitext(filename) + size = str(self.width) + '_' + str(self.height) + image = self.dest_dir + os.sep + name + '.' + self.scheme.id + '.' + size + '.png' + xml = name + '.xml' + + if not self.cache.exists(image) or not self.cache.exists(xml): + mess = 'Processing ' + media + self.logger.write_info(mess) + decoder = timeside.decoder.FileDecoder(media) + pipe = decoder | self.grapher + analyzers = [] + analyzers_sub = [] + for analyzer in self.analyzers: + subpipe = analyzer() + analyzers_sub.append(subpipe) + pipe = pipe | subpipe + pipe.run() + + mess = 'Rendering ' + image + self.logger.write_info(mess) + self.grapher.render(output=image) + + mess = 'Frames / Pixel = ' + str(self.grapher.graph.samples_per_pixel) + self.logger.write_info(mess) + + for analyzer in analyzers_sub: + value = analyzer.result() + if analyzer.id() == 'duration': + value = datetime.timedelta(0,value) + analyzers.append({'name':analyzer.name(), + 'id':analyzer.id(), + 'unit':analyzer.unit(), + 'value':str(value)}) + + self.cache.write_analyzer_xml(analyzers, xml) + + filename = name + data = name.split('.') + date = data[0] + collection_name = data[1] + other = '' + if len(data) > 2: + other = '.'.join(data[2:]) + + item = telemeta.models.media.MediaItem.objects.filter(code=filename) + collections = telemeta.models.media.MediaCollection.objects.filter(code=collection_name) + + if not collections: + c = telemeta.models.media.MediaCollection(code=collection_name) + c.title = collection_name + c.save() + msg = 'added' + self.logger.write_info(collection_name, msg) + collection = c + else: + collection = collections[0] + + if not item: + item = telemeta.models.media.MediaItem(collection=collection, code=filename) + item.title = filename + item.file = self.media_dir + os.sep + media + item.save() + msg = 'added item : ' + filename + self.logger.write_info(collection_name, msg) + + + +if __name__ == '__main__': + if len(sys.argv) <= 2: + print """ + Usage : python telemeta_preprocess_batch.py /path/to/project /path/to/media_dir /path/to/dest_dir /path/to/log + + Dependencies : timeside, python, python-numpy, python-gst0.10, gstreamer0.10-plugins-base + See http://code.google.com/p/timeside/ for more information. + """ + else: + project_dir = sys.argv[-2] + log_file = sys.argv[-1] + sys.path.append(project_dir) + import settings + setup_environ(settings) + media_dir = settings.MEDIA_ROOT + data_dir = settings.TELEMETA_DATA_CACHE_DIR + print media_dir, data_dir + t = TelemetaPreprocessImport(media_dir, data_dir, log_file) + t.process() diff --git a/scripts/old/telemeta_preprocess_cgi.py b/scripts/old/telemeta_preprocess_cgi.py new file mode 100755 index 0000000..317878b --- /dev/null +++ b/scripts/old/telemeta_preprocess_cgi.py @@ -0,0 +1,222 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2009-2010 Guillaume Pellerin + +# 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 . + +# Author: Guillaume Pellerin + +# for python2.5 + +version = '0.5' + + +import os +import sys +import time +import shutil +import datetime +import timeside + +# soon with python2.6 +#from multiprocessing import Process + +from django.core.management import setup_environ +from django.core.files.base import ContentFile +import cgi +fs = cgi.FieldStorage() + + +orig_media_dir = '/mnt/awdiomusic/musicbase' +project_dir = '/mnt/awdio' +log_file = project_dir + '/logs/process.log' +sys.path.append('/home/awdio/apps/telemeta-awdio') + + +class GrapherScheme: + + def __init__(self): + self.color = 255 + self.color_scheme = { + 'waveform': [ # Four (R,G,B) tuples for three main color channels for the spectral centroid method + (self.color,self.color,self.color) +# (0, 0, 0), (0, 0, 0), (0, 0, 0), (0,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) + ]} + + # Grapher id + self.id = 'waveform_awdio' + + # Width of the image + self.width = 1800 + + # Height of the image + self.height = 233 + + # Background color + self.bg_color = None + + # Force computation. By default, the class doesn't overwrite existing image files. + self.force = False + + # Nb of threads + # FIXME: memory leak for > 1 ! + self.threads = 1 + + +class TelemetaPreprocessImport(object): + + def __init__(self, root_dir, dest_dir, log_file): + from telemeta.cache import TelemetaCache as Cache + from telemeta.util.logger import Logger + self.media_item_dir = 'items' + self.root_dir = root_dir + 'items' + self.dest_dir = dest_dir + self.threads = 1 + self.logger = Logger(log_file) + self.counter = 0 + self.force = 0 + self.cache = Cache(self.dest_dir) + + self.scheme = GrapherScheme() + self.width = self.scheme.width + self.height = self.scheme.height + self.bg_color = self.scheme.bg_color + self.color_scheme = self.scheme.color_scheme + self.force = self.scheme.force + self.threads = self.scheme.threads + self.logger = Logger(log_file) + self.counter = 0 + self.collection_name = 'awdio' + self.collection = self.set_collection(self.collection_name) + + self.analyzers = timeside.core.processors(timeside.api.IAnalyzer) + self.grapher = timeside.grapher.WaveformAwdio(width=self.width, + height=self.height, + bg_color=self.bg_color, + color_scheme=self.color_scheme) + + + def set_collection(self, collection_name): + import telemeta.models + collections = telemeta.models.media.MediaCollection.objects.filter(code=collection_name) + if not collections: + c = telemeta.models.media.MediaCollection(code=collection_name) + c.title = collection_name + c.save() + msg = 'added' + self.logger.logger.info(collection_name, msg) + collection = c + else: + collection = collections[0] + return collection + + def process(self): + import telemeta.models + keys = fs.keys() + if keys[0] == 'file': + filename = fs['file'].value + media_orig = orig_media_dir + os.sep + filename + media = self.root_dir + os.sep + filename + + if not os.path.exists(media): + shutil.copy(media_orig, media) + os.system('chmod 644 ' + media) + + name, ext = os.path.splitext(filename) + size = str(self.width) + '_' + str(self.height) + image_name = name + '.' + self.scheme.id + '.' + size + '.png' + image = self.dest_dir + os.sep + image_name + xml = name + '.xml' + + if not self.cache.exists(image_name) or not self.cache.exists(xml): + mess = 'Processing ' + media + self.logger.logger.info(mess) + + print "Content-type: text/plain\n" + print mess + decoder = timeside.decoder.FileDecoder(media) + pipe = decoder | self.grapher + analyzers = [] + analyzers_sub = [] + for analyzer in self.analyzers: + subpipe = analyzer() + analyzers_sub.append(subpipe) + pipe = pipe | subpipe + pipe.run() + + mess = 'Rendering ' + image + self.logger.logger.info(mess) + self.grapher.render(output=image) + + mess = 'Frames / Pixel = ' + str(self.grapher.graph.samples_per_pixel) + self.logger.logger.info(mess) + + for analyzer in analyzers_sub: + value = analyzer.result() + if analyzer.id() == 'duration': + value = datetime.timedelta(0,value) + analyzers.append({'name':analyzer.name(), + 'id':analyzer.id(), + 'unit':analyzer.unit(), + 'value':str(value)}) + + self.cache.write_analyzer_xml(analyzers, xml) + + item = telemeta.models.media.MediaItem.objects.filter(code=name) + + if not item: + item = telemeta.models.media.MediaItem(collection=self.collection, code=name) + item.title = name + item.file = self.media_item_dir + os.sep + filename + item.save() + msg = 'added item : ' + filename + self.logger.logger.info(self.collection_name, msg) + + pipe = 0 + decoder = 0 + + print "OK" + + #except: + #pipe = 0 + #decoder = 0 + #mess = 'Could NOT process : ' + media + #self.logger.logger.error(mess) + #print mess + + else: + mess = "Nothing to do with file : " + media + self.logger.logger.info(mess) + print "Content-type: text/plain\n" + print mess + + else: + print "Content-type: text/plain\n" + print "No file given !" + + +if __name__ == '__main__': + sys.path.append(project_dir) + import settings + setup_environ(settings) + media_dir = settings.MEDIA_ROOT + data_dir = settings.TELEMETA_DATA_CACHE_DIR + t = TelemetaPreprocessImport(media_dir, data_dir, log_file) + t.process() diff --git a/scripts/old/waveform_batch_awdio.py b/scripts/old/waveform_batch_awdio.py new file mode 100644 index 0000000..8083c92 --- /dev/null +++ b/scripts/old/waveform_batch_awdio.py @@ -0,0 +1,151 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2009-2010 Guillaume Pellerin + +# 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 . + +# Author: Guillaume Pellerin + +version = '0.3' + +import os +import sys +import time +import timeside +from logger import Logger +import Queue +from threading import Thread + +class GrapherScheme: + + def __init__(self): + self.color = 255 + self.color_scheme = { + 'waveform': [ # Four (R,G,B) tuples for three main color channels for the spectral centroid method + (self.color,self.color,self.color) +# (0, 0, 0), (0, 0, 0), (0, 0, 0), (0,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) + ]} + + # Grapher id + self.id = 'waveform_awdio' + + # Width of the image + self.width = 1800 + + # Height of the image + self.height = 233 + + # Background color + self.bg_color = None + + # Force computation. By default, the class doesn't overwrite existing image files. + self.force = False + + # Nb of threads + # FIXME: memory leak for > 1 ! + self.threads = 1 + + +class Media2Waveform(object): + + def __init__(self, media_dir, img_dir, log_file): + self.root_dir = os.path.join(os.path.dirname(__file__), media_dir) + self.img_dir = os.path.join(os.path.dirname(__file__), img_dir) + self.scheme = GrapherScheme() + self.width = self.scheme.width + self.height = self.scheme.height + self.bg_color = self.scheme.bg_color + self.color_scheme = self.scheme.color_scheme + self.force = self.scheme.force + self.threads = self.scheme.threads + self.logger = Logger(log_file) + self.counter = 0 + + self.media_list = self.get_media_list() + if not os.path.exists(self.img_dir): + os.makedirs(self.img_dir) + self.path_dict = self.get_path_dict() + + def get_media_list(self): + media_list = [] + for root, dirs, files in os.walk(self.root_dir): + if root: + for file in files: + if file[0] != '.': + ext = file.split('.')[-1] + media_list.append(root+os.sep+file) + return media_list + + def get_path_dict(self): + path_dict = {} + for media in self.media_list: + filename = media.split(os.sep)[-1] + name, ext = os.path.splitext(filename) + size = str(self.width) + '_' + str(self.height) + image = self.img_dir + os.sep + name + '.' + self.scheme.id + '.' + size + '.png' + if not os.path.exists(image) or self.force: + path_dict[media] = image + return path_dict + + def process(self): + q = Queue.Queue() + for i in range(0, self.threads): + worker = Thread(target=Worker, args=(self.width, self.height, self.bg_color, self.color_scheme, q, self.logger)) + worker.setDaemon(True) + worker.start() + + mess = str(self.threads) + ' thread(s) started' + self.logger.write_info(mess) + + for media, image in self.path_dict.iteritems(): + q.put((media, image)) + q.join() + + +def Worker(width, height, bg_color, color_scheme, q, logger): + while True: + media, image = q.get() + mess = 'Processing ' + media + logger.write_info(mess) + decoder = timeside.decoder.FileDecoder(media) + grapher = timeside.grapher.WaveformAwdio(width=width, height=height, bg_color=bg_color, color_scheme=color_scheme) + (decoder | grapher).run() + mess = 'Rendering ' + image + logger.write_info(mess) + grapher.render(output=image) + mess = 'Frames / Pixel = ' + str(grapher.graph.samples_per_pixel) + logger.write_info(mess) + grapher.release() + q.task_done() + +if __name__ == '__main__': + if len(sys.argv) <= 2: + print """ + Usage : python waveform_batch /path/to/media_dir /path/to/img_dir + + Dependencies : timeside, python, python-numpy, python-gst0.10, gstreamer0.10-plugins-base + See http://code.google.com/p/timeside/ for more information. + """ + else: + media_dir = sys.argv[-3] + img_dir = sys.argv[-2] + log_file = sys.argv[-1] + m = Media2Waveform(media_dir, img_dir, log_file) + m.process() diff --git a/scripts/ts-waveforms b/scripts/ts-waveforms new file mode 100755 index 0000000..5be8e11 --- /dev/null +++ b/scripts/ts-waveforms @@ -0,0 +1,126 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2009-2010 Guillaume Pellerin + +# 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 . + +# Author: Guillaume Pellerin + +version = '0.2' + +import os +import sys +import timeside + + +class GrapherScheme: + + def __init__(self): + + self.color_scheme = { + 'waveform': [ + # Four (R,G,B) tuples for three main color channels for the spectral centroid method + (30,144,255), (30,144,255), (30,144,255), (30,144,255) + ], + '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) + ]} + + # Width of the image + self.width = 925 + + # Height of the image + self.height = 67 + + # Background color + self.bg_color = (-1, -1, -1, -1) + + # Force computation. By default, the class doesn't overwrite existing image files. + self.force = True + + +class Media2Waveform(object): + + def __init__(self, media_dir, img_dir): + self.root_dir = os.path.join(os.path.dirname(__file__), media_dir) + self.img_dir = os.path.join(os.path.dirname(__file__), img_dir) + self.scheme = GrapherScheme() + self.width = self.scheme.width + self.height = self.scheme.height + self.bg_color = self.scheme.bg_color + self.color_scheme = self.scheme.color_scheme + self.force = self.scheme.force + + self.media_list = self.get_media_list() + if not os.path.exists(self.img_dir): + os.makedirs(self.img_dir) + self.path_dict = self.get_path_dict() + + def get_media_list(self): + media_list = [] + for root, dirs, files in os.walk(self.root_dir): + if root: + for file in files: + ext = file.split('.')[-1] + if not file[0] == '.': + media_list.append(root+os.sep+file) + return media_list + + def get_path_dict(self): + path_dict = {} + for media in self.media_list: + filename = media.split(os.sep)[-1] + name, ext = os.path.splitext(filename) + path_dict[media] = self.img_dir + os.sep + filename.replace('.', '_') + '.png' + return path_dict + + def process(self): + waveform = timeside.grapher.Waveform(width=self.width, height=self.height, + bg_color=self.bg_color, color_scheme=self.color_scheme) + for source, image in self.path_dict.iteritems(): + if not os.path.exists(image) or self.force: + print 'Processing ', source + audio = os.path.join(os.path.dirname(__file__), source) + decoder = timeside.decoder.FileDecoder(audio) + duration = decoder.duration + (decoder | waveform).run() + img_name = os.path.split(image)[1] + image = os.path.split(image)[0]+os.sep+os.path.splitext(img_name)[0] + '_' +\ + '_'.join([str(self.width), str(self.height), + str(int(duration))])+os.path.splitext(img_name)[1] + waveform.graph.filename = image + print 'Rendering ', waveform.graph.filename + #print 'frames per pixel = ', waveform.graph.samples_per_pixel + waveform.render(output=image) + + +if __name__ == '__main__': + if len(sys.argv) <= 1: + print """ + TimeSide simple waveform generator + + Usage : python waveform_batch.py /path/to/media_dir /path/to/img_dir + + Dependencies : timeside, python, python-numpy, python-gst0.10, gstreamer0.10-plugins-base + See http://code.google.com/p/timeside/ for more information. + """ + else: + media_dir = sys.argv[-2] + img_dir = sys.argv[-1] + m = Media2Waveform(media_dir, img_dir) + m.process() diff --git a/setup.py b/setup.py index cfbb4cf..e76cf43 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup, find_packages -import os CLASSIFIERS = [ 'Intended Audience :: Science/Research', diff --git a/timeside/tools/telemeta_preprocess_batch.py b/timeside/tools/telemeta_preprocess_batch.py deleted file mode 100644 index 81986a2..0000000 --- a/timeside/tools/telemeta_preprocess_batch.py +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (c) 2009-2010 Guillaume Pellerin - -# 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 . - -# Author: Guillaume Pellerin - -version = '0.4' - -import os -import sys -import time -import datetime -import timeside -from logger import Logger -import Queue -from threading import Thread -from cache import Cache -from django.core.management import setup_environ -from django.core.files.base import ContentFile - - -class GrapherScheme: - - def __init__(self): - self.color = 255 - self.color_scheme = { - 'waveform': [ # Four (R,G,B) tuples for three main color channels for the spectral centroid method - (self.color,self.color,self.color) -# (0, 0, 0), (0, 0, 0), (0, 0, 0), (0,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) - ]} - - # Grapher id - self.id = 'waveform_awdio' - - # Width of the image - self.width = 1800 - - # Height of the image - self.height = 233 - - # Background color - self.bg_color = None - - # Force computation. By default, the class doesn't overwrite existing image files. - self.force = False - - # Nb of threads - # FIXME: memory leak for > 1 ! - self.threads = 1 - - -class TelemetaPreprocessImport(object): - - def __init__(self, media_dir, dest_dir, log_file): - self.root_dir = media_dir - self.dest_dir = dest_dir - self.threads = 1 - self.logger = Logger(log_file) - self.counter = 0 - self.force = 0 - self.cache = Cache(self.dest_dir) - - self.scheme = GrapherScheme() - self.width = self.scheme.width - self.height = self.scheme.height - self.bg_color = self.scheme.bg_color - self.color_scheme = self.scheme.color_scheme - self.force = self.scheme.force - self.threads = self.scheme.threads - self.logger = Logger(log_file) - self.counter = 0 - - self.analyzers = timeside.core.processors(timeside.api.IAnalyzer) - self.grapher = timeside.grapher.WaveformAwdio(width=self.width, - height=self.height, - bg_color=self.bg_color, - color_scheme=self.color_scheme) - - self.media_list = self.get_media_list() - if not os.path.exists(self.dest_dir): - os.makedirs(self.dest_dir) - - def get_media_list(self): - media_list = [] - for root, dirs, files in os.walk(self.root_dir): - if root: - for file in files: - if file[0] != '.': - ext = file.split('.')[-1] - media_list.append(root+os.sep+file) - return media_list - - def process(self): - for media in self.media_list: - filename = media.split(os.sep)[-1] - name, ext = os.path.splitext(filename) - size = str(self.width) + '_' + str(self.height) - image = self.dest_dir + os.sep + name + '.' + self.scheme.id + '.' + size + '.png' - xml = name + '.xml' - - if not self.cache.exists(image) or not self.cache.exists(xml): - mess = 'Processing ' + media - self.logger.write_info(mess) - decoder = timeside.decoder.FileDecoder(media) - pipe = decoder | self.grapher - analyzers = [] - analyzers_sub = [] - for analyzer in self.analyzers: - subpipe = analyzer() - analyzers_sub.append(subpipe) - pipe = pipe | subpipe - pipe.run() - - mess = 'Rendering ' + image - self.logger.write_info(mess) - self.grapher.render(output=image) - - mess = 'Frames / Pixel = ' + str(self.grapher.graph.samples_per_pixel) - self.logger.write_info(mess) - - for analyzer in analyzers_sub: - value = analyzer.result() - if analyzer.id() == 'duration': - value = datetime.timedelta(0,value) - analyzers.append({'name':analyzer.name(), - 'id':analyzer.id(), - 'unit':analyzer.unit(), - 'value':str(value)}) - - self.cache.write_analyzer_xml(analyzers, xml) - - filename = name - data = name.split('.') - date = data[0] - collection_name = data[1] - other = '' - if len(data) > 2: - other = '.'.join(data[2:]) - - item = telemeta.models.media.MediaItem.objects.filter(code=filename) - collections = telemeta.models.media.MediaCollection.objects.filter(code=collection_name) - - if not collections: - c = telemeta.models.media.MediaCollection(code=collection_name) - c.title = collection_name - c.save() - msg = 'added' - self.logger.write_info(collection_name, msg) - collection = c - else: - collection = collections[0] - - if not item: - item = telemeta.models.media.MediaItem(collection=collection, code=filename) - item.title = filename - item.file = self.media_dir + os.sep + media - item.save() - msg = 'added item : ' + filename - self.logger.write_info(collection_name, msg) - - - -if __name__ == '__main__': - if len(sys.argv) <= 2: - print """ - Usage : python telemeta_preprocess_batch.py /path/to/project /path/to/media_dir /path/to/dest_dir /path/to/log - - Dependencies : timeside, python, python-numpy, python-gst0.10, gstreamer0.10-plugins-base - See http://code.google.com/p/timeside/ for more information. - """ - else: - project_dir = sys.argv[-2] - log_file = sys.argv[-1] - sys.path.append(project_dir) - import settings - setup_environ(settings) - media_dir = settings.MEDIA_ROOT - data_dir = settings.TELEMETA_DATA_CACHE_DIR - print media_dir, data_dir - t = TelemetaPreprocessImport(media_dir, data_dir, log_file) - t.process() diff --git a/timeside/tools/telemeta_preprocess_cgi.py b/timeside/tools/telemeta_preprocess_cgi.py deleted file mode 100755 index 317878b..0000000 --- a/timeside/tools/telemeta_preprocess_cgi.py +++ /dev/null @@ -1,222 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (c) 2009-2010 Guillaume Pellerin - -# 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 . - -# Author: Guillaume Pellerin - -# for python2.5 - -version = '0.5' - - -import os -import sys -import time -import shutil -import datetime -import timeside - -# soon with python2.6 -#from multiprocessing import Process - -from django.core.management import setup_environ -from django.core.files.base import ContentFile -import cgi -fs = cgi.FieldStorage() - - -orig_media_dir = '/mnt/awdiomusic/musicbase' -project_dir = '/mnt/awdio' -log_file = project_dir + '/logs/process.log' -sys.path.append('/home/awdio/apps/telemeta-awdio') - - -class GrapherScheme: - - def __init__(self): - self.color = 255 - self.color_scheme = { - 'waveform': [ # Four (R,G,B) tuples for three main color channels for the spectral centroid method - (self.color,self.color,self.color) -# (0, 0, 0), (0, 0, 0), (0, 0, 0), (0,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) - ]} - - # Grapher id - self.id = 'waveform_awdio' - - # Width of the image - self.width = 1800 - - # Height of the image - self.height = 233 - - # Background color - self.bg_color = None - - # Force computation. By default, the class doesn't overwrite existing image files. - self.force = False - - # Nb of threads - # FIXME: memory leak for > 1 ! - self.threads = 1 - - -class TelemetaPreprocessImport(object): - - def __init__(self, root_dir, dest_dir, log_file): - from telemeta.cache import TelemetaCache as Cache - from telemeta.util.logger import Logger - self.media_item_dir = 'items' - self.root_dir = root_dir + 'items' - self.dest_dir = dest_dir - self.threads = 1 - self.logger = Logger(log_file) - self.counter = 0 - self.force = 0 - self.cache = Cache(self.dest_dir) - - self.scheme = GrapherScheme() - self.width = self.scheme.width - self.height = self.scheme.height - self.bg_color = self.scheme.bg_color - self.color_scheme = self.scheme.color_scheme - self.force = self.scheme.force - self.threads = self.scheme.threads - self.logger = Logger(log_file) - self.counter = 0 - self.collection_name = 'awdio' - self.collection = self.set_collection(self.collection_name) - - self.analyzers = timeside.core.processors(timeside.api.IAnalyzer) - self.grapher = timeside.grapher.WaveformAwdio(width=self.width, - height=self.height, - bg_color=self.bg_color, - color_scheme=self.color_scheme) - - - def set_collection(self, collection_name): - import telemeta.models - collections = telemeta.models.media.MediaCollection.objects.filter(code=collection_name) - if not collections: - c = telemeta.models.media.MediaCollection(code=collection_name) - c.title = collection_name - c.save() - msg = 'added' - self.logger.logger.info(collection_name, msg) - collection = c - else: - collection = collections[0] - return collection - - def process(self): - import telemeta.models - keys = fs.keys() - if keys[0] == 'file': - filename = fs['file'].value - media_orig = orig_media_dir + os.sep + filename - media = self.root_dir + os.sep + filename - - if not os.path.exists(media): - shutil.copy(media_orig, media) - os.system('chmod 644 ' + media) - - name, ext = os.path.splitext(filename) - size = str(self.width) + '_' + str(self.height) - image_name = name + '.' + self.scheme.id + '.' + size + '.png' - image = self.dest_dir + os.sep + image_name - xml = name + '.xml' - - if not self.cache.exists(image_name) or not self.cache.exists(xml): - mess = 'Processing ' + media - self.logger.logger.info(mess) - - print "Content-type: text/plain\n" - print mess - decoder = timeside.decoder.FileDecoder(media) - pipe = decoder | self.grapher - analyzers = [] - analyzers_sub = [] - for analyzer in self.analyzers: - subpipe = analyzer() - analyzers_sub.append(subpipe) - pipe = pipe | subpipe - pipe.run() - - mess = 'Rendering ' + image - self.logger.logger.info(mess) - self.grapher.render(output=image) - - mess = 'Frames / Pixel = ' + str(self.grapher.graph.samples_per_pixel) - self.logger.logger.info(mess) - - for analyzer in analyzers_sub: - value = analyzer.result() - if analyzer.id() == 'duration': - value = datetime.timedelta(0,value) - analyzers.append({'name':analyzer.name(), - 'id':analyzer.id(), - 'unit':analyzer.unit(), - 'value':str(value)}) - - self.cache.write_analyzer_xml(analyzers, xml) - - item = telemeta.models.media.MediaItem.objects.filter(code=name) - - if not item: - item = telemeta.models.media.MediaItem(collection=self.collection, code=name) - item.title = name - item.file = self.media_item_dir + os.sep + filename - item.save() - msg = 'added item : ' + filename - self.logger.logger.info(self.collection_name, msg) - - pipe = 0 - decoder = 0 - - print "OK" - - #except: - #pipe = 0 - #decoder = 0 - #mess = 'Could NOT process : ' + media - #self.logger.logger.error(mess) - #print mess - - else: - mess = "Nothing to do with file : " + media - self.logger.logger.info(mess) - print "Content-type: text/plain\n" - print mess - - else: - print "Content-type: text/plain\n" - print "No file given !" - - -if __name__ == '__main__': - sys.path.append(project_dir) - import settings - setup_environ(settings) - media_dir = settings.MEDIA_ROOT - data_dir = settings.TELEMETA_DATA_CACHE_DIR - t = TelemetaPreprocessImport(media_dir, data_dir, log_file) - t.process() diff --git a/timeside/tools/waveform_batch.py b/timeside/tools/waveform_batch.py deleted file mode 100644 index 5be8e11..0000000 --- a/timeside/tools/waveform_batch.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (c) 2009-2010 Guillaume Pellerin - -# 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 . - -# Author: Guillaume Pellerin - -version = '0.2' - -import os -import sys -import timeside - - -class GrapherScheme: - - def __init__(self): - - self.color_scheme = { - 'waveform': [ - # Four (R,G,B) tuples for three main color channels for the spectral centroid method - (30,144,255), (30,144,255), (30,144,255), (30,144,255) - ], - '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) - ]} - - # Width of the image - self.width = 925 - - # Height of the image - self.height = 67 - - # Background color - self.bg_color = (-1, -1, -1, -1) - - # Force computation. By default, the class doesn't overwrite existing image files. - self.force = True - - -class Media2Waveform(object): - - def __init__(self, media_dir, img_dir): - self.root_dir = os.path.join(os.path.dirname(__file__), media_dir) - self.img_dir = os.path.join(os.path.dirname(__file__), img_dir) - self.scheme = GrapherScheme() - self.width = self.scheme.width - self.height = self.scheme.height - self.bg_color = self.scheme.bg_color - self.color_scheme = self.scheme.color_scheme - self.force = self.scheme.force - - self.media_list = self.get_media_list() - if not os.path.exists(self.img_dir): - os.makedirs(self.img_dir) - self.path_dict = self.get_path_dict() - - def get_media_list(self): - media_list = [] - for root, dirs, files in os.walk(self.root_dir): - if root: - for file in files: - ext = file.split('.')[-1] - if not file[0] == '.': - media_list.append(root+os.sep+file) - return media_list - - def get_path_dict(self): - path_dict = {} - for media in self.media_list: - filename = media.split(os.sep)[-1] - name, ext = os.path.splitext(filename) - path_dict[media] = self.img_dir + os.sep + filename.replace('.', '_') + '.png' - return path_dict - - def process(self): - waveform = timeside.grapher.Waveform(width=self.width, height=self.height, - bg_color=self.bg_color, color_scheme=self.color_scheme) - for source, image in self.path_dict.iteritems(): - if not os.path.exists(image) or self.force: - print 'Processing ', source - audio = os.path.join(os.path.dirname(__file__), source) - decoder = timeside.decoder.FileDecoder(audio) - duration = decoder.duration - (decoder | waveform).run() - img_name = os.path.split(image)[1] - image = os.path.split(image)[0]+os.sep+os.path.splitext(img_name)[0] + '_' +\ - '_'.join([str(self.width), str(self.height), - str(int(duration))])+os.path.splitext(img_name)[1] - waveform.graph.filename = image - print 'Rendering ', waveform.graph.filename - #print 'frames per pixel = ', waveform.graph.samples_per_pixel - waveform.render(output=image) - - -if __name__ == '__main__': - if len(sys.argv) <= 1: - print """ - TimeSide simple waveform generator - - Usage : python waveform_batch.py /path/to/media_dir /path/to/img_dir - - Dependencies : timeside, python, python-numpy, python-gst0.10, gstreamer0.10-plugins-base - See http://code.google.com/p/timeside/ for more information. - """ - else: - media_dir = sys.argv[-2] - img_dir = sys.argv[-1] - m = Media2Waveform(media_dir, img_dir) - m.process() diff --git a/timeside/tools/waveform_batch_awdio.py b/timeside/tools/waveform_batch_awdio.py deleted file mode 100644 index 8083c92..0000000 --- a/timeside/tools/waveform_batch_awdio.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (c) 2009-2010 Guillaume Pellerin - -# 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 . - -# Author: Guillaume Pellerin - -version = '0.3' - -import os -import sys -import time -import timeside -from logger import Logger -import Queue -from threading import Thread - -class GrapherScheme: - - def __init__(self): - self.color = 255 - self.color_scheme = { - 'waveform': [ # Four (R,G,B) tuples for three main color channels for the spectral centroid method - (self.color,self.color,self.color) -# (0, 0, 0), (0, 0, 0), (0, 0, 0), (0,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) - ]} - - # Grapher id - self.id = 'waveform_awdio' - - # Width of the image - self.width = 1800 - - # Height of the image - self.height = 233 - - # Background color - self.bg_color = None - - # Force computation. By default, the class doesn't overwrite existing image files. - self.force = False - - # Nb of threads - # FIXME: memory leak for > 1 ! - self.threads = 1 - - -class Media2Waveform(object): - - def __init__(self, media_dir, img_dir, log_file): - self.root_dir = os.path.join(os.path.dirname(__file__), media_dir) - self.img_dir = os.path.join(os.path.dirname(__file__), img_dir) - self.scheme = GrapherScheme() - self.width = self.scheme.width - self.height = self.scheme.height - self.bg_color = self.scheme.bg_color - self.color_scheme = self.scheme.color_scheme - self.force = self.scheme.force - self.threads = self.scheme.threads - self.logger = Logger(log_file) - self.counter = 0 - - self.media_list = self.get_media_list() - if not os.path.exists(self.img_dir): - os.makedirs(self.img_dir) - self.path_dict = self.get_path_dict() - - def get_media_list(self): - media_list = [] - for root, dirs, files in os.walk(self.root_dir): - if root: - for file in files: - if file[0] != '.': - ext = file.split('.')[-1] - media_list.append(root+os.sep+file) - return media_list - - def get_path_dict(self): - path_dict = {} - for media in self.media_list: - filename = media.split(os.sep)[-1] - name, ext = os.path.splitext(filename) - size = str(self.width) + '_' + str(self.height) - image = self.img_dir + os.sep + name + '.' + self.scheme.id + '.' + size + '.png' - if not os.path.exists(image) or self.force: - path_dict[media] = image - return path_dict - - def process(self): - q = Queue.Queue() - for i in range(0, self.threads): - worker = Thread(target=Worker, args=(self.width, self.height, self.bg_color, self.color_scheme, q, self.logger)) - worker.setDaemon(True) - worker.start() - - mess = str(self.threads) + ' thread(s) started' - self.logger.write_info(mess) - - for media, image in self.path_dict.iteritems(): - q.put((media, image)) - q.join() - - -def Worker(width, height, bg_color, color_scheme, q, logger): - while True: - media, image = q.get() - mess = 'Processing ' + media - logger.write_info(mess) - decoder = timeside.decoder.FileDecoder(media) - grapher = timeside.grapher.WaveformAwdio(width=width, height=height, bg_color=bg_color, color_scheme=color_scheme) - (decoder | grapher).run() - mess = 'Rendering ' + image - logger.write_info(mess) - grapher.render(output=image) - mess = 'Frames / Pixel = ' + str(grapher.graph.samples_per_pixel) - logger.write_info(mess) - grapher.release() - q.task_done() - -if __name__ == '__main__': - if len(sys.argv) <= 2: - print """ - Usage : python waveform_batch /path/to/media_dir /path/to/img_dir - - Dependencies : timeside, python, python-numpy, python-gst0.10, gstreamer0.10-plugins-base - See http://code.google.com/p/timeside/ for more information. - """ - else: - media_dir = sys.argv[-3] - img_dir = sys.argv[-2] - log_file = sys.argv[-1] - m = Media2Waveform(media_dir, img_dir, log_file) - m.process()