Rename ovgenpy to corrscope

pull/357/head
nyanpasu64 2018-12-20 02:31:55 -08:00
rodzic 9aceabb2b7
commit 5c47c293cb
35 zmienionych plików z 229 dodań i 228 usunięć

1
.idea/.name 100644
Wyświetl plik

@ -0,0 +1 @@
corrscope

Wyświetl plik

@ -9,7 +9,7 @@
<excludeFolder url="file://$MODULE_DIR$/ovgenpy.build" />
<excludeFolder url="file://$MODULE_DIR$/ovgenpy.egg-info" />
</content>
<orderEntry type="jdk" jdkName="Python 3.6 (ovgenpy)" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3.7 (corrscope-py3.7)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PackageRequirementsSettings">

Wyświetl plik

@ -3,5 +3,5 @@
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (ovgenpy)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (corrscope-py3.7)" project-jdk-type="Python SDK" />
</project>

Wyświetl plik

@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/ovgenpy.iml" filepath="$PROJECT_DIR$/.idea/ovgenpy.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/corrscope.iml" filepath="$PROJECT_DIR$/.idea/corrscope.iml" />
</modules>
</component>
</project>

Wyświetl plik

@ -1,4 +1,4 @@
from ovgenpy import cli
from corrscope import cli
if __name__ == '__main__':
cli.main()

Wyświetl plik

@ -4,13 +4,13 @@ from typing import TYPE_CHECKING, Optional, Union
import attr
from ruamel.yaml.comments import CommentedMap
from ovgenpy.config import register_config, Alias, OvgenError
from ovgenpy.triggers import ITriggerConfig
from ovgenpy.util import coalesce
from ovgenpy.wave import _WaveConfig, Wave
from corrscope.config import register_config, Alias, CorrError
from corrscope.triggers import ITriggerConfig
from corrscope.util import coalesce
from corrscope.wave import _WaveConfig, Wave
if TYPE_CHECKING:
from ovgenpy.ovgenpy import Config
from corrscope.corrscope import Config
@register_config
@ -33,29 +33,29 @@ class ChannelConfig:
class Channel:
# trigger_samp is unneeded, since __init__ (not Ovgenpy) constructs triggers.
# trigger_samp is unneeded, since __init__ (not CorrScope) constructs triggers.
render_samp: int
# TODO add a "get_around" method for rendering (also helps test_channel_subsampling)
# Currently Ovgenpy peeks at Chanel.render_samp and render_stride (bad).
# Currently CorrScope peeks at Channel.render_samp and render_stride (bad).
# Product of ovgen_cfg.trigger/render_subsampling and trigger/render_width.
# Product of corr_cfg.trigger/render_subsampling and trigger/render_width.
trigger_stride: int
render_stride: int
def __init__(self, cfg: ChannelConfig, ovgen_cfg: 'Config'):
def __init__(self, cfg: ChannelConfig, corr_cfg: 'Config'):
self.cfg = cfg
# Create a Wave object.
wcfg = _WaveConfig(amplification=ovgen_cfg.amplification * cfg.ampl_ratio)
wcfg = _WaveConfig(amplification=corr_cfg.amplification * cfg.ampl_ratio)
self.wave = Wave(wcfg, abspath(cfg.wav_path))
# `subsampling` increases `stride` and decreases `nsamp`.
# `width` increases `stride` without changing `nsamp`.
tsub = ovgen_cfg.trigger_subsampling
tw = coalesce(cfg.trigger_width, ovgen_cfg.trigger_width)
tsub = corr_cfg.trigger_subsampling
tw = coalesce(cfg.trigger_width, corr_cfg.trigger_width)
rsub = ovgen_cfg.render_subsampling
rw = coalesce(cfg.render_width, ovgen_cfg.render_width)
rsub = corr_cfg.render_subsampling
rw = coalesce(cfg.render_width, corr_cfg.render_width)
# nsamp = orig / subsampling
# stride = subsampling * width
@ -63,8 +63,8 @@ class Channel:
width_s = width_ms / 1000
return round(width_s * self.wave.smp_s / sub)
trigger_samp = calculate_nsamp(ovgen_cfg.trigger_ms, tsub)
self.render_samp = calculate_nsamp(ovgen_cfg.render_ms, rsub)
trigger_samp = calculate_nsamp(corr_cfg.trigger_ms, tsub)
self.render_samp = calculate_nsamp(corr_cfg.render_ms, rsub)
self.trigger_stride = tsub * tw
self.render_stride = rsub * rw
@ -73,11 +73,11 @@ class Channel:
if isinstance(cfg.trigger, ITriggerConfig):
tcfg = cfg.trigger
elif isinstance(cfg.trigger, (CommentedMap, dict)): # CommentedMap may/not be subclass of dict.
tcfg = attr.evolve(ovgen_cfg.trigger, **cfg.trigger)
tcfg = attr.evolve(corr_cfg.trigger, **cfg.trigger)
elif cfg.trigger is None:
tcfg = ovgen_cfg.trigger
tcfg = corr_cfg.trigger
else:
raise OvgenError(
raise CorrError(
f'invalid per-channel trigger {cfg.trigger}, type={type(cfg.trigger)}, '
f'must be (*)TriggerConfig, dict, or None')
@ -85,6 +85,6 @@ class Channel:
wave=self.wave,
tsamp=trigger_samp,
stride=self.trigger_stride,
fps=ovgen_cfg.fps
fps=corr_cfg.fps
)

Wyświetl plik

@ -4,10 +4,10 @@ from typing import Optional, List, Tuple, Union
import click
from ovgenpy.channel import ChannelConfig
from ovgenpy.config import yaml
from ovgenpy.outputs import IOutputConfig, FFplayOutputConfig, FFmpegOutputConfig
from ovgenpy.ovgenpy import default_config, Ovgen, Config, Arguments
from corrscope.channel import ChannelConfig
from corrscope.config import yaml
from corrscope.outputs import IOutputConfig, FFplayOutputConfig, FFmpegOutputConfig
from corrscope.corrscope import default_config, CorrScope, Config, Arguments
Folder = click.Path(exists=True, file_okay=False)
@ -36,7 +36,7 @@ YAML_NAME = YAML_EXTS[0]
VIDEO_NAME = '.mp4'
DEFAULT_NAME = 'ovgenpy'
DEFAULT_NAME = 'corrscope'
def get_name(audio_file: Union[None, str, Path]) -> str:
# Write file to current working dir, not audio dir.
if audio_file:
@ -91,15 +91,15 @@ def main(
.yaml config.
"""
# GUI:
# ovgenpy
# ovgenpy file.yaml
# ovgenpy wildcard/wav/folder ... [--options]
# corrscope
# corrscope file.yaml
# corrscope wildcard/wav/folder ... [--options]
#
# CLI:
# ovgenpy wildcard/wav/folder ... [--options] --write-cfg file.yaml [--play]
# ovgenpy wildcard/wav/folder ... --play
# ovgenpy file.yaml --play
# ovgenpy file.yaml --write-yaml
# corrscope wildcard/wav/folder ... [--options] --write-cfg file.yaml [--play]
# corrscope wildcard/wav/folder ... --play
# corrscope file.yaml --play
# corrscope file.yaml --write-yaml
#
# - You can specify as many wildcards or wav files as you want.
# - You can only supply one folder, with no files/wildcards.
@ -164,7 +164,7 @@ def main(
cfg_dir = '.'
if show_gui:
from ovgenpy import gui
from corrscope import gui
gui.gui_main(cfg, cfg_path)
else:
@ -184,9 +184,9 @@ def main(
outputs.append(FFmpegOutputConfig(video_path))
if outputs:
assert Ovgen # to prevent PyCharm from deleting the import
assert CorrScope # to prevent PyCharm from deleting the import
arg = Arguments(cfg_dir=cfg_dir, outputs=outputs)
command = lambda: Ovgen(cfg, arg).play()
command = lambda: CorrScope(cfg, arg).play()
if profile:
import cProfile

Wyświetl plik

@ -11,7 +11,7 @@ if TYPE_CHECKING:
__all__ = ['yaml', 'copy_config',
'register_config', 'kw_config', 'Alias', 'Ignored', 'register_enum',
'OvgenError', 'OvgenWarning']
'CorrError', 'CorrWarning']
# Setup YAML loading (yaml object).
@ -148,7 +148,7 @@ class _ConfigMixin:
if isinstance(class_var, Alias):
target = class_var.key
if target in state:
raise OvgenError(
raise CorrError(
f'{type(self).__name__} received both Alias {key} and '
f'equivalent {target}'
)
@ -189,13 +189,13 @@ class _EnumMixin:
# Miscellaneous
class OvgenError(ValueError):
class CorrError(ValueError):
""" Error caused by invalid end-user input (via YAML/GUI config).
(Should be) caught by GUI and displayed to user. """
pass
class OvgenWarning(UserWarning):
class CorrWarning(UserWarning):
""" Warning about deprecated end-user config (YAML/GUI).
(Should be) caught by GUI and displayed to user. """
pass

Wyświetl plik

@ -9,17 +9,17 @@ from typing import Optional, List, Union, TYPE_CHECKING, Callable
import attr
from ovgenpy import outputs as outputs_
from ovgenpy.channel import Channel, ChannelConfig
from ovgenpy.config import kw_config, register_enum, Ignored, OvgenError, OvgenWarning
from ovgenpy.renderer import MatplotlibRenderer, RendererConfig
from ovgenpy.layout import LayoutConfig
from ovgenpy.triggers import ITriggerConfig, CorrelationTriggerConfig, PerFrameCache
from ovgenpy.util import pushd, coalesce
from ovgenpy.wave import Wave
from corrscope import outputs as outputs_
from corrscope.channel import Channel, ChannelConfig
from corrscope.config import kw_config, register_enum, Ignored, CorrError, CorrWarning
from corrscope.renderer import MatplotlibRenderer, RendererConfig
from corrscope.layout import LayoutConfig
from corrscope.triggers import ITriggerConfig, CorrelationTriggerConfig, PerFrameCache
from corrscope.util import pushd, coalesce
from corrscope.wave import Wave
if TYPE_CHECKING:
from ovgenpy.triggers import CorrelationTrigger
from corrscope.triggers import CorrelationTrigger
PRINT_TIMESTAMP = True
@ -89,7 +89,7 @@ class Config:
if not isinstance(self.benchmark_mode, BenchmarkMode):
self.benchmark_mode = BenchmarkMode[self.benchmark_mode]
except KeyError:
raise OvgenError(
raise CorrError(
f'invalid benchmark_mode mode {self.benchmark_mode} not in '
f'{[el.name for el in BenchmarkMode]}')
@ -104,7 +104,7 @@ class Config:
self.trigger_ms = coalesce(self.trigger_ms, width_ms)
self.render_ms = coalesce(self.render_ms, width_ms)
except TypeError:
raise OvgenError(
raise CorrError(
'Must supply either width_ms or both (trigger_ms and render_ms)')
deprecated = []
@ -114,7 +114,7 @@ class Config:
deprecated.append('render_width')
if deprecated:
warnings.warn(f"Options {deprecated} are deprecated and will be removed",
OvgenWarning)
CorrWarning)
_FPS = 60 # f_s
@ -161,7 +161,7 @@ class Arguments:
is_aborted: IsAborted = lambda: False
on_end: Callable[[], None] = lambda: None
class Ovgen:
class CorrScope:
def __init__(self, cfg: Config, arg: Arguments):
self.cfg = cfg
self.arg = arg
@ -178,7 +178,7 @@ class Ovgen:
self.output_cfgs = []
if len(self.cfg.channels) == 0:
raise OvgenError('Config.channels is empty')
raise CorrError('Config.channels is empty')
waves: List[Wave]
channels: List[Channel]
@ -209,7 +209,7 @@ class Ovgen:
def play(self):
if self.has_played:
raise ValueError('Cannot call Ovgen.play() more than once')
raise ValueError('Cannot call CorrScope.play() more than once')
self.has_played = True
self._load_channels()
@ -231,16 +231,16 @@ class Ovgen:
internals = self.cfg.show_internals
extra_outputs = SimpleNamespace()
if internals:
from ovgenpy.outputs import FFplayOutputConfig
from corrscope.outputs import FFplayOutputConfig
import attr
no_audio = attr.evolve(self.cfg, master_audio='')
ovgen = self
corr = self
class RenderOutput:
def __init__(self):
self.renderer = ovgen._load_renderer()
self.renderer = corr._load_renderer()
self.output = FFplayOutputConfig()(no_audio)
def render_frame(self, datas):

Wyświetl plik

@ -12,19 +12,19 @@ from PyQt5.QtCore import QModelIndex, Qt
from PyQt5.QtGui import QKeySequence, QFont, QCloseEvent
from PyQt5.QtWidgets import QShortcut
from ovgenpy import cli
from ovgenpy.channel import ChannelConfig
from ovgenpy.config import OvgenError, copy_config, yaml
from ovgenpy.gui.data_bind import PresentationModel, map_gui, behead, rgetattr, rsetattr
from ovgenpy.gui.util import color2hex, Locked, get_save_with_ext, find_ranges
from ovgenpy.outputs import IOutputConfig, FFplayOutputConfig, FFmpegOutputConfig
from ovgenpy.ovgenpy import Ovgen, Config, Arguments, default_config
from ovgenpy.triggers import CorrelationTriggerConfig, ITriggerConfig
from ovgenpy.util import obj_name
from corrscope import cli
from corrscope.channel import ChannelConfig
from corrscope.config import CorrError, copy_config, yaml
from corrscope.gui.data_bind import PresentationModel, map_gui, behead, rgetattr, rsetattr
from corrscope.gui.util import color2hex, Locked, get_save_with_ext, find_ranges
from corrscope.outputs import IOutputConfig, FFplayOutputConfig, FFmpegOutputConfig
from corrscope.corrscope import CorrScope, Config, Arguments, default_config
from corrscope.triggers import CorrelationTriggerConfig, ITriggerConfig
from corrscope.util import obj_name
FILTER_WAV_FILES = "WAV files (*.wav)"
APP_NAME = 'ovgenpy'
APP_NAME = 'corrscope'
APP_DIR = Path(__file__).parent
def res(file: str) -> str:
@ -88,8 +88,8 @@ class MainWindow(qw.QMainWindow):
self.actionRender.triggered.connect(self.on_action_render)
self.actionExit.triggered.connect(qw.QApplication.closeAllWindows)
# Initialize ovgen-thread attribute.
self.ovgen_thread: Locked[Optional[OvgenThread]] = Locked(None)
# Initialize CorrScope-thread attribute.
self.corr_thread: Locked[Optional[CorrThread]] = Locked(None)
# Bind config to UI.
self.load_cfg(cfg, cfg_path)
@ -273,11 +273,11 @@ class MainWindow(qw.QMainWindow):
return False
def on_action_play(self):
""" Launch ovgen and ffplay. """
""" Launch CorrScope and ffplay. """
error_msg = 'Cannot play, another play/render is active'
with self.ovgen_thread as t:
with self.corr_thread as t:
if t is not None:
self.ovgen_thread.unlock()
self.corr_thread.unlock()
qw.QMessageBox.critical(self, 'Error', error_msg)
return
@ -287,9 +287,9 @@ class MainWindow(qw.QMainWindow):
def on_action_render(self):
""" Get file name. Then show a progress dialog while rendering to file. """
error_msg = 'Cannot render to file, another play/render is active'
with self.ovgen_thread as t:
with self.corr_thread as t:
if t is not None:
self.ovgen_thread.unlock()
self.corr_thread.unlock()
qw.QMessageBox.critical(self, 'Error', error_msg)
return
@ -300,14 +300,14 @@ class MainWindow(qw.QMainWindow):
if path:
name = str(path)
# FIXME what if missing mp4?
dlg = OvgenProgressDialog(self, 'Rendering video')
dlg = CorrProgressDialog(self, 'Rendering video')
outputs = [FFmpegOutputConfig(name)]
self.play_thread(outputs, dlg)
def play_thread(self, outputs: List[IOutputConfig],
dlg: Optional['OvgenProgressDialog']):
""" self.ovgen_thread MUST be locked. """
dlg: Optional['CorrProgressDialog']):
""" self.corr_thread MUST be locked. """
arg = self._get_args(outputs)
if dlg:
arg = attr.evolve(arg,
@ -318,7 +318,7 @@ class MainWindow(qw.QMainWindow):
)
cfg = copy_config(self.model.cfg)
t = self.ovgen_thread.obj = OvgenThread(cfg, arg)
t = self.corr_thread.obj = CorrThread(cfg, arg)
t.error.connect(self.on_play_thread_error)
t.finished.connect(self.on_play_thread_finished)
t.start()
@ -327,7 +327,7 @@ class MainWindow(qw.QMainWindow):
qw.QMessageBox.critical(self, 'Error rendering oscilloscope', str(exc))
def on_play_thread_finished(self):
self.ovgen_thread.set(None)
self.corr_thread.set(None)
def _get_args(self, outputs: List[IOutputConfig]):
arg = Arguments(
@ -376,7 +376,7 @@ class ShortcutButton(qw.QPushButton):
self.setToolTip(keys.toString(QKeySequence.NativeText))
class OvgenThread(qc.QThread):
class CorrThread(qc.QThread):
def __init__(self, cfg: Config, arg: Arguments):
qc.QThread.__init__(self)
self.cfg = cfg
@ -386,7 +386,7 @@ class OvgenThread(qc.QThread):
cfg = self.cfg
arg = self.arg
try:
Ovgen(cfg, arg).play()
CorrScope(cfg, arg).play()
except Exception as e:
arg.on_end()
self.error.emit(e)
@ -396,7 +396,7 @@ class OvgenThread(qc.QThread):
error = qc.pyqtSignal(Exception)
class OvgenProgressDialog(qw.QProgressDialog):
class CorrProgressDialog(qw.QProgressDialog):
def __init__(self, parent: Optional[qw.QWidget], title: str):
super().__init__(parent)
self.setMinimumWidth(300)
@ -409,12 +409,12 @@ class OvgenProgressDialog(qw.QProgressDialog):
# Don't reset when rendering is approximately finished.
self.setAutoReset(False)
# Close after ovgen finishes.
# Close after CorrScope finishes.
self.setAutoClose(True)
def on_begin(self, begin_time, end_time):
self.setRange(int(round(begin_time)), int(round(end_time)))
# self.setValue is called by Ovgen, on the first frame.
# self.setValue is called by CorrScope, on the first frame.
def nrow_ncol_property(altered: str, unaltered: str) -> property:
@ -433,7 +433,7 @@ def nrow_ncol_property(altered: str, unaltered: str) -> property:
elif val == 0:
setattr(self.cfg.layout, altered, None)
else:
raise OvgenError(f"invalid input: {altered} < 0, should never happen")
raise CorrError(f"invalid input: {altered} < 0, should never happen")
return property(get, set)
@ -480,7 +480,7 @@ class ConfigModel(PresentationModel):
@render_video_size.setter
def render_video_size(self, value: str):
error = OvgenError(f"invalid video size {value}, must be WxH")
error = CorrError(f"invalid video size {value}, must be WxH")
for sep in 'x*,':
width_height = value.split(sep)
@ -592,7 +592,7 @@ class ChannelModel(qc.QAbstractTableModel):
t = cfg.trigger
if isinstance(t, ITriggerConfig):
if not isinstance(t, CorrelationTriggerConfig):
raise OvgenError(
raise CorrError(
f'Loading per-channel {obj_name(t)} not supported')
trigger_dict = attr.asdict(t)
else:

Wyświetl plik

@ -7,12 +7,12 @@ from PyQt5.QtCore import pyqtSlot
from PyQt5.QtGui import QPalette, QColor
from PyQt5.QtWidgets import QWidget
from ovgenpy.config import OvgenError
from ovgenpy.triggers import lerp
from ovgenpy.util import obj_name, perr
from corrscope.config import CorrError
from corrscope.triggers import lerp
from corrscope.util import obj_name, perr
if TYPE_CHECKING:
from ovgenpy.gui import MainWindow
from corrscope.gui import MainWindow
__all__ = ['PresentationModel', 'map_gui', 'behead', 'rgetattr', 'rsetattr']
@ -158,7 +158,7 @@ def model_setter(value_type: type) -> Callable:
assert isinstance(value, value_type)
try:
self.pmodel[self.path] = value
except OvgenError:
except CorrError:
self.setPalette(self.error_palette)
else:
self.setPalette(self.default_palette)

Wyświetl plik

@ -550,32 +550,32 @@
<customwidget>
<class>BoundLineEdit</class>
<extends>QLineEdit</extends>
<header>ovgenpy/gui/data_bind.h</header>
<header>corrscope/gui/data_bind.h</header>
</customwidget>
<customwidget>
<class>BoundSpinBox</class>
<extends>QSpinBox</extends>
<header>ovgenpy/gui/data_bind.h</header>
<header>corrscope/gui/data_bind.h</header>
</customwidget>
<customwidget>
<class>BoundDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>ovgenpy/gui/data_bind.h</header>
<header>corrscope/gui/data_bind.h</header>
</customwidget>
<customwidget>
<class>BoundComboBox</class>
<extends>QComboBox</extends>
<header>ovgenpy/gui/data_bind.h</header>
<header>corrscope/gui/data_bind.h</header>
</customwidget>
<customwidget>
<class>ShortcutButton</class>
<extends>QPushButton</extends>
<header>ovgenpy/gui/__init__.h</header>
<header>corrscope/gui/__init__.h</header>
</customwidget>
<customwidget>
<class>ChannelTableView</class>
<extends>QTableView</extends>
<header>ovgenpy/gui/__init__.h</header>
<header>corrscope/gui/__init__.h</header>
</customwidget>
</customwidgets>
<resources/>

Wyświetl plik

@ -7,16 +7,16 @@ import more_itertools
from PyQt5.QtCore import QMutex
from PyQt5.QtWidgets import QWidget, QFileDialog
from ovgenpy.config import OvgenError
from corrscope.config import CorrError
def color2hex(color):
try:
return matplotlib.colors.to_hex(color, keep_alpha=False)
except ValueError:
raise OvgenError(f'invalid color {color}')
raise CorrError(f'invalid color {color}')
except Exception as e:
raise OvgenError(
raise CorrError(
f'doubly invalid color {color}, raises {e} (report bug!)')

Wyświetl plik

@ -2,8 +2,8 @@ from typing import Optional, TypeVar, Callable, List
import numpy as np
from ovgenpy.config import register_config, OvgenError
from ovgenpy.util import ceildiv
from corrscope.config import register_config, CorrError
from corrscope.util import ceildiv
@register_config(always_dump='orientation')
@ -19,7 +19,7 @@ class LayoutConfig:
self.ncols = None
if self.nrows and self.ncols:
raise OvgenError('cannot manually assign both nrows and ncols')
raise CorrError('cannot manually assign both nrows and ncols')
if not self.nrows and not self.ncols:
self.ncols = 1
@ -41,7 +41,7 @@ class RendererLayout:
self.orientation = cfg.orientation
if self.orientation not in self.VALID_ORIENTATIONS:
raise OvgenError(f'Invalid orientation {self.orientation} not in '
raise CorrError(f'Invalid orientation {self.orientation} not in '
f'{self.VALID_ORIENTATIONS}')
def _calc_layout(self):

Wyświetl plik

@ -6,10 +6,10 @@ from abc import ABC, abstractmethod
from os.path import abspath
from typing import TYPE_CHECKING, Type, List, Union, Optional
from ovgenpy.config import register_config
from corrscope.config import register_config
if TYPE_CHECKING:
from ovgenpy.ovgenpy import Config
from corrscope.corrscope import Config
ByteBuffer = Union[bytes, np.ndarray]
@ -22,8 +22,8 @@ FRAMES_TO_BUFFER = 2
class IOutputConfig:
cls: 'Type[Output]'
def __call__(self, ovgen_cfg: 'Config'):
return self.cls(ovgen_cfg, cfg=self)
def __call__(self, corr_cfg: 'Config'):
return self.cls(corr_cfg, cfg=self)
class _Stop:
@ -34,11 +34,11 @@ Stop = _Stop()
class Output(ABC):
def __init__(self, ovgen_cfg: 'Config', cfg: IOutputConfig):
self.ovgen_cfg = ovgen_cfg
def __init__(self, corr_cfg: 'Config', cfg: IOutputConfig):
self.corr_cfg = corr_cfg
self.cfg = cfg
rcfg = ovgen_cfg.render
rcfg = corr_cfg.render
frame_bytes = rcfg.height * rcfg.width * RGB_DEPTH
self.bufsize = frame_bytes * FRAMES_TO_BUFFER
@ -69,26 +69,26 @@ def register_output(config_t: Type[IOutputConfig]):
# FFmpeg command line generation
class _FFmpegProcess:
def __init__(self, templates: List[str], ovgen_cfg: 'Config'):
def __init__(self, templates: List[str], corr_cfg: 'Config'):
self.templates = templates
self.ovgen_cfg = ovgen_cfg
self.corr_cfg = corr_cfg
self.templates += ffmpeg_input_video(ovgen_cfg) # video
if ovgen_cfg.master_audio:
self.templates += ffmpeg_input_video(corr_cfg) # video
if corr_cfg.master_audio:
# Load master audio and trim to timestamps.
self.templates.append(f'-ss {ovgen_cfg.begin_time}')
self.templates.append(f'-ss {corr_cfg.begin_time}')
audio_path = shlex.quote(abspath(ovgen_cfg.master_audio))
audio_path = shlex.quote(abspath(corr_cfg.master_audio))
self.templates += ffmpeg_input_audio(audio_path) # audio
if ovgen_cfg.end_time is not None:
dur = ovgen_cfg.end_time - ovgen_cfg.begin_time
if corr_cfg.end_time is not None:
dur = corr_cfg.end_time - corr_cfg.begin_time
self.templates.append(f'-to {dur}')
def add_output(self, cfg: 'Union[FFmpegOutputConfig, FFplayOutputConfig]') -> None:
self.templates.append(cfg.video_template) # video
if self.ovgen_cfg.master_audio:
if self.corr_cfg.master_audio:
self.templates.append(cfg.audio_template) # audio
def popen(self, extra_args, bufsize, **kwargs) -> subprocess.Popen:
@ -193,10 +193,10 @@ FFMPEG = 'ffmpeg'
@register_output(FFmpegOutputConfig)
class FFmpegOutput(PipeOutput):
def __init__(self, ovgen_cfg: 'Config', cfg: FFmpegOutputConfig):
super().__init__(ovgen_cfg, cfg)
def __init__(self, corr_cfg: 'Config', cfg: FFmpegOutputConfig):
super().__init__(corr_cfg, cfg)
ffmpeg = _FFmpegProcess([FFMPEG, '-y'], ovgen_cfg)
ffmpeg = _FFmpegProcess([FFMPEG, '-y'], corr_cfg)
ffmpeg.add_output(cfg)
ffmpeg.templates.append(cfg.args)
@ -220,10 +220,10 @@ FFPLAY = 'ffplay'
@register_output(FFplayOutputConfig)
class FFplayOutput(PipeOutput):
def __init__(self, ovgen_cfg: 'Config', cfg: FFplayOutputConfig):
super().__init__(ovgen_cfg, cfg)
def __init__(self, corr_cfg: 'Config', cfg: FFplayOutputConfig):
super().__init__(corr_cfg, cfg)
ffmpeg = _FFmpegProcess([FFMPEG, '-nostats'], ovgen_cfg)
ffmpeg = _FFmpegProcess([FFMPEG, '-nostats'], corr_cfg)
ffmpeg.add_output(cfg)
ffmpeg.templates.append('-f nut')

Wyświetl plik

@ -5,10 +5,10 @@ import matplotlib
import numpy as np
import attr
from ovgenpy.config import register_config
from ovgenpy.layout import RendererLayout, LayoutConfig
from ovgenpy.outputs import RGB_DEPTH, ByteBuffer
from ovgenpy.util import coalesce
from corrscope.config import register_config
from corrscope.layout import RendererLayout, LayoutConfig
from corrscope.outputs import RGB_DEPTH, ByteBuffer
from corrscope.util import coalesce
matplotlib.use('agg')
from matplotlib import pyplot as plt
@ -18,7 +18,7 @@ if TYPE_CHECKING:
from matplotlib.axes import Axes
from matplotlib.figure import Figure
from matplotlib.lines import Line2D
from ovgenpy.channel import ChannelConfig
from corrscope.channel import ChannelConfig
def default_color():

Wyświetl plik

@ -7,14 +7,14 @@ from scipy import signal
from scipy.signal import windows
import attr
from ovgenpy.config import kw_config, OvgenError, Alias, OvgenWarning
from ovgenpy.util import find, obj_name
from ovgenpy.utils.windows import midpad, leftpad
from ovgenpy.wave import FLOAT
from corrscope.config import kw_config, CorrError, Alias, CorrWarning
from corrscope.util import find, obj_name
from corrscope.utils.windows import midpad, leftpad
from corrscope.wave import FLOAT
if TYPE_CHECKING:
from ovgenpy.wave import Wave
from corrscope.wave import Wave
# Abstract classes
@ -133,7 +133,7 @@ class CorrelationTriggerConfig(ITriggerConfig):
warnings.warn(
"Ignoring old `CorrelationTriggerConfig.use_edge_trigger` flag, "
"overriden by newer `post` flag.",
OvgenWarning
CorrWarning
)
else:
self.post = ZeroCrossingTriggerConfig()
@ -141,7 +141,7 @@ class CorrelationTriggerConfig(ITriggerConfig):
def _validate_param(self, key: str, begin, end):
value = getattr(self, key)
if not begin <= value <= end:
raise OvgenError(
raise CorrError(
f'Invalid {key}={value} (should be within [{begin}, {end}])')
@ -176,7 +176,7 @@ class CorrelationTrigger(Trigger):
def _calc_data_taper(self):
""" Input data window. Zeroes out all data older than 1 frame old.
See https://github.com/nyanpasu64/ovgenpy/wiki/Correlation-Trigger
See https://github.com/nyanpasu64/corrscope/wiki/Correlation-Trigger
"""
N = self._buffer_nsamp
halfN = N // 2
@ -410,12 +410,12 @@ class PostTrigger(Trigger, ABC):
Trigger.__init__(self, *args, **kwargs)
if self._stride != 1:
raise OvgenError(
raise CorrError(
f'{obj_name(self)} with stride != 1 is not allowed '
f'(supplied {self._stride})')
if self.post:
raise OvgenError(
raise CorrError(
f'Passing {obj_name(self)} a post_trigger is not allowed '
f'({obj_name(self.post)})'
)
@ -457,7 +457,7 @@ class LocalPostTrigger(PostTrigger):
# Window data
if cache.period is None:
raise OvgenError(
raise CorrError(
"Missing 'cache.period', try stacking CorrelationTrigger "
"before LocalPostTrigger")

Wyświetl plik

@ -6,7 +6,7 @@ from scipy.io import wavfile
# Internal class, not exposed via YAML
from ovgenpy.config import OvgenError
from corrscope.config import CorrError
@attr.dataclass
@ -54,7 +54,7 @@ class Wave:
self.max_val = 1
else:
raise OvgenError(f'unexpected wavfile dtype {dtype}')
raise CorrError(f'unexpected wavfile dtype {dtype}')
def __getitem__(self, index: Union[int, slice]) -> 'np.ndarray[FLOAT]':
""" Copies self.data[item], converted to a FLOAT within range [-1, 1). """

Wyświetl plik

@ -4,4 +4,4 @@ testpaths = tests
[coverage:run]
branch = True
source =
ovgenpy
corrscope

Wyświetl plik

@ -1,10 +1,10 @@
from setuptools import setup
setup(
name='ovgenpy',
name='corrscope',
version='0',
packages=['ovgenpy'],
url='https://github.com/nyanpasu64/ovgenpy',
packages=['corrscope'],
url='https://github.com/nyanpasu64/corrscope',
license='BSD-2-Clause',
author='nyanpasu64',
author_email='',

Wyświetl plik

@ -6,13 +6,13 @@ from hypothesis import given
import hypothesis.strategies as hs
from pytest_mock import MockFixture
import ovgenpy.channel
import ovgenpy.ovgenpy
from ovgenpy.channel import ChannelConfig, Channel
from ovgenpy.config import OvgenError
from ovgenpy.ovgenpy import default_config, Ovgen, BenchmarkMode, Arguments
from ovgenpy.triggers import NullTriggerConfig
from ovgenpy.util import coalesce
import corrscope.channel
import corrscope.corrscope
from corrscope.channel import ChannelConfig, Channel
from corrscope.config import CorrError
from corrscope.corrscope import default_config, CorrScope, BenchmarkMode, Arguments
from corrscope.triggers import NullTriggerConfig
from corrscope.util import coalesce
positive = hs.integers(min_value=1, max_value=100)
@ -23,7 +23,7 @@ maybe = hs.one_of(hs.none(), positive)
Maybe = Optional[int]
@pytest.mark.filterwarnings("ignore::ovgenpy.config.OvgenWarning")
@pytest.mark.filterwarnings("ignore::corrscope.config.CorrWarning")
@given(
# Channel
c_trigger_width=maybe, c_render_width=maybe,
@ -53,9 +53,9 @@ def test_config_channel_width_stride(
"""
# region setup test variables
ovgenpy.ovgenpy.PRINT_TIMESTAMP = False # Cleanup Hypothesis testing logs
corrscope.corrscope.PRINT_TIMESTAMP = False # Cleanup Hypothesis testing logs
Wave = mocker.patch.object(ovgenpy.channel, 'Wave')
Wave = mocker.patch.object(corrscope.channel, 'Wave')
wave = Wave.return_value
def get_around(sample: int, region_nsamp: int, stride: int):
@ -90,7 +90,7 @@ def test_config_channel_width_stride(
# endregion
if not (width_ms or (trigger_ms and render_ms)):
with pytest.raises(OvgenError):
with pytest.raises(CorrError):
_cfg = get_cfg()
return
@ -123,10 +123,10 @@ def test_config_channel_width_stride(
assert trigger._tsamp == ideal_tsamp
assert trigger._stride == channel.trigger_stride
## Ensure ovgenpy calls render using channel.render_samp and render_stride.
ovgen = Ovgen(cfg, Arguments(cfg_dir='.', outputs=[]))
renderer = mocker.patch.object(Ovgen, '_load_renderer').return_value
ovgen.play()
## Ensure corrscope calls render using channel.render_samp and render_stride.
corr = CorrScope(cfg, Arguments(cfg_dir='.', outputs=[]))
renderer = mocker.patch.object(CorrScope, '_load_renderer').return_value
corr.play()
# Only render (not NullTrigger) calls wave.get_around().
(_sample, _region_nsamp, _subsampling), kwargs = wave.get_around.call_args

Wyświetl plik

@ -7,13 +7,13 @@ import click
import pytest
from click.testing import CliRunner
import ovgenpy.channel
from ovgenpy import cli
from ovgenpy.cli import YAML_NAME
from ovgenpy.config import yaml
from ovgenpy.outputs import FFmpegOutputConfig
from ovgenpy.ovgenpy import Config, Ovgen, Arguments
from ovgenpy.util import pushd
import corrscope.channel
from corrscope import cli
from corrscope.cli import YAML_NAME
from corrscope.config import yaml
from corrscope.outputs import FFmpegOutputConfig
from corrscope.corrscope import Config, CorrScope, Arguments
from corrscope.util import pushd
if TYPE_CHECKING:
import pytest_mock
@ -23,7 +23,7 @@ def call_main(argv):
return CliRunner().invoke(cli.main, argv, catch_exceptions=False, standalone_mode=False)
# ovgenpy configuration sinks
# corrscope configuration sinks
@pytest.fixture
def yaml_sink(mocker: 'pytest_mock.MockFixture') -> Callable:
@ -45,13 +45,13 @@ def yaml_sink(mocker: 'pytest_mock.MockFixture') -> Callable:
@pytest.fixture
def player_sink(mocker) -> Callable:
def _player_sink(command):
Ovgen = mocker.patch.object(cli, 'Ovgen')
CorrScope = mocker.patch.object(cli, 'CorrScope')
argv = shlex.split(command) + ['-p']
call_main(argv)
Ovgen.assert_called_once()
args, kwargs = Ovgen.call_args
CorrScope.assert_called_once()
args, kwargs = CorrScope.call_args
cfg = args[0]
assert isinstance(cfg, Config)
@ -70,7 +70,7 @@ def any_sink(request, mocker):
return sink(mocker)
# ovgenpy configuration sources
# corrscope configuration sources
def test_no_files(any_sink):
with pytest.raises(click.ClickException):
@ -126,14 +126,14 @@ def test_load_yaml_another_dir(yaml_sink, mocker, Popen):
cfg.begin_time = 100 # To skip all actual rendering
# Log execution of Ovgen().play()
Wave = mocker.spy(ovgenpy.channel, 'Wave')
# Log execution of CorrScope().play()
Wave = mocker.spy(corrscope.channel, 'Wave')
# Issue: this test does not use cli.main() to compute output path.
# Possible solution: Call cli.main() via Click runner.
output = FFmpegOutputConfig(cli.get_path(cfg.master_audio, cli.VIDEO_NAME))
ovgen = Ovgen(cfg, Arguments(subdir, [output]))
ovgen.play()
corr = CorrScope(cfg, Arguments(subdir, [output]))
corr.play()
# Compute absolute paths
wav_abs = abspath(f'{subdir}/{wav}')

Wyświetl plik

@ -1,7 +1,7 @@
import pytest
from ruamel.yaml import yaml_object
from ovgenpy.config import register_config, yaml, Alias, Ignored, kw_config, OvgenError
from corrscope.config import register_config, yaml, Alias, Ignored, kw_config, CorrError
# YAML Idiosyncrasies: https://docs.saltstack.com/en/develop/topics/troubleshooting/yaml_idiosyncrasies.html
@ -163,7 +163,7 @@ xx: 1
x: 1
xx: 1
'''
with pytest.raises(OvgenError):
with pytest.raises(CorrError):
yaml.load(s)

Wyświetl plik

@ -1,6 +1,6 @@
import pytest
from ovgenpy.gui.data_bind import rgetattr, rsetattr, rhasattr
from corrscope.gui.data_bind import rgetattr, rsetattr, rhasattr
def test_rgetattr():

Wyświetl plik

@ -1,7 +1,7 @@
import pytest
from ovgenpy.layout import LayoutConfig, RendererLayout
from ovgenpy.renderer import RendererConfig, MatplotlibRenderer
from corrscope.layout import LayoutConfig, RendererLayout
from corrscope.renderer import RendererConfig, MatplotlibRenderer
from tests.test_renderer import WIDTH, HEIGHT

Wyświetl plik

@ -4,11 +4,11 @@ from typing import TYPE_CHECKING
import pytest
from ovgenpy.channel import ChannelConfig
from ovgenpy.outputs import RGB_DEPTH, \
from corrscope.channel import ChannelConfig
from corrscope.outputs import RGB_DEPTH, \
FFmpegOutput, FFmpegOutputConfig, FFplayOutput, FFplayOutputConfig
from ovgenpy.ovgenpy import default_config, Ovgen, Arguments
from ovgenpy.renderer import RendererConfig, MatplotlibRenderer
from corrscope.corrscope import default_config, CorrScope, Arguments
from corrscope.renderer import RendererConfig, MatplotlibRenderer
from tests.test_renderer import WIDTH, HEIGHT, ALL_ZEROS
if TYPE_CHECKING:
@ -40,7 +40,7 @@ def test_output():
assert not Path('-').exists()
# Ensure ovgen closes pipe to output upon completion.
# Ensure CorrScope closes pipe to output upon completion.
@pytest.mark.usefixtures('Popen')
def test_close_output(Popen):
""" FFplayOutput unit test: Ensure ffmpeg and ffplay are terminated when Python
@ -57,7 +57,7 @@ def test_close_output(Popen):
popen.wait.assert_called() # Does wait() need to be called?
# Ensure ovgen terminates FFplay upon exceptions.
# Ensure CorrScope terminates FFplay upon exceptions.
@pytest.mark.usefixtures('Popen')
def test_terminate_ffplay(Popen):
""" FFplayOutput unit test: Ensure ffmpeg and ffplay are terminated when Python
@ -85,58 +85,58 @@ def sine440_config():
@pytest.mark.usefixtures('Popen')
def test_ovgen_terminate_ffplay(Popen, mocker: 'pytest_mock.MockFixture'):
""" Integration test: Ensure ovgenpy calls terminate() on ffmpeg and ffplay when
def test_corr_terminate_ffplay(Popen, mocker: 'pytest_mock.MockFixture'):
""" Integration test: Ensure corrscope calls terminate() on ffmpeg and ffplay when
Python exceptions occur. """
cfg = sine440_config()
ovgen = Ovgen(cfg, Arguments('.', [FFplayOutputConfig()]))
corr = CorrScope(cfg, Arguments('.', [FFplayOutputConfig()]))
render_frame = mocker.patch.object(MatplotlibRenderer, 'render_frame')
render_frame.side_effect = DummyException()
with pytest.raises(DummyException):
ovgen.play()
corr.play()
assert len(ovgen.outputs) == 1
output: FFplayOutput = ovgen.outputs[0]
assert len(corr.outputs) == 1
output: FFplayOutput = corr.outputs[0]
for popen in output._pipeline:
popen.terminate.assert_called()
@pytest.mark.skip('Launches ffmpeg and ffplay processes, creating a ffplay window')
def test_ovgen_terminate_works():
def test_corr_terminate_works():
""" Ensure that ffmpeg/ffplay terminate quickly after Python exceptions, when
`popen.terminate()` is called. """
cfg = sine440_config()
ovgen = Ovgen(cfg, Arguments('.', [FFplayOutputConfig()]))
ovgen.raise_on_teardown = DummyException
corr = CorrScope(cfg, Arguments('.', [FFplayOutputConfig()]))
corr.raise_on_teardown = DummyException
with pytest.raises(DummyException):
# Raises `subprocess.TimeoutExpired` if popen.terminate() doesn't work.
ovgen.play()
corr.play()
# TODO test to ensure ffplay is killed before it terminates
def test_ovgen_output_without_audio():
"""Ensure running ovgen with FFmpeg output, with master audio disabled,
def test_corr_output_without_audio():
"""Ensure running CorrScope with FFmpeg output, with master audio disabled,
does not crash.
"""
cfg = sine440_config()
cfg.master_audio = None
ovgen = Ovgen(cfg, Arguments('.', [NULL_OUTPUT]))
corr = CorrScope(cfg, Arguments('.', [NULL_OUTPUT]))
# Should not raise exception.
ovgen.play()
corr.play()
def test_render_subfps_one():
""" Ensure video gets rendered when render_subfps=1.
This test fails if ceildiv is used to calculate `ahead`.
"""
from ovgenpy.outputs import IOutputConfig, Output, register_output
from corrscope.outputs import IOutputConfig, Output, register_output
# region DummyOutput
class DummyOutputConfig(IOutputConfig):
@ -153,12 +153,12 @@ def test_render_subfps_one():
assert DummyOutput
# endregion
# Create Ovgen with render_subfps=1. Ensure multiple frames are outputted.
# Create CorrScope with render_subfps=1. Ensure multiple frames are outputted.
cfg = sine440_config()
cfg.render_subfps = 1
ovgen = Ovgen(cfg, Arguments('.', [DummyOutputConfig()]))
ovgen.play()
corr = CorrScope(cfg, Arguments('.', [DummyOutputConfig()]))
corr.play()
assert DummyOutput.frames_written >= 2
@ -177,17 +177,17 @@ def test_render_subfps_non_integer(mocker: 'pytest_mock.MockFixture'):
assert cfg.render_fps != int(cfg.render_fps)
assert Fraction(1) == int(1)
ovgen = Ovgen(cfg, Arguments('.', [NULL_OUTPUT]))
ovgen.play()
corr = CorrScope(cfg, Arguments('.', [NULL_OUTPUT]))
corr.play()
# But it seems FFmpeg actually allows decimal -framerate (although a bad idea).
# from ovgenpy.ovgenpy import Config
# from corrscope.corrscope import Config
# render_fps = mocker.patch.object(Config, 'render_fps',
# new_callable=mocker.PropertyMock)
# render_fps.return_value = 60 / 7
# assert isinstance(cfg.render_fps, float)
# ovgen = Ovgen(cfg, '.', outputs=[NULL_OUTPUT])
# ovgen.play()
# corr = CorrScope(cfg, '.', outputs=[NULL_OUTPUT])
# corr.play()
# Possibility: add a test to ensure that we render slightly ahead in time

Wyświetl plik

@ -2,10 +2,10 @@ import numpy as np
import pytest
from matplotlib.colors import to_rgb
from ovgenpy.channel import ChannelConfig
from ovgenpy.outputs import RGB_DEPTH
from ovgenpy.renderer import RendererConfig, MatplotlibRenderer
from ovgenpy.layout import LayoutConfig
from corrscope.channel import ChannelConfig
from corrscope.outputs import RGB_DEPTH
from corrscope.renderer import RendererConfig, MatplotlibRenderer
from corrscope.layout import LayoutConfig
WIDTH = 640
HEIGHT = 360

Wyświetl plik

@ -4,10 +4,10 @@ import pytest
from matplotlib.axes import Axes
from matplotlib.figure import Figure
from ovgenpy import triggers
from ovgenpy.triggers import CorrelationTriggerConfig, CorrelationTrigger, \
from corrscope import triggers
from corrscope.triggers import CorrelationTriggerConfig, CorrelationTrigger, \
PerFrameCache, ZeroCrossingTriggerConfig, LocalPostTriggerConfig
from ovgenpy.wave import Wave
from corrscope.wave import Wave
triggers.SHOW_TRIGGER = False
@ -179,7 +179,7 @@ def test_trigger_should_recalc_window():
# Test the ability to load legacy TriggerConfig
def test_load_trigger_config():
from ovgenpy.config import yaml
from corrscope.config import yaml
# Ensure no exceptions
yaml.load('''\

Wyświetl plik

@ -4,7 +4,7 @@ import numpy as np
import pytest
from delayed_assert import expect, assert_expectations
from ovgenpy.wave import Wave
from corrscope.wave import Wave
prefix = 'tests/wav-formats/'
wave_paths = [

Wyświetl plik

@ -2,7 +2,7 @@ import pytest
import numpy as np
from numpy.testing import assert_equal
from ovgenpy.utils.windows import leftpad, midpad
from corrscope.utils.windows import leftpad, midpad
def test_leftpad():