From: Guillaume Pellerin Date: Sun, 20 Oct 2013 16:36:00 +0000 (+0200) Subject: begin grapher refactoring X-Git-Tag: 0.5.1-0~28 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=5bc3390d1e24717be36838ab6acbaeeae69e5e3d;p=timeside.git begin grapher refactoring --- diff --git a/timeside/encoder/mp3.py b/timeside/encoder/mp3.py index 3056d47..28f6169 100644 --- a/timeside/encoder/mp3.py +++ b/timeside/encoder/mp3.py @@ -1,4 +1,4 @@ - # -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # # Copyright (C) 2007-2012 Parisson SARL # Copyright (c) 2006-2012 Guillaume Pellerin @@ -24,7 +24,7 @@ # Authors: Guillaume Pellerin # Paul Brossier -from timeside.core import Processor, implements, interfacedoc +from timeside.core import implements, interfacedoc from timeside.encoder.core import GstEncoder from timeside.api import IEncoder from timeside.tools import * diff --git a/timeside/grapher/core.py b/timeside/grapher/core.py index ffcaa55..ebc2c2e 100644 --- a/timeside/grapher/core.py +++ b/timeside/grapher/core.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# wav2png.py -- converts wave files to wave file and spectrogram images # Copyright (C) 2008 MUSIC TECHNOLOGY GROUP (MTG) # UNIVERSITAT POMPEU FABRA # @@ -31,31 +30,8 @@ except ImportError: import ImageFilter, ImageChops, Image, ImageDraw, ImageColor, ImageEnhance from timeside.core import FixedSizeInputAdapter - - -default_color_schemes = { - 'default': { - 'waveform': [(50,0,200), (0,220,80), (255,224,0), (255,0,0)], - 'spectrogram': [(0, 0, 0), (58/4,68/4,65/4), (80/2,100/2,153/2), (90,180,100), - (224,224,44), (255,60,30), (255,255,255)] - }, - 'iso': { - 'waveform': [(0,0,255), (0,255,255), (255,255,0), (255,0,0)], - 'spectrogram': [(0, 0, 0), (58/4,68/4,65/4), (80/2,100/2,153/2), (90,180,100), - (224,224,44), (255,60,30), (255,255,255)] - }, - 'purple': { - 'waveform': [(173,173,173), (147,149,196), (77,80,138), (108,66,0)], - 'spectrogram': [(0, 0, 0), (58/4,68/4,65/4), (80/2,100/2,153/2), (90,180,100), - (224,224,44), (255,60,30), (255,255,255)] - }, - 'awdio': { - 'waveform': [(255,255,255), (255,255,255), (255,255,255), (255,255,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)] - }, -} - +from color_schemes import default_color_schemes +from utils import * class Spectrum(object): """ FFT based frequency analysis of audio frames.""" @@ -113,35 +89,6 @@ class Spectrum(object): return (spectral_centroid, db_spectrum) -def interpolate_colors(colors, flat=False, num_colors=256): - """ Given a list of colors, create a larger list of colors interpolating - the first one. If flatten is True a list of numers will be returned. If - False, a list of (r,g,b) tuples. num_colors is the number of colors wanted - in the final list """ - - palette = [] - - for i in range(num_colors): - index = (i * (len(colors) - 1))/(num_colors - 1.0) - index_int = int(index) - alpha = index - float(index_int) - - if alpha > 0: - r = (1.0 - alpha) * colors[index_int][0] + alpha * colors[index_int + 1][0] - g = (1.0 - alpha) * colors[index_int][1] + alpha * colors[index_int + 1][1] - b = (1.0 - alpha) * colors[index_int][2] + alpha * colors[index_int + 1][2] - else: - r = (1.0 - alpha) * colors[index_int][0] - g = (1.0 - alpha) * colors[index_int][1] - b = (1.0 - alpha) * colors[index_int][2] - - if flat: - palette.extend((int(r), int(g), int(b))) - else: - palette.append((int(r), int(g), int(b))) - - return palette - class WaveformImage(object): """ Builds a PIL image representing a waveform of the audio stream. @@ -570,158 +517,6 @@ class SpectrogramImage(object): pass -class Noise(object): - """A class that mimics audiolab.sndfile but generates noise instead of reading - a wave file. Additionally it can be told to have a "broken" header and thus crashing - in the middle of the file. Also useful for testing ultra-short files of 20 samples.""" - - def __init__(self, num_frames, has_broken_header=False): - self.seekpoint = 0 - self.num_frames = num_frames - self.has_broken_header = has_broken_header - - def seek(self, seekpoint): - self.seekpoint = seekpoint - - def get_nframes(self): - return self.num_frames - - def get_samplerate(self): - return 44100 - - def get_channels(self): - return 1 - - def read_frames(self, frames_to_read): - if self.has_broken_header and self.seekpoint + frames_to_read > self.num_frames / 2: - raise IOError() - - num_frames_left = self.num_frames - self.seekpoint - if num_frames_left < frames_to_read: - will_read = num_frames_left - else: - will_read = frames_to_read - self.seekpoint += will_read - return numpy.random.random(will_read)*2 - 1 - - -# TOOLS - -def downsample(vector, factor): - """ - downsample(vector, factor): - Downsample (by averaging) a vector by an integer factor. - """ - if (len(vector) % factor): - print "Length of 'vector' is not divisible by 'factor'=%d!" % factor - return 0 - vector.shape = (len(vector)/factor, factor) - return numpy.mean(vector, axis=1) - - -def smooth(x, window_len=10, window='hanning'): - """ - Smooth the data using a window with requested size. - - This method is based on the convolution of a scaled window with the signal. - The signal is prepared by introducing reflected copies of the signal - (with the window size) in both ends so that transient parts are minimized - in the begining and end part of the output signal. - - Parameters - ---------- - x : numpy.array - the input signal - window_len : int - the dimension of the smoothing window - window : str - the type of window from 'flat', 'hanning', 'hamming', 'bartlett', 'blackman' - flat window will produce a moving average smoothing. - - Returns - ------- - The smoothed signal - - See Also - -------- - - numpy.hanning, numpy.hamming, numpy.bartlett, numpy.blackman, numpy.convolve - scipy.signal.lfilter - - - Examples - -------- - - >>> import numpy as np - >>> from timeside.grapher import smooth - >>> t = np.arange(-2,2,0.1) - >>> x = np.sin(t)+np.random.randn(len(t))*0.1 - >>> y = smooth(x) - >>> import matplotlib.pyplot as plt - >>> plt.plot(x) # doctest: +ELLIPSIS - [] - >>> plt.plot(y) # doctest: +ELLIPSIS - [] - >>> plt.legend(['Source signal', 'Smoothed signal']) # doctest: +ELLIPSIS - - >>> plt.show() # doctest: +SKIP - """ - - # TODO: the window parameter could be the window itself if an array instead of a string - - - if x.ndim != 1: - raise ValueError, "smooth only accepts 1 dimension arrays." - - if x.size < window_len: - raise ValueError, "Input vector needs to be bigger than window size." - - if window_len < 3: - return x - - if not window in ['flat', 'hanning', 'hamming', 'bartlett', 'blackman']: - raise ValueError, "Window is on of 'flat', 'hanning', 'hamming', 'bartlett', 'blackman'" - - s=numpy.r_[2*x[0]-x[window_len:1:-1], x, 2*x[-1]-x[-1:-window_len:-1]] - - if window == 'flat': #moving average - w = numpy.ones(window_len,'d') - else: - w = getattr(numpy, window)(window_len) - - y = numpy.convolve(w/w.sum(), s, mode='same') - return y[window_len-1:-window_len+1] - - -def reduce_opacity(im, opacity): - """Returns an image with reduced opacity.""" - assert opacity >= 0 and opacity <= 1 - if im.mode != 'RGBA': - im = im.convert('RGBA') - else: - im = im.copy() - alpha = im.split()[3] - alpha = ImageEnhance.Brightness(alpha).enhance(opacity) - im.putalpha(alpha) - return im - - -def im_watermark(im, inputtext, font=None, color=None, opacity=.6, margin=(30,30)): - """ - imprints a PIL image with the indicated text in lower-right corner - """ - if im.mode != "RGBA": - im = im.convert("RGBA") - textlayer = Image.new("RGBA", im.size, (0,0,0,0)) - textdraw = ImageDraw.Draw(textlayer) - textsize = textdraw.textsize(inputtext, font=font) - textpos = [im.size[i]-textsize[i]-margin[i] for i in [0,1]] - textdraw.text(textpos, inputtext, font=font, fill=color) - if opacity != 1: - textlayer = reduce_opacity(textlayer,opacity) - return Image.composite(textlayer, im, textlayer) - - if __name__ == "__main__": import doctest doctest.testmod() \ No newline at end of file