From: Guillaume Pellerin Date: Mon, 28 Oct 2013 22:42:52 +0000 (+0100) Subject: add tests for new graphers X-Git-Tag: 0.5.1-0~15 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=def1984b665624a7f6347fbb4e1595ec89740d02;p=timeside.git add tests for new graphers --- diff --git a/tests/test_graphing.py b/tests/test_graphing.py index ecd628d..88676ba 100755 --- a/tests/test_graphing.py +++ b/tests/test_graphing.py @@ -158,34 +158,63 @@ class TestGraphing(TestCase): self.image = "/tmp/test_waveform_contour_wh_sweep_ogg.png" self.grapher = WaveformContourWhite(width=1024, height=256, bg_color=(255,255,255), color_scheme='default') - # SPECTROGRAMS + # LOG SPECTROGRAMS def testWav2Spectrogram(self): "Test WAV to Spectrogram" - from timeside.grapher.spectrogram import Spectrogram + from timeside.grapher.spectrogram_log import SpectrogramLog self.source = os.path.join (os.path.dirname(__file__), "samples/sweep.wav") - self.image = "/tmp/test_spectrogram_sweep_wav.png" - self.grapher = Spectrogram(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') + self.image = "/tmp/test_spectrogram_log_sweep_wav.png" + self.grapher = SpectrogramLog(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') - def testMp32Spectrogram(self): - "Test MP3 to Spectrogram" - from timeside.grapher.spectrogram import Spectrogram + def testMp32SpectrogramLog(self): + "Test MP3 to SpectrogramLog" + from timeside.grapher.spectrogram_log import SpectrogramLog self.source = os.path.join (os.path.dirname(__file__), "samples/sweep.mp3") - self.image = "/tmp/test_spectrogram_sweep_mp3.png" - self.grapher = Spectrogram(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') + self.image = "/tmp/test_spectrogram_log_sweep_mp3.png" + self.grapher = SpectrogramLog(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') - def testFlac2Spectrogram(self): - "Test FLAC to Spectrogram" - from timeside.grapher.spectrogram import Spectrogram + def testFlac2SpectrogramLog(self): + "Test FLAC to SpectrogramLog" + from timeside.grapher.spectrogram_log import SpectrogramLog self.source = os.path.join (os.path.dirname(__file__), "samples/sweep.flac") - self.image = "/tmp/test_spectrogram_sweep_flac.png" - self.grapher = Spectrogram(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') + self.image = "/tmp/test_spectrogram_log_sweep_flac.png" + self.grapher = SpectrogramLog(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') - def testOgg2Spectrogram(self): - "Test OGG to Spectrogram" - from timeside.grapher.spectrogram import Spectrogram + def testOgg2SpectrogramLog(self): + "Test OGG to SpectrogramLog" + from timeside.grapher.spectrogram_log import SpectrogramLog self.source = os.path.join (os.path.dirname(__file__), "samples/sweep.ogg") - self.image = "/tmp/test_spectrogram_sweep_ogg.png" - self.grapher = Spectrogram(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') + self.image = "/tmp/test_spectrogram_log_sweep_ogg.png" + self.grapher = SpectrogramLog(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') + + # LIN SPECTROGRAMS + def testWav2Spectrogram(self): + "Test WAV to SpectrogramLinear" + from timeside.grapher.spectrogram_lin import SpectrogramLinear + self.source = os.path.join (os.path.dirname(__file__), "samples/sweep.wav") + self.image = "/tmp/test_spectrogram_lin_sweep_wav.png" + self.grapher = SpectrogramLinear(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') + + def testMp32SpectrogramLinear(self): + "Test MP3 to SpectrogramLinear" + from timeside.grapher.spectrogram_lin import SpectrogramLinear + self.source = os.path.join (os.path.dirname(__file__), "samples/sweep.mp3") + self.image = "/tmp/test_spectrogram_lin_sweep_mp3.png" + self.grapher = SpectrogramLinear(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') + + def testFlac2SpectrogramLinear(self): + "Test FLAC to SpectrogramLinear" + from timeside.grapher.spectrogram_lin import SpectrogramLinear + self.source = os.path.join (os.path.dirname(__file__), "samples/sweep.flac") + self.image = "/tmp/test_spectrogram_lin_sweep_flac.png" + self.grapher = SpectrogramLinear(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') + + def testOgg2SpectrogramLinear(self): + "Test OGG to SpectrogramLinear" + from timeside.grapher.spectrogram_lin import SpectrogramLinear + self.source = os.path.join (os.path.dirname(__file__), "samples/sweep.ogg") + self.image = "/tmp/test_spectrogram_lin_sweep_ogg.png" + self.grapher = SpectrogramLinear(width=1024, height=256, bg_color=(0,0,0), color_scheme='default') def tearDown(self): decoder = FileDecoder(self.source) diff --git a/timeside/grapher/__init__.py b/timeside/grapher/__init__.py index d49a41e..0d96038 100644 --- a/timeside/grapher/__init__.py +++ b/timeside/grapher/__init__.py @@ -5,5 +5,5 @@ from waveform_centroid import * from waveform_transparent import * from waveform_contour_black import * from waveform_contour_white import * -from spectrogram import * -from spectrogram_linear import * +from spectrogram_log import * +from spectrogram_lin import * diff --git a/timeside/grapher/spectrogram.py b/timeside/grapher/spectrogram.py deleted file mode 100644 index 7d7f691..0000000 --- a/timeside/grapher/spectrogram.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- 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 implements, interfacedoc -from timeside.api import IGrapher -from timeside.grapher.core import * - - -class Spectrogram(Grapher): - """ 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.""" - - implements(IGrapher) - - @interfacedoc - def __init__(self, width=1024, height=256, bg_color=(0,0,0), color_scheme='default'): - super(Spectrogram, self).__init__(width, height, bg_color, color_scheme) - self.colors = default_color_schemes[color_scheme]['spectrogram'] - self.pixels = [] - self.y_to_bin = [] - - @staticmethod - @interfacedoc - def id(): - return "spectrogram" - - @staticmethod - @interfacedoc - def name(): - return "Spectrogram" - - @interfacedoc - def setup(self, channels=None, samplerate=None, blocksize=None, totalframes=None): - super(Spectrogram, self).setup(channels, samplerate, blocksize, totalframes) - self.image = Image.new("P", (self.image_height, self.image_width)) - self.image.putpalette(interpolate_colors(self.colors, True)) - self.set_scale() - - def set_scale(self): - """generate the lookup which translates y-coordinate to fft-bin""" - - f_min = float(self.lower_freq) - f_max = float(self.higher_freq) - y_min = math.log10(f_min) - y_max = math.log10(f_max) - for y in range(self.image_height): - freq = math.pow(10.0, y_min + y / (self.image_height - 1.0) *(y_max - y_min)) - fft_bin = freq / f_max * (self.fft_size/2 + 1) - if fft_bin < self.fft_size/2: - alpha = fft_bin - int(fft_bin) - self.y_to_bin.append((int(fft_bin), alpha * 255)) - - def draw_spectrum(self, x, spectrum): - for (index, alpha) in self.y_to_bin: - self.pixels.append( int( ((255.0-alpha) * spectrum[index] + alpha * spectrum[index + 1] )) ) - for y in range(len(self.y_to_bin), self.image_height): - self.pixels.append(0) - - @interfacedoc - def process(self, frames, eod=False): - if len(frames) != 1: - chunk = frames[:,0].copy() - chunk.shape = (len(chunk),1) - for samples, end in self.pixels_adapter.process(chunk, eod): - if self.pixel_cursor < self.image_width: - (spectral_centroid, db_spectrum) = self.spectrum.process(samples, True) - self.draw_spectrum(self.pixel_cursor, db_spectrum) - self.pixel_cursor += 1 - return frames, eod - - def render(self, filename): - """ Apply last 2D transforms and write all pixels to the file. """ - self.image.putdata(self.pixels) - self.image.transpose(Image.ROTATE_90).save(filename) diff --git a/timeside/grapher/spectrogram_lin.py b/timeside/grapher/spectrogram_lin.py new file mode 100644 index 0000000..04df721 --- /dev/null +++ b/timeside/grapher/spectrogram_lin.py @@ -0,0 +1,64 @@ +# -*- 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 implements, interfacedoc +from timeside.api import IGrapher +from timeside.grapher.core import * +from timeside.grapher.spectrogram_log import SpectrogramLog + + +class SpectrogramLinear(SpectrogramLog): + """ 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.""" + + implements(IGrapher) + + @interfacedoc + def __init__(self, width=1024, height=256, bg_color=(0,0,0), color_scheme='default'): + super(SpectrogramLinear, self).__init__(width, height, bg_color, color_scheme) + + @staticmethod + @interfacedoc + def id(): + return "spectrogram_linear" + + @staticmethod + @interfacedoc + def name(): + return "Spectrogram linear" + + @interfacedoc + def setup(self, channels=None, samplerate=None, blocksize=None, totalframes=None): + super(SpectrogramLinear, self).setup(channels, samplerate, blocksize, totalframes) + + def set_scale(self): + """generate the lookup which translates y-coordinate to fft-bin""" + + f_min = float(self.lower_freq) + f_max = float(self.higher_freq) + y_min = f_min + y_max = f_max + for y in range(self.image_height): + freq = y_min + y / (self.image_height - 1.0) *(y_max - y_min) + fft_bin = freq / f_max * (self.fft_size/2 + 1) + if fft_bin < self.fft_size/2: + alpha = fft_bin - int(fft_bin) + self.y_to_bin.append((int(fft_bin), alpha * 255)) diff --git a/timeside/grapher/spectrogram_linear.py b/timeside/grapher/spectrogram_linear.py deleted file mode 100644 index 3ccdbc2..0000000 --- a/timeside/grapher/spectrogram_linear.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- 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 implements, interfacedoc -from timeside.api import IGrapher -from timeside.grapher.core import * -from timeside.grapher.spectrogram import Spectrogram - - -class SpectrogramLinear(Spectrogram): - """ 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.""" - - implements(IGrapher) - - @interfacedoc - def __init__(self, width=1024, height=256, bg_color=(0,0,0), color_scheme='default'): - super(SpectrogramLinear, self).__init__(width, height, bg_color, color_scheme) - - @staticmethod - @interfacedoc - def id(): - return "spectrogram_linear" - - @staticmethod - @interfacedoc - def name(): - return "Spectrogram linear" - - @interfacedoc - def setup(self, channels=None, samplerate=None, blocksize=None, totalframes=None): - super(SpectrogramLinear, self).setup(channels, samplerate, blocksize, totalframes) - - def set_scale(self): - """generate the lookup which translates y-coordinate to fft-bin""" - - f_min = float(self.lower_freq) - f_max = float(self.higher_freq) - y_min = f_min - y_max = f_max - for y in range(self.image_height): - freq = y_min + y / (self.image_height - 1.0) *(y_max - y_min) - fft_bin = freq / f_max * (self.fft_size/2 + 1) - if fft_bin < self.fft_size/2: - alpha = fft_bin - int(fft_bin) - self.y_to_bin.append((int(fft_bin), alpha * 255)) diff --git a/timeside/grapher/spectrogram_log.py b/timeside/grapher/spectrogram_log.py new file mode 100644 index 0000000..3f5349b --- /dev/null +++ b/timeside/grapher/spectrogram_log.py @@ -0,0 +1,92 @@ +# -*- 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 implements, interfacedoc +from timeside.api import IGrapher +from timeside.grapher.core import * + + +class SpectrogramLog(Grapher): + """ 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.""" + + implements(IGrapher) + + @interfacedoc + def __init__(self, width=1024, height=256, bg_color=(0,0,0), color_scheme='default'): + super(SpectrogramLog, self).__init__(width, height, bg_color, color_scheme) + self.colors = default_color_schemes[color_scheme]['spectrogram'] + self.pixels = [] + self.y_to_bin = [] + + @staticmethod + @interfacedoc + def id(): + return "spectrogram" + + @staticmethod + @interfacedoc + def name(): + return "SpectrogramLog" + + @interfacedoc + def setup(self, channels=None, samplerate=None, blocksize=None, totalframes=None): + super(SpectrogramLog, self).setup(channels, samplerate, blocksize, totalframes) + self.image = Image.new("P", (self.image_height, self.image_width)) + self.image.putpalette(interpolate_colors(self.colors, True)) + self.set_scale() + + def set_scale(self): + """generate the lookup which translates y-coordinate to fft-bin""" + + f_min = float(self.lower_freq) + f_max = float(self.higher_freq) + y_min = math.log10(f_min) + y_max = math.log10(f_max) + for y in range(self.image_height): + freq = math.pow(10.0, y_min + y / (self.image_height - 1.0) *(y_max - y_min)) + fft_bin = freq / f_max * (self.fft_size/2 + 1) + if fft_bin < self.fft_size/2: + alpha = fft_bin - int(fft_bin) + self.y_to_bin.append((int(fft_bin), alpha * 255)) + + def draw_spectrum(self, x, spectrum): + for (index, alpha) in self.y_to_bin: + self.pixels.append( int( ((255.0-alpha) * spectrum[index] + alpha * spectrum[index + 1] )) ) + for y in range(len(self.y_to_bin), self.image_height): + self.pixels.append(0) + + @interfacedoc + def process(self, frames, eod=False): + if len(frames) != 1: + chunk = frames[:,0].copy() + chunk.shape = (len(chunk),1) + for samples, end in self.pixels_adapter.process(chunk, eod): + if self.pixel_cursor < self.image_width: + (spectral_centroid, db_spectrum) = self.spectrum.process(samples, True) + self.draw_spectrum(self.pixel_cursor, db_spectrum) + self.pixel_cursor += 1 + return frames, eod + + def render(self, filename): + """ Apply last 2D transforms and write all pixels to the file. """ + self.image.putdata(self.pixels) + self.image.transpose(Image.ROTATE_90).save(filename)