corrscope/ovgenpy/ovgenpy.py

159 wiersze
4.3 KiB
Python
Czysty Zwykły widok Historia

# -*- coding: utf-8 -*-
2018-07-14 06:54:14 +00:00
import time
2018-07-12 22:27:26 +00:00
from pathlib import Path
2018-07-15 12:55:00 +00:00
from typing import NamedTuple, Optional, List
2018-07-12 22:27:26 +00:00
import click
from ovgenpy import outputs
2018-07-12 22:27:26 +00:00
2018-07-14 06:54:14 +00:00
from ovgenpy.renderer import MatplotlibRenderer, RendererConfig
from ovgenpy.triggers import TriggerConfig, CorrelationTrigger
from ovgenpy.wave import WaveConfig, Wave
2018-07-12 22:27:26 +00:00
2018-07-13 00:48:51 +00:00
2018-07-14 06:54:14 +00:00
RENDER_PROFILING = True
2018-07-12 22:27:26 +00:00
class Config(NamedTuple):
wave_dir: str
audio_path: Optional[str]
2018-07-12 22:27:26 +00:00
fps: int
2018-07-24 03:38:15 +00:00
amplification: float
time_visible_ms: int
scan_ratio: float
2018-07-12 22:27:26 +00:00
trigger: TriggerConfig # Maybe overriden per Wave
render: RendererConfig
outputs: List[outputs.OutputConfig]
create_window: bool
2018-07-13 02:29:05 +00:00
@property
def time_visible_s(self) -> float:
return self.time_visible_ms / 1000
2018-07-13 02:29:05 +00:00
2018-07-12 22:27:26 +00:00
Folder = click.Path(exists=True, file_okay=False)
File = click.Path(exists=True, dir_okay=False)
2018-07-13 12:37:22 +00:00
_FPS = 60 # f_s
2018-07-12 22:27:26 +00:00
2018-07-13 02:30:07 +00:00
2018-07-12 22:27:26 +00:00
@click.command()
@click.argument('wave-dir', type=Folder)
2018-07-24 00:47:10 +00:00
@click.option('--audio', '--audio-path', type=File, default=None)
2018-07-13 12:37:22 +00:00
@click.option('--fps', default=_FPS)
@click.option('--output', default='output.mp4')
def main(wave_dir: str, audio_path: Optional[str], fps: int, output: str):
2018-07-12 22:27:26 +00:00
cfg = Config(
wave_dir=wave_dir,
audio_path=audio_path,
2018-07-12 22:27:26 +00:00
fps=fps,
2018-07-24 03:38:15 +00:00
amplification=5,
time_visible_ms=25,
scan_ratio=1,
trigger=CorrelationTrigger.Config(
2018-07-14 22:42:10 +00:00
trigger_strength=10,
use_edge_trigger=True,
responsiveness=0.1,
falloff_width=.5,
2018-07-13 12:37:22 +00:00
),
render=RendererConfig( # todo
2018-07-13 11:05:31 +00:00
1280, 720,
2018-07-13 02:29:05 +00:00
ncols=1
),
outputs=[
2018-07-22 12:31:49 +00:00
# outputs.FFmpegOutputConfig(output),
outputs.FFplayOutputConfig(),
],
create_window=False
2018-07-12 22:27:26 +00:00
)
ovgen = Ovgen(cfg)
ovgen.write()
class Ovgen:
def __init__(self, cfg: Config):
self.cfg = cfg
self.waves: List[Wave] = []
self.nwaves: int = None
self.outputs: List[outputs.Output] = []
2018-07-12 22:27:26 +00:00
def write(self):
self._load_waves() # self.waves =
self._load_outputs() # self.outputs =
self._render()
2018-07-12 22:27:26 +00:00
def _load_waves(self):
2018-07-12 22:27:26 +00:00
wave_dir = Path(self.cfg.wave_dir)
waves = sorted(wave_dir.glob('*.wav'))
for idx, path in enumerate(waves):
2018-07-12 22:27:26 +00:00
wcfg = WaveConfig(
2018-07-24 03:38:15 +00:00
amplification=self.cfg.amplification
2018-07-12 22:27:26 +00:00
)
2018-07-13 12:37:22 +00:00
2018-07-12 22:27:26 +00:00
wave = Wave(wcfg, str(path))
trigger = self.cfg.trigger(
2018-07-13 12:37:22 +00:00
wave=wave,
scan_nsamp=round(
self.cfg.time_visible_s * self.cfg.scan_ratio * wave.smp_s),
# I tried extracting variable, but got confused as a result
)
wave.set_trigger(trigger)
2018-07-12 22:27:26 +00:00
self.waves.append(wave)
self.nwaves = len(self.waves)
def _load_outputs(self):
self.outputs = []
for output_cfg in self.cfg.outputs:
output = output_cfg(self.cfg)
self.outputs.append(output)
def _render(self):
2018-07-12 22:27:26 +00:00
# Calculate number of frames (TODO master file?)
time_visible_s = self.cfg.time_visible_s
2018-07-12 22:27:26 +00:00
fps = self.cfg.fps
create_window = self.cfg.create_window
2018-07-12 22:27:26 +00:00
nframes = fps * self.waves[0].get_s()
nframes = int(nframes) + 1
renderer = MatplotlibRenderer(self.cfg.render, self.nwaves, create_window)
2018-07-12 22:27:26 +00:00
2018-07-14 06:54:14 +00:00
if RENDER_PROFILING:
2018-07-13 11:05:31 +00:00
begin = time.perf_counter()
2018-07-12 22:27:26 +00:00
# For each frame, render each wave
for frame in range(nframes):
2018-07-13 00:48:51 +00:00
time_seconds = frame / fps
2018-07-12 22:27:26 +00:00
datas = []
# Get data from each wave
2018-07-12 22:27:26 +00:00
for wave in self.waves:
2018-07-13 00:48:51 +00:00
sample = round(wave.smp_s * time_seconds)
region_len = round(wave.smp_s * time_visible_s)
2018-07-12 22:27:26 +00:00
trigger_sample = wave.trigger.get_trigger(sample)
datas.append(wave.get_around(trigger_sample, region_len))
2018-07-12 22:27:26 +00:00
# Render frame
renderer.render_frame(datas)
2018-07-12 22:27:26 +00:00
# Output frame
if self.outputs:
frame = renderer.get_frame()
for output in self.outputs:
output.write_frame(frame)
2018-07-14 06:54:14 +00:00
if RENDER_PROFILING:
# noinspection PyUnboundLocalVariable
2018-07-13 11:05:31 +00:00
dtime = time.perf_counter() - begin
render_fps = nframes / dtime
print(f'FPS = {render_fps}')