framerudiments 0.1.4__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {framerudiments-0.1.4 → framerudiments-0.3.0}/MANIFEST.in +2 -0
- {framerudiments-0.1.4/src/framerudiments.egg-info → framerudiments-0.3.0}/PKG-INFO +36 -1
- {framerudiments-0.1.4 → framerudiments-0.3.0}/README.md +35 -0
- framerudiments-0.3.0/docs/beat-alignment.md +56 -0
- framerudiments-0.3.0/docs/media/beat-alignment-evidence.json +173 -0
- framerudiments-0.3.0/docs/media/beat-alignment.mp4 +0 -0
- framerudiments-0.3.0/docs/media/beat-alignment.png +0 -0
- framerudiments-0.3.0/docs/media/preset-test-cards.png +0 -0
- framerudiments-0.3.0/docs/media/test-card-inputs/colour-bars.png +0 -0
- framerudiments-0.3.0/docs/media/test-card-inputs/grid-rings.png +0 -0
- framerudiments-0.3.0/docs/media/test-card-inputs/text-card.png +0 -0
- framerudiments-0.3.0/docs/preset-profiling.md +200 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/docs/project-format.md +8 -1
- {framerudiments-0.1.4 → framerudiments-0.3.0}/docs/visualisers.md +12 -0
- framerudiments-0.3.0/integration/test_preset_analysis.py +42 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/integration/test_visualisers_gpu.py +16 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/pyproject.toml +1 -1
- framerudiments-0.3.0/scripts/profile_visualisers.py +10 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/__init__.py +1 -1
- framerudiments-0.3.0/src/framerudiments/beat_alignment.py +57 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/cli.py +31 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/io.py +11 -2
- framerudiments-0.3.0/src/framerudiments/preset_library.py +132 -0
- framerudiments-0.3.0/src/framerudiments/preset_profiling.py +296 -0
- framerudiments-0.3.0/src/framerudiments/profile_analysis.py +212 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/project.py +21 -4
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/projectm_backend.py +18 -2
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualiser_assets/butterchurn-page.js +16 -1
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualiser_assets/butterchurn-worker.mjs +16 -2
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualisers.py +12 -4
- {framerudiments-0.1.4 → framerudiments-0.3.0/src/framerudiments.egg-info}/PKG-INFO +36 -1
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments.egg-info/SOURCES.txt +17 -0
- framerudiments-0.3.0/tests/test_beat_alignment.py +144 -0
- framerudiments-0.3.0/tests/test_preset_profiling.py +123 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/AGENTS.md +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/LICENSE +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/docs/extraction.md +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/docs/media/demo-transcript.md +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/docs/media/effects-pipeline.svg +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/docs/media/full-frame-comparison.png +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/docs/media/full-frame-demo.mp4 +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/docs/media/media-evidence.json +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/docs/rudiment-renderers.md +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/docs/spectrum.md +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/docs/workflow-media.md +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/setup.cfg +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/__main__.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/atlas.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/choreography.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/compositor.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/demo.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/effects.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/encoding.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/flight.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/motion.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/render.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/rudiment_renderers.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/spectrum.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/stemlab.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/subtitles.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/timeline.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualiser_assets/feedback.json +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualiser_assets/feedback.milk +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualiser_assets/julia.json +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualiser_assets/julia.milk +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualiser_assets/kaleidoscope.json +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualiser_assets/kaleidoscope.milk +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualiser_assets/package-lock.json +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualiser_assets/package.json +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments/visualiser_setup.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments.egg-info/dependency_links.txt +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments.egg-info/entry_points.txt +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments.egg-info/requires.txt +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/src/framerudiments.egg-info/top_level.txt +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/tests/test_adapters.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/tests/test_extracted_helpers.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/tests/test_flight.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/tests/test_lyrics.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/tests/test_pipeline.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/tests/test_rudiment_renderers.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/tests/test_spectrum.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/tests/test_timeline.py +0 -0
- {framerudiments-0.1.4 → framerudiments-0.3.0}/tests/test_visualisers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: framerudiments
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Deterministic Shorts and lyric visualisers using DanceRudiments and StemLab evidence.
|
|
5
5
|
Author: Kieran Simkin
|
|
6
6
|
License-Expression: MIT
|
|
@@ -29,6 +29,19 @@ FrameRudiments renders Shorts, Canvas-style clips and full lyric visualisers
|
|
|
29
29
|
from one traceable timeline. It is the offline Python renderer in the
|
|
30
30
|
[DanceFlow ecosystem](https://kieransimkin.co.uk/danceflow/).
|
|
31
31
|
|
|
32
|
+
**0.2.0** accepts source-bound StemLab BPM/first-beat readings through
|
|
33
|
+
`clock.beat_alignment`. Procedural motion follows the fractional beat phase
|
|
34
|
+
after excerpt/repeat mapping. Audio, lyric/cue timestamps and captured
|
|
35
|
+
recordings retain their original source clock. See [beat alignment](docs/beat-alignment.md).
|
|
36
|
+
|
|
37
|
+

|
|
38
|
+
|
|
39
|
+
[Play the four-second demonstration](docs/media/beat-alignment.mp4): original
|
|
40
|
+
120 BPM clicks start at 0.125 seconds; the right movement uses the -16 pip
|
|
41
|
+
reading. Text and recorded bands keep source time. This synthetic example
|
|
42
|
+
demonstrates clock composition; it does not establish song-analysis accuracy.
|
|
43
|
+
[Encoded-frame verification and hashes](docs/media/beat-alignment-evidence.json).
|
|
44
|
+
|
|
32
45
|
It consolidates the shared Python/Pillow/FFmpeg mechanisms developed across
|
|
33
46
|
the existing Gilt Trip, Blame Putin, Clay, Paper Dreams, Free Danny Tommo,
|
|
34
47
|
Silly Sausage Britain and Moderate or Good renderers. Release-specific artwork,
|
|
@@ -229,3 +242,25 @@ Playback is user-controlled; no automatic media playback is required.
|
|
|
229
242
|
|
|
230
243
|
Generated vector illustration of the processing order. The comparison above
|
|
231
244
|
and linked video are captured renderer output; the diagram is explanatory.
|
|
245
|
+
|
|
246
|
+
## Explore and profile the preset library
|
|
247
|
+
|
|
248
|
+
Version 0.3.0 adds a separately installed, checksum-pinned library of **14,680
|
|
249
|
+
distinct upstream presets** (1,738 Butterchurn and 12,942 projectM), with source
|
|
250
|
+
notices, duplicate aliases and 67 shared textures. Real-engine acceptance is
|
|
251
|
+
recorded per preset; available catalogue entries are not claimed as tested.
|
|
252
|
+
|
|
253
|
+
Use `framerudiments presets-install`, then `framerudiments presets-profile` or
|
|
254
|
+
`scripts/profile_visualisers.py` to feed ordinary cover/lyric/audio projects and
|
|
255
|
+
three static calibration cards through each engine, replay every feedback frame,
|
|
256
|
+
capture chosen intervals and invoke released PrismMoves/PixelCue. Reports keep
|
|
257
|
+
input/output, temporal, tune/silence and same-card/different-tune comparisons
|
|
258
|
+
separate, with measured response ranges and explicit unknowns.
|
|
259
|
+
|
|
260
|
+

|
|
261
|
+
|
|
262
|
+
Generated calibration illustrations; not preset-output evidence. The maintained
|
|
263
|
+
My Songs suite uses Arcadians and The Truth is a Virus with their canonical
|
|
264
|
+
masters, covers and timed lyrics; those private assets are not bundled.
|
|
265
|
+
See [the complete capture, analysis and synthesis workflow](https://github.com/kieransimkin/FrameRudiments/blob/v0.3.0/docs/preset-profiling.md)
|
|
266
|
+
for pinned packs, licences, runtime setup, resume and interpretation limits.
|
|
@@ -4,6 +4,19 @@ FrameRudiments renders Shorts, Canvas-style clips and full lyric visualisers
|
|
|
4
4
|
from one traceable timeline. It is the offline Python renderer in the
|
|
5
5
|
[DanceFlow ecosystem](https://kieransimkin.co.uk/danceflow/).
|
|
6
6
|
|
|
7
|
+
**0.2.0** accepts source-bound StemLab BPM/first-beat readings through
|
|
8
|
+
`clock.beat_alignment`. Procedural motion follows the fractional beat phase
|
|
9
|
+
after excerpt/repeat mapping. Audio, lyric/cue timestamps and captured
|
|
10
|
+
recordings retain their original source clock. See [beat alignment](docs/beat-alignment.md).
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
[Play the four-second demonstration](docs/media/beat-alignment.mp4): original
|
|
15
|
+
120 BPM clicks start at 0.125 seconds; the right movement uses the -16 pip
|
|
16
|
+
reading. Text and recorded bands keep source time. This synthetic example
|
|
17
|
+
demonstrates clock composition; it does not establish song-analysis accuracy.
|
|
18
|
+
[Encoded-frame verification and hashes](docs/media/beat-alignment-evidence.json).
|
|
19
|
+
|
|
7
20
|
It consolidates the shared Python/Pillow/FFmpeg mechanisms developed across
|
|
8
21
|
the existing Gilt Trip, Blame Putin, Clay, Paper Dreams, Free Danny Tommo,
|
|
9
22
|
Silly Sausage Britain and Moderate or Good renderers. Release-specific artwork,
|
|
@@ -204,3 +217,25 @@ Playback is user-controlled; no automatic media playback is required.
|
|
|
204
217
|
|
|
205
218
|
Generated vector illustration of the processing order. The comparison above
|
|
206
219
|
and linked video are captured renderer output; the diagram is explanatory.
|
|
220
|
+
|
|
221
|
+
## Explore and profile the preset library
|
|
222
|
+
|
|
223
|
+
Version 0.3.0 adds a separately installed, checksum-pinned library of **14,680
|
|
224
|
+
distinct upstream presets** (1,738 Butterchurn and 12,942 projectM), with source
|
|
225
|
+
notices, duplicate aliases and 67 shared textures. Real-engine acceptance is
|
|
226
|
+
recorded per preset; available catalogue entries are not claimed as tested.
|
|
227
|
+
|
|
228
|
+
Use `framerudiments presets-install`, then `framerudiments presets-profile` or
|
|
229
|
+
`scripts/profile_visualisers.py` to feed ordinary cover/lyric/audio projects and
|
|
230
|
+
three static calibration cards through each engine, replay every feedback frame,
|
|
231
|
+
capture chosen intervals and invoke released PrismMoves/PixelCue. Reports keep
|
|
232
|
+
input/output, temporal, tune/silence and same-card/different-tune comparisons
|
|
233
|
+
separate, with measured response ranges and explicit unknowns.
|
|
234
|
+
|
|
235
|
+

|
|
236
|
+
|
|
237
|
+
Generated calibration illustrations; not preset-output evidence. The maintained
|
|
238
|
+
My Songs suite uses Arcadians and The Truth is a Virus with their canonical
|
|
239
|
+
masters, covers and timed lyrics; those private assets are not bundled.
|
|
240
|
+
See [the complete capture, analysis and synthesis workflow](https://github.com/kieransimkin/FrameRudiments/blob/v0.3.0/docs/preset-profiling.md)
|
|
241
|
+
for pinned packs, licences, runtime setup, resume and interpretation limits.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Beat alignment from saved StemLab evidence
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
[Play the four-second example](media/beat-alignment.mp4). Original synthetic
|
|
6
|
+
120 BPM clicks begin at 0.125 seconds. The left native bounce shows the original
|
|
7
|
+
grid; the right follows the -16 pip reading. The bands retain their recording
|
|
8
|
+
clock. Text changes at the original LRC times: “Signals into motion” at 0,
|
|
9
|
+
“Words into light” at 1.25, “Keep the clock in sight” at 2.50, then clears at
|
|
10
|
+
3.75 seconds. The synthetic text is a caption fixture, not sung lyrics.
|
|
11
|
+
[Encoded verification, source identity and hashes](media/beat-alignment-evidence.json).
|
|
12
|
+
|
|
13
|
+
Generate a source-bound reading from saved StemLab evidence, reviewing canonical,
|
|
14
|
+
combined, fitted and half/double-time interpretations and individual detectors:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
stemlab beat-offset RESULTS --output NEW --audio EXACT-MASTER.wav \
|
|
18
|
+
--alignment-analysis consensus --alignment-bpm-basis combined_fit
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Use `canonical` only when canonical BPM has an established authority. Retain the
|
|
22
|
+
full comparison report; a good beat-grid fit is not a listening or downbeat
|
|
23
|
+
confirmation. A normal half-time reading does not mean a detector failed.
|
|
24
|
+
|
|
25
|
+
Pin the resulting file exactly as every other project input:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
"clock": {
|
|
29
|
+
"authority": "Reviewed StemLab consensus constant-grid fit",
|
|
30
|
+
"status": "estimated",
|
|
31
|
+
"phase_status": "estimated",
|
|
32
|
+
"beat_alignment": {"path": "beat-alignment.json", "sha256": "EXACT_FILE_SHA256"}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The adapter validates the master SHA-256, source sample rate/frame bounds,
|
|
37
|
+
64-pip units, detector/report identities and exact rational clock equation.
|
|
38
|
+
An explicit BPM must agree. Do not also supply `origin` or `beat_grid`; the
|
|
39
|
+
reading owns this clock. An estimated BPM cannot become `confirmed` through
|
|
40
|
+
project metadata, and phase authority stays separate.
|
|
41
|
+
|
|
42
|
+
The existing BeatClock uses the first source beat as its origin. At that instant
|
|
43
|
+
the procedural clock is pip zero; before it, pips can be negative. Excerpts and
|
|
44
|
+
repeats map source time first and apply phase once. Keep the original master,
|
|
45
|
+
LRC, CUE and captured recording clocks unchanged. A recording's captured beat
|
|
46
|
+
zero and integer samples remain authoritative, including Fourier dimensions.
|
|
47
|
+
|
|
48
|
+
Missing, mismatched or poor evidence remains a review hold. A constant-grid
|
|
49
|
+
reading is not proof that a variable-tempo song fits one BPM. Existing projects
|
|
50
|
+
without a reading retain their explicit clock and report unverified phase when
|
|
51
|
+
no phase status was supplied.
|
|
52
|
+
|
|
53
|
+
Reproduce the actual fixture with `python examples/beat-alignment/generate.py
|
|
54
|
+
NEW-DIRECTORY --font /path/to/font.ttf`, then use normal `plan`, `preflight` and
|
|
55
|
+
`render` commands. Keep technical encoded QA separate from attended listening,
|
|
56
|
+
creative approval and any platform publication.
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
{
|
|
2
|
+
"context": "Actual FrameRudiments 0.2.0 encoded synthetic clock-composition example",
|
|
3
|
+
"frames": 240,
|
|
4
|
+
"fps": 60,
|
|
5
|
+
"dimensions": [
|
|
6
|
+
360,
|
|
7
|
+
640
|
|
8
|
+
],
|
|
9
|
+
"duration_seconds": 4,
|
|
10
|
+
"source_audio_sha256": "83e47effac0c8cf6c6c8c70f3babec9b55f61fcea0ba1a97822528e85b8ffe8c",
|
|
11
|
+
"first_beat_seconds": 0.125,
|
|
12
|
+
"offset_pips": -16,
|
|
13
|
+
"pips_per_beat": 64,
|
|
14
|
+
"screenshot_frame": 75,
|
|
15
|
+
"screenshot_source_seconds": 1.25,
|
|
16
|
+
"verification": {
|
|
17
|
+
"probe": {
|
|
18
|
+
"streams": [
|
|
19
|
+
{
|
|
20
|
+
"index": 0,
|
|
21
|
+
"codec_name": "h264",
|
|
22
|
+
"codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
|
|
23
|
+
"profile": "High",
|
|
24
|
+
"codec_type": "video",
|
|
25
|
+
"codec_tag_string": "avc1",
|
|
26
|
+
"codec_tag": "0x31637661",
|
|
27
|
+
"mime_codec_string": "avc1.64001f",
|
|
28
|
+
"width": 360,
|
|
29
|
+
"height": 640,
|
|
30
|
+
"coded_width": 368,
|
|
31
|
+
"coded_height": 640,
|
|
32
|
+
"has_b_frames": 2,
|
|
33
|
+
"pix_fmt": "yuv420p",
|
|
34
|
+
"level": 31,
|
|
35
|
+
"color_range": "tv",
|
|
36
|
+
"color_space": "bt709",
|
|
37
|
+
"chroma_location": "left",
|
|
38
|
+
"field_order": "progressive",
|
|
39
|
+
"refs": 4,
|
|
40
|
+
"is_avc": "true",
|
|
41
|
+
"nal_length_size": "4",
|
|
42
|
+
"id": "0x1",
|
|
43
|
+
"r_frame_rate": "60/1",
|
|
44
|
+
"avg_frame_rate": "60/1",
|
|
45
|
+
"time_base": "1/15360",
|
|
46
|
+
"start_pts": 0,
|
|
47
|
+
"start_time": "0.000000",
|
|
48
|
+
"duration_ts": 61440,
|
|
49
|
+
"duration": "4.000000",
|
|
50
|
+
"bit_rate": "108766",
|
|
51
|
+
"bits_per_raw_sample": "8",
|
|
52
|
+
"nb_frames": "240",
|
|
53
|
+
"nb_read_frames": "240",
|
|
54
|
+
"extradata_size": 49,
|
|
55
|
+
"disposition": {
|
|
56
|
+
"default": 1,
|
|
57
|
+
"dub": 0,
|
|
58
|
+
"original": 0,
|
|
59
|
+
"comment": 0,
|
|
60
|
+
"lyrics": 0,
|
|
61
|
+
"karaoke": 0,
|
|
62
|
+
"forced": 0,
|
|
63
|
+
"hearing_impaired": 0,
|
|
64
|
+
"visual_impaired": 0,
|
|
65
|
+
"clean_effects": 0,
|
|
66
|
+
"attached_pic": 0,
|
|
67
|
+
"timed_thumbnails": 0,
|
|
68
|
+
"non_diegetic": 0,
|
|
69
|
+
"captions": 0,
|
|
70
|
+
"descriptions": 0,
|
|
71
|
+
"metadata": 0,
|
|
72
|
+
"dependent": 0,
|
|
73
|
+
"still_image": 0,
|
|
74
|
+
"multilayer": 0
|
|
75
|
+
},
|
|
76
|
+
"tags": {
|
|
77
|
+
"language": "und",
|
|
78
|
+
"handler_name": "VideoHandler",
|
|
79
|
+
"encoder": "Lavc63.1.101 libx264"
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"index": 1,
|
|
84
|
+
"codec_name": "aac",
|
|
85
|
+
"codec_long_name": "AAC (Advanced Audio Coding)",
|
|
86
|
+
"profile": "LC",
|
|
87
|
+
"codec_type": "audio",
|
|
88
|
+
"codec_tag_string": "mp4a",
|
|
89
|
+
"codec_tag": "0x6134706d",
|
|
90
|
+
"mime_codec_string": "mp4a.40.2",
|
|
91
|
+
"sample_fmt": "fltp",
|
|
92
|
+
"sample_rate": "48000",
|
|
93
|
+
"channels": 2,
|
|
94
|
+
"channel_layout": "stereo",
|
|
95
|
+
"bits_per_sample": 0,
|
|
96
|
+
"initial_padding": 1024,
|
|
97
|
+
"id": "0x2",
|
|
98
|
+
"r_frame_rate": "0/0",
|
|
99
|
+
"avg_frame_rate": "0/0",
|
|
100
|
+
"time_base": "1/48000",
|
|
101
|
+
"start_pts": 0,
|
|
102
|
+
"start_time": "0.000000",
|
|
103
|
+
"duration_ts": 192000,
|
|
104
|
+
"duration": "4.000000",
|
|
105
|
+
"bit_rate": "35574",
|
|
106
|
+
"nb_frames": "189",
|
|
107
|
+
"nb_read_frames": "188",
|
|
108
|
+
"extradata_size": 5,
|
|
109
|
+
"disposition": {
|
|
110
|
+
"default": 1,
|
|
111
|
+
"dub": 0,
|
|
112
|
+
"original": 0,
|
|
113
|
+
"comment": 0,
|
|
114
|
+
"lyrics": 0,
|
|
115
|
+
"karaoke": 0,
|
|
116
|
+
"forced": 0,
|
|
117
|
+
"hearing_impaired": 0,
|
|
118
|
+
"visual_impaired": 0,
|
|
119
|
+
"clean_effects": 0,
|
|
120
|
+
"attached_pic": 0,
|
|
121
|
+
"timed_thumbnails": 0,
|
|
122
|
+
"non_diegetic": 0,
|
|
123
|
+
"captions": 0,
|
|
124
|
+
"descriptions": 0,
|
|
125
|
+
"metadata": 0,
|
|
126
|
+
"dependent": 0,
|
|
127
|
+
"still_image": 0,
|
|
128
|
+
"multilayer": 0
|
|
129
|
+
},
|
|
130
|
+
"tags": {
|
|
131
|
+
"language": "und",
|
|
132
|
+
"handler_name": "SoundHandler"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
"format": {
|
|
137
|
+
"nb_streams": 2,
|
|
138
|
+
"nb_programs": 0,
|
|
139
|
+
"nb_stream_groups": 0,
|
|
140
|
+
"format_name": "mov,mp4,m4a,3gp,3g2,mj2",
|
|
141
|
+
"format_long_name": "QuickTime / MOV",
|
|
142
|
+
"start_time": "0.000000",
|
|
143
|
+
"duration": "4.000000",
|
|
144
|
+
"size": "79895",
|
|
145
|
+
"bit_rate": "159790",
|
|
146
|
+
"probe_score": 100,
|
|
147
|
+
"tags": {
|
|
148
|
+
"major_brand": "isom",
|
|
149
|
+
"minor_version": "512",
|
|
150
|
+
"compatible_brands": "isomiso2avc1mp41",
|
|
151
|
+
"encoder": "Lavf63.1.101"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"full_decode": "passed",
|
|
156
|
+
"decoded_timestamps": "CFR from zero; all frames checked",
|
|
157
|
+
"audio_duration_error_seconds": 0.0,
|
|
158
|
+
"mp4_atoms": [
|
|
159
|
+
"ftyp",
|
|
160
|
+
"moov",
|
|
161
|
+
"free",
|
|
162
|
+
"mdat"
|
|
163
|
+
],
|
|
164
|
+
"listening_approved": false,
|
|
165
|
+
"platform_safe_zone_verified": false
|
|
166
|
+
},
|
|
167
|
+
"description": "Left: original pip-zero movement. Right: source-bound aligned movement. Bottom: captured recording keeps source clock. Text changes at original LRC timestamps. Soundtrack: original synthetic clicks.",
|
|
168
|
+
"limits": "Synthetic score, not detector accuracy, canonical-song authority or attended listening approval. Generated illustration omitted because actual rendered output demonstrates the composition.",
|
|
169
|
+
"files": {
|
|
170
|
+
"beat-alignment.mp4": "7e8a62a67fcc2967540121bd848263d2eff2bea02ca77e0b01f3be2966d45ccb",
|
|
171
|
+
"beat-alignment.png": "1755f09c51382cf04adbe0b18ce702036807e8b595633cc10cd116bfb9c5f88a"
|
|
172
|
+
}
|
|
173
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Preset libraries and input-response profiles
|
|
2
|
+
|
|
3
|
+
FrameRudiments installs **14,680 distinct upstream presets** separately from the
|
|
4
|
+
Python package: **1,738 Butterchurn** and **12,942 projectM** entries. Original
|
|
5
|
+
names remain searchable aliases after exact-byte deduplication. The five preset
|
|
6
|
+
packs contain 16,334 files before deduplication; 67 shared textures accompany them.
|
|
7
|
+
The six existing built-in presets (three per engine) remain available through
|
|
8
|
+
the ordinary project format.
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
Generated calibration illustrations: colour bars with grayscale ramp,
|
|
13
|
+
asymmetric grid/rings, and light/dark text. These are input cards, not evidence
|
|
14
|
+
of a preset's appearance. Their PNG hashes are recorded with each experiment.
|
|
15
|
+
|
|
16
|
+
The [actual four-second full-frame demonstration](https://kieransimkin.github.io/DanceFlow/framerudiments.html)
|
|
17
|
+
shows the composition/effect pipeline, with user-controlled video playback and
|
|
18
|
+
an accompanying transcript. It uses the earlier synthetic software demo;
|
|
19
|
+
profiling inputs are supplied separately and are never silently substituted.
|
|
20
|
+
|
|
21
|
+
## Install the complete pinned library
|
|
22
|
+
|
|
23
|
+
```powershell
|
|
24
|
+
framerudiments presets-install local/preset-library
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Installation explicitly downloads upstream executable equations/shaders. No
|
|
28
|
+
download happens during ordinary rendering. Every archive is SHA-256 pinned;
|
|
29
|
+
the catalogue retains source commits, notices, aliases, preset hashes and texture
|
|
30
|
+
hashes. Packages and caches remain outside the wheel/sdist. The installer reads
|
|
31
|
+
bounded ordinary archive members and writes content-addressed preset filenames,
|
|
32
|
+
avoiding original-path traversal and Windows filename/length problems.
|
|
33
|
+
|
|
34
|
+
| Pack | Source pin | Files before deduplication |
|
|
35
|
+
|---|---|---:|
|
|
36
|
+
| Butterchurn presets, all six stable bundles | npm 2.4.7 | 1,754 |
|
|
37
|
+
| Cream of the Crop | 0180df21f5e0bd39b9060cc5de420ed2f1f9e509 | 9,795 |
|
|
38
|
+
| Classic projectM | 14a6244a7d32eb7e114e1a92d1cb93358cdcc54a | 4,193 |
|
|
39
|
+
| Original MilkDrop | e03b83e3338d8f1ed6cbcf908c719f249ef24288 | 552 |
|
|
40
|
+
| En D | fff71ea81223109f3558351667eef851f2781c96 | 40 |
|
|
41
|
+
| Shared textures | 6368812f27bc747b517218fbf89d21d59afce4d9 | 67 images |
|
|
42
|
+
|
|
43
|
+
Butterchurn 2.6.7 accepts the stable pack's JavaScript-equation format. The
|
|
44
|
+
upstream 3.0 beta pack uses EEL fields and is not represented as compatible with
|
|
45
|
+
this engine. projectM remains pinned to unmodified development commit
|
|
46
|
+
`349b7cc2db312d47cef6be24c6856ced6643a385` (4.2.0-dev).
|
|
47
|
+
|
|
48
|
+
Butterchurn's pack supplies an MIT notice. Some projectM packs supply no explicit
|
|
49
|
+
licence grant; Cream/En D describe a historical public-domain assumption, which
|
|
50
|
+
does not establish author permission. Keep their exact notices and provenance.
|
|
51
|
+
FrameRudiments does not relicense or redistribute these packs as its own MIT
|
|
52
|
+
assets. Source availability, shader compatibility and public-use eligibility are
|
|
53
|
+
different states. Additional community packs require their own provenance and
|
|
54
|
+
format review; raw pack size alone does not establish useful coverage.
|
|
55
|
+
|
|
56
|
+
## Supply the two tunes, covers and lyrics
|
|
57
|
+
|
|
58
|
+
Create an ordinary untreated FrameRudiments project for each sample, with pinned
|
|
59
|
+
audio, cover background, font and timed LRC. Select explicit source sample bounds
|
|
60
|
+
covering the desired excerpt. Use saved StemLab evidence when choosing musical
|
|
61
|
+
sections or motion; the profiling runner does not estimate tempo or retime lyrics.
|
|
62
|
+
Native DanceRudiments sprite/atlas layers can remain in these projects and enter
|
|
63
|
+
the same full-frame processing path. The static-card conditions remove authored
|
|
64
|
+
layers and lyrics to isolate the calibration imagery.
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"schema": "framerudiments.preset-suite.v1",
|
|
69
|
+
"projects": [
|
|
70
|
+
{"path": "arcadians-project.json", "sha256": "EXACT_PROJECT_SHA256"},
|
|
71
|
+
{"path": "truth-project.json", "sha256": "EXACT_PROJECT_SHA256"}
|
|
72
|
+
],
|
|
73
|
+
"input_mix": 0.35,
|
|
74
|
+
"seed": 123
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
For the maintained My Songs experiment the selected tunes are **Arcadians** and
|
|
79
|
+
**The Truth is a Virus**, with their canonical masters, covers and manually timed
|
|
80
|
+
lyrics. Their private suite and evidence stay outside the public repository.
|
|
81
|
+
An optional `assets` list pins additional canonical/provenance files. Preserve
|
|
82
|
+
the original LRC if an export needs a documented parser-input adapter; never
|
|
83
|
+
silently alter its words or timings. An estimated clock used by a static test
|
|
84
|
+
does not become an approved musical grid.
|
|
85
|
+
|
|
86
|
+
## Capture, analyse and resume
|
|
87
|
+
|
|
88
|
+
Set up the two optional engines as described in [visualisers.md](visualisers.md).
|
|
89
|
+
Use a separate Python 3.13 interpreter with released **PrismMoves 0.1.0** and
|
|
90
|
+
**PixelCue 0.9.0**, plus NumPy/Pillow, for analysis. This keeps heavy optional
|
|
91
|
+
analysis dependencies out of the renderer's base installation. Existing local
|
|
92
|
+
model-free APIs are sufficient; no model download is needed.
|
|
93
|
+
|
|
94
|
+
```powershell
|
|
95
|
+
framerudiments presets-profile local/suite.json local/preset-library/catalogue.json `
|
|
96
|
+
--output local/response-run --intervals 0 1 2 4 `
|
|
97
|
+
--prism-python path/to/prism-python
|
|
98
|
+
|
|
99
|
+
# Equivalent script entrypoint in the source distribution:
|
|
100
|
+
python scripts/profile_visualisers.py local/suite.json local/preset-library/catalogue.json `
|
|
101
|
+
--output local/response-run --intervals 0 1 2 4 --prism-python path/to/prism-python
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Intervals are output seconds, rounded up to the next available frame and rejected
|
|
105
|
+
outside the programme. Every preceding frame is replayed sequentially. Sparse
|
|
106
|
+
captures skip unnecessary GPU readback; they do not skip feedback simulation.
|
|
107
|
+
Each preset/condition starts a clean engine with the same mix, frame cadence,
|
|
108
|
+
resolution and authored seed. projectM has no public seed API, so its random
|
|
109
|
+
state remains an explicit confound. GPU/driver output is not cross-platform
|
|
110
|
+
bit-identical.
|
|
111
|
+
|
|
112
|
+
Default conditions cross each sample with cover/timed-lyrics, colour bars,
|
|
113
|
+
grid/rings and text card, then programme audio and all-zero PCM controls: **16
|
|
114
|
+
conditions for two samples**. Programme PCM uses the encoder's exact native-rate
|
|
115
|
+
trim/repeat/fade filters and causal windows. Album imagery and captions undergo
|
|
116
|
+
the same effects as the rest of the composition. Static cards do not inherit
|
|
117
|
+
album colours or captions. The catalogue's verified textures are attached to the
|
|
118
|
+
actual engine APIs, with runtime receipts.
|
|
119
|
+
|
|
120
|
+
Use `--id EXACT_CATALOGUE_ID` repeatedly for a selected batch, or `--limit N`
|
|
121
|
+
for a pilot; omitted limits select the full catalogue. `--image cover-lyrics`
|
|
122
|
+
and `--audio-mode programme` narrow a declared experiment. Changing conditions
|
|
123
|
+
requires a new output directory. A full sweep of thousands of presets is an
|
|
124
|
+
explicit substantial workload: benchmark a representative batch first, retain
|
|
125
|
+
elapsed time and storage evidence, then use the chosen settings consistently.
|
|
126
|
+
Lowering frame rate changes feedback behaviour and must remain a labelled
|
|
127
|
+
preview, with `fps_reason`, rather than a production-appearance claim.
|
|
128
|
+
|
|
129
|
+
Re-run the identical command with `--resume` to reuse verified captures. Add
|
|
130
|
+
`--retry-failed` for fresh attempts while retaining failures and older profiles.
|
|
131
|
+
Changed inputs, runtime binaries, host bridges, textures, settings or capture
|
|
132
|
+
bytes prevent stale reuse. Failed shaders are retained explicitly; native shader
|
|
133
|
+
fallback errors are not accepted as a successful preset render.
|
|
134
|
+
|
|
135
|
+
## Assemble one coherent response profile
|
|
136
|
+
|
|
137
|
+
1. Read `experiment.json` and `index.json` for exact scope and coverage. Available
|
|
138
|
+
catalogue entries are not completed profiles. Every preset has `captures.json`
|
|
139
|
+
with per-condition times, hashes, PCM and engine/cleanup receipts.
|
|
140
|
+
2. Open `identity/report.html` to inspect matching input/output frames and the
|
|
141
|
+
original condition families. `identity/prism-*/` contains the actual PrismMoves
|
|
142
|
+
reports, measured palette graphics, PixelCue evidence and checksums. Statistics
|
|
143
|
+
remain observations; optional `--model clip`, `dinov2`, `blip` or `ocr` outputs
|
|
144
|
+
remain interpretations, with unavailable receipts. Models load local weights
|
|
145
|
+
only under the experiment's `models/`; this runner never enables downloads.
|
|
146
|
+
3. Use `identity/response.json` for source-to-output, successive-capture,
|
|
147
|
+
programme-versus-silence and same-card/different-tune comparisons. PixelCue's
|
|
148
|
+
`compare_profiles` supplies separate hue, texture and saturation distances and
|
|
149
|
+
supported embedding similarities. Named PixelCue luminance, edge/mirror,
|
|
150
|
+
texture/co-occurrence and spatial-frequency values also retain signed
|
|
151
|
+
input/output changes and observed ranges. No private analysis engine or invented
|
|
152
|
+
overall identity score is introduced.
|
|
153
|
+
4. Review palette, geometry, texture, text treatment and temporal behaviour for
|
|
154
|
+
each family before synthesising. Describe a visual thesis supported by named
|
|
155
|
+
conditions; retain controlled variation and outliers. Frame grabs from one
|
|
156
|
+
run share a lineage and are not independent artistic authorities. Keep a
|
|
157
|
+
response range when tunes or cards differ rather than averaging incompatible
|
|
158
|
+
looks into one claimed invariant.
|
|
159
|
+
5. Record remaining unknowns and production review: glyph legibility, safe zones,
|
|
160
|
+
sustained motion, flash safety, exact final frame rate, audio listening,
|
|
161
|
+
resource warnings and public-use rights. Measurements cannot establish these.
|
|
162
|
+
A failed preset receives a failure/unknown record, not an invented identity.
|
|
163
|
+
|
|
164
|
+
## Potential problems
|
|
165
|
+
|
|
166
|
+
- Thousands of available entries have not all been GPU accepted. Inspect each
|
|
167
|
+
capture state and runtime warnings; missing custom textures and old shader
|
|
168
|
+
dialects can produce failures or an altered appearance.
|
|
169
|
+
- Native GPU/driver stalls may still require operator recovery; a completed
|
|
170
|
+
Python report is not evidence that an interrupted job cleaned up. The normal
|
|
171
|
+
Butterchurn route closes its owned headless browser and removes only its
|
|
172
|
+
freshly allocated profile; projectM destroys its native instance/window.
|
|
173
|
+
- A report with unavailable neural/OCR models still has useful statistics.
|
|
174
|
+
Keep it partial; installing random/untrained checkpoints would not establish
|
|
175
|
+
visual understanding. No paid inference or automatic model sweep is implied.
|
|
176
|
+
- Comparison settings (matte, ICC handling, analysis edge, frame rate, source
|
|
177
|
+
offset, input mix) influence results. Preserve them across a comparison batch.
|
|
178
|
+
- Source PNGs and processed PNGs are renderer evidence, not decoded-video QA.
|
|
179
|
+
Encode and inspect the selected production preset using the normal render
|
|
180
|
+
pipeline before publishing a campaign video.
|
|
181
|
+
|
|
182
|
+
Evidence JSON writes use same-directory temporary files and atomic replacement,
|
|
183
|
+
so a failed update preserves the previous valid receipt. Disk exhaustion can
|
|
184
|
+
still leave incomplete PNGs or reports: retain the interrupted attempt and
|
|
185
|
+
resume only after hash validation, or start a fresh output directory.
|
|
186
|
+
|
|
187
|
+
On Windows, Chromium's internal cache filenames can exceed its path limit even
|
|
188
|
+
when Python can write the evidence folder. Profiling creates fresh profiles in
|
|
189
|
+
the short experiment-level `.browser/` directory, with normal verified cleanup.
|
|
190
|
+
For a deeply nested output root set `FRAMERUDIMENTS_BROWSER_PROFILE_ROOT` to a
|
|
191
|
+
short writable project-local folder. Existing user browser profiles are never
|
|
192
|
+
opened, read or reused.
|
|
193
|
+
|
|
194
|
+
To use a catalogue entry in an ordinary render, copy its verified `preset`
|
|
195
|
+
`{path, sha256}` reference into an effect stage with `engine` and
|
|
196
|
+
`trusted_preset: true` after the explicit library review. Set
|
|
197
|
+
`FRAMERUDIMENTS_TEXTURES_DIR` to the installed library's `textures/` directory
|
|
198
|
+
when the preset needs it; the runtime records image hashes and native warnings.
|
|
199
|
+
The profiler does this texture attachment automatically from the verified
|
|
200
|
+
catalogue. Keep public-use eligibility separate from rendering acceptance.
|
|
@@ -11,7 +11,7 @@ the inputs are checked again before and after a render.
|
|
|
11
11
|
| `purpose` | `short` (120 ms endpoint fades by default), `visualiser`, or `canvas` (no fades by default). |
|
|
12
12
|
| `width`, `height`, `fps`, `fps_reason` | Even dimensions, fps defaults to 60; other rates need a reason. No platform compliance is inferred. |
|
|
13
13
|
| `audio` | `source` file reference, verified `sample_rate`, start-inclusive `start_sample`, end-exclusive `end_sample`, optional positive integer `repeats` and `fade_seconds`. |
|
|
14
|
-
| `clock` | `bpm` or `
|
|
14
|
+
| `clock` | `bpm`, `beat_grid` or source-bound `beat_alignment` file reference; `authority`, `status` (`confirmed`, `estimated`, `synthetic`), optional `origin` in source seconds and `phase_status`. A reading owns its BPM/origin and cannot be combined with `beat_grid` or `origin`. |
|
|
15
15
|
| `font` | Pinned TTF/OTF file for authored text. |
|
|
16
16
|
| `lyrics`, `cues` | Separate LRC references; `.cue` files are also supported for structural cues. |
|
|
17
17
|
| `canonical_lyrics` | Optional pinned plain text whose performed nonempty lines must exactly match the LRC. Bracketed structural lines in this comparison file are excluded. |
|
|
@@ -30,6 +30,13 @@ control their appearance. `mapping` amplitudes are `dx`, `dy`, `rotation`
|
|
|
30
30
|
and `scale_axis` select index 0,1,2 of the motion projection. Defaults are
|
|
31
31
|
0,1,2,2 respectively. Set `y_axis: 0` to map a one-dimensional bounce vertically.
|
|
32
32
|
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
[Watch the synthetic clock example](media/beat-alignment.mp4) and follow the
|
|
36
|
+
[source-bound alignment setup](beat-alignment.md). Its first click at 0.125
|
|
37
|
+
seconds maps to pip zero; the screenshot is encoded frame 75 at source 1.25
|
|
38
|
+
seconds. [Verification and media hashes](media/beat-alignment-evidence.json).
|
|
39
|
+
|
|
33
40
|
Atlas configuration is `{columns, rows, count, cycle_ticks, phase_beats?}`.
|
|
34
41
|
The atlas must divide into exact cells. One beat is 16 ticks; cycle ticks are
|
|
35
42
|
explicitly authored rather than silently quantised. Cycles use a continuous
|
|
@@ -175,3 +175,15 @@ Playback is user-controlled; no automatic media playback is required.
|
|
|
175
175
|
|
|
176
176
|
Generated vector illustration of the processing order. The comparison above
|
|
177
177
|
and linked video are captured renderer output; the diagram is explanatory.
|
|
178
|
+
|
|
179
|
+
## Expanded libraries and response experiments
|
|
180
|
+
|
|
181
|
+
The [preset profiling workflow](preset-profiling.md) installs the complete pinned
|
|
182
|
+
upstream catalogue and uses matching-time captures, three static test cards,
|
|
183
|
+
programme/silence controls and released PrismMoves/PixelCue comparisons.
|
|
184
|
+
|
|
185
|
+

|
|
186
|
+
|
|
187
|
+
Generated input illustrations. Per-preset rendered captures and statistical
|
|
188
|
+
reports are retained separately by each experiment; catalogue presence does
|
|
189
|
+
not establish GPU compatibility or public-use rights.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Actual PrismMoves/PixelCue measurements on sequential native-engine captures."""
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from PIL import Image
|
|
7
|
+
|
|
8
|
+
from framerudiments.demo import create_demo
|
|
9
|
+
from framerudiments.io import read_json, write_json, sha256
|
|
10
|
+
from framerudiments.visualisers import ASSETS
|
|
11
|
+
from framerudiments.preset_profiling import profile_presets
|
|
12
|
+
from framerudiments.profile_analysis import summarise
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_real_prism_pixelcue_response_synthesis_and_controls(tmp_path):
|
|
16
|
+
project = create_demo(tmp_path/'sample', os.environ['FRAMERUDIMENTS_TEST_FONT'], width=128, height=128)
|
|
17
|
+
cover = project.parent/'cover.png'
|
|
18
|
+
Image.new('RGB', (128,128), 'navy').save(cover)
|
|
19
|
+
data = read_json(project)
|
|
20
|
+
data['background'] = dict(image=dict(path=str(cover),sha256=sha256(cover)))
|
|
21
|
+
data['layers'], data['identity'] = [], []
|
|
22
|
+
data['audio'].update(end_sample=48000,fade_seconds=0)
|
|
23
|
+
write_json(project,data)
|
|
24
|
+
suite = tmp_path/'suite.json'
|
|
25
|
+
write_json(suite,dict(schema='framerudiments.preset-suite.v1',projects=[dict(path=str(project),sha256=sha256(project))]))
|
|
26
|
+
preset=ASSETS/'feedback.milk'
|
|
27
|
+
catalogue=tmp_path/'catalogue.json'
|
|
28
|
+
write_json(catalogue,dict(schema='framerudiments.preset-library.v1',presets=[dict(id='native',name='Native fixture',engine='projectm',preset=dict(path=str(preset),sha256=sha256(preset)))]))
|
|
29
|
+
result=profile_presets(suite,catalogue,tmp_path/'run',intervals=[0,.1],images=['cover-lyrics','grid-rings'])
|
|
30
|
+
response=summarise(result[0]['manifest'],max_edge=64,models_dir=tmp_path/'models')
|
|
31
|
+
assert response['state']=='completed'
|
|
32
|
+
assert len(response['conditions'])==4
|
|
33
|
+
assert len(response['controlled_comparisons'])==2
|
|
34
|
+
assert all(len(x['source_to_output'])==2 for x in response['conditions'])
|
|
35
|
+
assert all(len(x['temporal'])==1 for x in response['conditions'])
|
|
36
|
+
assert response['settings']['versions']['prismmoves']=='0.1.0'
|
|
37
|
+
assert response['settings']['versions']['pixelcue']=='0.9.0'
|
|
38
|
+
assert all('median' in x for x in response['measured_response_ranges'].values())
|
|
39
|
+
assert summarise(result[0]['manifest'],max_edge=64,models_dir=tmp_path/'models')==response
|
|
40
|
+
report=Path(result[0]['manifest']).parent/'identity/report.html'
|
|
41
|
+
assert report.is_file() and 'matching-time capture' in report.read_text(encoding='utf-8')
|
|
42
|
+
assert json.loads((report.parent/'response.json').read_text())['settings']==response['settings']
|
|
@@ -133,3 +133,19 @@ def test_projectm_shader_error_cannot_silently_fall_back(tmp_path, kind):
|
|
|
133
133
|
path.write_text(preset, encoding="utf-8")
|
|
134
134
|
with pytest.raises(RuntimeError, match="projectM preset failed"):
|
|
135
135
|
ProjectMBackend((160, 240), 60, path, .8, 0, tmp_path)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@pytest.mark.parametrize("factory,extension", [(ProjectMBackend,"milk"),(ButterchurnBackend,"json")])
|
|
139
|
+
def test_sparse_capture_advances_real_feedback_and_retains_frame_clock(tmp_path,factory,extension):
|
|
140
|
+
image=glyph_frame()
|
|
141
|
+
backend=factory(image.size,60,ASSETS/f"feedback.{extension}",.75,12,tmp_path)
|
|
142
|
+
pcm=array("f",[0]*2048)
|
|
143
|
+
try:
|
|
144
|
+
for n in range(7):
|
|
145
|
+
assert backend.advance(image,SimpleNamespace(frame=n,output_seconds=n/60),pcm,capture=False) is None
|
|
146
|
+
final=backend.advance(image,SimpleNamespace(frame=7,output_seconds=7/60),pcm,capture=True)
|
|
147
|
+
assert final.mode=="RGBA" and final.size==image.size
|
|
148
|
+
assert final.getpixel((35,30))[0]>final.getpixel((35,30))[2]+80
|
|
149
|
+
finally:
|
|
150
|
+
backend.close()
|
|
151
|
+
assert all(backend.evidence["cleanup"].values())
|