Package timeside :: Package grapher :: Module spectrogram_log
[hide private]
[frames] | no frames]

Source Code for Module timeside.grapher.spectrogram_log

 1  # -*- coding: utf-8 -*- 
 2  # 
 3  # Copyright (c) 2007-2010 Guillaume Pellerin <yomguy@parisson.com> 
 4  # Copyright (c) 2010 Olivier Guilyardi <olivier@samalyse.com> 
 5   
 6  # This file is part of TimeSide. 
 7   
 8  # TimeSide is free software: you can redistribute it and/or modify 
 9  # it under the terms of the GNU General Public License as published by 
10  # the Free Software Foundation, either version 2 of the License, or 
11  # (at your option) any later version. 
12   
13  # TimeSide is distributed in the hope that it will be useful, 
14  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
16  # GNU General Public License for more details. 
17   
18  # You should have received a copy of the GNU General Public License 
19  # along with TimeSide.  If not, see <http://www.gnu.org/licenses/>. 
20   
21   
22  from timeside.core import implements, interfacedoc 
23  from timeside.api import IGrapher 
24  from timeside.grapher.core import * 
25 26 27 -class SpectrogramLog(Grapher):
28 """ Builds a PIL image representing a spectrogram of the audio stream (level vs. frequency vs. time). 29 Adds pixels iteratively thanks to the adapter providing fixed size frame buffers.""" 30 31 implements(IGrapher) 32 33 @interfacedoc
34 - def __init__(self, width=1024, height=256, bg_color=(0,0,0), color_scheme='default'):
35 super(SpectrogramLog, self).__init__(width, height, bg_color, color_scheme) 36 self.lower_freq = 100 37 self.colors = default_color_schemes[color_scheme]['spectrogram'] 38 self.pixels = [] 39 self.y_to_bin = []
40 41 @staticmethod 42 @interfacedoc
43 - def id():
44 return "spectrogram_log"
45 46 @staticmethod 47 @interfacedoc
48 - def name():
49 return "SpectrogramLog"
50 51 @interfacedoc
52 - def setup(self, channels=None, samplerate=None, blocksize=None, totalframes=None):
53 super(SpectrogramLog, self).setup(channels, samplerate, blocksize, totalframes) 54 self.image = self.image.convert("P") 55 self.image = self.image.transpose(Image.ROTATE_90) 56 self.image.putpalette(interpolate_colors(self.colors, True)) 57 self.set_scale()
58
59 - def set_scale(self):
60 """generate the lookup which translates y-coordinate to fft-bin""" 61 62 f_min = float(self.lower_freq) 63 f_max = float(self.higher_freq) 64 y_min = math.log10(f_min) 65 y_max = math.log10(f_max) 66 for y in range(self.image_height): 67 freq = math.pow(10.0, y_min + y / (self.image_height - 1.0) *(y_max - y_min)) 68 fft_bin = freq / f_max * (self.fft_size/2 + 1) 69 if fft_bin < self.fft_size/2: 70 alpha = fft_bin - int(fft_bin) 71 self.y_to_bin.append((int(fft_bin), alpha * 255))
72
73 - def draw_spectrum(self, x, spectrum):
74 for (index, alpha) in self.y_to_bin: 75 self.pixels.append( int( ((255.0-alpha) * spectrum[index] + alpha * spectrum[index + 1] )) ) 76 for y in range(len(self.y_to_bin), self.image_height): 77 self.pixels.append(0)
78 79 @interfacedoc
80 - def process(self, frames, eod=False):
81 if len(frames) != 1: 82 chunk = frames[:,0].copy() 83 chunk.shape = (len(chunk),1) 84 for samples, end in self.pixels_adapter.process(chunk, eod): 85 if self.pixel_cursor < self.image_width: 86 (spectral_centroid, db_spectrum) = self.spectrum.process(samples, True) 87 self.draw_spectrum(self.pixel_cursor, db_spectrum) 88 self.pixel_cursor += 1 89 return frames, eod
90 91 @interfacedoc
92 - def post_process(self):
93 """ Apply last 2D transforms""" 94 self.image.putdata(self.pixels) 95 self.image = self.image.transpose(Image.ROTATE_90)
96