Commit Graph

149 Commits

Author SHA1 Message Date
Skyler Lehmkuhl 2e07a88905 Phase 3a-2: async raster page-in (no UI block)
The fault-in drain no longer decodes on the UI thread. It now:
- dispatches each newly-requested keyframe's page-in to a background thread
  (deduped via an in-flight set, store cloned per request so path changes are
  picked up), and
- applies completed results from a channel at the top of update(), keeping the UI
  ticking while loads are outstanding.

Cold scrubs no longer freeze. The brief blank gap before a frame lands is removed
by the image proxy (3a-3); eviction to bound RAM while scrubbing is 3b.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 17:00:04 -04:00
Skyler Lehmkuhl 4228864259 Phase 3a-1: lazy fault-in of raster keyframe pixels
Raster keyframes are no longer eagerly decoded at load — `raw_pixels` stays empty
and is paged in on demand from the project container, so a big paint project opens
instantly and only touched frames hit RAM.

- core: `read_packed_media_readonly` (fresh read-only connection, can't conflict
  with an in-place save) + `RasterStore` (holds the container path; `load_pixels`
  reads+decodes a keyframe's PNG by id). `load_beam_sqlite` stops eager-decoding and
  instead marks every raster keyframe `needs_fault_in` (recursively, incl. nested);
  a freshly-created keyframe stays false (blank-resident, nothing to page). Added
  `Document::all_layers_mut`.
- editor: the canvas records a fault-in request when it needs a paged-out keyframe
  (empty pixels && needs_fault_in); the App drains the sink at the top of update(),
  pages the pixels in via the store, clears the flag, and repaints. Store path is set
  on load and after save. Export faults in synchronously per frame.

Cold-scrub still shows a 1-frame gap and the page-in is synchronous; the image proxy
(3a-2) and async load (3a-3) remove those next.
2026-06-19 16:59:46 -04:00
Skyler Lehmkuhl 097345be76 Fix video thumbnail strip bugs + persist thumbnails (resumable)
Thumbnail rendering fixes:
- Strip now tiles from each clip's true (unclamped) origin and draws only the
  tiles intersecting the visible rect, so it scrolls correctly and shows the
  right frames when a clip is scrolled partly off the left. Both render sites
  (collapsed group + expanded track) share one draw_video_thumbnail_strip helper.
- On-clip strip no longer freezes on the first thumbnail: get_thumbnail_at now
  returns the actual thumbnail timestamp and the GPU texture cache keys on it, so
  tiles refresh as closer thumbnails finish generating.
- Hover preview derives content time from the clip's true origin too (matches the
  strip when scrolled off-screen).
- insert_thumbnail keeps the cache sorted + deduped (fixes a latent unsorted
  binary_search bug, and makes concurrent restore + resume race-safe).

Thumbnail persistence (mirrors waveform persistence):
- MediaKind::Thumbnail rows, keyed by thumbnail_media_id(clip_id) (clip id XOR a
  sentinel). Each clip's thumbnails PNG-encoded into one opaque LBTN blob (editor
  owns the format), snapshotted cheaply (Arc clones) and encoded off the UI thread.
- Save writes the packs (kept in place on re-save); load reads them into
  LoadedProject.thumbnail_blobs; the editor decodes + inserts them on a background
  thread, so reload shows thumbnails instantly with no re-decode (even if the
  source video file is missing).
- Partial sets are persisted with a complete flag and RESUMED on load:
  generate_keyframe_thumbnails takes a should_skip predicate so a save made
  mid-generation continues from where it left off instead of redoing the work.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 15:36:56 -04:00
Skyler Lehmkuhl 3d7cff9ad0 Stream audio & video from .beam container; waveform LOD pyramid + persistence
Migrate the .beam container to SQLite and stream media from it instead of
decoding whole files into RAM on import/load.

Container & large files:
- SQLite .beam container (beam_archive) with in-place transactional saves and an
  incremental BlobReader; supports both packed (chunked blobs) and referenced
  (external path) media, with a user preference + first-import prompt for files
  over the large-media threshold.

Audio streaming:
- Stream packed compressed audio on load via an inversion-of-control blob factory
  (AudioBlobSourceFactory): daw-backend defines the trait, core implements it
  over BlobReader, so the audio engine stays container-agnostic.
- Bulk-activate disk streaming for all loaded clips after SetProject.
- Sample-accurate compressed seek (SeekMode::Accurate; Coarse mislands on VBR).

Video:
- Video frames decoded/streamed on demand; thumbnails generated asynchronously
  on a dedicated decoder so import/load never blocks the UI.
- The video's audio track is streamed on demand via an ffmpeg VideoAudioReader
  as a separate editable AudioClip (no /tmp WAV extraction).

Waveform overview:
- Streaming min/max LOD pyramid (waveform_pyramid), bounded memory, configurable
  floor B; serialized into the container and restored on load (or generated in
  the background from the packed blob when absent), so no re-decode on reload.
- GPU min/max upload path; integer-LOD textureLoad fixes zoom-dependent wobble.
2026-06-17 13:52:38 -04:00
Skyler Lehmkuhl 83609cc9dc Fix video export resolution scaling and post-export UI hang
- Scale the document to the selected output resolution. It was rendered
  at document size regardless of the export dimensions, so picking a
  different resolution didn't scale the stage.
- Run the audio+video mux on a background thread instead of the UI
  thread, keeping the app responsive (showing "Finalizing") during the
  re-mux pass.
- Send desktop notifications fire-and-forget. notify_rust's show() is a
  synchronous D-Bus call that blocked the UI for the full service
  activation timeout (~25s) when no notification daemon is running.
2026-06-16 08:35:52 -04:00
Skyler Lehmkuhl 54d5764bd0 Make beats canonical representation rather than seconds 2026-06-02 13:06:36 -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 cfb8e4462b All events now have three time references for seconds, measures/beats, frames 2026-03-30 10:15:55 -04:00
Skyler Lehmkuhl 65a550d8f4 Add piano roll note snapping 2026-03-24 19:24:24 -04:00
Skyler Lehmkuhl 434b488a4c Merge branch 'rust-ui' of https://git.skyler.io/skyler/Lightningbeam into rust-ui 2026-03-22 18:16:25 -04:00
Skyler Lehmkuhl f16e651610 work on vector graph 2026-03-22 18:16:17 -04:00
Skyler Lehmkuhl 0d7f15853c Set default timeline mode based on activity 2026-03-20 21:05:00 -04:00
Skyler Lehmkuhl 121fa3a50a Add count-in 2026-03-20 20:51:50 -04:00
Skyler Lehmkuhl c938ea44b0 Add metronome 2026-03-19 01:16:26 -04:00
Skyler Lehmkuhl 84a1a98452 Snap to beats in measures mode 2026-03-19 00:47:15 -04:00
Skyler Lehmkuhl 6b6ae230a1 Add pitch bend support 2026-03-18 23:11:24 -04:00
Skyler Lehmkuhl 4f3da810d0 Add automation inputs for audio graphs 2026-03-18 11:25:48 -04:00
Skyler Lehmkuhl be8514e2e6 Fix midi tracks recording previews 2026-03-11 12:53:26 -04:00
Skyler Lehmkuhl 3bc980d08d Use audio engine as source of truth for audio tracks 2026-03-11 12:37:31 -04:00
Skyler Lehmkuhl b8f847e167 Add drawing tablet input support 2026-03-11 10:58:30 -04:00
Skyler Lehmkuhl ce7ed2586f Support Vello CPU fallback on systems with older GPUs 2026-03-10 21:39:01 -04:00
Skyler Lehmkuhl 7a3f522735 Give metatracks explicit node graphs 2026-03-10 20:20:46 -04:00
Skyler Lehmkuhl 4118c75b86 Performance tweaks 2026-03-10 03:24:03 -04:00
Skyler Lehmkuhl ac2b4ff8ab Improve idle performance 2026-03-10 02:41:44 -04:00
Skyler Lehmkuhl 06973d185c Merge branch 'rust-ui' of https://git.skyler.io/skyler/Lightningbeam into rust-ui 2026-03-09 13:41:48 -04:00
Skyler Lehmkuhl dc93f78dc7 More work on DCEL correctness 2026-03-09 13:41:45 -04:00
Skyler Lehmkuhl 78e296ffde Improve export performance 2026-03-09 13:39:56 -04:00
Skyler Lehmkuhl a18a335c60 Export images 2026-03-09 11:22:51 -04:00
Skyler Lehmkuhl 09856ab52c Refactor tools and fix bugs 2026-03-08 18:44:32 -04:00
Skyler Lehmkuhl 1900792fa9 Magic wand selection 2026-03-07 03:39:09 -05:00
Skyler Lehmkuhl 922e8f78b6 Refactor tools 2026-03-06 10:07:24 -05:00
Skyler Lehmkuhl 901aa04246 Add sponge tool 2026-03-06 09:17:35 -05:00
Skyler Lehmkuhl 6590b249d1 Add dodge/burn tool 2026-03-06 09:05:14 -05:00
Skyler Lehmkuhl 7d55443b2a Add pattern stamp tool 2026-03-06 08:40:17 -05:00
Skyler Lehmkuhl 2c9d8c1589 Add tool skeletons 2026-03-06 07:22:50 -05:00
Skyler Lehmkuhl d1f47d7164 Merge branch 'rust-ui' of /home/skyler/Dev/Lightningbeam-2/. into rust-ui 2026-03-06 06:19:48 -05:00
Skyler Lehmkuhl 553cc383d5 separate brush and eraser in infopanel 2026-03-06 05:24:26 -05:00
Skyler Lehmkuhl f2c15d7f0d brush fixes and improvements 2026-03-05 20:24:38 -05:00
Skyler Lehmkuhl f97e61751f Fix DCEL selection bugs 2026-03-05 19:55:39 -05:00
Skyler Lehmkuhl 292328bf87 add brush library 2026-03-04 16:42:43 -05:00
Skyler Lehmkuhl e578aadd61 Merge branch 'rust-ui' of /home/skyler/Dev/Lightningbeam-2/. into rust-ui 2026-03-04 14:43:18 -05:00
Skyler Lehmkuhl 16b0d822e3 painting fixes 2026-03-04 14:40:08 -05:00
Skyler Lehmkuhl 885c52c02a organize raster buffers better 2026-03-02 11:24:12 -05:00
Skyler Lehmkuhl 6b3a286caf css fixes 2026-03-02 10:51:58 -05:00
Skyler Lehmkuhl ec46e22782 update css handling 2026-03-02 10:32:19 -05:00
Skyler Lehmkuhl 73ef9e3b9c fix double paste and make selections always floating 2026-03-02 09:19:55 -05:00
Skyler Lehmkuhl 6f1a706dd2 fix interaction with a fresh raster layer 2026-03-02 08:07:45 -05:00
Skyler Lehmkuhl 19617e4223 fix pasting image data from external programs 2026-03-02 07:59:29 -05:00
Skyler Lehmkuhl c1266c0377 remove legacy path that was still dumping into text clipboard 2026-03-02 07:54:14 -05:00
Skyler Lehmkuhl 75e35b0ac6 Don't dump json into text clipboard 2026-03-02 07:30:09 -05:00