remove old player core

This commit is contained in:
SrGooglo 2023-08-07 15:46:27 +00:00
parent 6657b6eb7d
commit 4a86cf7992
17 changed files with 35 additions and 1742 deletions

View File

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

View File

@ -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
}
}

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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]
})
}
}

View File

@ -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
}
})
}
}

View File

@ -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
}
}

View File

@ -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
}
}