feat: thêm soundfont và VSTi cho MIDI
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
// SonicForge Studio SoundFont Player Service
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// Web Audio API fallback synth
|
||||
let audioCtx = null;
|
||||
let gainNode = null;
|
||||
const activeOscillators = {};
|
||||
|
||||
function getCtx() {
|
||||
if (!audioCtx) {
|
||||
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||
gainNode = audioCtx.createGain();
|
||||
gainNode.gain.value = 0.3;
|
||||
gainNode.connect(audioCtx.destination);
|
||||
}
|
||||
return audioCtx;
|
||||
}
|
||||
|
||||
const SonicSF = {
|
||||
loadedFonts: {},
|
||||
|
||||
// Load SoundFont from URL → ArrayBuffer → store in memory
|
||||
loadSoundFont: async function (url) {
|
||||
if (this.loadedFonts[url]) return this.loadedFonts[url];
|
||||
const resp = await fetch(url);
|
||||
if (!resp.ok) throw new Error('Failed to load SoundFont: ' + url);
|
||||
const buffer = await resp.arrayBuffer();
|
||||
this.loadedFonts[url] = buffer;
|
||||
return buffer;
|
||||
},
|
||||
|
||||
// Play a MIDI note using Web Audio fallback
|
||||
playNote: function (note, velocity, durationMs) {
|
||||
const ctx = getCtx();
|
||||
const freq = 440 * Math.pow(2, (note - 69) / 12);
|
||||
const osc = ctx.createOscillator();
|
||||
const noteGain = ctx.createGain();
|
||||
osc.type = 'triangle';
|
||||
osc.frequency.value = freq;
|
||||
noteGain.gain.setValueAtTime(velocity / 127 * 0.3, ctx.currentTime);
|
||||
noteGain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + durationMs / 1000);
|
||||
osc.connect(noteGain);
|
||||
noteGain.connect(ctx.destination);
|
||||
osc.start(ctx.currentTime);
|
||||
osc.stop(ctx.currentTime + durationMs / 1000 + 0.05);
|
||||
activeOscillators[note] = osc;
|
||||
return osc;
|
||||
},
|
||||
|
||||
stopAll: function () {
|
||||
Object.values(activeOscillators).forEach(osc => {
|
||||
try { osc.stop(); } catch (e) { }
|
||||
});
|
||||
Object.keys(activeOscillators).forEach(k => delete activeOscillators[k]);
|
||||
},
|
||||
|
||||
// Save user SoundFont to IndexedDB via window.SonicStorage
|
||||
saveToIndexedDB: async function (name, arrayBuffer) {
|
||||
if (window.SonicStorage && window.SonicStorage.saveToIndexedDB) {
|
||||
await window.SonicStorage.saveToIndexedDB('soundfont_' + name, arrayBuffer);
|
||||
}
|
||||
},
|
||||
|
||||
// Load user SoundFont from IndexedDB
|
||||
loadFromIndexedDB: async function (name) {
|
||||
if (window.SonicStorage && window.SonicStorage.loadFromIndexedDB) {
|
||||
return await window.SonicStorage.loadFromIndexedDB('soundfont_' + name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
window.SonicSF = SonicSF;
|
||||
})();
|
||||
Reference in New Issue
Block a user