kopia lustrzana https://github.com/corrscope/corrscope
Replace samples_visible with time_visible_ms
Factor out wave-reading code from MatplotlibRenderer backend. MatplotlibRenderer backend hopefully plots arbitrary data, and can be swapped with other backends.pull/357/head
rodzic
cb3e7265ca
commit
8b71df0bbb
|
@ -16,12 +16,9 @@ RENDER_PROFILING = True
|
|||
|
||||
class Config(NamedTuple):
|
||||
wave_dir: str
|
||||
# TODO: if wave_dir is present, it should overwrite List[WaveConfig].
|
||||
# wave_dir will be commented out when writing to file.
|
||||
|
||||
master_wave: Optional[str]
|
||||
|
||||
fps: int
|
||||
time_visible_ms: int
|
||||
|
||||
trigger: TriggerConfig # Maybe overriden per Wave
|
||||
render: RendererConfig
|
||||
|
@ -42,6 +39,8 @@ def main(wave_dir: str, master_wave: Optional[str], fps: int):
|
|||
wave_dir=wave_dir,
|
||||
master_wave=master_wave,
|
||||
fps=fps,
|
||||
time_visible_ms=25,
|
||||
|
||||
trigger=CorrelationTrigger.Config(
|
||||
trigger_strength=10,
|
||||
use_edge_trigger=True,
|
||||
|
@ -51,7 +50,6 @@ def main(wave_dir: str, master_wave: Optional[str], fps: int):
|
|||
),
|
||||
render=RendererConfig( # todo
|
||||
1280, 720,
|
||||
samples_visible=1000,
|
||||
rows_first=False,
|
||||
ncols=1
|
||||
)
|
||||
|
@ -68,12 +66,13 @@ class Ovgen:
|
|||
def __init__(self, cfg: Config):
|
||||
self.cfg = cfg
|
||||
self.waves: List[Wave] = []
|
||||
self.nwaves: int = None
|
||||
|
||||
def write(self):
|
||||
self.load_waves() # self.waves =
|
||||
self.render()
|
||||
self._load_waves() # self.waves =
|
||||
self._render()
|
||||
|
||||
def load_waves(self):
|
||||
def _load_waves(self):
|
||||
wave_dir = Path(self.cfg.wave_dir)
|
||||
|
||||
for idx, path in enumerate(wave_dir.glob('*.wav')):
|
||||
|
@ -89,13 +88,17 @@ class Ovgen:
|
|||
wave.set_trigger(trigger)
|
||||
self.waves.append(wave)
|
||||
|
||||
def render(self):
|
||||
self.nwaves = len(self.waves)
|
||||
|
||||
def _render(self):
|
||||
# Calculate number of frames (TODO master file?)
|
||||
time_visible_ms = self.cfg.time_visible_ms
|
||||
fps = self.cfg.fps
|
||||
|
||||
nframes = fps * self.waves[0].get_s()
|
||||
nframes = int(nframes) + 1
|
||||
|
||||
renderer = MatplotlibRenderer(self.cfg.render, self.waves)
|
||||
renderer = MatplotlibRenderer(self.cfg.render, self.nwaves)
|
||||
|
||||
if RENDER_PROFILING:
|
||||
begin = time.perf_counter()
|
||||
|
@ -104,17 +107,22 @@ class Ovgen:
|
|||
for frame in range(nframes):
|
||||
time_seconds = frame / fps
|
||||
|
||||
center_smps = []
|
||||
datas = []
|
||||
# Get data from each wave
|
||||
for wave in self.waves:
|
||||
sample = round(wave.smp_s * time_seconds)
|
||||
region_len = round(wave.smp_s * time_visible_ms / 1000)
|
||||
|
||||
trigger_sample = wave.trigger.get_trigger(sample)
|
||||
print(f'- {trigger_sample}')
|
||||
center_smps.append(trigger_sample)
|
||||
|
||||
datas.append(wave.get_around(trigger_sample, region_len))
|
||||
|
||||
print(frame)
|
||||
renderer.render_frame(center_smps)
|
||||
renderer.render_frame(datas)
|
||||
|
||||
if RENDER_PROFILING:
|
||||
# noinspection PyUnboundLocalVariable
|
||||
dtime = time.perf_counter() - begin
|
||||
render_fps = nframes / dtime
|
||||
print(f'FPS = {render_fps}')
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
from itertools import count
|
||||
from typing import NamedTuple, Optional, List, Tuple, TYPE_CHECKING
|
||||
from typing import NamedTuple, Optional, List, Tuple
|
||||
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
|
@ -9,16 +8,11 @@ from matplotlib.lines import Line2D
|
|||
|
||||
from ovgenpy.util import ceildiv
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ovgenpy.wave import Wave
|
||||
|
||||
|
||||
class RendererConfig(NamedTuple):
|
||||
width: int
|
||||
height: int
|
||||
|
||||
samples_visible: int
|
||||
|
||||
rows_first: bool
|
||||
|
||||
nrows: Optional[int] = None # TODO set to 1
|
||||
|
@ -48,19 +42,19 @@ class MatplotlibRenderer:
|
|||
|
||||
DPI = 96
|
||||
|
||||
def __init__(self, cfg: RendererConfig, waves: List['Wave']):
|
||||
def __init__(self, cfg: RendererConfig, nplots: int):
|
||||
self.cfg = cfg
|
||||
self.waves = waves
|
||||
self.nwaves = len(waves)
|
||||
self.nplots = nplots
|
||||
self.fig: Figure = None
|
||||
|
||||
# Setup layout
|
||||
|
||||
self.nrows = 0
|
||||
self.ncols = 0
|
||||
|
||||
# Flat array of nrows*ncols elements, ordered by cfg.rows_first.
|
||||
self.axes: List[Axes] = None
|
||||
self.lines: List[Line2D] = None
|
||||
self.axes: List[Axes] = None # set by set_layout()
|
||||
self.lines: List[Line2D] = None # set by render_frame() first call
|
||||
|
||||
self.set_layout() # mutates self
|
||||
|
||||
|
@ -95,17 +89,7 @@ class MatplotlibRenderer:
|
|||
if not self.cfg.rows_first:
|
||||
axes2d = axes2d.T
|
||||
|
||||
self.axes: List[Axes] = axes2d.flatten().tolist()[:self.nwaves]
|
||||
|
||||
# Create oscilloscope line objects
|
||||
self.lines = []
|
||||
for ax in self.axes:
|
||||
# Setup axes limits
|
||||
ax.set_xlim(0, self.cfg.samples_visible)
|
||||
ax.set_ylim(-1, 1)
|
||||
|
||||
line = ax.plot([0] * self.cfg.samples_visible)[0]
|
||||
self.lines.append(line)
|
||||
self.axes: List[Axes] = axes2d.flatten().tolist()[:self.nplots]
|
||||
|
||||
# Setup figure geometry
|
||||
self.fig.set_dpi(self.DPI)
|
||||
|
@ -126,26 +110,37 @@ class MatplotlibRenderer:
|
|||
nrows = cfg.nrows
|
||||
if nrows is None:
|
||||
raise ValueError('invalid cfg: rows_first is True and nrows is None')
|
||||
ncols = ceildiv(self.nwaves, nrows)
|
||||
ncols = ceildiv(self.nplots, nrows)
|
||||
else:
|
||||
ncols = cfg.ncols
|
||||
if ncols is None:
|
||||
raise ValueError('invalid cfg: rows_first is False and ncols is None')
|
||||
nrows = ceildiv(self.nwaves, ncols)
|
||||
nrows = ceildiv(self.nplots, ncols)
|
||||
|
||||
return nrows, ncols
|
||||
|
||||
def render_frame(self, center_smps: List[int]) -> None:
|
||||
ncenters = len(center_smps)
|
||||
if self.nwaves != ncenters:
|
||||
def render_frame(self, datas: List[np.ndarray]) -> None:
|
||||
ndata = len(datas)
|
||||
if self.nplots != ndata:
|
||||
raise ValueError(
|
||||
f'incorrect wave offsets: {self.nwaves} waves but {ncenters} offsets')
|
||||
f'incorrect data to plot: {self.nplots} plots but {ndata} datas')
|
||||
|
||||
for idx, wave, center_smp in zip(count(), self.waves, center_smps):
|
||||
# Draw waveform data
|
||||
line = self.lines[idx]
|
||||
data = wave.get_around(center_smp, self.cfg.samples_visible)
|
||||
line.set_ydata(data)
|
||||
# Initialize axes and draw waveform data
|
||||
if self.lines is None:
|
||||
self.lines = []
|
||||
for idx, data in enumerate(datas):
|
||||
ax = self.axes[idx]
|
||||
ax.set_xlim(0, len(data) - 1)
|
||||
ax.set_ylim(-1, 1)
|
||||
|
||||
line = ax.plot(data)[0]
|
||||
self.lines.append(line)
|
||||
|
||||
# Draw waveform data
|
||||
else:
|
||||
for idx, data in enumerate(datas):
|
||||
line = self.lines[idx]
|
||||
line.set_ydata(data)
|
||||
|
||||
self.fig.canvas.draw()
|
||||
self.fig.canvas.flush_events()
|
||||
|
|
Ładowanie…
Reference in New Issue