@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 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
+ }