Commit Graph

31 Commits

Author SHA1 Message Date
Skyler Lehmkuhl 8ed2320dca Type AudioClip duration by clip kind; fix MIDI clips growing too fast
The MIDI-clip-end-grows-too-fast bug was a units confusion: AudioClip.duration
is documented "seconds" but MIDI clips store their length in BEATS (they share
the AudioClip struct with sampled clips). The timeline's effective_clip_duration
read it as raw seconds, so at 120 BPM a MIDI clip rendered ~2x too long. The old
backend-snapshot display had hidden this by forcing timeline_duration in beats.

Root fix — make the domain explicit and unforgeable:
- `duration` is now a private field. Reading it in the wrong unit is impossible
  because access goes through typed accessors: AudioClip::content_duration() ->
  ClipDuration (a Seconds|Beats enum tagged by clip_type) and
  set_content_duration(). serde still serializes the private field, so the .beam
  format is unchanged (bare number).
- ClipDuration::to_seconds(tempo_map) for display/sizing; ::native() for code
  that already works in the clip's native domain (trim math shares it).
- get_clip_duration + the timeline-endpoint calc go through to_seconds, so MIDI
  is converted correctly; effective_clip_duration delegates to get_clip_duration.
- Recording mirrors (audio/MIDI progress + finalize) write via set_content_duration
  (debug-asserts the value's domain matches the clip type).

Every former raw read/write of the field (core actions, timeline, piano roll,
infopanel, asset library, recording handlers) now goes through the accessors.
Whole workspace compiles; 299 core tests pass.
2026-07-11 19:23:37 -04:00
Skyler Lehmkuhl fd582828c2 Add text layers
Introduce editable text layers: a resizable text box with editable text,
font size, color, font family, and alignment.

Core:
- New TextLayer/TextContent (text_layer.rs), wired into AnyLayer/LayerType
  and all the exhaustive match sites; structured so content can be keyframed
  later via content_at().
- fonts.rs: thread-local parley FontContext with three bundled fonts
  (Liberation Sans/Serif/Mono, SIL OFL), system-font enumeration consolidated
  to base families, document-embedded fonts, glyph/caret/selection geometry,
  and a background preloader for the picker fonts.
- Rendering via parley layout + Scene::draw_glyphs (renderer.rs); text
  composites through the vector path.
- Actions: CreateTextClipAction (vector-layer branch, undoable),
  SetTextContentAction, ResizeTextBoxAction.
- .beam font embedding: MediaKind::Font rows (content-hash dedupe) written on
  save and registered on load, with bundled-default fallback.
- VectorClip content bounds include text boxes so text-only clips are
  selectable/draggable.

Editor:
- Text tool: click empty/raster/video to create a top-level text layer, or a
  vector layer to create+enter a clip containing the text; click an existing
  box to edit it.
- Hybrid in-place editing: a hidden egui TextEdit drives input/IME/caret while
  the text and caret/selection render in Vello; empty just-created layers are
  removed on commit.
- Selection outline + 8 resize handles (re-wrap text) with hover cursors;
  factored the corner/edge resize-cursor mapping shared with the Transform tool.
- Info panel: edit text, size, color, alignment, box size, and a font-family
  picker that previews each entry in its own font (fonts preloaded in the
  background to avoid hitches).

Deps: add parley (git, pinned to match vello's peniko); bundle Liberation
fonts under lightningbeam-core/assets/fonts. Gitignore the local
.cargo/config.toml used to select a machine's ffmpeg.
2026-06-27 18:14:47 -04:00
Skyler Lehmkuhl 701b57bfe8 video: thumbnails force CPU frames (fix black thumbs + decoder thrash)
The asset-library thumbnail called VideoManager::get_frame, which honors the
render-pass hardware flag — left ON by the preview, so the thumbnail got a GPU
frame with empty rgba_data → an all-black thumbnail. The thumbnail is also the
only consumer that requests a fixed low timestamp (1.0s) on the shared per-clip
decoder, so when it re-decodes during playback it yanks the decoder back to ~1s;
the next playback frame (6.x) is then ">2s forward" and re-seeks to the keyframe
+ re-decodes the whole GOP (the jerk: per-frame decode is ~5ms, but these seeks
cost 40ms + N-frame catch-up).

Add VideoManager::get_frame_cpu (forces want_gpu=false regardless of the render
flag); the thumbnail uses it. Now it produces a real RGBA thumbnail that the
editor texture-caches once, instead of re-decoding black frames.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 05:39:35 -04:00
Skyler Lehmkuhl f1fba186c1 video: decode at the consumer's target resolution (Stage 1)
The decoder's output size was frozen to the document size at import, and export
reused that decoder — so exporting above document res upscaled the video (real
source detail discarded) and a document resize never re-targeted the decode.

Decode size is now chosen per get_frame call: VideoDecoder::get_frame and
VideoManager::get_frame take a target (w, h), capped to native (never upscale),
with the swscale context and frame caches keyed on the output size so preview
(preview res) and an in-progress export (export res) don't collide. The renderer
derives the target from the document->output base_transform, so export decodes
at export res (full detail) and the canvas at preview res. Thumbnails/asset
library pass small targets.
2026-06-26 00:36:35 -04:00
Skyler Lehmkuhl f372a84313 Massive tempo refactor - make beats canonical time rep and allow them to be non constant 2026-04-02 10:26:01 -04:00
Skyler Lehmkuhl 6b6ae230a1 Add pitch bend support 2026-03-18 23:11:24 -04:00
Skyler Lehmkuhl ec46e22782 update css handling 2026-03-02 10:32:19 -05:00
Skyler Lehmkuhl 1c7256a12e Add raster layers 2026-03-01 13:16:49 -05:00
Skyler Lehmkuhl 13840ee45f add top-level selection 2026-03-01 10:22:46 -05:00
Skyler Lehmkuhl b87e4325c2 use group layers instead of linked tracks 2026-03-01 09:00:55 -05:00
Skyler Lehmkuhl 99f8dcfcf4 Change vector drawing primitive from shape to doubly-connected edge graph 2026-02-23 21:29:58 -05:00
Skyler Lehmkuhl 469849a0d6 Add nested audio tracks 2026-02-21 03:56:07 -05:00
Skyler Lehmkuhl 3ba6dcb3d2 Group shapes 2026-02-20 11:13:56 -05:00
Skyler Lehmkuhl 21a49235fc sampler improvements, live waveform preview 2026-02-17 10:08:49 -05:00
Skyler Lehmkuhl 777d3ef6be Clean up build warnings 2026-02-14 11:07:32 -05:00
Skyler Lehmkuhl c11dab928c Add spectrogram 2026-02-12 18:37:34 -05:00
Skyler Lehmkuhl 8ac5f52f28 Render audio waveforms on gpu 2026-02-11 14:38:58 -05:00
Skyler Lehmkuhl fc58f29ccd Record audio 2026-02-11 02:28:37 -05:00
Skyler Lehmkuhl c3e1160fa2 add drag preview for asset library 2026-01-13 20:38:51 -05:00
Skyler Lehmkuhl f4ffa7ecdd improve folders a bit 2026-01-13 20:30:16 -05:00
Skyler Lehmkuhl b19f66e648 add folders to asset library 2025-12-30 00:45:19 -05:00
Skyler Lehmkuhl efca9da2c9 show previews for effects 2025-12-08 13:32:11 -05:00
Skyler Lehmkuhl 7eb61ab0a8 start work on compositing, effects 2025-12-08 09:30:22 -05:00
Skyler Lehmkuhl 727d782190 initial audio export 2025-12-03 17:54:15 -05:00
Skyler Lehmkuhl c35b7a31de clean up some compiler warnings 2025-12-03 06:39:26 -05:00
Skyler Lehmkuhl ccb29a9e04 Audio from videos 2025-12-03 01:04:09 -05:00
Skyler Lehmkuhl d453571c9b Video import 2025-12-02 13:39:55 -05:00
Skyler Lehmkuhl ba9a4ee812 File save/load 2025-12-01 09:18:49 -05:00
Skyler Lehmkuhl 5379e3bc8c Import .mid files to midi tracks 2025-12-01 05:35:53 -05:00
Skyler Lehmkuhl c943f7bfe6 Add info panel 2025-11-30 10:01:10 -05:00
Skyler Lehmkuhl 4d1e052ee7 Add asset pane 2025-11-30 06:54:53 -05:00