From d16c303350ec5f67cd614f363047411bbc5bdc7d Mon Sep 17 00:00:00 2001 From: yomguy Date: Thu, 7 Oct 2010 21:56:42 +0000 Subject: [PATCH] (re)add joydiv waveform --- timeside/grapher/__init__.py | 2 +- timeside/grapher/waveform_joydiv.py | 184 ++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 timeside/grapher/waveform_joydiv.py diff --git a/timeside/grapher/__init__.py b/timeside/grapher/__init__.py index c0f9246..35f0db5 100644 --- a/timeside/grapher/__init__.py +++ b/timeside/grapher/__init__.py @@ -3,4 +3,4 @@ from core import * from waveform import * from spectrogram import * -#from waveform_joy import * +from waveform_joydiv import * diff --git a/timeside/grapher/waveform_joydiv.py b/timeside/grapher/waveform_joydiv.py new file mode 100644 index 0000000..5de1a34 --- /dev/null +++ b/timeside/grapher/waveform_joydiv.py @@ -0,0 +1,184 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2007-2010 Guillaume Pellerin +# Copyright (c) 2010 Olivier Guilyardi + +# 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 . + + +from timeside.core import Processor, implements, interfacedoc, FixedSizeInputAdapter +from timeside.api import IGrapher +from timeside.grapher.core import * + +class WaveformImageJoyContour(WaveformImage): + + def __init__(self, image_width, image_height, nframes, samplerate, fft_size, bg_color, color_scheme, ndiv=1, symetry=None): + WaveformImage.__init__(self, image_width, image_height, nframes, samplerate, fft_size, bg_color, color_scheme) + self.contour = numpy.zeros(self.image_width) + self.centroids = numpy.zeros(self.image_width) + self.ndiv = ndiv + self.x = numpy.r_[0:self.image_width-1:1] + self.dx1 = self.x[1]-self.x[0] + self.symetry = symetry + + def get_peaks_contour(self, x, peaks, spectral_centroid=None): + self.contour[x] = numpy.max(peaks) + self.centroids[x] = spectral_centroid + + def mean(self, samples): + return numpy.mean(samples) + + def normalize(self, contour): + contour = contour-min(contour) + return contour/max(contour) + + def draw_peaks_contour(self): + contour = self.contour.copy() + + # Smoothing + contour = smooth(contour, window_len=16) + + # Normalize + contour = self.normalize(contour) + + # Scaling + #ratio = numpy.mean(contour)/numpy.sqrt(2) + ratio = 1 + contour = self.normalize(numpy.expm1(contour/ratio))*(1-10**-6) + + # Spline + #contour = cspline1d(contour) + #contour = cspline1d_eval(contour, self.x, dx=self.dx1, x0=self.x[0]) + + if self.symetry: + height = int(self.image_height/2) + else: + height = self.image_height + + # Multicurve rotating + for i in range(0,self.ndiv): + self.previous_x, self.previous_y = None, None + + #bright_color = 255 + bright_color = int(255*(1-float(i)/(self.ndiv*2))) + bright_color = 255-bright_color+160 +# line_color = self.color_lookup[int(self.centroids[j]*255.0)] + line_color = (bright_color,bright_color,bright_color) + + # Linear + #contour = contour*(1.0-float(i)/self.ndiv) + #contour = contour*(1-float(i)/self.ndiv) + + # Cosine + contour = contour*numpy.arccos(float(i)/self.ndiv)*2/numpy.pi + #contour = self.contour*(1-float(i)*numpy.arccos(float(i)/self.ndiv)*2/numpy.pi/self.ndiv) + + # Negative Sine + #contour = contour + ((1-contour)*2/numpy.pi*numpy.arcsin(float(i)/self.ndiv)) + + curve = (height-1)*contour +# curve = contour*(height-2)/2+height/2 + + for x in self.x: + x = int(x) + y = curve[x] + if not x == 0: + if not self.symetry: + self.draw.line([self.previous_x, self.previous_y, x, y], line_color) + #self.draw_anti_aliased_pixels(x, y, y, line_color) + else: + self.draw.line([self.previous_x, self.previous_y+height, x, y+height], line_color) + #self.draw_anti_aliased_pixels(x, y+height, y+height, line_color) + self.draw.line([self.previous_x, -self.previous_y+height, x, -y+height], line_color) + #self.draw_anti_aliased_pixels(x, -y+height, -y+height, line_color) + else: + if not self.symetry: + self.draw.point((x, y), line_color) + else: + self.draw.point((x, y+height), line_color) + self.previous_x, self.previous_y = x, y + + def process(self, frames, eod): + if len(frames) != 1: + buffer = frames[:,0].copy() + buffer.shape = (len(buffer),1) + for samples, end in self.pixels_adapter.process(buffer, eod): + if self.pixel_cursor < self.image_width: + #(spectral_centroid, db_spectrum) = self.spectrum.process(buffer, True) + peaks = self.peaks(samples) + self.get_peaks_contour(self.pixel_cursor, peaks) + self.pixel_cursor += 1 + if eod: + self.draw_peaks_contour() + + def save(self, filename): + """ Apply last 2D transforms and write all pixels to the file. """ + # middle line (0 for none) + a = 1 + 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])) +# self.image = self.image.transpose(Image.FLIP_TOP_BOTTOM) + self.image.save(filename) + + +class WaveformJoyDiv(Processor): + implements(IGrapher) + + FFT_SIZE = 0x400 + + @interfacedoc + def __init__(self, width=1024, height=256, bg_color=(136,136,136), color_scheme='default'): + self.width = width + self.height = height + self.bg_color = bg_color + self.color_scheme = color_scheme + self.graph = None + self.ndiv = 4 + self.symetry = True + + @staticmethod + @interfacedoc + def id(): + return "waveform_joydiv" + + @staticmethod + @interfacedoc + def name(): + return "Waveform JoyDiv" + + @interfacedoc + def set_colors(self, background, scheme): + self.bg_color = background + self.color_scheme = scheme + + @interfacedoc + def setup(self, channels=None, samplerate=None, nframes=None): + super(WaveformJoyDiv, self).setup(channels, samplerate, nframes) + if self.graph: + self.graph = None + self.graph = WaveformImageJoyContour(self.width, self.height, self.nframes(), self.samplerate(), self.FFT_SIZE, + bg_color=self.bg_color, color_scheme=self.color_scheme, ndiv=self.ndiv, symetry=self.symetry) + + @interfacedoc + def process(self, frames, eod=False): + self.graph.process(frames, eod) + return frames, eod + + @interfacedoc + def render(self, output): + if output: + self.graph.save(output) + return self.graph.image -- 2.39.5