diff --git a/chart/chart.js b/chart/chart.js index d4e62c4c..324665e3 100755 --- a/chart/chart.js +++ b/chart/chart.js @@ -1,4 +1,4 @@ -import { mkdiv } from "https://unpkg.com/mkdiv@3.1.2/mkdiv.js"; +import { mkdiv } from "../mkdiv/mkdiv.js"; const WIDTH = 960, HEIGHT = 420; export function chart(canvasCtx, dataArray) { diff --git a/index.html b/index.html index 9ef7a18f..e1efd3ac 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,6 @@ + - - - + + + + + + \ No newline at end of file diff --git a/spin/src/spin.c b/spin/src/spin.c index 7d494d47..3675f690 100644 --- a/spin/src/spin.c +++ b/spin/src/spin.c @@ -14,7 +14,7 @@ unsigned char midi_cc_vals[nmidiChannels * 128] = {0}; float outputs[MAX_VOICE_CNT * RENDQ * 2]; float silence[440] = {.0f}; -float calc_pitch_diff_log(zone_t* z, pcm_t* pcm, unsigned char key); +float calc_pitch_diff_log(zone_t *z, pcm_t *pcm, unsigned char key); int output_arr_len = MAX_VOICE_CNT * RENDQ * 2; float volEgOut[RENDQ]; float modEgOut[RENDQ]; @@ -22,35 +22,42 @@ float lfo1Out[RENDQ]; float lfo2Out[RENDQ]; #define effect_floor(v) v <= -12000 ? 0 : calcp2over1200(v) -void sp_wipe_output_tab() { - for (int i = 0; i < output_arr_len; i++) { +void sp_wipe_output_tab() +{ + for (int i = 0; i < output_arr_len; i++) + { outputs[i] = 0.0f; } } -spinner* spRef(int idx) { return &sps[idx]; } -pcm_t* pcmRef(int sampleId) { return &pcms[sampleId]; } -spinner* allocate_sp() { - spinner* x = &sps[sp_idx % MAX_VOICE_CNT]; +spinner *spRef(int idx) { return &sps[idx]; } +pcm_t *pcmRef(int sampleId) { return &pcms[sampleId]; } +spinner *allocate_sp() +{ + spinner *x = &sps[sp_idx % MAX_VOICE_CNT]; x->outputf = &outputs[sp_idx * RENDQ * 2]; sp_idx++; return x; } -spinner* newSpinner(int ch) { - spinner* x = allocate_sp(); +spinner *newSpinner(int ch) +{ + spinner *x = allocate_sp(); x->outputf = &outputs[ch * RENDQ * 2]; x->inputf = silence; x->channelId = ch; return x; } -void trigger_release(spinner* x) { +void trigger_release(spinner *x) +{ _eg_release(&x->voleg); _eg_release(&x->modeg); - if (x->zone->SampleModes > 1) { + if (x->zone->SampleModes > 1) + { x->is_looping = 0; } } -void reset(spinner* x) { +void reset(spinner *x) +{ x->position = 0; x->stride = .0f; x->fract = 0.0f; @@ -67,11 +74,13 @@ void reset(spinner* x) { x->active_dynamics_flag = 0; } -void set_midi_cc_val(int channel, int metric, int val) { +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, uint32_t key, uint32_t velocity) { +float trigger_attack(spinner *x, uint32_t key, uint32_t velocity) +{ #define ccval(eff) midi_cc_vals[x->channelId * 128 + eff] x->velocity = (unsigned char)velocity; @@ -79,9 +88,9 @@ float trigger_attack(spinner* x, uint32_t key, uint32_t velocity) { x->fract = 0.0f; x->voleg.stage = init; x->key = (unsigned char)(key & 0x7f); - EG* eg = &x->voleg; + EG *eg = &x->voleg; float scaleFactor = SAMPLE_RATE / (float)x->pcm->sampleRate; - zone_t* z = x->zone; + zone_t *z = x->zone; eg->attack = (ccval(VCA_ATTACK_TIME) > 0) ? midi_p1200[ccval(VCA_ATTACK_TIME) | 0] : z->VolEnvAttack * scaleFactor; @@ -102,7 +111,8 @@ float trigger_attack(spinner* x, uint32_t key, uint32_t velocity) { eg = &x->modeg; eg->stage = init; - if (ccval(TML_BANK_SELECT_MSB) > 0) { + if (ccval(TML_BANK_SELECT_MSB) > 0) + { x->is_looping = 0; } @@ -146,7 +156,8 @@ float trigger_attack(spinner* x, uint32_t key, uint32_t velocity) { return x->stride; }; -void set_spinner_input(spinner* x, pcm_t* pcm) { +void set_spinner_input(spinner *x, pcm_t *pcm) +{ x->loopStart = pcm->loopstart; x->loopEnd = pcm->loopend; x->inputf = pcm->data; @@ -155,15 +166,17 @@ void set_spinner_input(spinner* x, pcm_t* pcm) { x->position = 0; } -float calc_pitch_diff_log(zone_t* z, pcm_t* pcm, unsigned char key) { +float calc_pitch_diff_log(zone_t *z, pcm_t *pcm, unsigned char key) +{ short rt = z->OverrideRootKey > -1 ? z->OverrideRootKey : pcm->originalPitch; float smpl_rate = rt * 100.f + z->CoarseTune * 100.f + z->FineTune; float diff = key * 100.f - smpl_rate; diff += ((pcm->sampleRate - SAMPLE_RATE) / 40.96f); return diff; } -void set_spinner_zone(spinner* x, zone_t* z) { - pcm_t* pcm = &pcms[z->SampleId]; +void set_spinner_zone(spinner *x, zone_t *z) +{ + pcm_t *pcm = &pcms[z->SampleId]; set_spinner_input(x, pcm); x->zone = z; @@ -177,7 +190,8 @@ void set_spinner_zone(spinner* x, zone_t* z) { x->sampleLength -= z->EndAddrOfs - (z->EndAddrCoarseOfs << 15); } -void _spinblock(spinner* x, int n, int blockOffset) { +void _spinblock(spinner *x, int n, int blockOffset) +{ #define ccval(eff) midi_cc_vals[x->channelId * 128 + eff] double db, dbInc; @@ -185,8 +199,8 @@ void _spinblock(spinner* x, int n, int blockOffset) { float pdiff = x->pitch_dff_log; int ch = x->channelId; - float* output_L = &x->outputf[blockOffset]; - float* output_R = &x->outputf[RENDQ + blockOffset]; + float *output_L = &x->outputf[blockOffset]; + float *output_R = &x->outputf[RENDQ + blockOffset]; eg_roll(&x->modeg, n, modEgOut); eg_roll(&x->voleg, n, volEgOut); LFO_roll_out(&x->modlfo, n, lfo1Out); @@ -202,7 +216,8 @@ void _spinblock(spinner* x, int n, int blockOffset) { kRateCB += (float)x->zone->Attenuation; kRateCB += midi_volume_log10(ccval(TML_VOLUME_MSB)); kRateCB += midi_volume_log10(midi_cc_vals[ch * 128 + TML_EXPRESSION_MSB]); - if (x->voleg.stage < decay) kRateCB += midi_volume_log10(x->velocity); + if (x->voleg.stage < decay) + kRateCB += midi_volume_log10(x->velocity); double panLeft = panleftLUT[midi_cc_vals[ch * 128 + TML_PAN_MSB]]; @@ -220,7 +235,8 @@ void _spinblock(spinner* x, int n, int blockOffset) { float Q = x->initialQ; short initFc = x->initialFc; - for (int i = 0; i < n; i++) { + for (int i = 0; i < n; i++) + { db = volEgOut[i] + lfo1_volume * lfo1Out[i]; pdiff += lfo1Out[i] * lfo1_pitch + modEgOut[i] * modeg_pitch + lfo2Out[i] * lfo2_pitch; @@ -228,23 +244,27 @@ void _spinblock(spinner* x, int n, int blockOffset) { stride = calcp2over1200(pdiff); fract = fract + stride; - while (fract >= 1.0f) { + while (fract >= 1.0f) + { position++; fract -= 1.0f; } - if (position >= x->loopEnd && isLooping > 0) position -= looplen; + if (position >= x->loopEnd && isLooping > 0) + position -= looplen; outputf = lerp(x->inputf[position], x->inputf[position + 1], fract); tfc = initFc + modeg_fc * modEgOut[i] + x->lfo1_fc * lfo1Out[i]; - if (position >= nsamples) { + if (position >= nsamples) + { position = 0; outputf = 0.0; x->voleg.stage = done; } outputf = applyCentible(outputf, (short)(db + kRateCB)); - if (tfc > .5) { + if (tfc > .5) + { fchertz = timecent2hertz(tfc) / SAMPLE_RATE; // new_lpf(&lpf, fchertz, Q);/ outputf = calc_lpf(&lpf, outputf); @@ -257,37 +277,43 @@ void _spinblock(spinner* x, int n, int blockOffset) { x->stride = stride; } -int spin(spinner* x, int n) { +int spin(spinner *x, int n) +{ _spinblock(x, 64, 0); _spinblock(x, 64, 64); - if (x->voleg.egval < -1440.f) { + if (x->voleg.egval < -1440.f) + { x->voleg.stage = done; return 0; } - if (x->voleg.stage == done) { + if (x->voleg.stage == done) + { return 0; } return 1; } unsigned int sp_byte_len() { return sizeof(spinner); } -EG* get_vol_eg(spinner* x) { return &x->voleg; } -EG* get_mod_eg(spinner* x) { return &x->modeg; } +EG *get_vol_eg(spinner *x) { return &x->voleg; } +EG *get_mod_eg(spinner *x) { return &x->modeg; } -float* get_sp_output(spinner* x) { return x->outputf; } -int get_sp_channel_id(spinner* x) { return x->channelId; } +float *get_sp_output(spinner *x) { return x->outputf; } +int get_sp_channel_id(spinner *x) { return x->channelId; } -void gm_reset() { - for (int idx = 0; idx < nmidiChannels; idx++) { +void gm_reset() +{ + for (int idx = 0; idx < nmidiChannels; idx++) + { midi_cc_vals[idx * num_cc_list + TML_VOLUME_MSB] = 100; midi_cc_vals[idx * num_cc_list + TML_PAN_MSB] = 64; midi_cc_vals[idx * num_cc_list + TML_EXPRESSION_MSB] = 127; if (idx == def_drum_c) midi_cc_vals[idx * num_cc_list + TML_BANK_SELECT_MSB] = 128; } - for (int i = 0; i < nchannels; i++) reset(&sps[i]); + for (int i = 0; i < nchannels; i++) + reset(&sps[i]); } // #include // #include diff --git a/src/eqslide.js b/src/eqslide.js index ee791298..032a3ca4 100644 --- a/src/eqslide.js +++ b/src/eqslide.js @@ -81,9 +81,7 @@ export function mkknob(params) { } export function mk_eq_bar(ch, onInput) { const post_val = (cc_num, val) => - port.postMessage( - new Uint8Array([midi_ch_cmds.continuous_change, ch, cc_num, val]) - ); + port.postMessage([midi_ch_cmds.continuous_change, ch, cc_num, val]); return mkdiv("fieldset", { class: "knob-set" }, [ mkdiv("legend", "EQ"), ...[31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000, 16000].map((f) => @@ -104,9 +102,7 @@ export function mk_vca_ctrl(ch, port) { const zdx = ["VolEnvAttack", "VolEnvDecay", "VolEnvSustain", "VolEnvRelease"]; const defaults = [9, 33, 66, 88]; const post_val = (cc_num, val) => - port.postMessage( - new Uint8Array([midi_ch_cmds.continuous_change, ch, cc_num, val]) - ); + port.postMessage([midi_ch_cmds.continuous_change, ch, cc_num, val]); for (let i = VCA_ATTACK_TIME; i <= VCA_RELEASE_TIME; i++) { divbox.push( mkknob({ @@ -131,9 +127,7 @@ export function mk_vcf_ctrl(ch, port) { const defaults = [9, 33, 66, 88, 0, 0]; const post_val = (cc_num, val) => - port.postMessage( - new Uint8Array([midi_ch_cmds.continuous_change, ch, cc_num, val]) - ); + port.postMessage([midi_ch_cmds.continuous_change, ch, cc_num, val]); const divbox = [mkdiv("legend", legendtitle)]; for (let i = from; i <= to; i++) { divbox.push( diff --git a/src/index.js b/src/index.js index da7bd7f1..93738885 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import {mkdiv, mkdiv2} from "https://unpkg.com/mkdiv@3.1.2/mkdiv.js"; +import { mkdiv, mkdiv2 } from "../mkdiv/mkdiv.js"; import { mkui } from "./ui.js"; import SF2Service from "../sf2-service/index.js"; import { fetchSF2List, fetchmidilist } from "./midilist.js"; @@ -10,7 +10,7 @@ import { mfilelist } from "../mfilelist.js"; import { readMidi } from "./midiread.js"; import { mkcanvas, chartRect, chart } from "../chart/chart.js"; -import * as sequence from "../dist/sequence.js"; +// import * as sequence from "../dist/sequence.js"; import { logdiv, mktabs, mkcollapse } from "./logdiv.js"; import { mk_vcf_ctrl, @@ -60,7 +60,7 @@ mkcollapse({ title: "debug", defaultOpen: false }, debugInfo).attachTo( debugContainer ); mkcollapse({ title: "ctr", defaultOpen: false }, ctrbar).attachTo( - document.querySelector("body") + document.querySelector("#ch_ctrl_bar") ); mkcollapse({ title: "debug2", defaultOpen: false }, debugInfo2).attachTo( debugContainer @@ -72,9 +72,6 @@ mkcollapse({ title: "Log Info", defaultOpen: false }, infoPanel).attachTo( const rend_took_len = []; window.stdout = stdout; window.stderr = (str) => (debugInfo.innerHTML = str); -window.stderrr = (str) => { - /*devnull*/ -}; //stderrrdiv.innerHTML = str; const midiUrl = new URL(document.location).searchParams.get("midi"); let sf2, uiControllers, ctx; @@ -186,9 +183,11 @@ eventPipe.onmessage(function (dd) { spinner.port.postMessage([cmd, ch, v1, v2]); break; case midi_ch_cmds.change_program: //change porg - console.log(cmd, ch, v1, v2); - channels[ch].setProgram(v1, v2); - + if (v1 == 0 && ch >= 0) { + channels[ch].setProgram(v1, 128); + } else { + channels[ch].setProgram(v1, ch === DRUMSCHANNEL ? 128 : 0); + } break; case midi_ch_cmds.note_on: if (velocity == 0) { diff --git a/src/logdiv.js b/src/logdiv.js index 2004794d..53022f70 100644 --- a/src/logdiv.js +++ b/src/logdiv.js @@ -1,4 +1,4 @@ -import {mkdiv} from "../mkdiv/mkdiv.js"; +import { mkdiv } from "../mkdiv/mkdiv.js"; const defaultsConfig = { rows: 120, size: 70, @@ -9,7 +9,9 @@ const defaultsConfig = { export function mktabs({ container, group }) { if (!container) container = mkdiv("div"); const tb = mkdiv("div", { class: "tabs" }); + const tabBody = mkdiv("div", { class: "tab-body" }); tb.attachTo(container); + tabBody.attachTo(container); return { tabs: tb, push_ch: (id, title, ch) => { @@ -26,81 +28,83 @@ export function mktabs({ container, group }) { }, title ).attachTo(tb); - ch.attachTo(tb); + ch.attachTo(tabBody); }, }; } export function logdiv(config = {}) { - const {rows, size, className, container, timestamp} = Object.assign(config, defaultsConfig); - const infoPanel = mkdiv("pre", { - id: "infop", - style: "width:80em;", - rows, - className, - }); - if (container) - infoPanel.attachTo(container); - let lp = performance.now(); - const logs = []; - new MutationObserver(() => { - requestIdleCallback(() => infoPanel.scrollTo({ - top: infoPanel.scrollHeight, - })); - }).observe(infoPanel, { - childList: true - }); - function stdout(...logp) { - const log = logp.join("\t"); - const ts = timestamp ? ((performance.now()) / 1e3).toFixed(3) + ": " : ""; - lp = performance.now(); - let offset = 0; - logs.push(lp + ":"); - while (offset < log.length) { - logs.push(log.substring(offset, 80) + "\n"); - offset += 80; - } - infoPanel.textContent += "\n" + ts + log.toString(); + const { rows, size, className, container, timestamp } = Object.assign( + config, + defaultsConfig + ); + const infoPanel = mkdiv("pre", { + id: "infop", + style: "width:80em;", + rows, + className, + }); + if (container) infoPanel.attachTo(container); + let lp = performance.now(); + const logs = []; + new MutationObserver(() => { + requestIdleCallback(() => + infoPanel.scrollTo({ + top: infoPanel.scrollHeight, + }) + ); + }).observe(infoPanel, { + childList: true, + }); + function stdout(...logp) { + const log = logp.join("\t"); + const ts = timestamp ? (performance.now() / 1e3).toFixed(3) + ": " : ""; + lp = performance.now(); + let offset = 0; + logs.push(lp + ":"); + while (offset < log.length) { + logs.push(log.substring(offset, 80) + "\n"); + offset += 80; } - return { - stdout, - infoPanel, - }; + infoPanel.textContent += "\n" + ts + log.toString(); + } + return { + stdout, + infoPanel, + }; } -export function mkcollapse({title, id, defaultOpen}, children) { - if (!id) - id = (Math.random() * 10000).toFixed(0); - const checked = `${defaultOpen ? "checked" : ""}`; - const wrap = mkdiv("div", { - class: "wrap-collapsible", - }); - wrap.innerHTML = - `` + - `` + - `
+export function mkcollapse({ title, id, defaultOpen }, children) { + if (!id) id = (Math.random() * 10000).toFixed(0); + const checked = `${defaultOpen ? "checked" : ""}`; + const wrap = mkdiv("div", { + class: "wrap-collapsible", + }); + wrap.innerHTML = + `` + + `` + + `

`; - const cd = wrap.querySelector(".collapsible-content"); - const innerContent = wrap.querySelector(".content-inner"); - if (!innerContent) - throw "typescript "; - innerContent.replaceChildren(children); - new MutationObserver((mutationList) => { - mutationList.forEach((mutation) => { - switch (mutation.type) { - case "attributes": - switch (mutation.attributeName) { - case "style": - console.log(mutation); - break; - } - break; - } - }); - }).observe(cd, { - attributeFilter: ["style"] + const cd = wrap.querySelector(".collapsible-content"); + const innerContent = wrap.querySelector(".content-inner"); + if (!innerContent) throw "typescript "; + innerContent.replaceChildren(children); + new MutationObserver((mutationList) => { + mutationList.forEach((mutation) => { + switch (mutation.type) { + case "attributes": + switch (mutation.attributeName) { + case "style": + console.log(mutation); + break; + } + break; + } }); - return wrap; + }).observe(cd, { + attributeFilter: ["style"], + }); + return wrap; } diff --git a/src/sequence/App.js b/src/sequence/App.js index 17a4a845..d315ff09 100644 --- a/src/sequence/App.js +++ b/src/sequence/App.js @@ -1,6 +1,6 @@ -import {useEffect, useRef, useState} from "react"; -import {Sequence} from "./sequence"; -import React from 'react'; +import { useEffect, useRef, useState } from "react"; +import { Sequence } from "./sequence"; +import React from "react"; import { TIMER_STATE, available_btns, @@ -12,25 +12,25 @@ import { } from "./constants"; import useTM from "./useTM"; import "./App.css"; -import {createPortal} from "react-dom"; +import { createPortal } from "react-dom"; const M_HEIGHT = window.visualViewport?.height - 120; const ranEvents = []; const notesDown = new Map(); -function App({timerWorker, midiInfo, eventPipe}) { +function App({ timerWorker, midiInfo, eventPipe }) { const presetMap = midiInfo.presets.reduce( - (map, {pid, channel}) => ({ + (map, { pid, channel }) => ({ ...map, [channel]: pid, }), - {0: 0} + { 0: 0 } ); const chRef = useRef([]); - const [tm, {setTempo, setTM, setTS1, setTS2}] = useTM( + const [tm, { setTempo, setTM, setTS1, setTS2 }] = useTM( get_time_base(midiInfo) ); - const {msqn, tempo, ts1, ppqn} = tm; - const [{ticks, clock}, setNow] = useState({ticks: 0, clock: 0}); + const { msqn, tempo, ts1, ppqn } = tm; + const [{ ticks, clock }, setNow] = useState({ ticks: 0, clock: 0 }); const [timerState, setTimerState] = useState(TIMER_STATE.INIT); const sequencerRef = useRef(); const tempos = midiInfo.tempos; @@ -46,7 +46,7 @@ function App({timerWorker, midiInfo, eventPipe}) { ranEvents.length && ranEvents[ranEvents.length - 1].event.t > ticks ) { - const {event, ch} = ranEvents.pop(); + const { event, ch } = ranEvents.pop(); midiInfo.tracks[ch].push(event); } queueMicrotask(() => setTimerState(TIMER_STATE.RUNNING)); @@ -73,7 +73,7 @@ function App({timerWorker, midiInfo, eventPipe}) { timerWorker.postMessage(tm); }, [timerWorker, tm]); useEffect(() => { - timerWorker.addEventListener("message", ({data}) => { + timerWorker.addEventListener("message", ({ data }) => { if (!data.ticks) return; for (let i in midiInfo.tracks) { const track = midiInfo.tracks[i]; @@ -81,7 +81,7 @@ function App({timerWorker, midiInfo, eventPipe}) { const event = track.shift(); if (!event.channel) continue; eventPipe.postMessage(event.channel); - ranEvents.push({event, ch: i}); + ranEvents.push({ event, ch: i }); // queueMicrotask(() => { // const [status, key, vel] = event.channel; // const cmd = status >> 4, @@ -106,7 +106,6 @@ function App({timerWorker, midiInfo, eventPipe}) { // break; // } // }); - } } @@ -119,16 +118,7 @@ function App({timerWorker, midiInfo, eventPipe}) { } setNow(data); }); - }, [ - timerWorker, - eventPipe, - midiInfo.tracks, - tempos, - setTM, - tm, - ppqn, - msqn, - ]); + }, [timerWorker, eventPipe, midiInfo.tracks, tempos, setTM, tm, ppqn, msqn]); useEffect(() => { if (sequencerRef.current) @@ -138,8 +128,7 @@ function App({timerWorker, midiInfo, eventPipe}) { if (!sequencerRef.current) return; let id1, id2; let ref = sequencerRef.current; - ref.style.setProperty("--timer-ticks", ticks) - + ref.style.setProperty("--timer-ticks", ticks); }, [sequencerRef.current, ticks]); const mkbtn = (cmd) => ( @@ -147,7 +136,7 @@ function App({timerWorker, midiInfo, eventPipe}) { type="button" key={cmd} onClick={() => { - timerWorker.postMessage({cmd}); + timerWorker.postMessage({ cmd }); if (Object.keys(cmd2stateChange).indexOf(cmd) > -1) { setTimerState(cmd2stateChange[cmd]); } @@ -159,9 +148,9 @@ function App({timerWorker, midiInfo, eventPipe}) { return ( <>
- +
clock: {(clock / 1000).toFixed(2).toString().split(".").join(":")} - +
{available_btns[timerState].map((cmd) => ( (e.target.value = ""), list: idx == DRUMSCHANNEL ? "drums" : "programs", onchange: (e) => { const pid = e.target.value & 0x7f; - const bkid = e.target.value & 0x80; + const bkid = e.target.value >> 7; const change_program = midi_ch_cmds.change_program; cb([change_program | idx, pid, bkid]); e.target.blur(); @@ -88,37 +81,17 @@ export function mkui( }, }), this.zoneEdit, - mkdiv("input", { - min: 1, - max: 127, - value: 100, - step: 1, - id: "vol", - type: "range", - oninput: (e) => cb([0xb0 | idx, 7, e.target.value]), - }), - "EXPR", - mkdiv("input", { - min: 1, - max: 127, - value: 100, - step: 1, - id: "vol", - type: "range", - oninput: (e) => - cb([0xb0 | idx, midi_effects.expressioncoarse, e.target.value]), - }), - "PAN", - mkdiv("input", { - min: 1, - max: 127, - value: 100, - step: 1, - id: "vol", - type: "range", - oninput: (e) => - cb([0xb0 | idx, midi_effects.pancoarse, e.target.value]), - }), + mkdiv("div", [ + mkdiv("input", { + min: 1, + max: 128, + value: 100, + step: 1, + id: "vol", + type: "range", + oninput: (e) => cb([0xb0 | idx, 7, e.target.value]), + }), + ]), ]); const ampshow = mkdiv("div", { class: "amp-indicate", @@ -179,13 +152,21 @@ export function mkui( this._active = false; this._midi = null; this.tt = 0; + this.toffset = 0; + this.timePerFrame = (W / this.config.pxpqn) * this.config.sPerqn; } rendFrame() { const ppt = this.config.pxpqn * 2; - + if (this.timePerFrame < this.tt - this.toffset) { + this.cctx.clearRect(0, 0, W, H); + this.toffset += this.timePerFrame; + } + this.cctx.clearRect(0, 0, 100, 20); + this.cctx.fillText(this.tt.toFixed(1), 0, 10, 100); + //this.tt + "|" + this.toffset, 0, 10, 100); + this.cctx.save(); for (const [t0, k0, dt] of this.timeline) { - const x0 = (t0 * ppt) % W; - + const x0 = (t0 - this.toffset) * ppt; if (this.tt > t0 + 10) continue; const h1 = this.config.pxPerSemi * (k0 - baseOctave); this.cctx.fillRect(x0, h1, dt * ppt, this.config.pxPerSemi); @@ -254,26 +235,15 @@ export function mkui( }); }, }, - mkdiv("ul", [ - mkdiv("input", { - role: "button", - value: "save", - type: "submit", - }), + mkdiv("table", [ + mkdiv("tr", [mkdiv("th", "name"), mkdiv("th", "value")]), ...Array.from(this._zone.arr).map((attr, index) => mkdiv("tr", [ - mkdiv( - "td", - { - class: attr === defZone[index] ? "hidden" : "", - }, - attributeKeys[index] - ), + mkdiv("td", attributeKeys[index]), mkdiv("td", {}, [ mkdiv("input", { value: attr, name: index, - class: attr === defZone[index] ? "hidden" : "", placeholder: "a", oninput: (a) => { zmap[attributeKeys[index]] = a.target.value; diff --git a/webpack.config.js b/webpack.config.js index cd844790..bb0fcc35 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -17,7 +17,8 @@ Fs.writeFileSync( .execSync("ls -rS static/midi/*mid") .toString() .trim() - .split("\n").map(f => encodeURI(f)) + .split("\n") + .map((f) => encodeURI(f)) )}` ); const path = require("path"); @@ -49,7 +50,7 @@ module.exports = { }, devtool: "inline-source-map", devServer: { - static: "." + static: ".", }, output: { filename: "[name].js",