Skip to content

Commit

Permalink
Added EQ
Browse files Browse the repository at this point in the history
  • Loading branch information
Waradu committed Apr 13, 2024
1 parent 3aec704 commit de1f6bf
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 44 deletions.
12 changes: 9 additions & 3 deletions components/Player.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
<IconsRepeat />
</div>
<div class="right-controls">
<IconsVolumeLoud v-if="volume > 50" />
<IconsVolumeMid v-else-if="volume > 0" />
<IconsVolumeMute v-else />
<IconsVolumeLoud @click="mute" v-if="volume > 50" />
<IconsVolumeMid @click="mute" v-else-if="volume > 0" />
<IconsVolumeMute @click="mute" v-else />

<input @input="setVolume" v-model="volume" step="1" min="0" max="100" type="range" name="" id="">
</div>
Expand Down Expand Up @@ -93,6 +93,12 @@ watch(currentSong, async (newSong, oldSong) => {
}
}, { immediate: true });
function mute() {
volume.value = 0
$music.setVolume(volume.value);
$settings.setVolume(volume.value)
}
function setVolume() {
$music.setVolume(volume.value);
$settings.setVolume(volume.value)
Expand Down
5 changes: 1 addition & 4 deletions layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
<Pages />
<Library />
</div>
<div class="main element">
<p class="element-title">Main</p>
<slot />
</div>
<slot />
</div>
<Player />
</div>
Expand Down
48 changes: 38 additions & 10 deletions pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
<template>
<div class="index">
<div v-for="song in songs" :key="song.id" class="song-item">
<img :src="song.coverURL" :alt="song.title" class="song-cover">
<p v-if="!song.id" class="error">Song ID is missing</p>
<div class="song-info">
<h2>{{ song.title }}</h2>
<p>{{ song.artist }}</p>
<p>{{ formatDuration(song.length) }}</p>
<p>{{ formatDate(song.date_added) }}</p>
<div class="main element">
<p class="element-title">Home</p>
<div class="index">
<div class="eq-controls">
<div v-for="(freq, index) in frequencies" :key="freq" class="eq-control">
<input
type="range"
min="-12"
max="12"
step="0.1"
v-model.number="eqGains[index]"
@input="updateEqGain(index, eqGains[index])"
/>
<label>{{ freq }} Hz</label>
<span>{{ eqGains[index].toFixed(1) }}</span>
</div>
</div>
<div v-for="song in songs" :key="song.id" class="song-item">
<img :src="song.coverURL" :alt="song.title" class="song-cover">
<p v-if="!song.id" class="error">Song ID is missing</p>
<div class="song-info">
<h2>{{ song.title }}</h2>
<p>{{ song.artist }}</p>
<p>{{ formatDuration(song.length) }}</p>
<p>{{ formatDate(song.date_added) }}</p>
</div>
<button @click="play(song.id)">Play</button>
</div>
<button @click="play(song.id)">Play</button>
</div>
</div>
</template>
Expand All @@ -21,6 +38,17 @@ const { $music } = useNuxtApp()
await $music.init()
const frequencies = [32, 64, 125, 250, 500, 1000, 2000, 4000, 8000, 16000];
const eqGains = ref(new Array(frequencies.length).fill(0));
function updateEqGain(filterIndex, gain) {
$music.setEqGain(filterIndex, gain);
const eqSettingsMap = new Map();
frequencies.forEach((freq, index) => {
eqSettingsMap.set(freq.toString(), eqGains.value[index]);
});
}
const songs = ref<Song[]>([]);
onMounted(async () => {
Expand Down
27 changes: 15 additions & 12 deletions pages/search.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
<template>
<div class="search">
<input type="text" v-model="searchTerm" @keyup.enter="searchSongs()" :disabled="isLoading"
placeholder="Search for songs" />
<ul v-if="searchResults.length > 0">
<li v-for="(song, index) in searchResults" :class="{ 'first-result': index === 0 }"
@click="handleSongClick(song)">
<img :src="song.thumbnail" alt="Cover image" />
<div>{{ song.title }}</div>
<div>{{ song.uploaderName }}</div>
</li>
</ul>
<div class="main element">
<p class="element-title">Search</p>
<div class="search">
<input type="text" v-model="searchTerm" @keyup.enter="searchSongs()" :disabled="isLoading"
placeholder="Search for songs" />
<ul v-if="searchResults.length > 0">
<li v-for="(song, index) in searchResults" :class="{ 'first-result': index === 0 }"
@click="handleSongClick(song)">
<img :src="song.thumbnail" alt="Cover image" />
<div>{{ song.title }}</div>
<div>{{ song.uploaderName }}</div>
</li>
</ul>
</div>
</div>
</template>

Expand Down Expand Up @@ -74,7 +77,7 @@ async function handleSongClick(song: MusicSearchResponseItem) {
}
try {
await invoke('download', { url: "https://youtube.com"+song.url, name: videoId+".webm" });
await invoke('download', { url: "https://youtube.com" + song.url, name: videoId + ".webm" });
const response = await axios.get(song.thumbnail.replace("w120-h120", "w500-h500"), { responseType: 'arraybuffer' });
const data = new Uint8Array(response.data);
Expand Down
89 changes: 74 additions & 15 deletions plugins/music.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import {
writeTextFile,
readTextFile,
} from "@tauri-apps/plugin-fs";
import type { Song, SongsConfig } from "~/types/types";
import type { EQSettings, Song, SongsConfig } from "~/types/types";

export default defineNuxtPlugin((nuxtApp) => {
const store = useMusicStore();
const musicStore = useMusicStore();
const settingsStore = useSettingsStore();

musicStore.player.audio.onplay = () => music.ensureAudioContextAndFilters();

const music = {
async init() {
Expand Down Expand Up @@ -54,32 +57,33 @@ export default defineNuxtPlugin((nuxtApp) => {
await readTextFile("Vleer/songs.json", { baseDir: BaseDirectory.Audio })
) as SongsConfig;

store.init(songsConfig);
musicStore.init(songsConfig);
},
getSongs() {
return store.songsConfig;
return musicStore.songsConfig;
},
async addSongData(song: Song) {
const songsConfig = JSON.parse(
await readTextFile("Vleer/songs.json", { baseDir: BaseDirectory.Audio })
) as SongsConfig;

store.replaceConfig(songsConfig);
musicStore.replaceConfig(songsConfig);

store.addSongData(song);
musicStore.addSongData(song);

const data = store.getSongsData()
const data = musicStore.getSongsData();

await writeTextFile("Vleer/songs.json", JSON.stringify(data, null, 2), {
baseDir: BaseDirectory.Audio
baseDir: BaseDirectory.Audio,
});
},
async setSong(id: string) {
const contents = await readFile(`Vleer/Songs/${id}.webm`, {
baseDir: BaseDirectory.Audio,
});
store.player.currentSongId = id;
await store.setSongFromBuffer(contents);
musicStore.player.currentSongId = id;
await musicStore.setSongFromBuffer(contents);
await this.ensureAudioContextAndFilters();
},
async getCoverURLFromID(id: string): Promise<string> {
const contents = await readFile(`Vleer/Covers/${id}.png`, {
Expand All @@ -90,18 +94,18 @@ export default defineNuxtPlugin((nuxtApp) => {
return coverObjectURL;
},
play() {
const audio = store.getAudio();
const audio = musicStore.getAudio();
audio.play();
},
pause() {
const audio = store.getAudio();
const audio = musicStore.getAudio();
audio.pause();
},
getAudio(): HTMLAudioElement {
return store.getAudio();
return musicStore.getAudio();
},
setVolume(volume: number) {
const audio = store.getAudio();
const audio = musicStore.getAudio();
if (volume == 0) {
audio.volume = 0;
return;
Expand All @@ -122,7 +126,62 @@ export default defineNuxtPlugin((nuxtApp) => {
audio.volume = Math.exp(minv + scale * (volume - minp));
},
getCurrentSong() {
return store.getSongByID(store.player.currentSongId);
return musicStore.getSongByID(musicStore.player.currentSongId);
},
createEqFilters(): BiquadFilterNode[] {
const frequencies = [
32, 64, 125, 250, 500, 1000, 2000, 4000, 8000, 16000,
];
return frequencies.map((freq) => {
const filter = musicStore.player.audioContext!.createBiquadFilter();
filter.type = "peaking";
filter.frequency.value = freq;
filter.Q.value = 1;
filter.gain.value = 0;
return filter;
});
},
connectEqFilters(): void {
let lastNode = musicStore.player.sourceNode!;
musicStore.player.eqFilters.forEach((filter) => {
lastNode.connect(filter);
lastNode = filter;
});
lastNode.connect(musicStore.player.audioContext!.destination);
},
async applyEqSettings() {
const eqSettings = (await settingsStore.getSettings()).eq;
musicStore.player.eqFilters.forEach((filter, index) => {
const gain =
eqSettings[filter.frequency.value.toString() as keyof EQSettings];
if (gain !== undefined) {
this.setEqGain(index, parseInt(gain));
}
});
},
setEqGain(filterIndex: number, gain: number): void {
if (musicStore.player.eqFilters[filterIndex]) {
musicStore.player.eqFilters[filterIndex].gain.value = gain;

this.ensureAudioContextAndFilters();
}
},
async ensureAudioContextAndFilters() {
if (!musicStore.player.audioContext) {
musicStore.player.audioContext = new AudioContext();
musicStore.player.sourceNode =
musicStore.player.audioContext.createMediaElementSource(
musicStore.player.audio
);
musicStore.player.eqFilters = this.createEqFilters();
this.connectEqFilters();
await this.applyEqSettings();
if (musicStore.player.audioContext.state === "suspended") {
await musicStore.player.audioContext.resume();
}
} else if (musicStore.player.audioContext.state === "suspended") {
await musicStore.player.audioContext.resume();
}
},
};

Expand Down
2 changes: 2 additions & 0 deletions types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export interface EQSettings {
"16000": string;
}

export type EQ = keyof EQSettings;

export interface PlayerSettings {
volume: number;
currentSong: string;
Expand Down

0 comments on commit de1f6bf

Please sign in to comment.