mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 18:44:16 +00:00
remove old player core
This commit is contained in:
parent
1911b53712
commit
7748e59439
@ -109,9 +109,30 @@ export default class Player extends Core {
|
||||
})
|
||||
}
|
||||
|
||||
internalEvents = {
|
||||
"player.state.update:loading": () => {
|
||||
app.cores.sync.music.dispatchEvent("music.player.state.update", this.state)
|
||||
},
|
||||
"player.state.update:track_manifest": () => {
|
||||
app.cores.sync.music.dispatchEvent("music.player.state.update", this.state)
|
||||
},
|
||||
"player.state.update:playback_status": () => {
|
||||
app.cores.sync.music.dispatchEvent("music.player.state.update", this.state)
|
||||
},
|
||||
"player.seeked": (to) => {
|
||||
app.cores.sync.music.dispatchEvent("music.player.seek", to)
|
||||
},
|
||||
}
|
||||
|
||||
async onInitialize() {
|
||||
this.native_controls.initialize()
|
||||
|
||||
this.initializeAudioProcessors()
|
||||
|
||||
for (const [eventName, eventHandler] of Object.entries(this.internalEvents)) {
|
||||
this.eventBus.on(eventName, eventHandler)
|
||||
}
|
||||
|
||||
Observable.observe(this.state, async (changes) => {
|
||||
try {
|
||||
changes.forEach((change) => {
|
File diff suppressed because it is too large
Load Diff
@ -1,172 +0,0 @@
|
||||
export default class ProcessorNode {
|
||||
constructor(PlayerCore) {
|
||||
if (!PlayerCore) {
|
||||
throw new Error("PlayerCore is required")
|
||||
}
|
||||
|
||||
this.PlayerCore = PlayerCore
|
||||
this.audioContext = PlayerCore.audioContext
|
||||
}
|
||||
|
||||
async _init() {
|
||||
// check if has init method
|
||||
if (typeof this.init === "function") {
|
||||
await this.init(this.audioContext)
|
||||
}
|
||||
|
||||
// check if has declared bus events
|
||||
if (typeof this.busEvents === "object") {
|
||||
Object.entries(this.busEvents).forEach((event, fn) => {
|
||||
app.eventBus.on(event, fn)
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof this.processor._last === "undefined") {
|
||||
this.processor._last = this.processor
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
_attach(instance, index) {
|
||||
if (typeof instance !== "object") {
|
||||
instance = this.PlayerCore.currentAudioInstance
|
||||
}
|
||||
|
||||
// check if has dependsOnSettings
|
||||
if (Array.isArray(this.constructor.dependsOnSettings)) {
|
||||
// check if the instance has the settings
|
||||
if (!this.constructor.dependsOnSettings.every((setting) => app.cores.settings.get(setting))) {
|
||||
this.console.warn(`Skipping attachment for [${this.constructor.refName ?? this.constructor.name}] node, cause is not passing the settings dependecy > ${this.constructor.dependsOnSettings.join(", ")}`)
|
||||
|
||||
return instance
|
||||
}
|
||||
}
|
||||
|
||||
// if index is not defined, attach to the last node
|
||||
if (!index) {
|
||||
index = instance.attachedProcessors.length
|
||||
}
|
||||
|
||||
const prevNode = instance.attachedProcessors[index - 1]
|
||||
const nextNode = instance.attachedProcessors[index + 1]
|
||||
|
||||
const currentIndex = this._findIndex(instance)
|
||||
|
||||
// check if is already attached
|
||||
if (currentIndex !== false) {
|
||||
this.console.warn(`[${this.constructor.refName ?? this.constructor.name}] node is already attached`)
|
||||
|
||||
return instance
|
||||
}
|
||||
|
||||
// first check if has prevNode and if is connected to something
|
||||
// if has, disconnect it
|
||||
// if it not has, its means that is the first node, so connect to the media source
|
||||
if (prevNode && prevNode.processor._last.numberOfOutputs > 0) {
|
||||
//this.console.log(`[${this.constructor.refName ?? this.constructor.name}] node is already attached to the previous node, disconnecting...`)
|
||||
// if has outputs, disconnect from the next node
|
||||
prevNode.processor._last.disconnect()
|
||||
|
||||
// now, connect to the processor
|
||||
prevNode.processor._last.connect(this.processor)
|
||||
} else {
|
||||
//this.console.log(`[${this.constructor.refName ?? this.constructor.name}] node is the first node, connecting to the media source...`)
|
||||
instance.media.connect(this.processor)
|
||||
}
|
||||
|
||||
// now, check if it has a next node
|
||||
// if has, connect to it
|
||||
// if not, connect to the destination
|
||||
if (nextNode) {
|
||||
this.processor.connect(nextNode.processor)
|
||||
}
|
||||
|
||||
// add to the attachedProcessors
|
||||
instance.attachedProcessors.splice(index, 0, this)
|
||||
|
||||
// handle instance mutation
|
||||
if (typeof this.mutateInstance === "function") {
|
||||
instance = this.mutateInstance(instance)
|
||||
}
|
||||
|
||||
return instance
|
||||
}
|
||||
|
||||
_detach(instance) {
|
||||
if (typeof instance !== "object") {
|
||||
instance = this.PlayerCore.currentAudioInstance
|
||||
}
|
||||
|
||||
// find index of the node within the attachedProcessors serching for matching refName
|
||||
const index = this._findIndex(instance)
|
||||
|
||||
if (!index) {
|
||||
return instance
|
||||
}
|
||||
|
||||
// retrieve the previous and next nodes
|
||||
const prevNode = instance.attachedProcessors[index - 1]
|
||||
const nextNode = instance.attachedProcessors[index + 1]
|
||||
|
||||
// check if has previous node and if has outputs
|
||||
if (prevNode && prevNode.processor._last.numberOfOutputs > 0) {
|
||||
// if has outputs, disconnect from the previous node
|
||||
prevNode.processor._last.disconnect()
|
||||
}
|
||||
|
||||
// disconnect
|
||||
instance = this._destroy(instance)
|
||||
|
||||
// now, connect the previous node to the next node
|
||||
if (prevNode && nextNode) {
|
||||
prevNode.processor._last.connect(nextNode.processor)
|
||||
} else {
|
||||
// it means that this is the last node, so connect to the destination
|
||||
prevNode.processor._last.connect(this.audioContext.destination)
|
||||
}
|
||||
|
||||
return instance
|
||||
}
|
||||
|
||||
_destroy(instance) {
|
||||
if (typeof instance !== "object") {
|
||||
instance = this.PlayerCore.currentAudioInstance
|
||||
}
|
||||
|
||||
const index = this._findIndex(instance)
|
||||
|
||||
if (!index) {
|
||||
return instance
|
||||
}
|
||||
|
||||
this.processor.disconnect()
|
||||
|
||||
instance.attachedProcessors.splice(index, 1)
|
||||
|
||||
return instance
|
||||
}
|
||||
|
||||
_findIndex(instance) {
|
||||
if (!instance) {
|
||||
instance = this.PlayerCore.currentAudioInstance
|
||||
}
|
||||
|
||||
if (!instance) {
|
||||
this.console.warn(`Instance is not defined`)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// find index of the node within the attachedProcessors serching for matching refName
|
||||
const index = instance.attachedProcessors.findIndex((node) => {
|
||||
return node.constructor.refName === this.constructor.refName
|
||||
})
|
||||
|
||||
if (index === -1) {
|
||||
return false
|
||||
}
|
||||
|
||||
return index
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import AudioPlayerStorage from "../../storage"
|
||||
import ProcessorNode from "../../processorNode"
|
||||
import AudioPlayerStorage from "../../player.storage"
|
||||
import ProcessorNode from "../node"
|
||||
|
||||
export default class CompressorProcessorNode extends ProcessorNode {
|
||||
static refName = "compressor"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import ProcessorNode from "../../processorNode"
|
||||
import AudioPlayerStorage from "../../storage"
|
||||
import ProcessorNode from "../node"
|
||||
import AudioPlayerStorage from "../../player.storage"
|
||||
|
||||
export default class EqProcessorNode extends ProcessorNode {
|
||||
static refName = "eq"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import AudioPlayerStorage from "../../storage"
|
||||
import ProcessorNode from "../../processorNode"
|
||||
import AudioPlayerStorage from "../../player.storage"
|
||||
import ProcessorNode from "../node"
|
||||
|
||||
export default class GainProcessorNode extends ProcessorNode {
|
||||
static refName = "gain"
|
||||
|
@ -4,17 +4,19 @@ export default {
|
||||
"tidal": async (manifest) => {
|
||||
const resolvedManifest = await SyncModel.tidalCore.getTrackManifest(manifest.id)
|
||||
|
||||
this.console.log(resolvedManifest)
|
||||
|
||||
manifest.source = resolvedManifest.playback.url
|
||||
|
||||
manifest.title = resolvedManifest.metadata.title
|
||||
manifest.artist = resolvedManifest.metadata.artists.map(artist => artist.name).join(", ")
|
||||
manifest.album = resolvedManifest.metadata.album.title
|
||||
if (!manifest.metadata) {
|
||||
manifest.metadata = {}
|
||||
}
|
||||
|
||||
manifest.metadata.title = resolvedManifest.metadata.title
|
||||
manifest.metadata.artist = resolvedManifest.metadata.artists.map(artist => artist.name).join(", ")
|
||||
manifest.metadata.album = resolvedManifest.metadata.album.title
|
||||
|
||||
const coverUID = resolvedManifest.metadata.album.cover.replace(/-/g, "/")
|
||||
|
||||
manifest.cover = `https://resources.tidal.com/images/${coverUID}/1280x1280.jpg`
|
||||
manifest.metadata.cover = `https://resources.tidal.com/images/${coverUID}/1280x1280.jpg`
|
||||
|
||||
return manifest
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
import store from "store"
|
||||
|
||||
export default class AudioPlayerStorage {
|
||||
static storeKey = "audioPlayer"
|
||||
|
||||
static get(key) {
|
||||
const data = store.get(AudioPlayerStorage.storeKey)
|
||||
|
||||
if (data) {
|
||||
return data[key]
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
static set(key, value) {
|
||||
const data = store.get(AudioPlayerStorage.storeKey) ?? {}
|
||||
|
||||
data[key] = value
|
||||
|
||||
store.set(AudioPlayerStorage.storeKey, data)
|
||||
|
||||
return data
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
import AudioPlayerStorage from "../../player.storage"
|
||||
import ProcessorNode from "../node"
|
||||
|
||||
export default class CompressorProcessorNode extends ProcessorNode {
|
||||
static refName = "compressor"
|
||||
static dependsOnSettings = ["player.compressor"]
|
||||
static defaultCompressorValues = {
|
||||
threshold: -50,
|
||||
knee: 40,
|
||||
ratio: 12,
|
||||
attack: 0.003,
|
||||
release: 0.25,
|
||||
}
|
||||
|
||||
state = {
|
||||
compressorValues: AudioPlayerStorage.get("compressor") ?? CompressorProcessorNode.defaultCompressorValues,
|
||||
}
|
||||
|
||||
exposeToPublic = {
|
||||
modifyValues: function (values) {
|
||||
this.state.compressorValues = {
|
||||
...this.state.compressorValues,
|
||||
...values,
|
||||
}
|
||||
|
||||
AudioPlayerStorage.set("compressor", this.state.compressorValues)
|
||||
|
||||
this.applyValues()
|
||||
}.bind(this),
|
||||
resetDefaultValues: function () {
|
||||
this.exposeToPublic.modifyValues(CompressorProcessorNode.defaultCompressorValues)
|
||||
|
||||
return this.state.compressorValues
|
||||
}.bind(this),
|
||||
detach: this._detach.bind(this),
|
||||
attach: this._attach.bind(this),
|
||||
values: this.state.compressorValues,
|
||||
}
|
||||
|
||||
async init(AudioContext) {
|
||||
if (!AudioContext) {
|
||||
throw new Error("AudioContext is required")
|
||||
}
|
||||
|
||||
this.processor = AudioContext.createDynamicsCompressor()
|
||||
|
||||
this.applyValues()
|
||||
}
|
||||
|
||||
applyValues() {
|
||||
Object.keys(this.state.compressorValues).forEach((key) => {
|
||||
this.processor[key].value = this.state.compressorValues[key]
|
||||
})
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
import ProcessorNode from "../node"
|
||||
import AudioPlayerStorage from "../../player.storage"
|
||||
|
||||
export default class EqProcessorNode extends ProcessorNode {
|
||||
static refName = "eq"
|
||||
static lock = true
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
state = {
|
||||
eqValues: AudioPlayerStorage.get("eq_values") ?? EqProcessorNode.defaultEqValue,
|
||||
}
|
||||
|
||||
exposeToPublic = {
|
||||
modifyValues: function (values) {
|
||||
Object.keys(values).forEach((key) => {
|
||||
if (isNaN(key)) {
|
||||
delete values[key]
|
||||
}
|
||||
})
|
||||
|
||||
this.state.eqValues = {
|
||||
...this.state.eqValues,
|
||||
...values,
|
||||
}
|
||||
|
||||
AudioPlayerStorage.set("eq_values", this.state.eqValues)
|
||||
|
||||
this.applyValues()
|
||||
}.bind(this),
|
||||
resetDefaultValues: function () {
|
||||
this.exposeToPublic.modifyValues(EqProcessorNode.defaultEqValue)
|
||||
|
||||
return this.state
|
||||
}.bind(this),
|
||||
values: () => this.state,
|
||||
}
|
||||
|
||||
async init() {
|
||||
if (!this.audioContext) {
|
||||
throw new Error("audioContext is required")
|
||||
}
|
||||
|
||||
this.processor = this.audioContext.createGain()
|
||||
|
||||
this.processor.gain.value = 1
|
||||
|
||||
this.processor.eqNodes = []
|
||||
|
||||
const values = Object.entries(this.state.eqValues).map((entry) => {
|
||||
return {
|
||||
freq: parseFloat(entry[0]),
|
||||
gain: parseFloat(entry[1].gain),
|
||||
}
|
||||
})
|
||||
|
||||
values.forEach((eqValue, index) => {
|
||||
// chekc if freq and gain is valid
|
||||
if (isNaN(eqValue.freq)) {
|
||||
eqValue.freq = 0
|
||||
}
|
||||
if (isNaN(eqValue.gain)) {
|
||||
eqValue.gain = 0
|
||||
}
|
||||
|
||||
this.processor.eqNodes[index] = this.audioContext.createBiquadFilter()
|
||||
this.processor.eqNodes[index].type = "peaking"
|
||||
this.processor.eqNodes[index].frequency.value = eqValue.freq
|
||||
this.processor.eqNodes[index].gain.value = eqValue.gain
|
||||
})
|
||||
|
||||
// connect nodes
|
||||
for await (let [index, eqNode] of this.processor.eqNodes.entries()) {
|
||||
const nextNode = this.processor.eqNodes[index + 1]
|
||||
|
||||
if (index === 0) {
|
||||
this.processor.connect(eqNode)
|
||||
}
|
||||
|
||||
if (nextNode) {
|
||||
eqNode.connect(nextNode)
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
this.console.debug(`[EQ] Applying values to ${processor.frequency.value} Hz frequency with gain ${gainValue}`)
|
||||
processor.gain.value = this.state.eqValues[processor.frequency.value].gain
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
import AudioPlayerStorage from "../../player.storage"
|
||||
import ProcessorNode from "../node"
|
||||
|
||||
export default class GainProcessorNode extends ProcessorNode {
|
||||
static refName = "gain"
|
||||
|
||||
static lock = true
|
||||
|
||||
static defaultValues = {
|
||||
gain: 1,
|
||||
}
|
||||
|
||||
state = {
|
||||
gain: AudioPlayerStorage.get("gain") ?? GainProcessorNode.defaultValues.gain,
|
||||
}
|
||||
|
||||
exposeToPublic = {
|
||||
modifyValues: function (values) {
|
||||
this.state = {
|
||||
...this.state,
|
||||
...values,
|
||||
}
|
||||
|
||||
AudioPlayerStorage.set("gain", this.state.gain)
|
||||
|
||||
this.applyValues()
|
||||
}.bind(this),
|
||||
resetDefaultValues: function () {
|
||||
this.exposeToPublic.modifyValues(GainProcessorNode.defaultValues)
|
||||
|
||||
return this.state
|
||||
}.bind(this),
|
||||
values: () => this.state,
|
||||
}
|
||||
|
||||
applyValues() {
|
||||
// apply to current instance
|
||||
this.processor.gain.value = app.cores.player.volume() * this.state.gain
|
||||
}
|
||||
|
||||
async init() {
|
||||
if (!this.audioContext) {
|
||||
throw new Error("audioContext is required")
|
||||
}
|
||||
|
||||
this.processor = this.audioContext.createGain()
|
||||
|
||||
this.applyValues()
|
||||
}
|
||||
|
||||
mutateInstance(instance) {
|
||||
if (!instance) {
|
||||
throw new Error("instance is required")
|
||||
}
|
||||
|
||||
instance.gainNode = this.processor
|
||||
|
||||
return instance
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
import SyncModel from "comty.js/models/sync"
|
||||
|
||||
export default {
|
||||
"tidal": async (manifest) => {
|
||||
const resolvedManifest = await SyncModel.tidalCore.getTrackManifest(manifest.id)
|
||||
|
||||
manifest.source = resolvedManifest.playback.url
|
||||
|
||||
if (!manifest.metadata) {
|
||||
manifest.metadata = {}
|
||||
}
|
||||
|
||||
manifest.metadata.title = resolvedManifest.metadata.title
|
||||
manifest.metadata.artist = resolvedManifest.metadata.artists.map(artist => artist.name).join(", ")
|
||||
manifest.metadata.album = resolvedManifest.metadata.album.title
|
||||
|
||||
const coverUID = resolvedManifest.metadata.album.cover.replace(/-/g, "/")
|
||||
|
||||
manifest.metadata.cover = `https://resources.tidal.com/images/${coverUID}/1280x1280.jpg`
|
||||
|
||||
return manifest
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user