From 5cc8796580782d29c803d568120579fd91412892 Mon Sep 17 00:00:00 2001 From: Yisheng Jiang Date: Sun, 9 Apr 2023 14:22:23 -0700 Subject: [PATCH] a --- spin/spin-proc.js | 67 ++++++++++++++++++++++++++++--------------- spin/spin-structs.js | 31 ++++++++++---------- spin/spin.wasm | Bin 540539 -> 540581 bytes spin/spin.wasm.js | 2 +- spin/src/spin.c | 18 +++++++----- spin/src/spin.h | 2 +- src/createChannel.js | 3 +- src/index.js | 28 +++++++++--------- style.css | 67 ++----------------------------------------- 9 files changed, 92 insertions(+), 126 deletions(-) diff --git a/spin/spin-proc.js b/spin/spin-proc.js index 185bc6da..9d23ad68 100644 --- a/spin/spin-proc.js +++ b/spin/spin-proc.js @@ -62,7 +62,7 @@ class SpinProcessor extends AudioWorkletProcessor { setup_wasm() { this.memory = new WebAssembly.Memory({ maximum: 1024 * 4, - initial: 1024 * 4 + initial: 1024 * 4, }); let lastfl; const imports = { @@ -133,51 +133,48 @@ class SpinProcessor extends AudioWorkletProcessor { }); } }else if (data.query) { - const ref = this.inst.exports.spRef(parseInt(data.query)); - const spinfo = spRef2json(this.memory.buffer, ref); - const egInfo = egStruct( - this.memory.buffer, - this.inst.exports.get_vol_eg(ref) - ); - this.port.postMessage({ - queryResponse: { - spinfo, - egInfo, - }, - }); + const spref = this.inst.exports.spRef(parseInt(data.query)); + this.respondQuery(spref); } else { const [cmd, channel, ...args] = data; const [metric, value] = args; switch (cmd) { + case 0xe0: + break; case 0xb0: - case 0x00b0: this.inst.exports.set_midi_cc_val(channel, metric, value); break; case 0x80: - case 0x0080: + this.respondQuery(this.spinners[channel]); + this.inst.exports.trigger_release(channel); + this.port.postMessage({ ack: [0x80, channel] }); break; - case 1: - case 0x0090: + case 0x90: { - const [ratio, velocity, [presetId, zoneRef]] = args; + const [key, velocity, [presetId, zoneRef]] = args; const zonePtr = this.presetRefs[presetId]?.[zoneRef]; + if (!zonePtr) { console.error("cannot find present zoneref", presetId, zoneRef); return; } if (this.spinners[channel] == null) { this.instantiate(channel); + this.inst.exports.reset(this.spinners[ch]); } let ch = channel; - this.inst.exports.reset(this.spinners[ch]); this.inst.exports.set_spinner_zone(this.spinners[ch], zonePtr); + + // console.log(calc_pitch_diff_log(x -> zone, x -> pcm, key)); this.inst.exports.trigger_attack( this.spinners[ch], - ratio, + key, velocity - ); + ); + this.respondQuery(this.spinners[ch]); + } break; default: @@ -185,6 +182,21 @@ class SpinProcessor extends AudioWorkletProcessor { } } } + respondQuery(ref) { + + const spinfo = spRef2json(this.memory.buffer, ref); + const egInfo = egStruct( + this.memory.buffer, + this.inst.exports.get_vol_eg(ref) + ); + this.port.postMessage({ + queryResponse: { + spinfo, + egInfo, + }, + }); + } + setZone(ref, arr, presetId) { const ptr = this.malololc(120); if (!this.presetRefs[presetId]) { @@ -211,6 +223,15 @@ class SpinProcessor extends AudioWorkletProcessor { this.spinners[i] = this.inst.exports.newSpinner(i); const spIO = new Uint32Array(this.memory.buffer, this.spinners[i], 3); this.spinners[i]; + // this.dv[i] = new DataView( + // this.memory.buffer, + // this.spinners[i], + // this.inst.exports.sp_byte_len + // ); + //console.log(this.dv[i]); + + //queueMicrotask(() => this.port.postMessage({ sp: i, dv: this.dv[i] })); + this.outputs[i] = new Float32Array(this.memory.buffer, spIO[1], 128 * 2); return this.spinners[i]; } @@ -223,7 +244,7 @@ class SpinProcessor extends AudioWorkletProcessor { if (!this.spinners[i]) continue; const shouldRend = this.inst.exports.spin(this.spinners[i], 128); if (!shouldRend) { - delete this.spinners[i]; + // delete this.spinners[i]; return true; } for (let j = 0;j < 128;j++) { @@ -264,7 +285,7 @@ class SpinProcessor extends AudioWorkletProcessor { queryResponse: { now: now(), spinfo, - egInfo, + // egInfo, egStags: this.eg_vol_stag, }, }); diff --git a/spin/spin-structs.js b/spin/spin-structs.js index b3ddae2f..fb44193f 100644 --- a/spin/spin-structs.js +++ b/spin/spin-structs.js @@ -20,22 +20,23 @@ export function spRef2json(heap, ref) { loopStart, loopEnd, ] = new Uint32Array(heap, ref, 8); // 8*4 - const [fract, stride] = new Float32Array(heap, ref + 32, 3); // 8*3 + const [fract, stride, pdiff] = new Float32Array(heap, ref + 32, 3); // 8*3 const [zoneRef, volEGRef, modEGRef, modflo, vibrlfo, pcmRef] = new Uint32Array(heap, ref + 44, 6); return { fract, - stride, - inputRef, - outputRef, + stride, + pdiff, + // inputRef, + // outputRef, position, loopStart, loopEnd, zoneRef, - volEGRef, - modflo, - vibrlfo, + // volEGRef, + // modflo, + // vibrlfo, channelId, key, velocity, @@ -56,7 +57,7 @@ typedef struct { export function egStruct(heap, ref) { const [egval, egIncrement] = new Float32Array(heap, ref, 2); - const [hasRelease, stage, nsamples] = new Int32Array(heap, ref + 4, 3); + const [hasRelease, stage, nsteps] = new Int32Array(heap, ref + 4, 3); const [delay, attack, hold, decay, sustain, release] = new Int16Array( heap, ref + 20, @@ -68,12 +69,12 @@ export function egStruct(heap, ref) { egIncrement, hasRelease, stage, - nsamples, - delay, - attack, - hold, - decay, - sustain, - release, + nsteps, + adsr: [delay, + attack, + hold, + decay, + sustain, + release].join(",") }; } diff --git a/spin/spin.wasm b/spin/spin.wasm index 4c2130111c905afcf2338f9da399833207e37807..0b5c2b9a5369cadea7fcab5051758c525b587b1d 100755 GIT binary patch delta 318 zcmezUPhshQg$Yxb*w{BtOJUX!PEO28jxWe8NzRB*$xKU&&&f|`P!cRoEr~BK$jr-2 zEsD>~D=015ti+{(8c=DI$pz9Plar-SFs__DUuLq{CZGu?oTex+YccWkOtN6&0I@hG zYsr)_{+JvqyGUp;$RGtKpxGdT!;DF1GK<`Q#-p2AKf2E^>!CDl2S#MQBdfHGzPOkZTj GaT5S*GFqVk delta 275 zcmZ4bU*Y#Zg$Yxb*x5EtOJUX!EKV(nFD}T;%S$ba&&(?*En!d+PEO28jxWe8NzRB* z$xKU&&&f~Uti+IWxHExKFlV;s8l=aKD~hAiIclQA0xm z!(position; @@ -96,12 +96,13 @@ void set_midi_cc_val(int channel, int metric, int val) { midi_cc_vals[channel * 128 + metric] = (char)(val & 0x7f); } -float trigger_attack(spinner* x, int ratio, int velocity) { - x->stride = ratio; +float trigger_attack(spinner* x, int key, int velocity) { + x->stride = 1.0f; x->velocity = velocity; x->position = 0; x->fract = 0.0f; x->voleg->stage = init; + x->pdiff = calc_pitch_diff_log(x->zone, x->pcm, key); init_mod_eg(x->modeg, x->zone, x->pcm->sampleRate); init_vol_eg(x->voleg, x->zone, x->pcm->sampleRate); @@ -123,7 +124,8 @@ void set_spinner_input(spinner* x, pcm_t* pcm) { float calc_pitch_diff_log(zone_t* z, pcm_t* pcm, int key) { short rt = z->OverrideRootKey > -1 ? z->OverrideRootKey : pcm->originalPitch; float smpl_rate = rt * 100.0f + z->CoarseTune * 100.0f + (float)z->FineTune; - float diff = (key * 100 - smpl_rate) / 1200 + pcm->sampleRate - SAMPLE_RATE; + float diff = key * 100.0f - smpl_rate; + // diff += ((pcm->sampleRate - SAMPLE_RATE) / 4096.f * 100.f); return diff; } void set_spinner_zone(spinner* x, zone_t* z) { @@ -135,6 +137,7 @@ void set_spinner_zone(spinner* x, zone_t* z) { pcm = pcms + z->SampleId; } set_spinner_input(x, pcm); + x->zone = z; x->position += z->StartAddrOfs + (z->StartAddrCoarseOfs << 15); x->loopStart += z->StartLoopAddrOfs + (z->StartLoopAddrCoarseOfs << 15); x->loopEnd -= z->EndLoopAddrOfs - (z->EndLoopAddrCoarseOfs << 15); @@ -189,9 +192,9 @@ void _spinblock(spinner* x, int n, int blockOffset) { short modeg_vol = effect_floor(x->zone->ModEnv2Pitch); for (int i = 0; i < n; i++) { - stride = stride * - (12.0f + lfo1Out[i] * lfo1_pitch + lfo2Out[i] * lfo2_pitch) / - 12.0f; + stride = calcp2over200(x->pdiff + lfo1Out[i] * lfo1_pitch + + lfo2Out[i] * lfo2_pitch); + fract = fract + stride; while (fract >= 1.0f) { @@ -215,6 +218,7 @@ void _spinblock(spinner* x, int n, int blockOffset) { applyCentible(outputf, (short)(db + kRateCB + panRight)); db += dbInc; } + x->stride = stride; x->position = position; x->fract = fract; } diff --git a/spin/src/spin.h b/spin/src/spin.h index 3ce2855e..f68be1a3 100644 --- a/spin/src/spin.h +++ b/spin/src/spin.h @@ -19,7 +19,7 @@ typedef struct { float *inputf, *outputf; uint32_t channelId, key, velocity; uint32_t position, loopStart, loopEnd; - float fract, stride, calc_pitch_diff_log; + float fract, stride, pdiff; zone_t* zone; EG *voleg, *modeg; LFO *modlfo, *vibrlfo; diff --git a/src/createChannel.js b/src/createChannel.js index 6c58e8b0..ce6fe9d1 100644 --- a/src/createChannel.js +++ b/src/createChannel.js @@ -33,8 +33,7 @@ export function createChannel(uiController, channelId, sf2, apath) { spinner.port.postMessage([ midi_ch_cmds.note_on, channelId * 2 + i, - zone.calcPitchRatio(key, spinner.context.sampleRate), - vel, + key, vel, [this.presetId, zone.ref], ]); if (zone.FilterFC < 13500) { diff --git a/src/index.js b/src/index.js index 0f160b8a..a8164416 100644 --- a/src/index.js +++ b/src/index.js @@ -8,16 +8,13 @@ import {midi_ch_cmds} from "./constants.js"; import { sf2list } from "../sflist.js"; import {readMidi} from './midiread.js' import {mkcanvas, chart} from "../chart/chart.js"; +import * as sequence from "../dist/sequence.js" import {logdiv, mkcollapse} from "./logdiv.js"; const $ = (sel) => document.querySelector(sel); - const sf2select = $("#sf2select"), col4 = $("#col4"), col5 = $("#col5"); -// fetch("../sequence.build/asset-manifest.json").then(res => res.json()).then(json => { -// json.entrypoints.forEach(link => importScripts(link)) -// }) const drumList = document.querySelector("#drums"); const programList = document.querySelector("#programs"); const navhead = document.querySelector("header"); @@ -31,8 +28,8 @@ const {stdout, infoPanel} = logdiv(); mkcollapse({title: "Log Info", defaultOpen: true}, infoPanel).attachTo(stdoutdiv); window.stdout = stdout; -window.stderr = (str) => (document.querySelector("footer").innerHTML = str); -main("./file.sf2"); +window.stderr = stdout;// (str) => (document.querySelector("footer").innerHTML = str); +main(); const appState = {}; globalThis.appState = new Proxy(appState, { get(target, attr) { @@ -104,9 +101,7 @@ async function main(sf2file) { }, }); uiControllers = ui.controllers; - for (let i = 0; i < 16; i++) { - uiControllers[i].hidden = true; - + for (let i = 0;i < 16;i++) { channels.push(createChannel(uiControllers[i], i, sf2, apath)); } @@ -186,6 +181,7 @@ async function main(sf2file) { apath.bindKeyboard(() => ui.activeChannel, eventPipe); async function loadSF2File(sf2url) { sf2 = new SF2Service(sf2url); + sf2select.value = sf2url; await sf2.load(); programList.innerHTML = ""; drumList.innerHTML = ""; @@ -217,6 +213,9 @@ async function main(sf2file) { const bkid = channel == 10 ? 128 : 0; return channels[channel].setProgram(pid, bkid); })); + const rootElement = $("#sequenceroot"); + runSequence({midiInfo, rootElement, eventPipe}); + /* const worker = new Worker("./src/timer.js"); let msqn = midiInfo.tempos?.[0]?.tempo || 500000; @@ -250,18 +249,21 @@ async function main(sf2file) { midiInfo, eventPipe, rootElement: $("#sequenceroot") }); - // document.querySelector("#channelContainer").style.background = "none" - // document.querySelector("#channelContainer").style.background = "none" + document.querySelector("#channelContainer").style.background = "none" + document.querySelector("#channelContainer").style.background = "none" + */ + document.querySelector("#channelContainer").style.background = "none" + } apath.ctrl_bar(document.getElementById("ctrls")); apath.bindToolbar(); - const ffholder = mkdiv("div"), iffholder = mkdiv("div"); + const ffholder = mkdiv("div"); const [cv1, cv2] = [mkcanvas({container: ffholder}), mkcanvas({container: ffholder})]; mkcollapse({title: "fft", defaultOpen: true}, ffholder).attachTo(analyze); - loadSF2File("static/GeneralUserGS.sf2") + loadSF2File("static/FluidR3_GM.sf2") function draw() { chart(cv1, apath.analysis.frequencyBins); diff --git a/style.css b/style.css index 91548ecc..c665e2c9 100644 --- a/style.css +++ b/style.css @@ -1,12 +1,7 @@ th { - background: white; position: sticky; - top: 0; /* Don't forget this, required for the stickiness */ - box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.4); } .channelCard { - margin: 30px; - position:relative; } .channelCard:hover { @@ -14,6 +9,9 @@ th { color:black; } +#stdout{ + position:fixed;bottom:0; +} .amp-indicate { height: 20px; @@ -37,7 +35,6 @@ main { } #channelContainer{ grid-area: channelP; - max-height: 80vh; overflow-y: scroll; } #stdout{ @@ -64,61 +61,3 @@ main { } /* Makes sure that everything is 100% height */ - - html,body { - height: 100%; - overflow: hidden; background: rgba(255,255,255,.0); - - } - - /* gets the actual input out of the way; - we're going to style the label instead */ - - #drawer-toggle { - position: absolute; - opacity: 0; - } - - #drawer-toggle-label { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - left: 0px; - height:50px; - width: 50px; - display: block; - position: fixed; - background: rgba(255,255,255,.0); - z-index: 1; - } - - /* adds our "hamburger" menu icon */ - - #drawer-toggle-label:before { - content: ''; - display: block; - position: absolute; - height: 2px; - width: 24px; - background: #8d8d8d; - left: 13px; - top: 18px; - box-shadow: 0 6px 0 #8d8d8d, 0 12px 0 #8d8d8d; - } - - header { - width: 100%; - position: fixed; - left: 0px; - padding: 10px 10px 10px 50px; - font-size: 30px; - line-height: 30px; - z-index: 0; - margin:20px; - } - - /* drawer menu pane - note the 0px width */ - \ No newline at end of file