Skip to content

Convert tracks with ffmpeg on the way to a USB - #17

Merged
claw1200 merged 2 commits into
mainfrom
usb-export-convert
Oct 27, 2026
Merged

claw1200 merged 2 commits into
mainfrom
usb-export-convert

Conversation

@claw1200

Copy link
Copy Markdown
Owner

Part 5 of the "convert audio on USB export" series. Stacked on #16; the SDK submodule points at claw1200/es-rekordbox-sdk#3 (which includes #2) — re-point after those merge.

Backend for "convert tracks to a chosen format when exporting to USB". Nothing in the library changes: conversion happens inside the USB export, straight onto the stick.

Flow

usb.syncReview / usb.sync accept an optional convert preset (same shape as track conversion) → main → es-node (clean_preset) → es-engine inspect_volume / sync_volume(…, convert) → USB job schema 4 gains conversion → es-usb builds an Ffmpeg converter and passes it to rb_usb::Options.converter for both the review and the export (so the review token covers the chosen format).

es-usb Ffmpeg converter (AudioConverter from SDK #3)

  • wants: es_convert::matches_format is false → only tracks not already in the format are converted (format only, quality ignored).
  • convert: es_convert::encode into the stick's staging, then reads bitrate/sample rate/bit depth (es_tags, as library conversion does) and the delay offset (delay_offset_ms).
  • shift_analysis: rb_anlz::write::shift_timeline (SDK improve db latency #2) — grid and detail waveforms move like library conversion (Move rekordbox's detail waveforms with the grid when converting a track #15).
  • profile: es-ffmpeg-v1:<format>-<quality>; bump ENCODER_VERSION if output changes and sticks should be re-converted.
  • ffmpeg is checked up front for an export (inherits EXPORTSTUDIO_FFMPEG from the app).
  • The SDK's converting stage now reports as its own convert phase instead of copy.

Behaviour verified end-to-end (es-engine/tests/sync.rs, real es-usb + ffmpeg)

  • Sync with MP3 128: the stick gets One.mp3 at 128 kbps; the library row still points at One.wav; nothing is written beside the library file.
  • Review again with the same preset: copy 0, convert 0, keep 1; a second sync has no copy/convert phase.
  • Review without conversion: copy 1 (the original goes back).

The UI (format picker, plan counts, phase label) follows in the next PR; until then nothing sends convert, so behaviour is unchanged.

Note: es-engine sync tests use the es-usb found by exporter(); a stale target/release/es-usb (schema 3) will fail them — set EXPORTSTUDIO_USB_EXPORT to the debug build or rebuild release.

A sync and its review can name a format. The USB job (schema 4) carries it,
and es-usb hands the SDK an ffmpeg converter: tracks not already in that
format are encoded straight onto the stick, their cues, beat grid and detail
waveforms moved by the encoder delay. The library and its files are left as
they are. The stick records each conversion, so syncing again with the same
format re-encodes and re-copies nothing, and the review says so.

Converting gets its own progress phase. The SDK submodule moves to the
branch with the converter hook.

Copilot AI 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.

🟡 Changes recommended

AAC bitrate metadata can be inaccurate, and the outdated device-import fixture is rejected by the new job schema.

2 open issues
What changed in this PR

Adds backend support for converting audio during USB export without changing library files. The conversion preset flows through the app and native layers into the USB exporter; UI controls remain deferred.

Changes:

  • Pass optional conversion presets through review and sync using job schema 4.
  • Add an ffmpeg converter with output metadata, analysis shifting, size estimates, and a distinct conversion phase.
  • Extend sync-plan types and tests for converted exports and unchanged repeat syncs.
File Description
native/​crates/​es-usb/​src/​main.rs Accepts schema 4 jobs and connects the converter to review and export.
native/​crates/​es-usb/​src/​convert.rs Implements ffmpeg conversion and associated metadata handling.
native/​crates/​es-usb/​Cargo.toml Adds conversion, tag-reading, and analysis dependencies.
native/​crates/​es-node/​src/​usb.rs Validates and forwards conversion presets.
native/​crates/​es-node/​src/​library.rs Exposes optional presets through native bindings.
native/​crates/​es-engine/​tests/​sync.rs Covers converted exports, library preservation, and repeat syncs.
native/​crates/​es-engine/​src/​sync.rs Serializes conversion presets into schema 4 jobs.
native/​crates/​es-engine/​src/​library.rs Threads presets through library service methods.
native/​Cargo.lock Records the USB exporter's added dependencies.
app/​src/​preload/​engine.ts Defines conversion parameters and expanded sync-plan fields.
app/​src/​main/​library.ts Forwards conversion parameters to native methods.
app/​src/​main/​audio/​native.ts Updates native interface signatures for optional conversion.

Review effort: Balanced

Comment thread native/crates/es-usb/src/convert.rs Resolved
Comment thread native/crates/es-usb/src/main.rs Resolved
…test uses job schema 4

Only MP3 is encoded at a constant bitrate, so other conversions record the
bitrate measured from the output (the requested one when none is read). The
device import fixture sends job schema 4 like the exporter now expects. The
SDK moves to the reviewed converter branch.
@claw1200
claw1200 changed the base branch from es-convert-crate to main October 27, 2026 21:30
@claw1200
claw1200 merged commit a0a7115 into main Oct 27, 2026
3 checks passed
@claw1200
claw1200 deleted the usb-export-convert branch October 27, 2026 21:31
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.

2 participants