diff --git a/packages/app/constants/settings/components/slidersWithPresets/index.jsx b/packages/app/constants/settings/components/slidersWithPresets/index.jsx
new file mode 100644
index 00000000..634f290f
--- /dev/null
+++ b/packages/app/constants/settings/components/slidersWithPresets/index.jsx
@@ -0,0 +1,127 @@
+import React from "react"
+import { Select, Input, Button, Modal } from "antd"
+import { Icons } from "components/Icons"
+
+import Sliders from "../sliderValues"
+
+export default (props) => {
+ const [selectedPreset, setSelectedPreset] = React.useState(props.controller.presets.currentPresetKey)
+ const [presets, setPresets] = React.useState(props.controller.presets.presets ?? {})
+
+ const createPreset = (key) => {
+ setPresets(props.controller.createPreset(key))
+ setSelectedPreset(key)
+ }
+
+ const handleCreateNewPreset = () => {
+ app.layout.modal.open("create_preset", (props) => {
+ const [presetKey, setPresetKey] = React.useState("")
+
+ return
+
New preset
+
+ {
+ setPresetKey(e.target.value.trim())
+ }}
+ />
+
+
+
+ })
+ }
+
+ const handleDeletePreset = () => {
+ Modal.confirm({
+ title: "Delete preset",
+ content: "Are you sure you want to delete this preset?",
+ onOk: () => {
+ props.controller.deletePreset(selectedPreset)
+ setPresets(props.controller.presets.presets ?? {})
+ setSelectedPreset(props.controller.presets.currentPresetKey)
+ }
+ })
+ }
+
+ const options = [
+ {
+ value: "new",
+ label: Create new,
+ },
+ ...Object.keys(presets).map((key) => {
+ return {
+ value: key,
+ label: key,
+ }
+ })
+ ]
+
+ React.useEffect(() => {
+ const presets = props.controller.presets.presets ?? {}
+ const preset = presets[selectedPreset]
+
+ if (props.controller.presets.currentPresetKey !== selectedPreset) {
+ props.controller.changePreset(selectedPreset)
+ }
+
+ props.ctx.updateCurrentValue(preset)
+ }, [selectedPreset])
+
+ return <>
+
+
+
+
+
+ >
+}
\ No newline at end of file
diff --git a/packages/app/constants/settings/player/index.jsx b/packages/app/constants/settings/player/index.jsx
index 3fcc8935..da9ee37d 100755
--- a/packages/app/constants/settings/player/index.jsx
+++ b/packages/app/constants/settings/player/index.jsx
@@ -1,5 +1,7 @@
import loadable from "@loadable/component"
+
+
export default {
id: "player",
icon: "PlayCircleOutlined",
@@ -104,27 +106,10 @@ export default {
group: "general",
description: "Adjust compression values (Warning: may cause distortion when changing values)",
experimental: true,
- extraActions: [
- {
- id: "reset",
- title: "Reset",
- icon: "MdRefresh",
- onClick: (ctx) => {
- const values = app.cores.player.compressor.resetDefaultValues()
-
- ctx.updateCurrentValue(values)
- }
- }
- ],
- defaultValue: () => {
- return app.cores.player.compressor.values
+ dependsOn: {
+ "player.compressor": true
},
- onUpdate: (value) => {
- app.cores.player.compressor.modifyValues(value)
-
- return value
- },
- component: loadable(() => import("../components/sliderValues")),
+ component: loadable(() => import("./items/player.compressor")),
props: {
valueFormat: (value) => `${value}dB`,
sliders: [
@@ -163,8 +148,22 @@ export default {
},
],
},
- dependsOn: {
- "player.compressor": true
+ extraActions: [
+ {
+ id: "reset",
+ title: "Reset",
+ icon: "MdRefresh",
+ onClick: async (ctx) => {
+ const values = await app.cores.player.compressor.resetDefaultValues()
+
+ ctx.updateCurrentValue(values)
+ }
+ }
+ ],
+ onUpdate: (value) => {
+ app.cores.player.compressor.modifyValues(value)
+
+ return value
},
storaged: false,
},
@@ -201,7 +200,7 @@ export default {
group: "general",
icon: "MdGraphicEq",
description: "Enable equalizer for audio output",
- component: loadable(() => import("../components/sliderValues")),
+ component: loadable(() => import("./items/player.eq")),
extraActions: [
{
id: "reset",
@@ -212,12 +211,12 @@ export default {
ctx.updateCurrentValue(values)
}
- }
+ },
],
usePadding: false,
props: {
valueFormat: (value) => `${value}dB`,
- marks:[
+ marks: [
{
value: 0,
}
@@ -286,20 +285,9 @@ export default {
}
]
},
- defaultValue: () => {
- const values = app.cores.player.eq.values().eqValues
-
- return Object.keys(values).reduce((acc, key) => {
- acc[key] = values[key].gain
-
- return acc
- }, {})
- },
onUpdate: (value) => {
const values = Object.keys(value).reduce((acc, key) => {
- acc[key] = {
- gain: value[key]
- }
+ acc[key] = value[key]
return acc
}, {})
diff --git a/packages/app/constants/settings/player/items/player.compressor/index.jsx b/packages/app/constants/settings/player/items/player.compressor/index.jsx
new file mode 100644
index 00000000..caafdb6d
--- /dev/null
+++ b/packages/app/constants/settings/player/items/player.compressor/index.jsx
@@ -0,0 +1,8 @@
+import SlidersWithPresets from "../../../components/slidersWithPresets"
+
+export default (props) => {
+ return
+}
\ No newline at end of file
diff --git a/packages/app/constants/settings/player/items/player.eq/index.jsx b/packages/app/constants/settings/player/items/player.eq/index.jsx
new file mode 100644
index 00000000..52ea7de6
--- /dev/null
+++ b/packages/app/constants/settings/player/items/player.eq/index.jsx
@@ -0,0 +1,8 @@
+import SlidersWithPresets from "../../../components/slidersWithPresets"
+
+export default (props) => {
+ return
+}
\ No newline at end of file
diff --git a/packages/app/src/cores/player/presets.js b/packages/app/src/cores/player/presets.js
new file mode 100644
index 00000000..a8fa40cb
--- /dev/null
+++ b/packages/app/src/cores/player/presets.js
@@ -0,0 +1,117 @@
+import AudioPlayerStorage from "./player.storage"
+
+export default class Presets {
+ constructor({
+ storage_key,
+ defaultPresetValue,
+ }) {
+ if (!storage_key) {
+ throw new Error("storage_key is required")
+ }
+
+ this.storage_key = storage_key
+ this.defaultPresetValue = defaultPresetValue
+
+ return this
+ }
+
+ get presets() {
+ return AudioPlayerStorage.get(`${this.storage_key}_presets`) ?? {
+ default: this.defaultPresetValue
+ }
+ }
+
+ set presets(presets) {
+ AudioPlayerStorage.set(`${this.storage_key}_presets`, presets)
+
+ return presets
+ }
+
+ set currentPresetKey(key) {
+ AudioPlayerStorage.set(`${this.storage_key}_current-key`, key)
+
+ return key
+ }
+
+ get currentPresetKey() {
+ return AudioPlayerStorage.get(`${this.storage_key}_current-key`) ?? "default"
+ }
+
+ get currentPresetValues() {
+ const presets = this.presets
+ const key = this.currentPresetKey
+
+ if (!presets || !presets[key]) {
+ return this.defaultPresetValue
+ }
+
+ return presets[key]
+ }
+
+ deletePreset(key) {
+ if (key === "default") {
+ app.message.error("Cannot delete default preset")
+ return false
+ }
+
+ if (this.currentPresetKey === key) {
+ this.changePreset("default")
+ }
+
+ let presets = this.presets
+
+ delete presets[key]
+
+ this.presets = presets
+
+ return presets
+ }
+
+ createPreset(key, values) {
+ let presets = this.presets
+
+ if (presets[key]) {
+ app.message.error("Preset already exists")
+ return false
+ }
+
+ presets[key] = values ?? this.defaultPresetValue
+
+ this.presets = presets
+
+ return presets[key]
+ }
+
+ changePreset(key) {
+ let presets = this.presets
+
+ // create new one
+ if (!presets[key]) {
+ presets[key] = this.defaultPresetValue
+
+ this.presets = presets
+ }
+
+ this.currentPresetKey = key
+
+ return presets[key]
+ }
+
+ setToCurrent(values) {
+ let preset = this.currentPresetValues
+
+ preset = {
+ ...preset,
+ ...values,
+ }
+
+ // update presets
+ let presets = this.presets
+
+ presets[this.currentPresetKey] = preset
+
+ this.presets = presets
+
+ return preset
+ }
+}
\ No newline at end of file
diff --git a/packages/app/src/cores/player/processors/compressorNode/index.js b/packages/app/src/cores/player/processors/compressorNode/index.js
index 14aa0083..26439949 100644
--- a/packages/app/src/cores/player/processors/compressorNode/index.js
+++ b/packages/app/src/cores/player/processors/compressorNode/index.js
@@ -1,40 +1,110 @@
-import AudioPlayerStorage from "../../player.storage"
+import { Modal } from "antd"
import ProcessorNode from "../node"
+import Presets from "../../presets"
export default class CompressorProcessorNode extends ProcessorNode {
+ constructor(props) {
+ super(props)
+
+ this.presets_controller = new Presets({
+ storage_key: "compressor",
+ defaultPresetValue: {
+ threshold: -50,
+ knee: 40,
+ ratio: 12,
+ attack: 0.003,
+ release: 0.25,
+ },
+ })
+
+ this.state = {
+ compressorValues: this.presets_controller.currentPresetValues,
+ }
+
+ this.exposeToPublic = {
+ presets: new Proxy(this.presets_controller, {
+ get: function (target, key) {
+ if (!key) {
+ return target
+ }
+
+ return target[key]
+ }
+ }),
+ deletePreset: this.deletePreset.bind(this),
+ createPreset: this.createPreset.bind(this),
+ changePreset: this.changePreset.bind(this),
+ resetDefaultValues: this.resetDefaultValues.bind(this),
+ modifyValues: this.modifyValues.bind(this),
+ detach: this._detach.bind(this),
+ attach: this._attach.bind(this),
+ values: this.state.compressorValues,
+ }
+ }
+
static refName = "compressor"
static dependsOnSettings = ["player.compressor"]
- static defaultCompressorValues = {
- threshold: -50,
- knee: 40,
- ratio: 12,
- attack: 0.003,
- release: 0.25,
+
+ deletePreset(key) {
+ this.changePreset("default")
+
+ this.presets_controller.deletePreset(key)
+
+ return this.presets_controller.presets
}
- state = {
- compressorValues: AudioPlayerStorage.get("compressor") ?? CompressorProcessorNode.defaultCompressorValues,
+ createPreset(key, values) {
+ this.state = {
+ ...this.state,
+ compressorValues: this.presets_controller.createPreset(key, values),
+ }
+
+ this.presets_controller.changePreset(key)
+
+ return this.presets_controller.presets
}
- exposeToPublic = {
- modifyValues: function (values) {
- this.state.compressorValues = {
- ...this.state.compressorValues,
- ...values,
- }
+ changePreset(key) {
+ const values = this.presets_controller.changePreset(key)
- AudioPlayerStorage.set("compressor", this.state.compressorValues)
+ this.state = {
+ ...this.state,
+ compressorValues: values,
+ }
- this.applyValues()
- }.bind(this),
- resetDefaultValues: function () {
- this.exposeToPublic.modifyValues(CompressorProcessorNode.defaultCompressorValues)
+ this.applyValues()
- return this.state.compressorValues
- }.bind(this),
- detach: this._detach.bind(this),
- attach: this._attach.bind(this),
- values: this.state.compressorValues,
+ return values
+ }
+
+ modifyValues(values) {
+ values = this.presets_controller.setToCurrent(values)
+
+ this.state.compressorValues = {
+ ...this.state.compressorValues,
+ ...values,
+ }
+
+ this.applyValues()
+
+ return this.state.compressorValues
+ }
+
+ async resetDefaultValues() {
+ return await new Promise((resolve) => {
+ Modal.confirm({
+ title: "Reset to default values?",
+ content: "Are you sure you want to reset to default values?",
+ onOk: () => {
+ this.modifyValues(this.presets_controller.defaultPresetValue)
+
+ resolve(this.state.compressorValues)
+ },
+ onCancel: () => {
+ resolve(this.state.compressorValues)
+ }
+ })
+ })
}
async init(AudioContext) {
diff --git a/packages/app/src/cores/player/processors/eqNode/index.js b/packages/app/src/cores/player/processors/eqNode/index.js
index 41b8c3ec..88f4066e 100644
--- a/packages/app/src/cores/player/processors/eqNode/index.js
+++ b/packages/app/src/cores/player/processors/eqNode/index.js
@@ -1,70 +1,119 @@
+import { Modal } from "antd"
import ProcessorNode from "../node"
-import AudioPlayerStorage from "../../player.storage"
+import Presets from "../../presets"
export default class EqProcessorNode extends ProcessorNode {
- static refName = "eq"
- static lock = true
+ constructor(props) {
+ super(props)
- static defaultEqValue = {
- 32: {
- gain: 0,
- },
- 64: {
- gain: 0,
- },
- 125: {
- gain: 0,
- },
- 250: {
- gain: 0,
- },
- 500: {
- gain: 0,
- },
- 1000: {
- gain: 0,
- },
- 2000: {
- gain: 0,
- },
- 4000: {
- gain: 0,
- },
- 8000: {
- gain: 0,
- },
- 16000: {
- gain: 0,
+ this.presets_controller = new Presets({
+ storage_key: "eq",
+ defaultPresetValue: {
+ 32: 0,
+ 64: 0,
+ 125: 0,
+ 250: 0,
+ 500: 0,
+ 1000: 0,
+ 2000: 0,
+ 4000: 0,
+ 8000: 0,
+ 16000: 0,
+ },
+ })
+
+ this.state = {
+ eqValues: this.presets_controller.currentPresetValues,
+ }
+
+ this.exposeToPublic = {
+ presets: new Proxy(this.presets_controller, {
+ get: function (target, key) {
+ if (!key) {
+ return target
+ }
+
+ return target[key]
+ },
+ }),
+ deletePreset: this.deletePreset.bind(this),
+ createPreset: this.createPreset.bind(this),
+ changePreset: this.changePreset.bind(this),
+ modifyValues: this.modifyValues.bind(this),
+ resetDefaultValues: this.resetDefaultValues.bind(this),
}
}
- state = {
- eqValues: AudioPlayerStorage.get("eq_values") ?? EqProcessorNode.defaultEqValue,
+ static refName = "eq"
+ static lock = true
+
+ deletePreset(key) {
+ this.changePreset("default")
+
+ this.presets_controller.deletePreset(key)
+
+ return this.presets_controller.presets
}
- exposeToPublic = {
- modifyValues: function (values) {
- Object.keys(values).forEach((key) => {
- if (isNaN(key)) {
- delete values[key]
- }
- })
+ createPreset(key, values) {
+ this.state = {
+ ...this.state,
+ eqValues: this.presets_controller.createPreset(key, values),
+ }
- this.state.eqValues = {
- ...this.state.eqValues,
- ...values,
+ this.presets_controller.changePreset(key)
+
+ return this.presets_controller.presets
+ }
+
+ changePreset(key) {
+ const values = this.presets_controller.changePreset(key)
+
+ this.state = {
+ ...this.state,
+ eqValues: values,
+ }
+
+ this.applyValues()
+
+ return values
+ }
+
+ modifyValues(values) {
+ values = this.presets_controller.setToCurrent(values)
+
+ this.state = {
+ ...this.state,
+ eqValues: values,
+ }
+
+ this.applyValues()
+
+ return values
+ }
+
+ resetDefaultValues() {
+ Modal.confirm({
+ title: "Reset to default values?",
+ content: "Are you sure you want to reset to default values?",
+ onOk: () => {
+ this.modifyValues(this.presets_controller.defaultPresetValue)
}
+ })
- AudioPlayerStorage.set("eq_values", this.state.eqValues)
+ return this.state.eqValues
+ }
- this.applyValues()
- }.bind(this),
- resetDefaultValues: function () {
- this.exposeToPublic.modifyValues(EqProcessorNode.defaultEqValue)
+ applyValues() {
+ // apply to current instance
+ this.processor.eqNodes.forEach((processor) => {
+ const gainValue = this.state.eqValues[processor.frequency.value]
- return this.state
- }.bind(this),
- values: () => this.state,
+ if (processor.gain.value !== gainValue) {
+ console.debug(`[EQ] Applying values to ${processor.frequency.value} Hz frequency with gain ${gainValue}`)
+ processor.gain.value = gainValue
+ }
+ })
}
async init() {
@@ -81,7 +130,7 @@ export default class EqProcessorNode extends ProcessorNode {
const values = Object.entries(this.state.eqValues).map((entry) => {
return {
freq: parseFloat(entry[0]),
- gain: parseFloat(entry[1].gain),
+ gain: parseFloat(entry[1]),
}
})
@@ -116,16 +165,4 @@ export default class EqProcessorNode extends ProcessorNode {
// set last processor for processor node can properly connect to the next node
this.processor._last = this.processor.eqNodes.at(-1)
}
-
- applyValues() {
- // apply to current instance
- this.processor.eqNodes.forEach((processor) => {
- const gainValue = this.state.eqValues[processor.frequency.value].gain
-
- if (processor.gain.value !== gainValue) {
- console.debug(`[EQ] Applying values to ${processor.frequency.value} Hz frequency with gain ${gainValue}`)
- processor.gain.value = this.state.eqValues[processor.frequency.value].gain
- }
- })
- }
}
\ No newline at end of file