init
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,13 @@
|
||||
import { EasyAudio } from "./utils";
|
||||
|
||||
import water_interface from "./Water Interface Button 03.mp3"
|
||||
import whoosh from "./Whoosh 01.mp3"
|
||||
import shimmering_light from "./Shimmering Light 02.mp3"
|
||||
|
||||
const ea = new EasyAudio([
|
||||
{ name: "water_interface", audioUrl: water_interface, volume: 0.8 },
|
||||
{ name: "whoosh", audioUrl: whoosh, volume: 0.9 },
|
||||
{ name: "shimmering_light", audioUrl: shimmering_light, volume: 0.9 },
|
||||
]);
|
||||
|
||||
export default ea;
|
||||
@@ -0,0 +1,114 @@
|
||||
export class EasyAudio {
|
||||
private static audioCtx: AudioContext | null = null;
|
||||
private buffers: Map<string, AudioBuffer> = new Map();
|
||||
private sources: Map<string, AudioBufferSourceNode> = new Map();
|
||||
private audioOptions: Map<
|
||||
string,
|
||||
{ audioUrl: string; loop?: boolean; volume?: number }
|
||||
> = new Map();
|
||||
|
||||
private get audioCtx(): AudioContext {
|
||||
if (!EasyAudio.audioCtx) {
|
||||
EasyAudio.audioCtx = new AudioContext();
|
||||
}
|
||||
return EasyAudio.audioCtx;
|
||||
}
|
||||
|
||||
constructor(
|
||||
audios?:
|
||||
| { name: string; audioUrl: string | URL; loop?: boolean; volume?: number }
|
||||
| { name: string; audioUrl: string | URL; loop?: boolean; volume?: number }[]
|
||||
) {
|
||||
if (audios) {
|
||||
this.add(audios);
|
||||
}
|
||||
}
|
||||
|
||||
private async createAudioBuffer(audioUrl: string): Promise<AudioBuffer> {
|
||||
const response = await fetch(audioUrl);
|
||||
const arrayBuffer = await response.arrayBuffer();
|
||||
return await this.audioCtx.decodeAudioData(arrayBuffer);
|
||||
}
|
||||
|
||||
private async loadAudio(name: string) {
|
||||
const options = this.audioOptions.get(name);
|
||||
if (!options) {
|
||||
throw new Error(`音频 ${name} 未找到`);
|
||||
}
|
||||
const buffer = await this.createAudioBuffer(options.audioUrl);
|
||||
this.buffers.set(name, buffer);
|
||||
}
|
||||
|
||||
async load(): Promise<void> {
|
||||
const promises = Array.from(this.audioOptions.keys()).map(name =>
|
||||
this.loadAudio(name)
|
||||
);
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
add(
|
||||
audios:
|
||||
| { name: string; audioUrl: string | URL; loop?: boolean; volume?: number }
|
||||
| { name: string; audioUrl: string | URL; loop?: boolean; volume?: number }[]
|
||||
): void {
|
||||
if (Array.isArray(audios)) {
|
||||
audios.forEach(audio => {
|
||||
this.audioOptions.set(audio.name, {
|
||||
audioUrl: typeof (audio.audioUrl) === "string" ? audio.audioUrl : audio.audioUrl.href,
|
||||
loop: audio.loop,
|
||||
volume: audio.volume,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.audioOptions.set(audios.name, {
|
||||
audioUrl: typeof (audios.audioUrl) === "string" ? audios.audioUrl : audios.audioUrl.href,
|
||||
loop: audios.loop,
|
||||
volume: audios.volume,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async play(name: string) {
|
||||
if (!this.buffers.has(name)) {
|
||||
await this.loadAudio(name);
|
||||
}
|
||||
|
||||
const buffer = this.buffers.get(name);
|
||||
const options = this.audioOptions.get(name);
|
||||
if (!buffer || !options) {
|
||||
throw new Error(`音频 ${name} 未找到`);
|
||||
}
|
||||
|
||||
const source = this.audioCtx.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
source.loop = options.loop || false;
|
||||
|
||||
let gainNode: GainNode | null = null;
|
||||
if (options.volume !== undefined) {
|
||||
gainNode = this.audioCtx.createGain();
|
||||
gainNode.gain.value = options.volume;
|
||||
source.connect(gainNode);
|
||||
gainNode.connect(this.audioCtx.destination);
|
||||
} else {
|
||||
source.connect(this.audioCtx.destination);
|
||||
}
|
||||
|
||||
source.start();
|
||||
this.sources.set(name, source);
|
||||
console.log(`音频 ${name} 播放`);
|
||||
|
||||
}
|
||||
|
||||
stop(name: string) {
|
||||
const source = this.sources.get(name);
|
||||
if (source) {
|
||||
source.stop();
|
||||
this.sources.delete(name);
|
||||
}
|
||||
}
|
||||
|
||||
stopAll() {
|
||||
this.sources.forEach(source => source.stop());
|
||||
this.sources.clear();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 496 B |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user