Skip to content

feat: Support for modifying playback pitch#507

Merged
cyanChill merged 8 commits into
devfrom
feat/pitch
Jun 6, 2026
Merged

feat: Support for modifying playback pitch#507
cyanChill merged 8 commits into
devfrom
feat/pitch

Conversation

@cyanChill

@cyanChill cyanChill commented Jun 6, 2026

Copy link
Copy Markdown
Member

Why

This PR adds support for modifying the pitch of the current track. This setting appears in the "Audio Effects" screen when we navigate to it via the "Playback Options" sheet.

Other Changes

  • Fixed debouncing logic not working the way we expect when _debounceMultipler = 1 due to floating point math.
  • Make it less likely for horizontal sliders to interrupt scroll.
  • Revised the design of the "Playback Speed" slider to match the design of the slider used for "ReplayGain Pre-amp".

Checklist

  • Documentation is up to date to reflect these changes.
  • Ensure dependency licenses are up-to-date by running pnpm sync:licenses.
  • This diff will work correctly for pnpm android:prod.

Summary by CodeRabbit

  • New Features

    • Playback pitch adjustment: new settings UI with real-time slider, presets, and a voice-selection icon.
    • Combined playback parameter settings panel exposing pitch and speed controls.
  • Refactor

    • Improved slider debouncing and numeric rounding to reduce floating‑point jitter.
    • Pre-amp slider debounce behavior adjusted for smoother interactions.
  • Removed

    • Legacy playback speed setting replaced by the new parameter settings.

cyanChill added 7 commits June 5, 2026 17:08
- Currently, we copy & pasted the Playback Speed setting design.
- We're going to update the design of these 2 components & make the layout more reusable.
- Called this group "PlaybackParametersSetting" since both speed & pitch are set via the `PlaybackParameters` class in ExoPlayer.
- There was a chance when using `_debounceMultiplier={1}` where `Math.abs(debounceFrom.get() - value)` may not be exact due to the floating-point math being off.
- It was due to the initial fix to the issue where changing the pitch may result in playback breaking.
- This is only really effective when the slider is in a scrollable list.
- This helps prevent accidentally activating the Playback Speed, Playback Pitch, and ReplayGain Pre-amp while scrolling the "Audio Effects" screen.
@cyanChill cyanChill added the enhancement New feature or request label Jun 6, 2026
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a37248d2-e46f-458d-b765-fcf86bfc1143

📥 Commits

Reviewing files that changed from the base of the PR and between 2bb2555 and 59d7752.

📒 Files selected for processing (1)
  • mobile/src/modules/audio/_components/PlaybackParameterSlider.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • mobile/src/modules/audio/_components/PlaybackParameterSlider.tsx

📝 Walkthrough

Walkthrough

This PR adds pitch control to playback settings via new parameterized slider components, improves CachedSlider debouncing to respect step decimal precision and gesture activation, persists playbackPitch in the session store, and updates the audio settings screen and related assets.

Changes

Playback Pitch Control

Layer / File(s) Summary
Session store contract and utility helpers
mobile/src/stores/Session/constants.ts, mobile/src/stores/Session/store.ts, mobile/src/utils/number.ts, mobile/package.json
Session store gains playbackPitch (initialized to 1, documented 0.25–2). Adds countDecimals utility for numeric precision. react-native-audio-browser dependency commit pin updated.
CachedSlider precision and gesture improvements
mobile/src/components/Form/Slider.tsx, mobile/src/modules/audio/replayGain/components/PreAmpSlider.tsx
CachedSlider debouncing computes decimal precision from step and rounds deltas before threshold comparison; adds roundToDecimal worklet and explicit activeOffsetX/activeOffsetY gesture configuration. PreAmpSlider _debounceMultiplier changed to 1.
Playback parameter slider components and UI
mobile/src/modules/audio/_components/PlaybackParameterSlider.tsx, mobile/src/modules/audio/_components/PlaybackParameterSettings.tsx, mobile/src/resources/icons/VoiceSelection.tsx, mobile/src/modules/i18n/translations/en.json
Adds PlaybackParameterSlider (session syncing, Reanimated shared value, presets, formatted display) and PlaybackParameterSettings composing pitch and speed sliders. Introduces VoiceSelection icon and feat.playback.extra.pitch translation.
Audio effects screen integration
mobile/src/modules/audio/_screens.tsx
Swaps hidden playback UI: replaces PlaybackSpeedSetting with PlaybackParameterSettings and updates imports.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Support for modifying playback pitch' directly and clearly summarizes the main change—adding pitch modification capability to the audio playback settings.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
mobile/src/modules/audio/_components/PlaybackParameterSlider.tsx (1)

27-34: 💤 Low value

Remove unnecessary eslint-disable comment.

The dependency array [props.onUpdate, fieldName] appears complete - all values used in the callback are listed. The eslint-disable-next-line react-hooks/exhaustive-deps comment on line 32 may be unnecessary.

♻️ Proposed cleanup
  const setField = useCallback(
    (value: number) => {
      sessionStore.setState({ [fieldName]: value });
      props.onUpdate(value);
    },
-    // eslint-disable-next-line react-hooks/exhaustive-deps
    [props.onUpdate, fieldName],
  );
🤖 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/_components/PlaybackParameterSlider.tsx` around
lines 27 - 34, Remove the unnecessary eslint-disable comment above the
useCallback for setField: the dependency array already includes props.onUpdate
and fieldName which are the only external values used, so delete the "//
eslint-disable-next-line react-hooks/exhaustive-deps" line and keep the
useCallback as-is (setField -> sessionStore.setState({ [fieldName]: value });
props.onUpdate(value);) to let the linter validate the deps for setField.
🤖 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/_components/PlaybackParameterSlider.tsx`:
- Around line 24-25: The slider's local shared value cachedValue (created via
useSharedValue) is only initialized from storedValue and won't update if
useSessionStore's storedValue changes; inside PlaybackParameterSlider.tsx add a
useEffect that watches storedValue (and cachedValue) and calls
cachedValue.set(storedValue) so the shared value stays in sync with external
updates from useSessionStore.

---

Nitpick comments:
In `@mobile/src/modules/audio/_components/PlaybackParameterSlider.tsx`:
- Around line 27-34: Remove the unnecessary eslint-disable comment above the
useCallback for setField: the dependency array already includes props.onUpdate
and fieldName which are the only external values used, so delete the "//
eslint-disable-next-line react-hooks/exhaustive-deps" line and keep the
useCallback as-is (setField -> sessionStore.setState({ [fieldName]: value });
props.onUpdate(value);) to let the linter validate the deps for setField.
🪄 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: 94b4f25a-c96a-4d50-85db-8485b6fb4f29

📥 Commits

Reviewing files that changed from the base of the PR and between 5868365 and 2bb2555.

⛔ Files ignored due to path filters (1)
  • mobile/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • mobile/package.json
  • mobile/src/components/Form/Slider.tsx
  • mobile/src/modules/audio/_components/PlaybackParameterSettings.tsx
  • mobile/src/modules/audio/_components/PlaybackParameterSlider.tsx
  • mobile/src/modules/audio/_components/PlaybackSpeedSetting.tsx
  • mobile/src/modules/audio/_screens.tsx
  • mobile/src/modules/audio/replayGain/components/PreAmpSlider.tsx
  • mobile/src/modules/i18n/translations/en.json
  • mobile/src/resources/icons/VoiceSelection.tsx
  • mobile/src/stores/Session/constants.ts
  • mobile/src/stores/Session/store.ts
  • mobile/src/utils/number.ts
💤 Files with no reviewable changes (1)
  • mobile/src/modules/audio/_components/PlaybackSpeedSetting.tsx

Comment thread mobile/src/modules/audio/_components/PlaybackParameterSlider.tsx
@cyanChill cyanChill merged commit 2804e8c into dev Jun 6, 2026
1 check passed
@cyanChill cyanChill deleted the feat/pitch branch June 6, 2026 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant