Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-111997.svg)](#build--distribution)
[![Electron](https://img.shields.io/badge/Electron-43-47848F.svg)](https://www.electronjs.org/)
[![Downloads](https://img.shields.io/github/downloads/CaYatur/SoundVisualizer/total?label=downloads)](https://github.com/CaYatur/SoundVisualizer/releases)
[![Tests](https://img.shields.io/badge/tests-2081%20passing-2ea043.svg)](#tests)
[![Tests](https://img.shields.io/badge/tests-2108%20passing-2ea043.svg)](#tests)
[![cayadev.com](https://img.shields.io/badge/cayadev.com-e11d2a.svg)](https://cayadev.com)

</div>
Expand Down Expand Up @@ -360,6 +360,15 @@ that asserts the bar profile has no step in it.
scanned in full before you are asked. No preset pack ships with the app. Measured with real
packs: a 9,795-preset folder was scanned in 1.1 s and imported in 6.2 s, and importing it again
added nothing.
- **Preset thumbnails.** The MilkDrop panel's list has a *Grid* layout: every preset shows a small
picture of itself, so a preset can be found by its look. Each thumbnail is drawn once in the
background — the first two seconds of the preset with the demo sound, from a black screen — kept
in the app's data, and drawn again when the preset or a texture it uses changes. Only the
presets you scroll to are drawn. A visualizer window drawing MilkDrop at the same time barely
noticed: none of its frames took longer than 27 ms. Found while building this: when another
MilkDrop window was drawing and the computer was busy, a MilkDrop picture that had just set up its
buffers (a new window, a resize, a thumbnail, a video export) could start from the other window's
picture. Buffers now start from zeros.
- **Sprites from `milk_img.ini`.** MilkDrop 2 draws images of your own over the picture during a
show: each one is defined in `milk_img.ini` with an image, code that runs once and code that
runs every frame, and launched by number. Choose the file in the MilkDrop panel and launch from
Expand Down Expand Up @@ -1259,7 +1268,7 @@ npm test
npm start -- --smoke
```

**2081 unit tests, all passing.** They are written to check answers, not to exercise lines:
**2108 unit tests, all passing.** They are written to check answers, not to exercise lines:

- **Formulas** are checked against values derived by hand from their definitions — Viviani's curve
staying on its sphere, the torus tube radius, Chladni's m↔n antisymmetry, every attractor
Expand Down
13 changes: 11 additions & 2 deletions README.tr.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-111997.svg)](#paketleme--dağıtım)
[![Electron](https://img.shields.io/badge/Electron-43-47848F.svg)](https://www.electronjs.org/)
[![İndirme](https://img.shields.io/github/downloads/CaYatur/SoundVisualizer/total?label=indirme)](https://github.com/CaYatur/SoundVisualizer/releases)
[![Test](https://img.shields.io/badge/test-2081%20geçiyor-2ea043.svg)](#testler)
[![Test](https://img.shields.io/badge/test-2108%20geçiyor-2ea043.svg)](#testler)
[![cayadev.com](https://img.shields.io/badge/cayadev.com-e11d2a.svg)](https://cayadev.com)

</div>
Expand Down Expand Up @@ -353,6 +353,15 @@ profilinde basamak olmadığını doğruluyor.
baştan taranıyor. Uygulamayla hiçbir preset paketi gelmiyor. Gerçek paketlerle ölçüldü: 9.795
presetlik bir klasör 1,1 sn'de tarandı, 6,2 sn'de içe aktarıldı; ikinci kez almak hiçbir şey
eklemedi.
- **Preset küçük resimleri.** MilkDrop panelindeki listenin *Izgara* düzeni var: her preset kendi
küçük resmiyle görünüyor, yani bir preset görünüşünden bulunabiliyor. Her küçük resim arka planda
bir kez çiziliyor — presetin ilk iki saniyesi, örnek sesle, siyah bir ekrandan — uygulamanın
verisinde saklanıyor ve preset ya da kullandığı bir doku değişince yeniden çiziliyor. Yalnız
kaydırıp baktığınız presetler çiziliyor. Aynı anda MilkDrop çizen bir görselleştirici penceresi
bunu neredeyse hiç fark etmedi: hiçbir karesi 27 ms'den uzun sürmedi. Bunu yaparken bulundu: başka
bir MilkDrop penceresi çizerken ve bilgisayar meşgulken, tamponlarını yeni kuran bir MilkDrop
görüntüsü (yeni bir pencere, yeniden boyutlandırma, küçük resim, video dışa aktarımı) öbür
pencerenin görüntüsüyle başlayabiliyordu. Tamponlar artık sıfırdan başlıyor.
- **`milk_img.ini`'den sprite'lar.** MilkDrop 2 gösteri sırasında kendi resimlerinizi görüntünün
üstüne çiziyor: her biri `milk_img.ini`de bir resim, bir kez çalışan ve her kare çalışan koduyla
tanımlı ve numarasıyla başlatılıyor. Dosyayı MilkDrop panelinde seçin; panelin listesinden, bir
Expand Down Expand Up @@ -1256,7 +1265,7 @@ npm test
npm start -- --smoke
```

**2081 birim testi, hepsi geçiyor.** Satır çalıştırmak için değil, cevap denetlemek için yazıldılar:
**2108 birim testi, hepsi geçiyor.** Satır çalıştırmak için değil, cevap denetlemek için yazıldılar:

- **Formüller**, tanımlarından elle türetilmiş değerlerle sınanıyor — Viviani eğrisinin küre
üzerinde kalması, simidin boru yarıçapı, Chladni'nin m↔n antisimetrisi, her çekicinin sınırlı
Expand Down
125 changes: 123 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ npm test
npm start -- --smoke
```

- **2081 unit tests, all passing** on `main`. 703 of those shipped in v3.1.0;
- **2108 unit tests, all passing** on `main`. 703 of those shipped in v3.1.0;
105 came with v3.1.1; 163 came with v3.1.2; 157 came with v3.1.3 — 1128 at
that tag — 469 more with v3.1.4, most of them from the MilkDrop work, and 484
that tag — 469 more with v3.1.4, most of them from the MilkDrop work, and 511
on `main` since.
Formulas are checked against values derived
by hand from their definitions — Viviani's curve staying on its sphere, the
Expand Down Expand Up @@ -1737,6 +1737,127 @@ rest after. No version number yet.
main-process handlers, the engine's texture counter, and the panel
drawn with a fake DOM, confirmation and rescan included. 57 of 57
mutations are caught.
- **Preset thumbnails (#575)** · done. The MilkDrop panel's list gets a
*Layout* choice, *List* or *Grid*. In the grid every preset shows a
thumbnail, drawn once in a hidden window and kept in the user data
(`milkdrop-thumbs/`).
- **Recipe, measured** on a seeded 200-preset sample of the corpus: a
black start; 60 frames of the demo sound at 1/30 s; drawn at 640x360
and scaled to a 256x144 WebP (~3.6 KB). A fixed seed image (a builtin
preset for 45 frames, then a hard cut) lowered the black thumbnails only
from 20 to 18 — fixing four and breaking two — made each job 45% longer
and painted its own colours into the thumbnails of presets that draw
nothing like it. 90 and 150 frames gave 20 and 22 black thumbnails (some
presets fade out), at a median of 350 and 538 ms against 259 ms. Drawing
at 640x360 instead of 320x180 barely moved the time (250 against 259 ms
median): the work is the per-frame code, not the pixels.
- **The same every time.** Each thumbnail is drawn by a new engine
instance, whose context `dispose` releases, from black buffers.
`Math.random` and the preset's seed come from the key. A texture the
preset asks for is waited for right after the frame that asks, and a
thumbnail whose texture does not arrive within 8 s is not written;
neither is one whose frames were not all drawn on a live context (with
no context the engine draws a placeholder, after a loss it keeps the
last frame — either would be kept for good under a content key). A
crashed drawing process is replaced instead of making every later cell
wait for the 30 s limit. Checked in the real page: seven presets, each
drawn after two different busy presets, gave the same bytes both times
— the five busiest of 40 (6.8–13 KB), a textured one and one using
`sampler_randNN`. Also checked under load (below): one preset drawn 48
times with a visualizer window drawing MilkDrop and the CPU busy gave
the same bytes every time.
- **Key** = a hash of the recipe (the bytes of every file the thumbnail
page loads, plus the sizes and the frame count) + the preset's source +
a signature of the textures it asks for (name, size, modification time;
the whole list for `sampler_randNN`). An engine change (#580, #567)
therefore retires every thumbnail by itself, an edited preset or a
changed texture gets a new one, and two presets with the same content
share one. Once per session, files no current preset produces are
deleted.
- **Panel.** The visible cells are asked for; cached thumbnails come back
at once, the rest as they are drawn, newest request first, one at a
time. A waiting cell is striped and a failed one has a dashed frame, so
neither looks like a thumbnail that is really black (about 9% are). The
layout is the viewer's own choice, kept in browser storage rather than
in the settings. Images come through an `sv-thumb:` protocol that
accepts only a key and reads only the thumbnail folder. The hidden
window closes after 20 s idle and when the panel closes — otherwise it
would keep the app from quitting.
- **Found on the way — a picture from another window in a new buffer.**
The engine allocated its render targets empty and cleared them with
`gl.clear`. With another MilkDrop context drawing on the same GPU and
the CPU busy, a freshly allocated feedback buffer could still hold that
context's picture, and the feedback loop grew it: a preset whose
thumbnail is black came out as the starburst the visualizer window was
showing at the time, in 13 of 24 draws with the flash limiter off and 3
of 16 with it on. Neither condition alone did it (18 of 18 clean with
the window drawing bars under load, and with the window drawing MilkDrop
and the CPU idle). The same GPU, context attributes and formats were
reported every time. Targets are now allocated from zeros — a shared
zero buffer that is never written (8 MB at 1080p) — and the clear
stays; the same conditions gave 0 of 48. This is not only about
thumbnails: any window whose buffers are allocated again (a second
window opening, a resize, a restored context) and the video export
could start from another window's picture. Drawing alone is unchanged:
200 presets gave identical results before and after. The price is paid
only when buffers are allocated: a full rebuild of the targets at
1920x1080 (feedback, blur and flash limiter) takes 8.6 ms instead of
3.3 ms, less than one frame.
- **Found on the way, smaller:** `sampler_randNN` picked from the texture
list in the order the file system returned — alphabetical on Windows,
arbitrary on Linux — so the same preset could get another texture on
another machine; the list is now sorted the way the measurement script
sorts it. The importer (#574) did not strip the filter/wrap prefix from
sampler names, so a preset asking for `sampler_fw_worms` did not bring
the `worms.jpg` beside it; now it does. The builtin presets module gave
Node nothing; the main process now reads their sources from it. The
light colour sampler (#589) read its 64x16 canvas with `getImageData`
about 30 times a second and Chromium warned about it — the smoke test
caught the warning once lights were set to take MilkDrop's colours; the
downscale stays on the GPU and only the 4 KB result is read back from a
canvas made for reading.
- **Found on the way — the smoke test could drive real lights.** The smoke
test and the screenshot tool run on the user's own profile. With
Dynamic Lighting on in the settings, the app drove the lights at
start-up in those runs too, and the smoke test itself turns OpenRGB on
in the panel. As with the camera, which automation never opens, the
physical outputs are now off in these runs: every Dynamic Lighting
setting goes through one function that sends it switched off, the
device scan is skipped, and OpenRGB and Art-Net are never started.
Diagnostics (`--diag`) still drives the lights, since that is what it
is for.
- **Measured** in an isolated copy with 120 corpus presets and the panel
driven: the first thumbnail after 1.0 s, the 20 visible cells full in
10–17 s. With a visualizer window drawing MilkDrop at 75 Hz, 20 s idle
against 20 s while 31 thumbnails were drawn: frame time p99 13.5 against
13.6 ms, longest frame 17.2 against 26.7 ms, none over 33 ms either way
— so no pause between jobs was added. Asking for 40 cached thumbnails
took 2.9 ms (median round trip from the panel) with no texture folder
and 4.2 ms with the corpus texture pack chosen, so the texture listing
is not cached. The English UI was checked.
- **Not done:** thumbnails in the web remote and in the list view;
drawing every thumbnail ahead of time (only what is looked at is drawn;
10,000 presets would take over an hour); a thumbnail shows the first two
seconds, not a preset's later look. Thumbnails always use the engine's
defaults (MilkDrop fidelity on, mesh 64, smooth lines, flash limiter
on): with other settings the live picture differs a little.
- **Tests.** 22 tests: recipe and page files, key and texture signature,
the queue (cache, one job per key, newest first, failure, staleness,
cap, clear), cleanup, the protocol, the page driver with a fake engine
(new instance per job, seeding, texture wait and timeout, no or lost
context, a frame not drawn), the builtins
in Node, the main-process pins, and the panel's grid with a fake DOM.
The smoke test draws a builtin preset's thumbnail through the whole
chain — the recipe files read from the package, the hidden window, the
protocol and the panel's CSP — into a temporary folder, not the user's
data. One engine test drives `_makeTarget` against a fake GL: a zero
array of the right type and length for both formats, the unpack
alignment set first, the clear kept, the buffer shared and grown. One
checks that the light sampler reads only the small canvas made for
reading, and three check that every path to the lights passes the
automation flag. 57 of 58 mutations are caught; the survivor removes
the "no context" check, which the frame counter already makes (without
a context no frame is drawn).

## v3.1.6 — Comprehensive video export

Expand Down
2 changes: 1 addition & 1 deletion src/admin/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html lang="tr">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data: blob: sv-logo:; connect-src 'self' sv-logo:; media-src 'self' sv-media: blob: data:; style-src 'self' 'unsafe-inline';" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data: blob: sv-logo: sv-thumb:; connect-src 'self' sv-logo:; media-src 'self' sv-media: blob: data:; style-src 'self' 'unsafe-inline';" />
<title>Ses Görselleştirici — Yönetici Paneli</title>
<link rel="stylesheet" href="admin.css" />
<link rel="stylesheet" href="studio.css" />
Expand Down
Loading
Loading