🧪feat: ReplayGain + Pre-amp support#504
Conversation
- The idea currently is to fetch this as well when getting the database entry for the current/upcoming track.
- No way to turn it off right now. - Don't really know if its working or not.
- We expose a new `setReplayGainStatus` in our `react-native-audio-browser` fork. - Current location in "Playback Options" sheet is temporary - we'll probably have a new "Audio Effects" tab where we'll move this into.
- We'll eventually move some other settings from the Preference store into here (in a different PR).
- First thing we export is an `applyReplayGainToTrack` which handles getting the replaygain tag value & combining it with track data to create a "Track" object that can be passed to AudioBrowser.
- Will only be applied when Replay Gain is enabled.
- Current strategy will result in changes only apply on the next track forwards.
…layGain` feature
- This is due to getting the effect of having 2 opac elements of the same color overlapping each other. - `needsOffscreenAlphaCompositing` is the solution for this case.
- This was due to our "optimization" of not fetching the embedded replay gain tags when we play a track when the feature is disabled.
- React Native docs suggest we turn them off when we're not using them.
📝 WalkthroughWalkthroughThis PR introduces a complete ReplayGain audio processing feature with user-adjustable pre-amp controls. It extends playback state persistence, implements R128 gain fetching with tag-aware pre-amp variants, adds UI settings with navigation integration, and applies gain normalization throughout all track loading paths. ChangesReplayGain Audio Processing
🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@mobile/src/modules/audio/replayGain/core/apply.ts`:
- Around line 16-21: applyReplayGainToTrack currently awaits
getR128Gain(track.uri) without error handling which can throw and break
playback; wrap the await call in a try/catch inside applyReplayGainToTrack
(keeping the existing apply parameter logic) and on any error set replayGain to
null (or otherwise skip using tag gain) so finalDB falls back to preAmpWOTags;
reference the function applyReplayGainToTrack, the call to
getR128Gain(track.uri), and the state variables preAmpWTags/preAmpWOTags from
playbackStore when making the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: ab0688fd-7dff-4bb3-a394-44f6577b1174
⛔ Files ignored due to path filters (1)
mobile/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (18)
mobile/package.jsonmobile/pnpm-workspace.yamlmobile/src/data/track/utils.tsmobile/src/initServices.tsmobile/src/modules/audio/_screens.tsxmobile/src/modules/audio/replayGain/components/ReplayGainSettings.tsxmobile/src/modules/audio/replayGain/core/actions.tsmobile/src/modules/audio/replayGain/core/apply.tsmobile/src/modules/i18n/translations/en.jsonmobile/src/modules/scanning/hooks/useSetup.tsmobile/src/navigation/routes.tsxmobile/src/navigation/screens/settings/ExperimentalSettingsView.tsxmobile/src/resources/icons/GraphicEQ.tsxmobile/src/stores/Playback/actions/playbackControls.tsmobile/src/stores/Playback/actions/queue.tsmobile/src/stores/Playback/actions/resynchronize.tsmobile/src/stores/Playback/constants.tsmobile/src/stores/Playback/store.ts
💤 Files with no reviewable changes (1)
- mobile/src/data/track/utils.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/replaygain.md`:
- Line 5: Update the sentence in docs/replaygain.md that begins "ReplayGain is a
feature..." to clarify that ReplayGain normalizes perceived loudness to a
reference level rather than peak amplitude; specifically replace the phrase "its
peak loudness hits `89 dB`" with wording like "its perceived loudness to a
reference level (commonly cited as 89 dB SPL)"; keep the rest of the sentence
about enabled audio becoming quieter.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: e6205209-74d5-4b47-a4f2-47739049d2ab
📒 Files selected for processing (8)
docs/experimental-features.mddocs/replaygain.mdmobile/src/modules/audio/replayGain/components/ReplayGainSettings.tsxmobile/src/modules/audio/replayGain/core/actions.tsmobile/src/modules/audio/replayGain/core/apply.tsmobile/src/modules/audio/replayGain/core/constants.tsmobile/src/stores/Playback/actions/playbackControls.tsmobile/src/stores/Playback/constants.ts
💤 Files with no reviewable changes (1)
- mobile/src/stores/Playback/actions/playbackControls.ts
✅ Files skipped from review due to trivial changes (2)
- mobile/src/modules/audio/replayGain/core/constants.ts
- docs/experimental-features.md
🚧 Files skipped from review as they are similar to previous changes (3)
- mobile/src/stores/Playback/constants.ts
- mobile/src/modules/audio/replayGain/core/actions.ts
- mobile/src/modules/audio/replayGain/core/apply.ts
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
mobile/src/modules/audio/replayGain/core/actions.ts (1)
8-12:⚠️ Potential issue | 🟠 Major | ⚡ Quick winConsider error handling for native synchronization.
If
AudioBrowser.setReplayGainStatusthrows, the store state will be updated but the native player won't be synchronized, leading to inconsistent behavior. Consider wrapping the native call in a try-catch and reverting the store state on failure, or reordering the operations to call the native API before updating the store.🛡️ Proposed fix with error handling
export function toggleStatus() { - const nextState = !playbackStore.getState().isReplayGainEnabled; - playbackStore.setState({ isReplayGainEnabled: nextState }); - AudioBrowser.setReplayGainStatus(nextState); + const nextState = !playbackStore.getState().isReplayGainEnabled; + try { + AudioBrowser.setReplayGainStatus(nextState); + playbackStore.setState({ isReplayGainEnabled: nextState }); + } catch (error) { + console.error('[ReplayGain] Failed to sync status to native:', error); + throw error; + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@mobile/src/modules/audio/replayGain/core/actions.ts` around lines 8 - 12, The toggleStatus function updates playbackStore before calling the native API (AudioBrowser.setReplayGainStatus), which can cause state drift if the native call fails; change toggleStatus to synchronize with native first or add try/catch around the native call and revert the store on failure. Specifically, either call AudioBrowser.setReplayGainStatus(nextState) before playbackStore.setState(...) (so the store only updates on success), or wrap the native call in try/catch and if it throws call playbackStore.setState({ isReplayGainEnabled: !nextState }) to roll back; reference the toggleStatus function, playbackStore.getState()/setState, and AudioBrowser.setReplayGainStatus when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@mobile/src/modules/audio/replayGain/core/actions.ts`:
- Around line 8-12: The toggleStatus function updates playbackStore before
calling the native API (AudioBrowser.setReplayGainStatus), which can cause state
drift if the native call fails; change toggleStatus to synchronize with native
first or add try/catch around the native call and revert the store on failure.
Specifically, either call AudioBrowser.setReplayGainStatus(nextState) before
playbackStore.setState(...) (so the store only updates on success), or wrap the
native call in try/catch and if it throws call playbackStore.setState({
isReplayGainEnabled: !nextState }) to roll back; reference the toggleStatus
function, playbackStore.getState()/setState, and
AudioBrowser.setReplayGainStatus when making the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 5dc5ae17-9a3e-4377-9bde-f7389b030f82
📒 Files selected for processing (8)
docs/experimental-features.mddocs/replaygain.mdmobile/src/modules/audio/replayGain/components/ReplayGainSettings.tsxmobile/src/modules/audio/replayGain/core/actions.tsmobile/src/modules/audio/replayGain/core/apply.tsmobile/src/modules/audio/replayGain/core/constants.tsmobile/src/stores/Playback/actions/playbackControls.tsmobile/src/stores/Playback/constants.ts
💤 Files with no reviewable changes (1)
- mobile/src/stores/Playback/actions/playbackControls.ts
✅ Files skipped from review due to trivial changes (1)
- mobile/src/modules/audio/replayGain/core/constants.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- mobile/src/stores/Playback/constants.ts
- mobile/src/modules/audio/replayGain/components/ReplayGainSettings.tsx
- mobile/src/modules/audio/replayGain/core/apply.ts
Why
This PR adds experimental support for
ReplayGain& aReplayGain Pre-amp. The strategy on how it gets applied is as followed:getR128Gain()function from our@missingcore/react-native-metadata-retrieverpackage to get the embedded value on the fly.ReplayGain Pre-amp(value used is based on whether there's an embedded ReplayGain tag or not).dBadjustment (given theReplayGainfeature is enabled).Current expectations when
ReplayGainis enabled is for the audio to be noticeably quieter (as it normalize the audio to89 dB).Deep Rescanis not required.These settings currently can only be found in the
Audio Effectssettings screen, which is currently located in theExperimental Featuressettings screen.Checklist
pnpm sync:licenses.pnpm android:prod.Summary by CodeRabbit
New Features
Documentation