@tir.jp/asg3 0.1.20260404-ALPHA
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/dist/asg3.min.mjs +1 -0
- package/dist/asg3.mjs +646 -0
- package/package.json +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
zlib License
|
|
2
|
+
|
|
3
|
+
(C) 2026 ayamada
|
|
4
|
+
|
|
5
|
+
This software is provided 'as-is', without any express or implied
|
|
6
|
+
warranty. In no event will the authors be held liable for any damages
|
|
7
|
+
arising from the use of this software.
|
|
8
|
+
|
|
9
|
+
Permission is granted to anyone to use this software for any purpose,
|
|
10
|
+
including commercial applications, and to alter it and redistribute it
|
|
11
|
+
freely, subject to the following restrictions:
|
|
12
|
+
|
|
13
|
+
1. The origin of this software must not be misrepresented; you must not
|
|
14
|
+
claim that you wrote the original software. If you use this software
|
|
15
|
+
in a product, an acknowledgment in the product documentation would be
|
|
16
|
+
appreciated but is not required.
|
|
17
|
+
2. Altered source versions must be plainly marked as such, and must not be
|
|
18
|
+
misrepresented as being the original software.
|
|
19
|
+
3. This notice may not be removed or altered from any source distribution.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var de,B=(e=521288629)=>de=e;B();var ye=Number.EPSILON*2,ge=1-Number.EPSILON*2,ve=e=>Math.max(ye,Math.min(e,ge));var $=(e,t=521288629)=>{let n=t+Math.imul(e+1|0,1831565813)|0;return xe(n)},xe=e=>{let t=Math.imul(e^e>>>15,e|1);return t=t+Math.imul(t^t>>>7,t|61)^t,ve(((t^t>>>14)>>>0)/4294967296)};var j=e=>7040*2**((e-69)/12-4),X=(e,t=4)=>{let n=e.length;if(t*2<n)for(let o=0;o<t;o++){let r=o/t;e[o]*=r,e[n-1-o]*=r}},H=(e,t,n,o=1)=>{if(o<=0)return e+(t-e)*n;let r;if(o===1)r=(1-Math.cos(n*Math.PI))*.5;else{let i=-Math.cos(n*Math.PI),c=i;o>1&&(c=Math.sign(i)*Math.pow(Math.abs(i),1/o));let s=(c+1)*.5;o<1?r=n*(1-o)+s*o:r=s}return e+(t-e)*r},O=(e,t,n)=>.5*(e+t-(t-e)*Math.cos(n*Math.PI)),V=(e,t,n,o)=>O(e,t,Math.min(1,n*Math.max(1,o)));var Z=(e,t,n)=>{let o=n*e.length,r=Math.floor(o),i=o%1,c=e[r%e.length],s=e[(r+1)%e.length],l=.5/e.length/t;return V(c,s,i,l)},b=.95,Fe=e=>{let t=e.lapProgress*4,n=t<1?t:t<3?2-t:t-4,o=Math.abs(n)-b;if(o<=0)return n;let r=o/(1-b),i=r*(1-r*.5);return Math.sign(n)*(b+i*(1-b))},J=e=>{let t=1-e*2,n=-b,o=b;if(n<=t&&t<=o)return t;let r=t<0?t+2:t,i=n+2,c=o,s=(r-i)/(c-i);return O(n,o,s)},v=(e,t)=>$(t*2+(e.seedOffset||0)),ke=e=>v(e,e.tick)*2-1,Me=e=>v(e,e.tick)>=.5?1:-1,Ne=e=>v(e,e.lapCount)*2-1,Q=e=>v(e,e.lapCount)>=.5?1:-1,be=e=>{let t=v(e,e.lapCount)*2-1,n=e.lapCount?v(e,e.lapCount-1)*2-1:t;return V(n,t,e.lapProgress,1)},Le=e=>{let t=v(e,e.lapCount)>=.5?1:-1,n=e.lapCount?v(e,e.lapCount-1)>=.5?1:-1:t;return V(n,t,e.lapProgress,1)},Ie=(e,t,n)=>{let o=[],r=0;for(let i=e;i<=t;i++){let c=n(i);o.push(c),r+=c}return i=>{let c=i.lapCount+i.lapProgress,s=0;for(let l=e;l<=t;l++){let u=2**l,a=Math.floor(c*u)*13+l,f=v(i,a)*2-1;s+=f*o[l-e]}return s/r}},Te=e=>.8**Math.abs(e),We=Ie(-4,4,Te),Y={sine:e=>Math.sin(e.lapProgress*2*Math.PI),saw:e=>J(e.lapProgress),"saw-reverse":e=>J(1-e.lapProgress),square:(e=>Z([1,-1],e.noteFreqByTick,e.lapProgress)),triangle:Fe,noise:Q,"noise-binary":Q,"noise-white":Ne,"noise-binary-rounded":Le,"noise-white-rounded":be,"noise-binary-frequencyless":Me,"noise-white-frequencyless":ke,"noise-fractal":We},Ae=(e,t)=>e?.constructor===String||e?.constructor===Function||Array.isArray(e)&&e.every(Number.isFinite)?e:t,C=(e,t)=>{if(e=Ae(e,t),e instanceof Function)return e;if(Array.isArray(e))return(o=>Z(e,o.noteFreqByTick,o.lapProgress));let n;return e?.constructor===String&&(n=Y[e]),n||(n=Y["noise-binary-frequencyless"]),n};var Se=1,U=["envelope","sweep","vibrato","tremolo","lfo","morph"],M=(e,t,n=0)=>{let o=[{x:0,v:n}],r=0;if(Number.isFinite(e))return()=>e;if(e&&e.length>0)for(let s of e){let l=Array.isArray(s)&&Number.isFinite(s[0])?s[0]:0,u=Array.isArray(s)&&Number.isFinite(s[1])?s[1]:n,p=Array.isArray(s)&&Number.isFinite(s[2])?s[2]:Se;r+=l,o.push({x:r,v:u,interpolationIntensity:p})}else return()=>n;let i=r||1,c=0;return s=>{let l=s/Math.max(1,t-1)*i;for(;c<o.length-1&&o[c+1].x<=l;)c++;for(;c>0&&o[c].x>l;)c--;let u=o[c],p=o[c+1];if(!p)return u.v;let a=p.x-u.x;if(a<=1e-9)return p.v;let f=(l-u.x)/a;return H(u.v,p.v,f,p.interpolationIntensity)}},Pe=e=>{let t=0;if(e){let n=0;for(let o=0;o<e.length;o++){let r=e[o],i=Array.isArray(r)&&Number.isFinite(r[0])?r[0]:0;n<i&&(t=o,n=i)}}return t},ee=(e,t,n=void 0)=>{if(e.duration===void 0||e.duration===t)return e;let o=null;for(let a of U)if(Array.isArray(e[a])&&e[a].length>0){o=e[a];break}if(n===void 0&&(n=e.preferredScaleGraphTargetIdx??Pe(o)),!o||!o[n])return{...e,duration:t};let r=o.reduce((a,f)=>{let h=Array.isArray(f)&&Number.isFinite(f[0])?f[0]:0;return a+h},0);if(r<=0)return{...e,duration:t};let i=Array.isArray(o[n])&&Number.isFinite(o[n][0])?o[n][0]:0,c=t/e.duration,s=r*c,l=i+(s-r),u=t;if(l<0){l=0;let a=r-i;u=e.duration*(a/r)}let p={...e,duration:u};for(let a of U)Array.isArray(p[a])&&(p[a]=p[a].map((f,h)=>h===n?[l,f[1]]:f));return p};var Ce=[[0,1],[1,0]],te="triangle",qe="sine",ne=(e,t)=>{let n=e.lapProgress+t,o=Math.floor(n);e.lapCount+=o,e.lapProgress=n-o},W=(e,t)=>{let n=Number.isFinite(t.noteNumber)?t.noteNumber:69,o=Number.isFinite(t.velocity)?t.velocity:100,r=Number.isFinite(t.duration)?t.duration:1,i=C(t.waveform,te),c=t.morphWaveform?C(t.morphWaveform,te):null,s=C(t.lfoWaveform,qe);B();let l=Math.max(4,Math.ceil(r*e)),u=new Float32Array(l),p=M(t.envelope||Ce,l,t.envelope?.length?0:1),a=M(t.sweep,l,0),f=M(t.vibrato,l,0),h=M(t.tremolo,l,0),N=M(t.lfo,l,4),d=M(t.morph,l,0),m={tick:0,lapProgress:0,lapCount:0,noteFreqByTick:0,seedOffset:0},y={tick:0,lapProgress:0,lapCount:0,noteFreqByTick:0,seedOffset:1},A=o/127;for(;m.tick<l;){y.tick=m.tick;let w=p(m.tick),L=a(m.tick),g=f(m.tick),I=h(m.tick),S=N(m.tick),k=d(m.tick);y.noteFreqByTick=S/e,ne(y,y.noteFreqByTick);let T=s(y),q=I*T,R=g*T,me=j(n+L+R);m.noteFreqByTick=me/e,ne(m,m.noteFreqByTick);let P=i(m);if(c&&k>0)if(k>=1)P=c(m);else{let he=c(m);P=P*(1-k)+he*k}u[m.tick]=P*A*w*Math.max(0,1+q),m.tick++}return X(u),[u]};var Be=(e=69,t=69)=>e+t-69,Oe=(e=100,t=100)=>e*t/100,D=(e,t)=>({noteNumber:Be(e.noteNumber,t.noteNumber),velocity:Oe(e.velocity,t.velocity),duration:e.duration,graphScaleIdx:e.graphScaleIdx}),E=(e,t)=>`${e}-${t.noteNumber}-${t.velocity}-${t.duration}-${t.graphScaleIdx}`,_e=e=>Number.isInteger(e),oe=(e,t)=>{let n=new Map;for(let c of e)for(let s of c)if(!_e(s)){let l=s.calibrateParams||{},u=D(l,t),p=s.inst||0,a=E(p,u);n.set(a,(n.get(a)||0)+1)}let o=[];for(let[c,s]of n.entries())s>=2&&o.push({key:c,count:s});o.sort((c,s)=>s.count-c.count);let r=Math.floor(o.length*.2);o.length>0&&r===0&&(r=1);let i=new Set;for(let c=0;c<r;c++)i.add(o[c].key);return i};var re=(e,t,n)=>(console.log("niy"),t),se=e=>(console.log("niy"),e);var ce=e=>Number.isInteger(e),De=e=>Math.max(8,Math.floor(e*.001)),ie=(e,t,n)=>{let o=Math.min(n,e.length-t);for(let r=0;r<o;r++)t+r<0||(e[t+r]*=r/n)},le=(e,t,n)=>{let o=Math.min(n,t);for(let r=0;r<o;r++)t-r-1<0||(e[t-r-1]*=r/n)},ae=(e,t,n,o)=>{let r=Math.min(n.length,e.length-t);if(!(r<=0))if(o===1)e.set(n.subarray(0,r),t);else for(let i=0;i<r;i++)t+i<0||(e[t+i]=n[i]*o)},ue=(e,t,n,o,r,i,c)=>{let s,l=0;for(let d of n)ce(d)?l+=d:s??=l;s??=0;let u=s,p=l-s,a=new Float32Array(p),f=new Float32Array(p),h=-u,N=De(e);for(let d of n)if(ce(d))h+=d;else{le(a,h,N),le(f,h,N);let m=d.calibrateParams||{},y=D(m,o),A=d.inst||0,w=t[A],L=E(A,y),g;r.has(L)?(g=i.get(L),g||(g=c(e,y,w),i.set(L,g))):g=c(e,y,w);let I=g[0],S=g[1]||I;ie(a,h+I.length,N),ie(f,h+S.length,N);let k=d.amp??1,T=d.pan||0,q=k*Math.min(1,1-T),R=k*Math.min(1,1+T);ae(a,h,I,q),ae(f,h,S,R)}return{offsetTick:u,bufL:a,bufR:f}};var Ee=e=>{let r=0;for(let s=0;s<e.length;s++){let l=e[s],u=l.length;for(let p=0;p<u;p+=11){let a=l[p];a<0&&(a=-a),r<a&&(r=a)}}let c=(()=>{let s=r;return s<1?r:(s=(s-1)/3+1,s<2||(s=(s-2)/3+2),s)})();if(.96<c){let s=.96/c;for(let l=0;l<e.length;l++){let u=e[l],p=u.length;for(let a=0;a<p;a++){let f=u[a];f>=1?(f=(f-1)/3+1,f>=2&&(f=(f-2)/3+2)):f<=-1&&(f=(f+1)/3-1,f<=-2&&(f=(f+2)/3-2)),u[a]=f*s}}}},fe=e=>{let t=Math.max(4,...e.map(({offsetTick:i,bufL:c})=>i+c.length)),n=new Float32Array(t),o=new Float32Array(t);e.forEach(({offsetTick:i,bufL:c,bufR:s})=>{let l=c.length;for(let u=0;u<l;u++)n[i+u]+=c[u],o[i+u]+=s[u]});let r=[n,o];return Ee(r),r};var Ge=(e,t,n={})=>{if(n.type==="M")return G(e,n,t);{let r={noteNumber:69,velocity:100,duration:1,...n};if(t.noteNumber!=null&&(r.noteNumber+=t.noteNumber-69),t.velocity!=null&&(r.velocity*=t.velocity/100),t.duration!=null){let i=r.duration,c=t.duration;c!=null&&i!=c&&(r=ee(r,c,t.graphScaleIdx))}return W(e,r)}},G=(e,t,n={})=>{let o=Array.isArray(t.instruments)?t.instruments:[],r=Array.isArray(t.musicScore)?t.musicScore:[],i=t.fullyResolvedLanes;i||=re(e,se(r),n);let c=oe(i,n),s=new Map,l=i.map(u=>ue(e,o,u,n,c,s,Ge));return fe(l)};var ze=48e3,$e=e=>{let t=Number.isFinite(e)?e:ze;return Math.max(8e3,Math.min(96e3,t))},Ke={I:W,M:G},z=e=>{let t=$e(e.sampleRate),n=e.name,r=(Ke[e.type]||W)(t,e);return{sampleRate:t,channels:r,name:n}};var dt="0.1.20260404-ALPHA";function pe(e){let t=[];if(e&&Array.isArray(e.channels))for(let n of e.channels)n&&n.buffer instanceof ArrayBuffer&&t.push(n.buffer);return t}typeof self<"u"&&typeof self.postMessage=="function"&&typeof window>"u"?self.onmessage=e=>{let t=z(e.data);self.postMessage(t,pe(t))}:typeof process<"u"&&process.versions&&process.versions.node&&import("node:worker_threads").then(({isMainThread:e,parentPort:t})=>{!e&&t&&t.on("message",n=>{let o=z(n);t.postMessage(o,pe(o))})}).catch(()=>{});export{z as render,dt as version};
|
package/dist/asg3.mjs
ADDED
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
// src/render/instrument/prng.mjs
|
|
2
|
+
var bit32 = 2 ** 32;
|
|
3
|
+
var seedDefault = 521288629;
|
|
4
|
+
var acc;
|
|
5
|
+
var reset = (seed = seedDefault) => acc = seed;
|
|
6
|
+
reset();
|
|
7
|
+
var roundMinVal = Number.EPSILON * 2;
|
|
8
|
+
var roundMaxVal = 1 - Number.EPSILON * 2;
|
|
9
|
+
var roundForSafety = (v) => Math.max(roundMinVal, Math.min(v, roundMaxVal));
|
|
10
|
+
var emulatedMathRandomIndexed = (index, seed = seedDefault) => {
|
|
11
|
+
const indexedAcc = seed + Math.imul(index + 1 | 0, 1831565813) | 0;
|
|
12
|
+
return emulatedMathRandomByAcc(indexedAcc);
|
|
13
|
+
};
|
|
14
|
+
var emulatedMathRandomByAcc = (a) => {
|
|
15
|
+
let t = Math.imul(a ^ a >>> 15, a | 1);
|
|
16
|
+
t = t + Math.imul(t ^ t >>> 7, t | 61) ^ t;
|
|
17
|
+
return roundForSafety(((t ^ t >>> 14) >>> 0) / bit32);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// src/render/instrument/math.mjs
|
|
21
|
+
var standardNoteNumber = 69;
|
|
22
|
+
var standardVelocity = 100;
|
|
23
|
+
var maxVelocity = 127;
|
|
24
|
+
var standardDuration = 1;
|
|
25
|
+
var standardNoteNumberFrequency = 440;
|
|
26
|
+
var correctOctave = 4;
|
|
27
|
+
var calculateNoteFreq = (noteNumber) => standardNoteNumberFrequency * 2 ** correctOctave * 2 ** ((noteNumber - standardNoteNumber) / 12 - correctOctave);
|
|
28
|
+
var postProcessSample = (sample, level = 4) => {
|
|
29
|
+
const totalTick = sample.length;
|
|
30
|
+
if (level * 2 < totalTick) {
|
|
31
|
+
for (let i = 0; i < level; i++) {
|
|
32
|
+
const fadePower = i / level;
|
|
33
|
+
sample[i] *= fadePower;
|
|
34
|
+
sample[totalTick - 1 - i] *= fadePower;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var trigonometricallyInterpolate = (a, b, progress, intensity = 1) => {
|
|
39
|
+
if (intensity <= 0) {
|
|
40
|
+
return a + (b - a) * progress;
|
|
41
|
+
}
|
|
42
|
+
let modulatedProgress;
|
|
43
|
+
if (intensity === 1) {
|
|
44
|
+
modulatedProgress = (1 - Math.cos(progress * Math.PI)) * 0.5;
|
|
45
|
+
} else {
|
|
46
|
+
const cosVal = -Math.cos(progress * Math.PI);
|
|
47
|
+
let powed = cosVal;
|
|
48
|
+
if (intensity > 1) {
|
|
49
|
+
powed = Math.sign(cosVal) * Math.pow(Math.abs(cosVal), 1 / intensity);
|
|
50
|
+
}
|
|
51
|
+
const normalized = (powed + 1) * 0.5;
|
|
52
|
+
if (intensity < 1) {
|
|
53
|
+
modulatedProgress = progress * (1 - intensity) + normalized * intensity;
|
|
54
|
+
} else {
|
|
55
|
+
modulatedProgress = normalized;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return a + (b - a) * modulatedProgress;
|
|
59
|
+
};
|
|
60
|
+
var cosineComplement = (a, b, progress) => 0.5 * (a + b - (b - a) * Math.cos(progress * Math.PI));
|
|
61
|
+
var roundedSquareComplement = (a, b, progress, div) => cosineComplement(a, b, Math.min(1, progress * Math.max(1, div)));
|
|
62
|
+
|
|
63
|
+
// src/render/instrument/waveform.mjs
|
|
64
|
+
var calculateWaveformValueFromWaveformArray = (waveformArray, noteFreqByTick, progress) => {
|
|
65
|
+
const lapTotal = progress * waveformArray.length;
|
|
66
|
+
const lapCount = Math.floor(lapTotal);
|
|
67
|
+
const lapProgress = lapTotal % 1;
|
|
68
|
+
const a = waveformArray[lapCount % waveformArray.length];
|
|
69
|
+
const b = waveformArray[(lapCount + 1) % waveformArray.length];
|
|
70
|
+
const div = 0.5 / waveformArray.length / noteFreqByTick;
|
|
71
|
+
return roundedSquareComplement(a, b, lapProgress, div);
|
|
72
|
+
};
|
|
73
|
+
var chamferThreshold = 0.95;
|
|
74
|
+
var triangleFn = (state) => {
|
|
75
|
+
const p = state.lapProgress * 4;
|
|
76
|
+
const v = p < 1 ? p : p < 3 ? 2 - p : p - 4;
|
|
77
|
+
const vertexPower = Math.abs(v) - chamferThreshold;
|
|
78
|
+
if (vertexPower <= 0) {
|
|
79
|
+
return v;
|
|
80
|
+
}
|
|
81
|
+
const normalizedVertexPower = vertexPower / (1 - chamferThreshold);
|
|
82
|
+
const chamferedNormalizedVertexPower = normalizedVertexPower * (1 - normalizedVertexPower * 0.5);
|
|
83
|
+
return Math.sign(v) * (chamferThreshold + chamferedNormalizedVertexPower * (1 - chamferThreshold));
|
|
84
|
+
};
|
|
85
|
+
var calculateSawWaveFromLapProgress = (lapProgress) => {
|
|
86
|
+
const v = 1 - lapProgress * 2;
|
|
87
|
+
const lesserSawWaveThresholdV = -chamferThreshold;
|
|
88
|
+
const greaterSawWaveThresholdV = chamferThreshold;
|
|
89
|
+
if (lesserSawWaveThresholdV <= v && v <= greaterSawWaveThresholdV) {
|
|
90
|
+
return v;
|
|
91
|
+
}
|
|
92
|
+
const shiftedV = v < 0 ? v + 2 : v;
|
|
93
|
+
const start = lesserSawWaveThresholdV + 2;
|
|
94
|
+
const end = greaterSawWaveThresholdV;
|
|
95
|
+
const cosineProgress = (shiftedV - start) / (end - start);
|
|
96
|
+
return cosineComplement(lesserSawWaveThresholdV, greaterSawWaveThresholdV, cosineProgress);
|
|
97
|
+
};
|
|
98
|
+
var getIndexedRandom = (state, index) => emulatedMathRandomIndexed(index * 2 + (state.seedOffset || 0));
|
|
99
|
+
var noiseWhiteFrequencylessFn = (state) => getIndexedRandom(state, state.tick) * 2 - 1;
|
|
100
|
+
var noiseBinaryFrequencylessFn = (state) => getIndexedRandom(state, state.tick) >= 0.5 ? 1 : -1;
|
|
101
|
+
var noiseWhiteFn = (state) => getIndexedRandom(state, state.lapCount) * 2 - 1;
|
|
102
|
+
var noiseBinaryFn = (state) => getIndexedRandom(state, state.lapCount) >= 0.5 ? 1 : -1;
|
|
103
|
+
var noiseWhiteRoundedFn = (state) => {
|
|
104
|
+
const currentValue = getIndexedRandom(state, state.lapCount) * 2 - 1;
|
|
105
|
+
const prevValue = state.lapCount ? getIndexedRandom(state, state.lapCount - 1) * 2 - 1 : currentValue;
|
|
106
|
+
return roundedSquareComplement(prevValue, currentValue, state.lapProgress, 1);
|
|
107
|
+
};
|
|
108
|
+
var noiseBinaryRoundedFn = (state) => {
|
|
109
|
+
const currentValue = getIndexedRandom(state, state.lapCount) >= 0.5 ? 1 : -1;
|
|
110
|
+
const prevValue = state.lapCount ? getIndexedRandom(state, state.lapCount - 1) >= 0.5 ? 1 : -1 : currentValue;
|
|
111
|
+
return roundedSquareComplement(prevValue, currentValue, state.lapProgress, 1);
|
|
112
|
+
};
|
|
113
|
+
var createFractalNoiseFn = (octavesDown, octavesUp, weightFn) => {
|
|
114
|
+
const weights = [];
|
|
115
|
+
let totalWeight = 0;
|
|
116
|
+
for (let i = octavesDown; i <= octavesUp; i++) {
|
|
117
|
+
const w = weightFn(i);
|
|
118
|
+
weights.push(w);
|
|
119
|
+
totalWeight += w;
|
|
120
|
+
}
|
|
121
|
+
return (state) => {
|
|
122
|
+
const lapTotal = state.lapCount + state.lapProgress;
|
|
123
|
+
let sum = 0;
|
|
124
|
+
for (let i = octavesDown; i <= octavesUp; i++) {
|
|
125
|
+
const scale = 2 ** i;
|
|
126
|
+
const index = Math.floor(lapTotal * scale);
|
|
127
|
+
const uniqueIndex = index * 13 + i;
|
|
128
|
+
const val = getIndexedRandom(state, uniqueIndex) * 2 - 1;
|
|
129
|
+
sum += val * weights[i - octavesDown];
|
|
130
|
+
}
|
|
131
|
+
return sum / totalWeight;
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
var octaveWeightFn = (i) => 0.8 ** Math.abs(i);
|
|
135
|
+
var noiseFractalFn = createFractalNoiseFn(-4, 4, octaveWeightFn);
|
|
136
|
+
var resolveEmbedWaveformFnFromName = {
|
|
137
|
+
"sine": (state) => Math.sin(state.lapProgress * 2 * Math.PI),
|
|
138
|
+
"saw": (state) => calculateSawWaveFromLapProgress(state.lapProgress),
|
|
139
|
+
"saw-reverse": (state) => calculateSawWaveFromLapProgress(1 - state.lapProgress),
|
|
140
|
+
"square": ((state) => calculateWaveformValueFromWaveformArray([1, -1], state.noteFreqByTick, state.lapProgress)),
|
|
141
|
+
"triangle": triangleFn,
|
|
142
|
+
// ノイズ
|
|
143
|
+
"noise": noiseBinaryFn,
|
|
144
|
+
// short name alias
|
|
145
|
+
"noise-binary": noiseBinaryFn,
|
|
146
|
+
"noise-white": noiseWhiteFn,
|
|
147
|
+
// 角丸めノイズ
|
|
148
|
+
"noise-binary-rounded": noiseBinaryRoundedFn,
|
|
149
|
+
"noise-white-rounded": noiseWhiteRoundedFn,
|
|
150
|
+
// 周波数なし(sampleRate固定)ノイズ
|
|
151
|
+
"noise-binary-frequencyless": noiseBinaryFrequencylessFn,
|
|
152
|
+
"noise-white-frequencyless": noiseWhiteFrequencylessFn,
|
|
153
|
+
// フラクタルノイズ
|
|
154
|
+
"noise-fractal": noiseFractalFn
|
|
155
|
+
};
|
|
156
|
+
var waveformOrFallback = (waveform, fallbackWaveform2) => waveform?.constructor === String || waveform?.constructor === Function || Array.isArray(waveform) && waveform.every(Number.isFinite) ? waveform : fallbackWaveform2;
|
|
157
|
+
var resolveWaveformFn = (waveform, fallbackWaveform2) => {
|
|
158
|
+
waveform = waveformOrFallback(waveform, fallbackWaveform2);
|
|
159
|
+
if (waveform instanceof Function) {
|
|
160
|
+
return waveform;
|
|
161
|
+
}
|
|
162
|
+
if (Array.isArray(waveform)) {
|
|
163
|
+
return ((state) => calculateWaveformValueFromWaveformArray(waveform, state.noteFreqByTick, state.lapProgress));
|
|
164
|
+
}
|
|
165
|
+
let resultFn;
|
|
166
|
+
if (waveform?.constructor === String) {
|
|
167
|
+
resultFn = resolveEmbedWaveformFnFromName[waveform];
|
|
168
|
+
}
|
|
169
|
+
if (!resultFn) {
|
|
170
|
+
resultFn = resolveEmbedWaveformFnFromName["noise-binary-frequencyless"];
|
|
171
|
+
}
|
|
172
|
+
return resultFn;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// src/render/instrument/graph.mjs
|
|
176
|
+
var fallbackInterpolationIntensity = 1;
|
|
177
|
+
var graphKeys = ["envelope", "sweep", "vibrato", "tremolo", "lfo", "morph"];
|
|
178
|
+
var createGraphInterpolator = (nodes, totalTick, defaultValue = 0) => {
|
|
179
|
+
const points = [{ x: 0, v: defaultValue }];
|
|
180
|
+
let currentX = 0;
|
|
181
|
+
if (Number.isFinite(nodes)) {
|
|
182
|
+
return () => nodes;
|
|
183
|
+
} else if (nodes && nodes.length > 0) {
|
|
184
|
+
for (const node of nodes) {
|
|
185
|
+
const w = Array.isArray(node) && Number.isFinite(node[0]) ? node[0] : 0;
|
|
186
|
+
const v = Array.isArray(node) && Number.isFinite(node[1]) ? node[1] : defaultValue;
|
|
187
|
+
const interpolationIntensity = Array.isArray(node) && Number.isFinite(node[2]) ? node[2] : fallbackInterpolationIntensity;
|
|
188
|
+
currentX += w;
|
|
189
|
+
points.push({ x: currentX, v, interpolationIntensity });
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
return () => defaultValue;
|
|
193
|
+
}
|
|
194
|
+
const totalW = currentX || 1;
|
|
195
|
+
let nodeIdx = 0;
|
|
196
|
+
return (tick) => {
|
|
197
|
+
const targetX = tick / Math.max(1, totalTick - 1) * totalW;
|
|
198
|
+
while (nodeIdx < points.length - 1 && points[nodeIdx + 1].x <= targetX) {
|
|
199
|
+
nodeIdx++;
|
|
200
|
+
}
|
|
201
|
+
while (nodeIdx > 0 && points[nodeIdx].x > targetX) {
|
|
202
|
+
nodeIdx--;
|
|
203
|
+
}
|
|
204
|
+
const p1 = points[nodeIdx];
|
|
205
|
+
const p2 = points[nodeIdx + 1];
|
|
206
|
+
if (!p2) return p1.v;
|
|
207
|
+
const segmentW = p2.x - p1.x;
|
|
208
|
+
if (segmentW <= 1e-9) return p2.v;
|
|
209
|
+
const progress = (targetX - p1.x) / segmentW;
|
|
210
|
+
return trigonometricallyInterpolate(p1.v, p2.v, progress, p2.interpolationIntensity);
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
var guessScaleGraphTargetIdx = (firstGraph) => {
|
|
214
|
+
let resultIdx = 0;
|
|
215
|
+
if (firstGraph) {
|
|
216
|
+
let lastW = 0;
|
|
217
|
+
for (let i = 0; i < firstGraph.length; i++) {
|
|
218
|
+
const node = firstGraph[i];
|
|
219
|
+
const w = Array.isArray(node) && Number.isFinite(node[0]) ? node[0] : 0;
|
|
220
|
+
if (lastW < w) {
|
|
221
|
+
resultIdx = i;
|
|
222
|
+
lastW = w;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return resultIdx;
|
|
227
|
+
};
|
|
228
|
+
var adjustInstrumentDuration = (data, newDuration, targetIdx = void 0) => {
|
|
229
|
+
if (data["duration"] === void 0 || data["duration"] === newDuration) {
|
|
230
|
+
return data;
|
|
231
|
+
}
|
|
232
|
+
let firstGraph = null;
|
|
233
|
+
for (const key of graphKeys) {
|
|
234
|
+
if (Array.isArray(data[key]) && data[key].length > 0) {
|
|
235
|
+
firstGraph = data[key];
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (targetIdx === void 0) {
|
|
240
|
+
targetIdx = data["preferredScaleGraphTargetIdx"] ?? guessScaleGraphTargetIdx(firstGraph);
|
|
241
|
+
}
|
|
242
|
+
if (!firstGraph || !firstGraph[targetIdx]) {
|
|
243
|
+
return { ...data, ["duration"]: newDuration };
|
|
244
|
+
}
|
|
245
|
+
const oldTotalW = firstGraph.reduce((sum, node) => {
|
|
246
|
+
const w = Array.isArray(node) && Number.isFinite(node[0]) ? node[0] : 0;
|
|
247
|
+
return sum + w;
|
|
248
|
+
}, 0);
|
|
249
|
+
if (oldTotalW <= 0) {
|
|
250
|
+
return { ...data, ["duration"]: newDuration };
|
|
251
|
+
}
|
|
252
|
+
const oldTargetW = Array.isArray(firstGraph[targetIdx]) && Number.isFinite(firstGraph[targetIdx][0]) ? firstGraph[targetIdx][0] : 0;
|
|
253
|
+
const ratio = newDuration / data["duration"];
|
|
254
|
+
const newTotalW = oldTotalW * ratio;
|
|
255
|
+
let newTargetW = oldTargetW + (newTotalW - oldTotalW);
|
|
256
|
+
let actualNewDuration = newDuration;
|
|
257
|
+
if (newTargetW < 0) {
|
|
258
|
+
newTargetW = 0;
|
|
259
|
+
const actualNewTotalW = oldTotalW - oldTargetW;
|
|
260
|
+
actualNewDuration = data["duration"] * (actualNewTotalW / oldTotalW);
|
|
261
|
+
}
|
|
262
|
+
const newData = { ...data, ["duration"]: actualNewDuration };
|
|
263
|
+
for (const key of graphKeys) {
|
|
264
|
+
if (Array.isArray(newData[key])) {
|
|
265
|
+
newData[key] = newData[key].map(
|
|
266
|
+
(node, i) => i === targetIdx ? [newTargetW, node[1]] : node
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return newData;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// src/render/instrument.mjs
|
|
274
|
+
var fallbackEnvelopeGraph = [[0, 1], [1, 0]];
|
|
275
|
+
var fallbackWaveform = "triangle";
|
|
276
|
+
var fallbackLfoWaveform = "sine";
|
|
277
|
+
var advanceLap = (state, delta) => {
|
|
278
|
+
const total = state.lapProgress + delta;
|
|
279
|
+
const count = Math.floor(total);
|
|
280
|
+
state.lapCount += count;
|
|
281
|
+
state.lapProgress = total - count;
|
|
282
|
+
};
|
|
283
|
+
var renderInstrument = (sampleRate, data) => {
|
|
284
|
+
const noteNumber = Number.isFinite(data["noteNumber"]) ? data["noteNumber"] : standardNoteNumber;
|
|
285
|
+
const velocity = Number.isFinite(data["velocity"]) ? data["velocity"] : standardVelocity;
|
|
286
|
+
const duration = Number.isFinite(data["duration"]) ? data["duration"] : standardDuration;
|
|
287
|
+
const waveformFn = resolveWaveformFn(data["waveform"], fallbackWaveform);
|
|
288
|
+
const morphWaveformFn = data["morphWaveform"] ? resolveWaveformFn(data["morphWaveform"], fallbackWaveform) : null;
|
|
289
|
+
const lfoWaveformFn = resolveWaveformFn(data["lfoWaveform"], fallbackLfoWaveform);
|
|
290
|
+
reset();
|
|
291
|
+
const totalTick = Math.max(4, Math.ceil(duration * sampleRate));
|
|
292
|
+
const sample = new Float32Array(totalTick);
|
|
293
|
+
const nextEnv = createGraphInterpolator(data["envelope"] || fallbackEnvelopeGraph, totalTick, data["envelope"]?.length ? 0 : 1);
|
|
294
|
+
const nextSwe = createGraphInterpolator(data["sweep"], totalTick, 0);
|
|
295
|
+
const nextVib = createGraphInterpolator(data["vibrato"], totalTick, 0);
|
|
296
|
+
const nextTre = createGraphInterpolator(data["tremolo"], totalTick, 0);
|
|
297
|
+
const nextLfo = createGraphInterpolator(data["lfo"], totalTick, 4);
|
|
298
|
+
const nextMorph = createGraphInterpolator(data["morph"], totalTick, 0);
|
|
299
|
+
const state = {
|
|
300
|
+
tick: 0,
|
|
301
|
+
lapProgress: 0,
|
|
302
|
+
lapCount: 0,
|
|
303
|
+
noteFreqByTick: 0,
|
|
304
|
+
seedOffset: 0
|
|
305
|
+
};
|
|
306
|
+
const lfoState = {
|
|
307
|
+
tick: 0,
|
|
308
|
+
lapProgress: 0,
|
|
309
|
+
lapCount: 0,
|
|
310
|
+
noteFreqByTick: 0,
|
|
311
|
+
seedOffset: 1
|
|
312
|
+
// LFO用の乱数系列を分ける
|
|
313
|
+
};
|
|
314
|
+
const velValue = velocity / maxVelocity;
|
|
315
|
+
while (state.tick < totalTick) {
|
|
316
|
+
lfoState.tick = state.tick;
|
|
317
|
+
const envPower = nextEnv(state.tick);
|
|
318
|
+
const swePower = nextSwe(state.tick);
|
|
319
|
+
const vibPower = nextVib(state.tick);
|
|
320
|
+
const trePower = nextTre(state.tick);
|
|
321
|
+
const lfoFreq = nextLfo(state.tick);
|
|
322
|
+
const morphPower = nextMorph(state.tick);
|
|
323
|
+
lfoState.noteFreqByTick = lfoFreq / sampleRate;
|
|
324
|
+
advanceLap(lfoState, lfoState.noteFreqByTick);
|
|
325
|
+
const lfoWaveformValue = lfoWaveformFn(lfoState);
|
|
326
|
+
const treCurrent = trePower * lfoWaveformValue;
|
|
327
|
+
const vibCurrent = vibPower * lfoWaveformValue;
|
|
328
|
+
const noteFreq = calculateNoteFreq(noteNumber + swePower + vibCurrent);
|
|
329
|
+
state.noteFreqByTick = noteFreq / sampleRate;
|
|
330
|
+
advanceLap(state, state.noteFreqByTick);
|
|
331
|
+
let waveformValue = waveformFn(state);
|
|
332
|
+
if (morphWaveformFn && morphPower > 0) {
|
|
333
|
+
if (morphPower >= 1) {
|
|
334
|
+
waveformValue = morphWaveformFn(state);
|
|
335
|
+
} else {
|
|
336
|
+
const morphWaveformValue = morphWaveformFn(state);
|
|
337
|
+
waveformValue = waveformValue * (1 - morphPower) + morphWaveformValue * morphPower;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
sample[state.tick] = waveformValue * velValue * envPower * Math.max(0, 1 + treCurrent);
|
|
341
|
+
state.tick++;
|
|
342
|
+
}
|
|
343
|
+
postProcessSample(sample);
|
|
344
|
+
return [sample];
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
// src/render/music/cache.mjs
|
|
348
|
+
var mergeNoteNumber = (nn1 = standardNoteNumber, nn2 = standardNoteNumber) => nn1 + nn2 - standardNoteNumber;
|
|
349
|
+
var mergeVelocity = (v1 = standardVelocity, v2 = standardVelocity) => v1 * v2 / standardVelocity;
|
|
350
|
+
var getMergedCalibrateParams = (calibrateParams, parentCalibrateParams) => {
|
|
351
|
+
return {
|
|
352
|
+
noteNumber: mergeNoteNumber(calibrateParams.noteNumber, parentCalibrateParams.noteNumber),
|
|
353
|
+
velocity: mergeVelocity(calibrateParams.velocity, parentCalibrateParams.velocity),
|
|
354
|
+
duration: calibrateParams.duration,
|
|
355
|
+
// NB: これは親の値を参照してはいけない
|
|
356
|
+
graphScaleIdx: calibrateParams.graphScaleIdx
|
|
357
|
+
// NB: これは親の値を参照してはいけない
|
|
358
|
+
};
|
|
359
|
+
};
|
|
360
|
+
var getCacheKey = (inst, mergedCalibrateParams) => {
|
|
361
|
+
return `${inst}-${mergedCalibrateParams.noteNumber}-${mergedCalibrateParams.velocity}-${mergedCalibrateParams.duration}-${mergedCalibrateParams.graphScaleIdx}`;
|
|
362
|
+
};
|
|
363
|
+
var isRestTick = (op) => Number.isInteger(op);
|
|
364
|
+
var analyzeCacheTargets = (fullyResolvedLanes, parentCalibrateParams) => {
|
|
365
|
+
const counts = /* @__PURE__ */ new Map();
|
|
366
|
+
for (const lane of fullyResolvedLanes) {
|
|
367
|
+
for (const playOrRestTick of lane) {
|
|
368
|
+
if (!isRestTick(playOrRestTick)) {
|
|
369
|
+
const calibrateParams = playOrRestTick.calibrateParams || {};
|
|
370
|
+
const mergedCalibrateParams = getMergedCalibrateParams(calibrateParams, parentCalibrateParams);
|
|
371
|
+
const inst = playOrRestTick.inst || 0;
|
|
372
|
+
const key = getCacheKey(inst, mergedCalibrateParams);
|
|
373
|
+
counts.set(key, (counts.get(key) || 0) + 1);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const candidates = [];
|
|
378
|
+
for (const [key, count] of counts.entries()) {
|
|
379
|
+
if (count >= 2) {
|
|
380
|
+
candidates.push({ key, count });
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
candidates.sort((a, b) => b.count - a.count);
|
|
384
|
+
let targetCount = Math.floor(candidates.length * 0.2);
|
|
385
|
+
if (candidates.length > 0 && targetCount === 0) {
|
|
386
|
+
targetCount = 1;
|
|
387
|
+
}
|
|
388
|
+
const targets = /* @__PURE__ */ new Set();
|
|
389
|
+
for (let i = 0; i < targetCount; i++) {
|
|
390
|
+
targets.add(candidates[i].key);
|
|
391
|
+
}
|
|
392
|
+
return targets;
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// src/render/music/score.mjs
|
|
396
|
+
var resolveOpmapsInLanes = (_sampleRate, extractedMusicLanes, _calibrateParams) => {
|
|
397
|
+
console.log("niy");
|
|
398
|
+
return extractedMusicLanes;
|
|
399
|
+
};
|
|
400
|
+
var extractMusicLanes = (musicScore) => {
|
|
401
|
+
console.log("niy");
|
|
402
|
+
return musicScore;
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
// src/render/music/lane.mjs
|
|
406
|
+
var isRestTick2 = (op) => Number.isInteger(op);
|
|
407
|
+
var getFadeStep = (sampleRate) => Math.max(8, Math.floor(sampleRate * 1e-3));
|
|
408
|
+
var fadeInAfterCursor = (buf, cursor, fadeStep) => {
|
|
409
|
+
const len = Math.min(fadeStep, buf.length - cursor);
|
|
410
|
+
for (let i = 0; i < len; i++) {
|
|
411
|
+
if (cursor + i < 0) continue;
|
|
412
|
+
buf[cursor + i] *= i / fadeStep;
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
var fadeOutBeforeCursor = (buf, cursor, fadeStep) => {
|
|
416
|
+
const len = Math.min(fadeStep, cursor);
|
|
417
|
+
for (let i = 0; i < len; i++) {
|
|
418
|
+
if (cursor - i - 1 < 0) continue;
|
|
419
|
+
buf[cursor - i - 1] *= i / fadeStep;
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
var overwriteBuf = (buf, pos, samples, amp) => {
|
|
423
|
+
const len = Math.min(samples.length, buf.length - pos);
|
|
424
|
+
if (len <= 0) return;
|
|
425
|
+
if (amp === 1) {
|
|
426
|
+
buf.set(samples.subarray(0, len), pos);
|
|
427
|
+
} else {
|
|
428
|
+
for (let i = 0; i < len; i++) {
|
|
429
|
+
if (pos + i < 0) continue;
|
|
430
|
+
buf[pos + i] = samples[i] * amp;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
var renderLane = (sampleRate, instruments, lane, parentCalibrateParams, cacheTargets, cachePool, buildSamplesInternalCallback) => {
|
|
435
|
+
let startTick;
|
|
436
|
+
let endTick = 0;
|
|
437
|
+
for (const playOrRestTick of lane) {
|
|
438
|
+
if (isRestTick2(playOrRestTick)) {
|
|
439
|
+
endTick += playOrRestTick;
|
|
440
|
+
} else {
|
|
441
|
+
startTick ??= endTick;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
startTick ??= 0;
|
|
445
|
+
const offsetTick = startTick;
|
|
446
|
+
const len = endTick - startTick;
|
|
447
|
+
const bufL = new Float32Array(len);
|
|
448
|
+
const bufR = new Float32Array(len);
|
|
449
|
+
let cursor = -offsetTick;
|
|
450
|
+
const fadeStep = getFadeStep(sampleRate);
|
|
451
|
+
for (const playOrRestTick of lane) {
|
|
452
|
+
if (isRestTick2(playOrRestTick)) {
|
|
453
|
+
cursor += playOrRestTick;
|
|
454
|
+
} else {
|
|
455
|
+
fadeOutBeforeCursor(bufL, cursor, fadeStep);
|
|
456
|
+
fadeOutBeforeCursor(bufR, cursor, fadeStep);
|
|
457
|
+
const calibrateParams = playOrRestTick.calibrateParams || {};
|
|
458
|
+
const mergedCalibrateParams = getMergedCalibrateParams(calibrateParams, parentCalibrateParams);
|
|
459
|
+
const inst = playOrRestTick.inst || 0;
|
|
460
|
+
const instrumentDefinition = instruments[inst];
|
|
461
|
+
const cacheKey = getCacheKey(inst, mergedCalibrateParams);
|
|
462
|
+
let samples;
|
|
463
|
+
if (cacheTargets.has(cacheKey)) {
|
|
464
|
+
samples = cachePool.get(cacheKey);
|
|
465
|
+
if (!samples) {
|
|
466
|
+
samples = buildSamplesInternalCallback(sampleRate, mergedCalibrateParams, instrumentDefinition);
|
|
467
|
+
cachePool.set(cacheKey, samples);
|
|
468
|
+
}
|
|
469
|
+
} else {
|
|
470
|
+
samples = buildSamplesInternalCallback(sampleRate, mergedCalibrateParams, instrumentDefinition);
|
|
471
|
+
}
|
|
472
|
+
const sampleL = samples[0];
|
|
473
|
+
const sampleR = samples[1] || sampleL;
|
|
474
|
+
fadeInAfterCursor(bufL, cursor + sampleL.length, fadeStep);
|
|
475
|
+
fadeInAfterCursor(bufR, cursor + sampleR.length, fadeStep);
|
|
476
|
+
const amp = playOrRestTick.amp ?? 1;
|
|
477
|
+
const pan = playOrRestTick.pan || 0;
|
|
478
|
+
const powerL = amp * Math.min(1, 1 - pan);
|
|
479
|
+
const powerR = amp * Math.min(1, 1 + pan);
|
|
480
|
+
overwriteBuf(bufL, cursor, sampleL, powerL);
|
|
481
|
+
overwriteBuf(bufR, cursor, sampleR, powerR);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return { offsetTick, bufL, bufR };
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// src/render/music/merge.mjs
|
|
488
|
+
var compressStereoSamples = (samples) => {
|
|
489
|
+
const peakLevel = 0.96;
|
|
490
|
+
const keepLevel1 = 1;
|
|
491
|
+
const keepLevel2 = 2;
|
|
492
|
+
let maxLevel = 0;
|
|
493
|
+
for (let c = 0; c < samples.length; c++) {
|
|
494
|
+
const sample = samples[c];
|
|
495
|
+
const len = sample.length;
|
|
496
|
+
for (let i = 0; i < len; i += 11) {
|
|
497
|
+
let v = sample[i];
|
|
498
|
+
if (v < 0) v = -v;
|
|
499
|
+
if (maxLevel < v) {
|
|
500
|
+
maxLevel = v;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const getFixedMaxLevel = () => {
|
|
505
|
+
let absV = maxLevel;
|
|
506
|
+
if (absV < keepLevel1) {
|
|
507
|
+
return maxLevel;
|
|
508
|
+
}
|
|
509
|
+
absV = (absV - keepLevel1) / 3 + keepLevel1;
|
|
510
|
+
if (absV < keepLevel2) {
|
|
511
|
+
return absV;
|
|
512
|
+
}
|
|
513
|
+
absV = (absV - keepLevel2) / 3 + keepLevel2;
|
|
514
|
+
return absV;
|
|
515
|
+
};
|
|
516
|
+
const fixedMaxLevel = getFixedMaxLevel();
|
|
517
|
+
if (peakLevel < fixedMaxLevel) {
|
|
518
|
+
const rate = peakLevel / fixedMaxLevel;
|
|
519
|
+
for (let c = 0; c < samples.length; c++) {
|
|
520
|
+
const sample = samples[c];
|
|
521
|
+
const len = sample.length;
|
|
522
|
+
for (let i = 0; i < len; i++) {
|
|
523
|
+
let v = sample[i];
|
|
524
|
+
if (v >= keepLevel1) {
|
|
525
|
+
v = (v - keepLevel1) / 3 + keepLevel1;
|
|
526
|
+
if (v >= keepLevel2) v = (v - keepLevel2) / 3 + keepLevel2;
|
|
527
|
+
} else if (v <= -keepLevel1) {
|
|
528
|
+
v = (v + keepLevel1) / 3 - keepLevel1;
|
|
529
|
+
if (v <= -keepLevel2) v = (v + keepLevel2) / 3 - keepLevel2;
|
|
530
|
+
}
|
|
531
|
+
sample[i] = v * rate;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
var mergeLanes = (renderedLanes) => {
|
|
537
|
+
const totalTick = Math.max(4, ...renderedLanes.map(({ offsetTick, bufL }) => offsetTick + bufL.length));
|
|
538
|
+
const resultL = new Float32Array(totalTick);
|
|
539
|
+
const resultR = new Float32Array(totalTick);
|
|
540
|
+
renderedLanes.forEach(({ offsetTick, bufL, bufR }) => {
|
|
541
|
+
const len = bufL.length;
|
|
542
|
+
for (let i = 0; i < len; i++) {
|
|
543
|
+
resultL[offsetTick + i] += bufL[i];
|
|
544
|
+
resultR[offsetTick + i] += bufR[i];
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
const result = [resultL, resultR];
|
|
548
|
+
compressStereoSamples(result);
|
|
549
|
+
return result;
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
// src/render/music.mjs
|
|
553
|
+
var buildSamplesInternal = (sampleRate, calibrateParams, instrument = {}) => {
|
|
554
|
+
const isM = instrument.type === "M";
|
|
555
|
+
if (isM) {
|
|
556
|
+
return renderMusic(sampleRate, instrument, calibrateParams);
|
|
557
|
+
} else {
|
|
558
|
+
let transformedInstrument = {
|
|
559
|
+
noteNumber: standardNoteNumber,
|
|
560
|
+
velocity: standardVelocity,
|
|
561
|
+
duration: standardDuration,
|
|
562
|
+
...instrument
|
|
563
|
+
};
|
|
564
|
+
if (calibrateParams.noteNumber != null) {
|
|
565
|
+
transformedInstrument.noteNumber += calibrateParams.noteNumber - standardNoteNumber;
|
|
566
|
+
}
|
|
567
|
+
if (calibrateParams.velocity != null) {
|
|
568
|
+
transformedInstrument.velocity *= calibrateParams.velocity / standardVelocity;
|
|
569
|
+
}
|
|
570
|
+
if (calibrateParams.duration != null) {
|
|
571
|
+
const oldDuration = transformedInstrument.duration;
|
|
572
|
+
const newDuration = calibrateParams.duration;
|
|
573
|
+
if (newDuration != null && oldDuration != newDuration) {
|
|
574
|
+
transformedInstrument = adjustInstrumentDuration(transformedInstrument, newDuration, calibrateParams.graphScaleIdx);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return renderInstrument(sampleRate, transformedInstrument);
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
var renderMusic = (sampleRate, data, calibrateParams = {}) => {
|
|
581
|
+
const instruments = Array.isArray(data["instruments"]) ? data["instruments"] : [];
|
|
582
|
+
const musicScore = Array.isArray(data["musicScore"]) ? data["musicScore"] : [];
|
|
583
|
+
let fullyResolvedLanes = data["fullyResolvedLanes"];
|
|
584
|
+
fullyResolvedLanes ||= resolveOpmapsInLanes(sampleRate, extractMusicLanes(musicScore), calibrateParams);
|
|
585
|
+
const cacheTargets = analyzeCacheTargets(fullyResolvedLanes, calibrateParams);
|
|
586
|
+
const cachePool = /* @__PURE__ */ new Map();
|
|
587
|
+
const renderedLanes = fullyResolvedLanes.map((lane) => renderLane(sampleRate, instruments, lane, calibrateParams, cacheTargets, cachePool, buildSamplesInternal));
|
|
588
|
+
return mergeLanes(renderedLanes);
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
// src/render.mjs
|
|
592
|
+
var defaultSampleRate = 48e3;
|
|
593
|
+
var reformSampleRate = (sampleRate) => {
|
|
594
|
+
const sr = Number.isFinite(sampleRate) ? sampleRate : defaultSampleRate;
|
|
595
|
+
return Math.max(8e3, Math.min(96e3, sr));
|
|
596
|
+
};
|
|
597
|
+
var renderTable = {
|
|
598
|
+
"I": renderInstrument,
|
|
599
|
+
"M": renderMusic
|
|
600
|
+
};
|
|
601
|
+
var render = (data) => {
|
|
602
|
+
const sampleRate = reformSampleRate(data["sampleRate"]);
|
|
603
|
+
const name = data["name"];
|
|
604
|
+
const renderFn = renderTable[data["type"]] || renderInstrument;
|
|
605
|
+
const channels = renderFn(sampleRate, data);
|
|
606
|
+
return {
|
|
607
|
+
sampleRate,
|
|
608
|
+
channels,
|
|
609
|
+
name
|
|
610
|
+
// TODO: add more meta data
|
|
611
|
+
};
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
// src/index.mjs
|
|
615
|
+
var version = true ? "0.1.20260404-ALPHA" : "0.0.0-DEV";
|
|
616
|
+
function getTransferList(data) {
|
|
617
|
+
const transfer = [];
|
|
618
|
+
if (data && Array.isArray(data.channels)) {
|
|
619
|
+
for (const item of data.channels) {
|
|
620
|
+
if (item && item.buffer instanceof ArrayBuffer) {
|
|
621
|
+
transfer.push(item.buffer);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return transfer;
|
|
626
|
+
}
|
|
627
|
+
if (typeof self !== "undefined" && typeof self.postMessage === "function" && typeof window === "undefined") {
|
|
628
|
+
self.onmessage = (event) => {
|
|
629
|
+
const result = render(event.data);
|
|
630
|
+
self.postMessage(result, getTransferList(result));
|
|
631
|
+
};
|
|
632
|
+
} else if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
633
|
+
import("node:worker_threads").then(({ isMainThread, parentPort }) => {
|
|
634
|
+
if (!isMainThread && parentPort) {
|
|
635
|
+
parentPort.on("message", (data) => {
|
|
636
|
+
const result = render(data);
|
|
637
|
+
parentPort.postMessage(result, getTransferList(result));
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
}).catch(() => {
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
export {
|
|
644
|
+
render,
|
|
645
|
+
version
|
|
646
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tir.jp/asg3",
|
|
3
|
+
"version": "0.1.20260404-ALPHA",
|
|
4
|
+
"description": "",
|
|
5
|
+
"keywords": [],
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/asg3.min.mjs",
|
|
8
|
+
"module": "dist/asg3.min.mjs",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/asg3.min.mjs",
|
|
11
|
+
"./full": "./dist/asg3.mjs"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"esbuild": "0.28.0",
|
|
18
|
+
"oxlint": "1.58.0"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"test": "npm run build && node --test tests/*.test.mjs",
|
|
22
|
+
"build": "node scripts/build.mjs",
|
|
23
|
+
"lint": "oxlint ."
|
|
24
|
+
},
|
|
25
|
+
"author": "ayamada",
|
|
26
|
+
"contributors": [
|
|
27
|
+
"mac"
|
|
28
|
+
],
|
|
29
|
+
"license": "Zlib",
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
}
|
|
33
|
+
}
|