From 48e9339594868a399be378e656c7f760cd2bdf04 Mon Sep 17 00:00:00 2001 From: Guillaume Pellerin Date: Thu, 23 Oct 2014 13:08:02 +0200 Subject: [PATCH] add SpectorgramBuffer with an extensible buffer based on tables, update docstrings --- timeside/analyzer/spectrogram.py | 29 +++---- timeside/analyzer/spectrogram_buffer.py | 110 ++++++++++++++++++++++++ timeside/core.py | 4 +- timeside/grapher/render_analyzers.py | 4 +- timeside/grapher/spectrogram_log.py | 2 +- 5 files changed, 128 insertions(+), 21 deletions(-) create mode 100644 timeside/analyzer/spectrogram_buffer.py diff --git a/timeside/analyzer/spectrogram.py b/timeside/analyzer/spectrogram.py index 34c9c75..5819153 100644 --- a/timeside/analyzer/spectrogram.py +++ b/timeside/analyzer/spectrogram.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (c) 2013-2014 Parisson SARL -# Copyright (c) 2013-2014 Thomas Fillon +# Copyright (c) 2013 Paul Brossier # This file is part of TimeSide. @@ -18,22 +17,23 @@ # You should have received a copy of the GNU General Public License # along with TimeSide. If not, see . -# Author: Thomas Fillon - +# Author: Paul Brossier from __future__ import division from timeside.core import implements, interfacedoc from timeside.analyzer.core import Analyzer from timeside.api import IAnalyzer from timeside.analyzer.preprocessors import downmix_to_mono, frames_adapter -from timeside.tools.parameters import Int, HasTraits from timeside.tools.buffering import BufferTable +from ..tools.parameters import Int, HasTraits +from timeside.tools.pyx.cfft import cfft import numpy as np class Spectrogram(Analyzer): + """ - Spectrogram analyzer + Spectrogram image builder with an extensible buffer based on tables Parameters ---------- @@ -73,9 +73,8 @@ class Spectrogram(Analyzer): pipe.run() res = spectrogram.results['spectrogram_analyzer'] res.render() - - """ + implements(IAnalyzer) # Define Parameters @@ -99,7 +98,7 @@ class Spectrogram(Analyzer): else: self.fft_size = fft_size - self.values = BufferTable() + self.values = [] @interfacedoc def setup(self, channels=None, samplerate=None, @@ -125,24 +124,22 @@ class Spectrogram(Analyzer): @downmix_to_mono @frames_adapter def process(self, frames, eod=False): - stft = np.fft.rfft(frames, self.fft_size) - self.values.append('stft', stft) - return frames, eod + self.values.append(np.abs(np.fft.rfft(frames, self.fft_size))) + return frames, eod def post_process(self): spectrogram = self.new_result(data_mode='value', time_mode='framewise') spectrogram.parameters = {'fft_size': self.fft_size} - spectrogram.data_object.value = np.abs(self.values['stft']) + # spectrogram.data_object.value = self.values['spectrogram'] + spectrogram.data_object.value = self.values nb_freq = spectrogram.data_object.value.shape[1] spectrogram.data_object.y_value = (np.arange(0, nb_freq) * self.samplerate() / self.fft_size) self.add_result(spectrogram) - def release(self): - self.values.close() if __name__ == "__main__": import doctest import timeside - doctest.testmod(timeside.analyzer.spectrogram, verbose=True) + doctest.testmod(timeside.analyzer.spectrogram, verbose=True) \ No newline at end of file diff --git a/timeside/analyzer/spectrogram_buffer.py b/timeside/analyzer/spectrogram_buffer.py new file mode 100644 index 0000000..25edaac --- /dev/null +++ b/timeside/analyzer/spectrogram_buffer.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2013-2014 Parisson SARL +# Copyright (c) 2013-2014 Thomas Fillon + +# 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: Thomas Fillon + +from __future__ import division +from timeside.core import implements, interfacedoc +from timeside.analyzer.core import Analyzer +from timeside.api import IAnalyzer +from timeside.analyzer.preprocessors import downmix_to_mono, frames_adapter +from timeside.tools.parameters import Int, HasTraits +from timeside.tools.buffering import BufferTable +from timeside.analyzer.spectrogram import Spectrogram + +import numpy as np + + +class SpectrogramBuffer(Spectrogram): + """ + Spectrogram image builder with an extensible buffer based on tables + + Parameters + ---------- + input_blocksize : int, optional + Blocksize of the input signal, default to 2048 + input_stepsize : str, optional + The second parameter, default to half blocksize. + fft_size : int, optional + The size of the fft, default to blocksize. + + Examples + -------- + >>> import timeside + >>> from timeside.core import get_processor + >>> from timeside.tools.test_samples import samples + >>> audio_source = samples['sweep.wav'] + >>> decoder = get_processor('file_decoder')(uri=audio_source) + >>> spectrogram = get_processor('spectrogram_analyzer')(input_blocksize=2048, input_stepsize=1024) + >>> pipe = (decoder | spectrogram) + >>> pipe.run() + >>> spectrogram.results.keys() + ['spectrogram_analyzer'] + >>> result = spectrogram.results['spectrogram_analyzer'] + >>> result.data.shape + (344, 1025) + + .. plot:: + + import timeside + from timeside.core import get_processor + from timeside.tools.test_samples import samples + audio_source = samples['sweep.wav'] + decoder = get_processor('file_decoder')(uri=audio_source) + spectrogram = get_processor('spectrogram_analyzer')(input_blocksize=2048, + input_stepsize=1024) + pipe = (decoder | spectrogram) + pipe.run() + res = spectrogram.results['spectrogram_analyzer'] + res.render() + """ + + implements(IAnalyzer) + + def __init__(self, input_blocksize=2048, input_stepsize=None, + fft_size=None): + super(SpectrogramBuffer, self).__init__() + self.values = BufferTable() + + @staticmethod + @interfacedoc + def id(): + return "spectrogram_analyzer_buffer" + + @staticmethod + @interfacedoc + def name(): + return "Spectrogram Analyzer with extensible buffer" + + @downmix_to_mono + @frames_adapter + def process(self, frames, eod=False): + stft = np.fft.rfft(frames, self.fft_size) + self.values.append('stft', stft) + return frames, eod + + def release(self): + self.values.close() + + +if __name__ == "__main__": + import doctest + import timeside + doctest.testmod(timeside.analyzer.spectrogram_buffer, verbose=True) \ No newline at end of file diff --git a/timeside/core.py b/timeside/core.py index 30368d3..917752f 100644 --- a/timeside/core.py +++ b/timeside/core.py @@ -298,12 +298,12 @@ def list_processors(interface=IProcessor, prefix=""): def list_processors_rst(interface=IProcessor, prefix=""): - print '\n' + prefix + interface.__name__ + print '\n' + interface.__name__ if len(prefix): underline_char = '-' else: underline_char = '=' - print prefix + underline_char * len(interface.__name__) + '\n' + print underline_char * len(interface.__name__) + '\n' subinterfaces = interface.__subclasses__() for i in subinterfaces: list_processors_rst(interface=i, prefix=prefix + " ") diff --git a/timeside/grapher/render_analyzers.py b/timeside/grapher/render_analyzers.py index 19fa7ab..1407eb9 100644 --- a/timeside/grapher/render_analyzers.py +++ b/timeside/grapher/render_analyzers.py @@ -29,7 +29,7 @@ from ..exceptions import PIDError class DisplayAnalyzer(Grapher): """ - Builds a PIL image from analyzer result + image from analyzer result This is an Abstract base class """ dpi = 72 # Web default value for Telemeta @@ -121,7 +121,7 @@ class DisplayAnalyzer(Grapher): def name(): return grapher_name - __doc__ = """Builds a PIL image representing """ + grapher_name + __doc__ = """Image representing """ + grapher_name NewGrapher.__name__ = 'Display' + '.' + result_id diff --git a/timeside/grapher/spectrogram_log.py b/timeside/grapher/spectrogram_log.py index 2441781..b367d71 100644 --- a/timeside/grapher/spectrogram_log.py +++ b/timeside/grapher/spectrogram_log.py @@ -29,7 +29,7 @@ import math class SpectrogramLog(Grapher): - """logarithmic scaled spectrogram (level vs. frequency vs. time). + """Logarithmic scaled spectrogram (level vs. frequency vs. time). Adds pixels iteratively thanks to the adapter providing fixed size frame buffers.""" -- 2.39.5