Skip to content

Conversation

@MrSimmo
Copy link

@MrSimmo MrSimmo commented Jan 29, 2026

I noticed a gap in the market for music players that have really decent, but easy to use, Parametric EQ capabilities. Amperfy is my go-to music player. So I wrote one!

This PR swaps the existing graphic EQ system for a comprehensive Parametric EQ system.

I've run it through the testing and formatting tools in the Amperfy repo, all of which pass. I've built it locally on my Mac and tested using simulators, but would welcome on-device testing.

It would be great to be able to allow the user to switch between the existing graphic and Parametric EQ's. Happy to build this functionality out if useful.

  • Replace fixed 10-band graphic EQ with fully parametric EQ
  • Support Bell, Low Shelf, and High Shelf filter types
  • Add interactive frequency response curve with draggable nodes
  • Implement undo/redo stack
  • Add automatic migration from legacy graphic EQ presets
  • Include unit tests for band parameters and migration logic

Features:

  • Interactive frequency response curve with draggable band nodes
  • Flexible filter types: Bell (parametric), Low Shelf, High Shelf
  • Per-band controls: Frequency (20Hz-20kHz), Gain (-12 to +12 dB), Q (0.1-10.0)
  • Professional features: Undo/Redo, A-B comparison, global bypass
  • Automatic migration from existing graphic EQ presets

Changes

New Files

  • Amperfy/SwiftUI/Settings/Player/ParametricEQ/ (5 files)
  • AmperfyKitTests/Cases/Player/ParametricEQTest.swift

Modified Files

  • AmperfyKit/Storage/PersistentStorage.swift - New types and settings
  • AmperfyKit/AmperfyKit.swift - Migration logic
  • AmperfyKit/Player/BackendAudioPlayer.swift - Parametric EQ engine
  • AmperfyKit/Player/PlayerFacade.swift - Protocol update
  • Amperfy/SwiftUI/Settings/ObservableSettings.swift - Observable properties
  • Amperfy/SwiftUI/Settings/Player/EqualizerSettingsView.swift - UI rewrite
  • Amperfy/Screens/ViewController/SettingsHostVC.swift - Settings bindings

Testing

  • Unit tests for band parameters and migration
  • Manual testing on device
  • Code formatted with ./BuildTools/applyFormat.sh

Screenshots

image image

- Replace fixed 10-band graphic EQ with fully parametric EQ
- Support Bell, Low Shelf, and High Shelf filter types
- Add interactive frequency response curve with draggable nodes
- Implement undo/redo stack and A-B comparison
- Add automatic migration from legacy graphic EQ presets
- Include unit tests for band parameters and migration logic

nonisolated private func addLowPrio(objects: [(DownloadElementInfo, Downloadable)], library: LibraryStorage) -> [(DownloadElementInfo, Downloadable, Download)] {

nonisolated private func addLowPrio(
Copy link
Owner

@BLeeEZ BLeeEZ Jan 29, 2026

Choose a reason for hiding this comment

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

This looks like a merge error.

@@ -229,6 +229,7 @@ public protocol PlayerFacade {

func updateEqualizerEnabled(isEnabled: Bool)
func updateEqualizerSetting(eqSetting: EqualizerSetting)
Copy link
Owner

Choose a reason for hiding this comment

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

I think this could be removed since we only use the ParametricEQ

@@ -509,6 +510,10 @@ class PlayerFacadeImpl: PlayerFacade {
backendAudioPlayer.updateEqualizerSetting(eqSetting: eqSetting)
Copy link
Owner

Choose a reason for hiding this comment

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

This one too.

return downloadMOs?.compactMap { Download(managedObject: $0) } ?? [Download]()
}

Copy link
Owner

Choose a reason for hiding this comment

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

remove

set { _activeParametricEqualizerSetting = newValue }
}

private var _equalizerMigrationCompleted: Bool = false
Copy link
Owner

Choose a reason for hiding this comment

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

This is not needed. Check that the old EQ Settings are not empty. Do the conversion once and let the old EQ settings.


private func migrateEqualizerSettingsIfNeeded() {
// Check if migration has already been completed
guard !storage.settings.user.equalizerMigrationCompleted else { return }
Copy link
Owner

Choose a reason for hiding this comment

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

Check for old EQ settings are empty

Copy link
Owner

@BLeeEZ BLeeEZ left a comment

Choose a reason for hiding this comment

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

Great job. The settings view looks great. To be honest the calculation is way over my head. I have no idea if that what is displayed is correctly applied to the audio engine. I left a couple of comments.

@BLeeEZ
Copy link
Owner

BLeeEZ commented Jan 30, 2026

I have two other questions:

  1. Why did changed from +-6dB to +-12dB range. Is there a special reason? I received a couple of messages that would like a range of +-10dB.
  2. Is the old fixed frequency editor complete obsolete or should the old one be supported too?

@MrSimmo
Copy link
Author

MrSimmo commented Jan 31, 2026

Thanks BLeeEZ,

I'll go through and apply the changes and update 😊

I used the CoreAudio engine calculations as the base, so hopefully they should be accurate. You never know with Apple whether that will change something in the future which will break the calculations.

It's a very good thought, I will try to add a 'detail' slider to hide/show the detail such as the gain/cut calculations as some users may find it too technical.

For your other questions:

  1. This is my background in music production coming to my design - most prosumer/pro EQs have a boost/cut range of +-12db so I went with that. It would be easy enough to change the range in the UI t another value if you felt it would be better to change it?
  2. Very good question, Im not sure of the answer. I would not use the graphic eq if there were a parametric eq available, but others may wish to. I didn't remove the code for the Graphic EQ so I could add a switch between them. It might make it overly complicated for the user though. What do you think?
    2a - I added a migration task as well in the code so any presets that the user had previously created would be migrated to the Parametric eq. Hopefully helps the user journey.

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.

3 participants