diff --git a/README.md b/README.md index 5073a27..ab7568c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +![banner](banner.png) + Charidotella (https://en.wikipedia.org/wiki/Charidotella_sexpunctata) is a toolbox to organise and visualise Event Stream (.es) recordings. It supports Python 3.9, 3.10, and 3.11. diff --git a/banner.png b/banner.png new file mode 100644 index 0000000..ed0c7aa Binary files /dev/null and b/banner.png differ diff --git a/charidotella/__init__.py b/charidotella/__init__.py index 12355a9..2730859 100644 --- a/charidotella/__init__.py +++ b/charidotella/__init__.py @@ -53,6 +53,11 @@ TASKS: dict[str, tuple[str, task_run]] = { "colourtime": (tasks.colourtime.EXTENSION, tasks.colourtime.run), "event_rate": (tasks.event_rate.EXTENSION, tasks.event_rate.run), + "spatiospectrogram": ( + tasks.spatiospectrogram.EXTENSION, + tasks.spatiospectrogram.run, + ), + "spectrogram": (tasks.spectrogram.EXTENSION, tasks.spectrogram.run), "video": (tasks.video.EXTENSION, tasks.video.run), "wiggle": (tasks.wiggle.EXTENSION, tasks.wiggle.run), } @@ -90,6 +95,12 @@ def main(): action="store_true", help="Do not generate new names for the recordings", ) + init_parser.add_argument( + "--spatiospectrograms", + "-s", + action="store_true", + help="Generate spatio-spectrogram tasks", + ) run_parser = subparsers.add_parser("run", help="Process a configuration file") run_parser.add_argument( "--configuration", @@ -381,9 +392,11 @@ def run_generators(configuration: dict[str, typing.Any]): "tasks": [ "colourtime-.+", "event-rate-.+", + "spectrogram", "wiggle-.+", "video-real-time", - ], + ] + + (["spatiospectrogram"] if args.spatiospectrograms else []), } ) with open( @@ -471,9 +484,63 @@ def run_generators(configuration: dict[str, typing.Any]): ) configuration_file.write("\n\n# tasks configuration\n\n") + tasks = { + "spectrogram": { + "type": "spectrogram", + "icon": "🎻", + "tau": utilities.timestamp_to_timecode(100000), + "mode": "all", + "maximum": 10000.0, + "frequencies": 100, + "times": 1000, + "gamma": 0.5, + }, + "video-real-time": { + "type": "video", + "icon": "🎬", + "frametime": utilities.timestamp_to_timecode(20000), + "tau": utilities.timestamp_to_timecode(200000), + "style": "exponential", + "on_color": "#F4C20D", + "off_color": "#1E88E5", + "idle_color": "#191919", + "cumulative_ratio": 0.01, + "timecode": True, + "h264_crf": 15, + "ffmpeg": "ffmpeg", + "scale": 1, + }, + } toml.dump( { "tasks": { + "spatiospectrogram": { + "type": "spatiospectrogram", + "icon": "🎸", + "frametime": utilities.timestamp_to_timecode(20000), + "scale": 1, + "tau": utilities.timestamp_to_timecode(100000), + "mode": "all", + "minimum": 10.0, + "maximum": 10000.0, + "frequencies": 100, + "frequency-gamma": 0.5, + "amplitude-gamma": 0.5, + "discard": 0.001, + "timecode": True, + "h264_crf": 15, + "ffmpeg": "ffmpeg", + }, + "spectrogram": { + "type": "spectrogram", + "icon": "🎻", + "tau": utilities.timestamp_to_timecode(100000), + "mode": "all", + "maximum": 10000.0, + "frequencies": 100, + "times": 1000, + "gamma": 0.5, + }, "video-real-time": { "type": "video", "icon": "🎬", @@ -488,7 +555,22 @@ def run_generators(configuration: dict[str, typing.Any]): "h264_crf": 15, "ffmpeg": "ffmpeg", "scale": 1, - } + }, + "video-slow-motion": { + "type": "video", + "icon": "🎬", + "frametime": utilities.timestamp_to_timecode(2000), + "tau": utilities.timestamp_to_timecode(20000), + "style": "exponential", + "on_color": "#F4C20D", + "off_color": "#1E88E5", + "idle_color": "#191919", + "cumulative_ratio": 0.01, + "timecode": True, + "h264_crf": 15, + "ffmpeg": "ffmpeg", + "scale": 1, + }, }, }, configuration_file, @@ -539,8 +621,8 @@ def run_generators(configuration: dict[str, typing.Any]): "axis_color": "#000000", "main_grid_color": "#555555", "secondary_grid_color": "#DDDDDD", - "width": 1920, - "height": 1080, + "width": 1280, + "height": 720, }, }, { @@ -556,7 +638,7 @@ def run_generators(configuration: dict[str, typing.Any]): "template": { "name": "wiggle-@suffix", "type": "wiggle", - "icon": "🌀", + "icon": "👋", "forward_duration": "@raw(forward_duration)", "tau_to_frametime_ratio": 3.0, "style": "cumulative", @@ -616,9 +698,15 @@ def run_generators(configuration: dict[str, typing.Any]): "tasks": [ "colourtime-.+", "event-rate-.+", + "spectrogram", "wiggle-.+", "video-real-time", - ], + ] + + ( + ["spatiospectrogram"] + if args.spatiospectrograms + else [] + ), }, } ] diff --git a/charidotella/setup.py b/charidotella/setup.py deleted file mode 100644 index e69de29..0000000 diff --git a/charidotella/tasks/__init__.py b/charidotella/tasks/__init__.py index 20bf628..60d1930 100644 --- a/charidotella/tasks/__init__.py +++ b/charidotella/tasks/__init__.py @@ -1,4 +1,6 @@ from . import colourtime as colourtime from . import event_rate as event_rate +from . import spatiospectrogram as spatiospectrogram +from . import spectrogram as spectrogram from . import video as video from . import wiggle as wiggle diff --git a/charidotella/tasks/spatiospectrogram.py b/charidotella/tasks/spatiospectrogram.py new file mode 100644 index 0000000..1583c8f --- /dev/null +++ b/charidotella/tasks/spatiospectrogram.py @@ -0,0 +1,107 @@ +import atexit +import importlib.resources +import pathlib +import subprocess +import typing + +EXTENSION = ".mp4" + + +def run( + input: pathlib.Path, + output: pathlib.Path, + begin: int, + end: int, + parameters: dict[str, typing.Any], +): + width, height = ( + int(value) + for value in subprocess.run( + [ + str(importlib.resources.files("charidotella").joinpath("assets/size")), + str(input), + ], + check=True, + capture_output=True, + ).stdout.split(b"x") + ) + width *= parameters["scale"] + height *= parameters["scale"] + spatiospectrogram_arguments = [ + str( + importlib.resources.files("charidotella").joinpath( + "assets/spatiospectrogram" + ) + ), + f"--input={input}", + f"--begin={begin}", + f"--end={end}", + f"--frametime={parameters['frametime']}", + f"--scale={parameters['scale']}", + f"--tau={parameters['tau']}", + f"--mode={parameters['mode']}", + f"--minimum={parameters['minimum']}", + f"--maximum={parameters['maximum']}", + f"--frequencies={parameters['frequencies']}", + f"--frequency-gamma={parameters['frequency-gamma']}", + f"--amplitude-gamma={parameters['amplitude-gamma']}", + f"--discard={parameters['discard']}", + ] + if parameters["timecode"]: + spatiospectrogram_arguments.append("--add-timecode") + spatiospectrogram = subprocess.Popen( + spatiospectrogram_arguments, + stdout=subprocess.PIPE, + ) + assert spatiospectrogram.stdout is not None + ffmpeg = subprocess.Popen( + [ + parameters["ffmpeg"], + "-hide_banner", + "-loglevel", + "warning", + "-stats", + "-f", + "rawvideo", + "-s", + f"{width}x{height}", + "-framerate", + "50", + "-pix_fmt", + "rgb24", + "-i", + "-", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-crf", + str(parameters["h264_crf"]), + "-f", + "mp4", + "-y", + str(output), + ], + stdin=subprocess.PIPE, + ) + assert ffmpeg.stdin is not None + frame_size = width * height * 3 + + def cleanup(): + if es_to_frames is not None: + es_to_frames.kill() + if ffmpeg is not None: + ffmpeg.kill() + + atexit.register(cleanup) + while True: + frame = spatiospectrogram.stdout.read(frame_size) + if len(frame) != frame_size: + break + ffmpeg.stdin.write(frame) + ffmpeg.stdin.close() + spatiospectrogram.wait() + es_to_frames = None + ffmpeg.wait() + ffmpeg = None + atexit.unregister(cleanup) diff --git a/charidotella/tasks/spectrogram.py b/charidotella/tasks/spectrogram.py new file mode 100644 index 0000000..600e209 --- /dev/null +++ b/charidotella/tasks/spectrogram.py @@ -0,0 +1,40 @@ +import importlib.resources +import pathlib +import subprocess +import typing + +EXTENSION = ".png" + + +def run( + input: pathlib.Path, + output: pathlib.Path, + begin: int, + end: int, + parameters: dict[str, typing.Any], +): + arguments = [ + str(importlib.resources.files("charidotella").joinpath("assets/spectrogram")), + str(input), + str(output), + str(output.with_suffix(".json")), + f"--begin={begin}", + f"--end={end}", + f"--tau={parameters['tau']}", + f"--mode={parameters['mode']}", + f"--maximum={parameters['maximum']}", + f"--frequencies={parameters['frequencies']}", + f"--times={parameters['times']}", + f"--gamma={parameters['gamma']}", + ] + if "minimum" in parameters: + arguments.append(f"--minimum={parameters['minimum']}") + if "region-of-interest" in parameters: + arguments.append(f"--left={parameters['region-of-interest'][0]}") + arguments.append(f"--bottom={parameters['region-of-interest'][1]}") + arguments.append(f"--width={parameters['region-of-interest'][2]}") + arguments.append(f"--height={parameters['region-of-interest'][3]}") + subprocess.run( + arguments, + check=True, + ) diff --git a/charidotella/version.py b/charidotella/version.py index 91bf823..4802e90 100644 --- a/charidotella/version.py +++ b/charidotella/version.py @@ -1 +1 @@ -__version__ = "0.10" +__version__ = "1.0" diff --git a/command_line_tools b/command_line_tools index 30c06b4..cc9e13a 160000 --- a/command_line_tools +++ b/command_line_tools @@ -1 +1 @@ -Subproject commit 30c06b4da1854500788dffd680efa5e702a220cb +Subproject commit cc9e13a26d33520fbdc943ff5442c8b719176045 diff --git a/configuration-schema.json b/configuration-schema.json index b7ce65f..f1f3af4 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -1,37 +1,55 @@ { - "type": "object", + "additionalProperties": false, "properties": { + "attachments": { + "additionalProperties": { + "items": { + "properties": { + "source": { + "type": "string" + }, + "target": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "object" + }, "directory": { "type": "string" }, "filters": { - "type": "object", "additionalProperties": { "anyOf": [ { - "type": "object", + "additionalProperties": false, "properties": { - "type": { - "type": "string", - "enum": ["default"] - }, "icon": { "type": "string" }, "suffix": { "type": "string" + }, + "type": { + "enum": [ + "default" + ], + "type": "string" } }, - "additionalProperties": false, - "required": ["type", "icon", "suffix"] + "required": [ + "type", + "icon", + "suffix" + ], + "type": "object" }, { - "type": "object", + "additionalProperties": false, "properties": { - "type": { - "type": "string", - "enum": ["arbiter_saturation"] - }, "icon": { "type": "string" }, @@ -39,49 +57,58 @@ "type": "string" }, "threshold": { - "type": "integer", - "exclusiveMinimum": 0 + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "enum": [ + "arbiter_saturation" + ], + "type": "string" } }, - "additionalProperties": false, - "required": ["type", "icon", "suffix", "threshold"] + "required": [ + "type", + "icon", + "suffix", + "threshold" + ], + "type": "object" }, { - "type": "object", + "additionalProperties": false, "properties": { - "type": { - "type": "string", - "enum": ["hot_pixels"] - }, "icon": { "type": "string" }, + "ratio": { + "minimum": 0, + "type": "number" + }, "suffix": { "type": "string" }, - "ratio": { - "type": "number", - "minimum": 0.0 + "type": { + "enum": [ + "hot_pixels" + ], + "type": "string" } }, - "additionalProperties": false, - "required": ["type", "icon", "suffix", "ratio"] + "required": [ + "type", + "icon", + "suffix", + "ratio" + ], + "type": "object" }, { - "type": "object", "properties": { - "type": { - "type": "string", - "enum": ["transpose"] - }, "icon": { "type": "string" }, - "suffix": { - "type": "string" - }, "method": { - "type": "string", "enum": [ "flip_left_right", "flip_top_bottom", @@ -90,77 +117,168 @@ "rotate_270", "transpose", "transverse" - ] + ], + "type": "string" + }, + "suffix": { + "type": "string" + }, + "type": { + "enum": [ + "transpose" + ], + "type": "string" } - } + }, + "type": "object" } ] - } + }, + "type": "object" }, "filters-generators": { - "type": "array", "items": { - "type": "object", + "additionalProperties": false, "properties": { "parameters": { - "type": "object", "additionalProperties": { "type": "array" - } + }, + "type": "object" }, "template": { - "type": "object", "properties": { "name": { "type": "string" } }, - "required": ["name"] + "required": [ + "name" + ], + "type": "object" } }, - "required": ["parameters", "template"], - "additionalProperties": false - } + "required": [ + "parameters", + "template" + ], + "type": "object" + }, + "type": "array" + }, + "jobs": { + "items": { + "additionalProperties": false, + "properties": { + "begin": { + "type": [ + "string", + "integer" + ] + }, + "end": { + "type": [ + "string", + "integer" + ] + }, + "filters": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "name": { + "type": "string" + }, + "tasks": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "name", + "begin", + "end", + "filters" + ], + "type": "object" + }, + "type": "array" + }, + "jobs-generators": { + "items": { + "additionalProperties": false, + "properties": { + "parameters": { + "additionalProperties": { + "type": "array" + }, + "type": "object" + }, + "template": { + "type": "object" + } + }, + "required": [ + "parameters", + "template" + ], + "type": "object" + }, + "type": "array" + }, + "sources": { + "additionalProperties": { + "type": "string" + }, + "type": "object" }, "tasks": { - "type": "object", "additionalProperties": { "anyOf": [ { - "type": "object", + "additionalProperties": false, "properties": { - "type": { - "type": "string", - "enum": ["colourtime"] + "alpha": { + "exclusiveMinimum": 0, + "maximum": 1, + "type": "number" }, - "icon": { + "background_color": { "type": "string" }, "colormap": { "type": "string" }, - "alpha": { - "type": "number", - "exclusiveMinimum": 0.0, - "maximum": 1.0 + "cycle": { + "type": [ + "string", + "integer" + ] + }, + "icon": { + "type": "string" }, "png_compression_level": { - "type": "integer", + "maximum": 9, "minimum": 0, - "maximum": 9 - }, - "background_color": { - "type": "string" + "type": "integer" }, "scale": { - "type": "integer", - "exclusiveMinimum": 0 + "exclusiveMinimum": 0, + "type": "integer" }, - "cycle": { - "type": ["string", "integer"] + "type": { + "enum": [ + "colourtime" + ], + "type": "string" } }, - "additionalProperties": false, "required": [ "type", "icon", @@ -169,49 +287,57 @@ "png_compression_level", "background_color", "scale" - ] + ], + "type": "object" }, { - "type": "object", + "additionalProperties": false, "properties": { - "type": { - "type": "string", - "enum": ["event_rate"] + "axis_color": { + "type": "string" + }, + "height": { + "exclusiveMinimum": 0, + "type": "integer" }, "icon": { "type": "string" }, "long_tau": { - "type": ["string", "integer"] - }, - "short_tau": { - "type": ["string", "integer"] + "type": [ + "string", + "integer" + ] }, "long_tau_color": { "type": "string" }, - "short_tau_color": { + "main_grid_color": { "type": "string" }, - "axis_color": { + "secondary_grid_color": { "type": "string" }, - "main_grid_color": { + "short_tau": { + "type": [ + "string", + "integer" + ] + }, + "short_tau_color": { "type": "string" }, - "secondary_grid_color": { + "type": { + "enum": [ + "event_rate" + ], "type": "string" }, "width": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "height": { - "type": "integer", - "exclusiveMinimum": 0 + "exclusiveMinimum": 0, + "type": "integer" } }, - "additionalProperties": false, "required": [ "type", "icon", @@ -224,69 +350,77 @@ "secondary_grid_color", "width", "height" - ] + ], + "type": "object" }, { - "type": "object", + "additionalProperties": false, "properties": { - "type": { - "type": "string", - "enum": ["video"] + "cumulative_ratio": { + "maximum": 1, + "minimum": 0, + "type": "number" }, - "icon": { + "ffmpeg": { "type": "string" }, "frametime": { - "type": ["string", "integer"] + "type": [ + "string", + "integer" + ] }, - "tau": { - "type": ["string", "integer"] + "h264_crf": { + "maximum": 51, + "minimum": 0, + "type": "integer" + }, + "icon": { + "type": "string" + }, + "idle_color": { + "type": "string" + }, + "lambda_max": { + "minimum": 0, + "type": "number" + }, + "off_color": { + "type": "string" + }, + "on_color": { + "type": "string" + }, + "scale": { + "exclusiveMinimum": 0, + "type": "integer" }, "style": { - "type": "string", "enum": [ "exponential", "linear", "window", "cumulative", "cumulative-shared" - ] - }, - "on_color": { - "type": "string" - }, - "off_color": { + ], "type": "string" }, - "idle_color": { - "type": "string" - }, - "cumulative_ratio": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0 + "tau": { + "type": [ + "string", + "integer" + ] }, "timecode": { "type": "boolean" }, - "h264_crf": { - "type": "integer", - "minimum": 0, - "maximum": 51 - }, - "ffmpeg": { + "type": { + "enum": [ + "video" + ], "type": "string" - }, - "scale": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "lambda_max": { - "type": "number", - "minimum": 0.0 } }, - "additionalProperties": false, "required": [ "type", "icon", @@ -301,65 +435,230 @@ "h264_crf", "scale", "ffmpeg" - ] + ], + "type": "object" }, { - "type": "object", + "additionalProperties": false, "properties": { - "type": { - "type": "string", - "enum": ["wiggle"] + "frequencies": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "gamma": { + "exclusiveMinimum": 0, + "type": "number" }, "icon": { "type": "string" }, - "forward_duration": { - "type": ["string", "integer"] + "maximum": { + "exclusiveMinimum": 0, + "type": "number" }, - "tau_to_frametime_ratio": { - "type": "number", - "exclusiveMinimum": 0.0 + "minimum": { + "exclusiveMinimum": 0, + "type": "number" }, - "style": { - "type": "string", + "mode": { "enum": [ - "exponential", - "linear", - "window", - "cumulative", - "cumulative-shared" + "on", + "off", + "all", + "abs" + ], + "type": "string" + }, + "region-of-interest": { + "items": { + "minimum": 0, + "type": "integer" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "tau": { + "type": [ + "string", + "integer" ] }, - "on_color": { + "times": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "enum": [ + "spectrogram" + ], "type": "string" + } + }, + "required": [ + "type", + "icon", + "tau", + "mode", + "maximum", + "frequencies", + "times", + "gamma" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "amplitude-gamma": { + "exclusiveMinimum": 0, + "type": "number" }, - "off_color": { + "discard": { + "exclusiveMaximum": 1, + "minimum": 0, + "type": "number" + }, + "ffmpeg": { "type": "string" }, - "idle_color": { + "frametime": { + "type": [ + "string", + "integer" + ] + }, + "frequencies": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "frequency-gamma": { + "exclusiveMinimum": 0, + "type": "number" + }, + "h264_crf": { + "maximum": 51, + "minimum": 0, + "type": "integer" + }, + "icon": { "type": "string" }, - "cumulative_ratio": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0 + "maximum": { + "exclusiveMinimum": 0, + "type": "number" + }, + "minimum": { + "exclusiveMinimum": 0, + "type": "number" + }, + "mode": { + "enum": [ + "on", + "off", + "all", + "abs" + ], + "type": "string" + }, + "scale": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "tau": { + "type": [ + "string", + "integer" + ] }, "timecode": { "type": "boolean" }, + "type": { + "enum": [ + "spatiospectrogram" + ], + "type": "string" + } + }, + "required": [ + "type", + "icon", + "frametime", + "scale", + "tau", + "mode", + "minimum", + "maximum", + "frequencies", + "frequency-gamma", + "amplitude-gamma", + "discard", + "timecode" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "cumulative_ratio": { + "maximum": 1, + "minimum": 0, + "type": "number" + }, "ffmpeg": { "type": "string" }, - "scale": { - "type": "integer", - "exclusiveMinimum": 0 + "forward_duration": { + "type": [ + "string", + "integer" + ] + }, + "icon": { + "type": "string" + }, + "idle_color": { + "type": "string" }, "lambda_max": { - "type": "number", - "minimum": 0.0 + "minimum": 0, + "type": "number" + }, + "off_color": { + "type": "string" + }, + "on_color": { + "type": "string" + }, + "scale": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "style": { + "enum": [ + "exponential", + "linear", + "window", + "cumulative", + "cumulative-shared" + ], + "type": "string" + }, + "tau_to_frametime_ratio": { + "exclusiveMinimum": 0, + "type": "number" + }, + "timecode": { + "type": "boolean" + }, + "type": { + "enum": [ + "wiggle" + ], + "type": "string" } }, - "additionalProperties": false, "required": [ "type", "icon", @@ -372,109 +671,47 @@ "cumulative_ratio", "ffmpeg", "scale" - ] + ], + "type": "object" } ] - } + }, + "type": "object" }, "tasks-generators": { - "type": "array", "items": { - "type": "object", + "additionalProperties": false, "properties": { "parameters": { - "type": "object", "additionalProperties": { "type": "array" - } + }, + "type": "object" }, "template": { - "type": "object", "properties": { "name": { "type": "string" } }, - "required": ["name"] - } - }, - "required": ["parameters", "template"], - "additionalProperties": false - } - }, - "jobs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "begin": { - "type": ["string", "integer"] - }, - "end": { - "type": ["string", "integer"] - }, - "filters": { - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1 - }, - "tasks": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": ["name", "begin", "end", "filters"], - "additionalProperties": false - } - }, - "jobs-generators": { - "type": "array", - "items": { - "type": "object", - "properties": { - "parameters": { - "type": "object", - "additionalProperties": { - "type": "array" - } - }, - "template": { + "required": [ + "name" + ], "type": "object" } }, - "required": ["parameters", "template"], - "additionalProperties": false - } - }, - "sources": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "attachments": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "object", - "properties": { - "source": { - "type": "string" - }, - "target": { - "type": "string" - } - } - } - } + "required": [ + "parameters", + "template" + ], + "type": "object" + }, + "type": "array" } }, - "required": ["directory", "sources"], - "additionalProperties": false -} + "required": [ + "directory", + "sources" + ], + "type": "object" +} \ No newline at end of file diff --git a/setup.py b/setup.py index 8ed6aa2..3d346f3 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ with open(dirname / "README.md") as file: long_description = file.read() -executables = ["es_to_frames", "event_rate", "size"] +executables = ["es_to_frames", "event_rate", "size", "spatiospectrogram", "spectrogram"] if not "-h" in sys.argv and not "--help" in sys.argv: manifest_lines = [