123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- /*
- Partial IAudioPlayer implementation using the high level "soundfont-player" library.
- */
- import { MidiInstrument } from "../MusicalScore/VoiceData/Instructions/ClefInstruction";
- import { IAudioPlayer } from "../Common/Interfaces/IAudioPlayer";
- import { AudioContext as SAudioContext } from "standardized-audio-context";
- import * as SoundfontPlayer from "soundfont-player";
- import midiNames from "./midiNames";
- export class BasicAudioPlayer implements IAudioPlayer<SoundfontPlayer.Player> {
- private ac: SAudioContext = new SAudioContext();
- // private mainTuningRatio: number = 1.0;
- private channelVolumes: number[] = [];
- // private activeSamples: Map<number, any> = new Map();
- private piano: SoundfontPlayer.Player;
- protected memoryLoadedSoundFonts: Map<MidiInstrument, SoundfontPlayer.Player> = new Map();
- protected channelToSoundFont: Map<number, number> = new Map();
- public SoundfontInstrumentOptions = {}; // e.g. set { from: 'server.com/soundfonts/' } for soundfont fetching url
- public async open(uniqueInstruments: number[], numberOfinstruments: number = 16): Promise<void> {
- if (this.piano === undefined) {
- this.piano = await SoundfontPlayer.instrument(
- this.ac as unknown as AudioContext,
- midiNames[MidiInstrument.Acoustic_Grand_Piano].toLowerCase() as any,
- this.SoundfontInstrumentOptions
- );
- }
- for (let i: number = 0; i < numberOfinstruments; i++) {
- this.channelVolumes[i] = 0.8;
- }
- }
- public close(): void {
- // _activeSamples.Clear();
- }
- public tuningChanged(tuningInHz: number): void {
- console.warn("BasicAudioPlayer tuningChanged not implemented");
- //this.mainTuningRatio = tuningInHz / 440;
- }
- public playSound(
- instrumentChannel: number,
- key: number,
- volume: number,
- lengthInMs: number
- ): void {
- if (key >= 128) { return; }
- const sampleVolume: number = Math.min(
- 1,
- this.channelVolumes[instrumentChannel] * volume
- );
- const soundFont: SoundfontPlayer.Player = this.memoryLoadedSoundFonts.get(
- this.channelToSoundFont.get(instrumentChannel)
- );
- soundFont.schedule(0, [
- { note: key, duration: lengthInMs / 1000, gain: sampleVolume },
- ]);
- }
- public stopSound(instrumentChannel: number, volume: number): void {
- //this.memoryLoadedSoundFonts.get(this.channelToSoundFont.get(instrumentChannel))?.stop(); // abrupt
- //console.warn("BasicAudioPlayer stopSound not implemented");
- }
- public async setSound(
- instrumentChannel: number,
- soundId: MidiInstrument
- ): Promise<void> {
- if (this.memoryLoadedSoundFonts.get(soundId) === undefined) {
- await this.loadSoundFont(soundId);
- }
- this.channelToSoundFont.set(instrumentChannel, soundId);
- }
- public async loadSoundFont(soundId: MidiInstrument): Promise<SoundfontPlayer.Player> {
- if (this.memoryLoadedSoundFonts.get(soundId) !== undefined) {
- return this.memoryLoadedSoundFonts.get(soundId);
- }
- let nameOrUrl: any = midiNames[soundId].toLowerCase();
- if (soundId === MidiInstrument.Percussion) {
- // percussion unfortunately doesn't exist in the original soundfonts
- nameOrUrl = "https://paulrosen.github.io/midi-js-soundfonts/FluidR3_GM/percussion-mp3.js";
- }
- const player: SoundfontPlayer.Player = await SoundfontPlayer.instrument(
- this.ac as unknown as AudioContext,
- nameOrUrl,
- this.SoundfontInstrumentOptions
- );
- this.memoryLoadedSoundFonts.set(soundId, player);
- return player;
- }
- public setVolume(instrumentChannel: number, volume: number): void {
- this.channelVolumes[instrumentChannel] = volume;
- }
- public setSoundFontFilePath(soundId: MidiInstrument, path: string): void {
- // TODO: Remove function, not needed for web. If not used to load different soundfonts from URLs?
- }
- public playbackHasStopped(): void {
- //console.warn("BasicAudioPlayer playbackHasStopped not implemented");
- }
- public getMemoryLoadedSoundFonts(): SoundfontPlayer.Player[] {
- return [...this.memoryLoadedSoundFonts.values()];
- }
- }
|