Skip to content

refactor: assorted fixes, clean-ups, improvements and performance tuning#47

Merged
flexiondotorg merged 9 commits into
mainfrom
dead
Jun 8, 2026
Merged

refactor: assorted fixes, clean-ups, improvements and performance tuning#47
flexiondotorg merged 9 commits into
mainfrom
dead

Conversation

@flexiondotorg

Copy link
Copy Markdown
Contributor

No description provided.

…able

- Remove Duration and FinalizeTime from RenderComplete (redundant with
  TotalTime)
- Extract borderless table configuration to theme.BorderlessTable()
  shared helper
- Update summary and help tables to use unified table styling
- Simplify timing calculation in Pass 2 completion

Signed-off-by: Martin Wimpress <code@wimpress.io>
- Reuse audioSamples buffer for initial audio write instead of
  allocating
- Merge bar render and mirror loops in Frame.drawBars for clarity
- Remove guard on font face in text overlay (self-guarded method)
- Extract maxLineWidth helper to boxwidth_test.go where it is used
- Remove redundant timing fields from UI model (overallStartTime,
  pass1StartTime, completionTime, quitting) and unused height field

Signed-off-by: Martin Wimpress <code@wimpress.io>
…ities

- Use unsafe.Slice() instead of custom unsafeByteSlice() helper in audio
  decoding
- Replace manual unsafe pointer cast with unsafe.Slice() in encoder
  sample writing
- Replace manual loops with slices.Max() in spectrum rendering
- Replace manual min/max finding with slices.Min/Max in sparkline
  generation

Signed-off-by: Martin Wimpress <code@wimpress.io>
The audio reader downmixes all input to mono. For --channels 2, the
encoder expects interleaved L,R pairs, but mono samples were being sent
unchanged—reinterpreted as interleaved stereo, resulting in half-length,
double-speed, desynchronised audio.

Duplicate each mono sample into both channels (s, s) when building the
encoder buffer for stereo output. Pre-allocate stereoSamples buffer to
avoid per-frame allocation, matching the existing buffer discipline.

Also:
- Add unit tests for internal/yuv RGB→YCbCr conversions (pin fixed-point
  arithmetic against stdlib color.RGBToYCbCr to catch clamp bugs)
- Update justfile test-encoder to exercise --channels 2 and assert
  output audio duration matches source (catches reinterpreted-buffer
  regressions)

Signed-off-by: Martin Wimpress <code@wimpress.io>
…hot paths

Remove allocations from both the FFT analysis and video encode loops by
reusing buffers and pooling resources:

- FFT: fold real→complex conversion into windowing loop, reuse complex
  buffer (0 allocs/op, ~19% faster per ProcessChunk)
- Audio read: introduce ReadInto(dst) to avoid throwaway slices per
  frame
- Audio decode: decode directly into sampleBuffer tail via slices.Grow
- Encoder: pre-allocate and reuse YUV/RGBA frames and video packets
  (software and NVENC paths)
- YUV: replace per-frame goroutine spawning with persistent worker pool

For a 30-minute encode: ~108k FFT allocs eliminated, ~54k per-frame
frame allocations removed, ~864k goroutine spawns eliminated. Realistic
5-15% total wall-clock improvement on CPU-bound encodes. Output
byte-identical verified by TestConversionEquivalence.

Signed-off-by: Martin Wimpress <code@wimpress.io>
Extracted helpers and variants to eliminate code duplication and improve
maintainability:

- Extract expandMonoToStereo helper: stereo channel expansion now lives
  in one place, reducing bug-fix surface (main.go)
- Extract receiveAndWriteAudioPackets helper: consolidate duplicated
  audio packet drain loops; fixes latent bug where FlushAudioEncoder was
  silently swallowing write errors (encoder.go)
- Add SelectBestEncoderFrom variant: hardware encoder selection now
  accepts a pre-probed slice, eliminating redundant probe calls on the
  error path (hwaccel.go, main.go)
- Consolidate image path dispatch: custom-vs-default resolution now
  lives solely in RuntimeConfig.Get*ImagePath methods, removing
  duplicated logic from renderer call sites (config.go,
  renderer/assets.go, renderer/thumbnail.go)

The FlushAudioEncoder fix means failed audio packet writes during the
final flush are no longer silently discarded; they now propagate as
errors.

Signed-off-by: Martin Wimpress <code@wimpress.io>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 24 files

Confidence score: 3/5

  • There is a concrete regression risk in internal/encoder/encoder.go: worker goroutines are started before fallible setup, and failure paths return without shutting them down.
  • Because this issue is medium severity (6/10) with high confidence (9/10), it can cause resource/goroutine leaks during initialization errors and may impact stability over time.
  • Pay close attention to internal/encoder/encoder.go - ensure all init-error paths cleanly stop/close started workers before returning.

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread internal/encoder/encoder.go
…s, and eliminate encoder allocations

- Fix A/V sync drift for non-44.1 kHz inputs by deriving samplesPerFrame
  from the file's actual sample rate instead of assuming hardcoded 44100
  Hz. Update metadata tracking and config comments to clarify per-frame
  budget calculation.
- Surface non-fatal asset-load warnings (background image, font) after
  Bubbletea alt screen exits so they remain visible instead of being
  silently dropped. Add PrintWarning helper to CLI styles.
- Eliminate per-iteration alloc/free cycle in encoder.Close() drain loop
  by reusing the shared e.pkt; consolidate inline channel layout mapping
  to channelLayoutName helper function.

Signed-off-by: Martin Wimpress <code@wimpress.io>
Stop RowPool workers if a later setup step fails, preventing goroutine
leaks. Use named return with error guard to clean up resources before
returning an error, since the caller only defers Close once Initialize
returns successfully.

Signed-off-by: Martin Wimpress <code@wimpress.io>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 6 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread cmd/jivefire/main.go
Comment thread internal/audio/analyzer.go
Comment thread cmd/jivefire/main.go
…Warnings race

- Guard samplesPerFrame divisions against zero/negative rates to prevent
  divide-by-zero panic in Pass 1 estimate and infinite loop in analyzer
- Move assetWarnings from shared slice to RenderComplete message field
  to eliminate data race between goroutines; caller reads warnings from
  final model after p.Run() returns

Signed-off-by: Martin Wimpress <code@wimpress.io>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 3 files (changes from recent commits).

Requires human review: The PR modifies over 1000 lines across 20+ files touching core logic in audio analysis, encoding, frame rendering, streaming I/O, and UI progress, which carries significant risk of regression even though the AI review found no issues.

Re-trigger cubic

@flexiondotorg flexiondotorg merged commit 73c7922 into main Jun 8, 2026
16 checks passed
@flexiondotorg flexiondotorg deleted the dead branch June 8, 2026 00:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant