From 3126aa4e264b5eafe4493dd62abe2b9933e2c0fa Mon Sep 17 00:00:00 2001 From: rbn42 Date: Mon, 25 Sep 2017 05:32:44 +1300 Subject: [PATCH] fix stereo visualization --- panon/visualizer/__init__.py | 16 ++------ panon/visualizer/fallback.py | 18 +++++---- panon/visualizer/spectrum.py | 75 +++++++++++++++++++++--------------- 3 files changed, 59 insertions(+), 50 deletions(-) diff --git a/panon/visualizer/__init__.py b/panon/visualizer/__init__.py index 6b056c2..6e75e68 100644 --- a/panon/visualizer/__init__.py +++ b/panon/visualizer/__init__.py @@ -6,7 +6,6 @@ from .. import config from .fallback import VisualizerCairo from .opengl import VisualizerGL -from .source import Source from .spectrum import Spectrum from queue import Queue from threading import Thread @@ -23,20 +22,13 @@ def tick(self): def destory(self): self.stop_gen_data = True - def __init__(self, background_color, fps=60, channel_count=2, sample_rate=44100, padding=4, use_opengl=False): + def __init__(self, background_color, fps=60, padding=4, use_opengl=False): super(Visualizer, self).__init__() - self.sample_rate = sample_rate self.background_color = helper.color(background_color) self.data_queue = Queue(3) self.padding = padding - self.fps = fps - self.channel_count = channel_count - self.sample_rate = sample_rate - self.sample = Source(channel_count, sample_rate) - buffer_size = sample_rate // fps * channel_count - self.spectrum = Spectrum( - self.sample, buffer_size, config.visualizer_decay) + self.spectrum = Spectrum(fps, config.visualizer_decay) GObject.timeout_add(1000 // fps, self.tick) self.use_opengl = use_opengl @@ -67,11 +59,11 @@ def do_button_release_event(self, widget, event=None): if event and event.button == 1: if not self.stop: self.da.stop() - self.sample.stop() + self.spectrum.stop() self.stop = True else: self.stop = False - self.sample.start() + self.spectrum.start() self.da.start() return True else: diff --git a/panon/visualizer/fallback.py b/panon/visualizer/fallback.py index e566e5f..3d7a4a1 100644 --- a/panon/visualizer/fallback.py +++ b/panon/visualizer/fallback.py @@ -67,6 +67,7 @@ def do_draw_cb(self, widget, cr): if self.empty: return bins = self.getData() + assert bins.shape[0]==2 x, y = self.padding, self.padding w, h = w - 2 * self.padding, h - 2 * self.padding @@ -77,14 +78,17 @@ def do_draw_cb(self, widget, cr): cr.set_source(source) cr.set_operator(cairo.OPERATOR_SOURCE) cr.move_to(x + 0, y + h / 2) # middle left - width = 2 * w / len(bins) - for i in range(len(bins) // 2): - height = rel * h * bins[i] + width = w / bins.shape[1] + for i in range(bins.shape[1]): + height = rel * h * bins[0,i] cr.line_to(x + i * width, y + h / 2 - height / 2) cr.line_to(x + w, y + h / 2) # middle right - for i in range(len(bins) // 2, len(bins)): - freq = len(bins) - i - height = rel * h * bins[i] - cr.line_to(x + freq * width, y + h / 2 + height / 2) + cr.close_path() + + cr.move_to(x + 0, y + h / 2) # middle left + for i in range(bins.shape[1]): + height = rel * h * bins[1,i] + cr.line_to(x + i * width, y + h / 2 + height / 2) + cr.line_to(x + w, y + h / 2) # middle right cr.close_path() cr.fill() diff --git a/panon/visualizer/spectrum.py b/panon/visualizer/spectrum.py index bc4e2a6..b867fcf 100644 --- a/panon/visualizer/spectrum.py +++ b/panon/visualizer/spectrum.py @@ -1,36 +1,57 @@ import numpy as np +from .source import Source class Spectrum: - def __init__(self, sample, buffer_size, decay): - self.sample = sample + + def __init__(self, fps, decay, channel_count=2, sample_rate=44100,): + self.sample = Source(channel_count, sample_rate) self.decay = decay - self.history = np.zeros(buffer_size * 8, dtype='int16') - self.history_index = 0 + + buffer_size = sample_rate // fps self.buffer_size = buffer_size + + self.history = np.zeros( + (channel_count, buffer_size * 8), dtype='int16') + self.history_index = 0 + self.min_sample = 10 self.max_sample = self.min_sample + def stop(self): + self.sample.stop() + + def start(self): + self.sample.start() + def updateHistory(self): data = self.sample.read() data = np.fromstring(data, 'int16') - assert len(data) < len(self.history) - if self.history_index + len(data) > len(self.history): - self.history[self.history_index:] = data[:len( - self.history) - self.history_index] - self.history[:self.history_index + len(data) - len( - self.history)] = data[len(self.history) - self.history_index:] - self.history_index -= len(self.history) + + len_data = len(data) // self.history.shape[0] + + len_history = self.history.shape[1] + index = self.history_index + assert len_data < len_history + + data = data.reshape((len_data, self.history.shape[0])) + data = np.rollaxis(data, 1) + + if index + len_data > len_history: + self.history[:, index:] = data[:, :len_history - index] + self.history[:, :index + len_data - + len_history] = data[:, len_history - index:] + self.history_index -= len_history else: - self.history[self.history_index:self.history_index + - len(data)] = data - self.history_index += len(data) + self.history[:, index:index + len_data] = data + self.history_index += len_data data_history = np.concatenate([ - self.history[self.history_index:], - self.history[:self.history_index], - ]) + self.history[:, self.history_index:], + self.history[:, :self.history_index], + ], axis=1) + return data_history def getData(self): @@ -40,21 +61,13 @@ def getData(self): def fun(start, end, rel): size = self.buffer_size - if rel > 20: - start, end = int(start), int(end) - rel = int(rel) - d = data_history[-size * rel:].reshape((rel, size)) - d = np.mean(d, axis=0) - else: - start = int(start * rel) - end = int(end * rel) - size = int(size * rel) - d = data_history[-size:] + start = int(start * rel) + end = int(end * rel) + size = int(size * rel) + d = data_history[:, -size:] fft = np.absolute(np.fft.rfft(d, n=size)) - end = min(len(fft) // 2, end) - fft_freq.insert(0, fft[start:end]) - fft_freq.append(fft[len(fft) - end:len(fft) - start]) + fft_freq.insert(0, fft[:, start:end]) # higher resolution and latency for lower frequency fun(110, 150, 2) @@ -64,7 +77,7 @@ def fun(start, end, rel): fun(10, 30, 6) fun(0, 10, 8) - fft = np.concatenate(fft_freq) + fft = np.concatenate(fft_freq, axis=1) exp = 2 retain = (1 - self.decay)**exp