// JYE SOUNDS procedural sound pack. No external samples or generative model. const fs=require('node:fs'),path=require('node:path'),crypto=require('node:crypto'); const SR=44100, ROOT=path.resolve(process.argv[2]||__dirname), TAU=Math.PI*2; const sin=p=>Math.sin(TAU*p), clamp=(v,a,b)=>Math.max(a,Math.min(b,v)); fs.mkdirSync(ROOT,{recursive:true}); const names={ 'ui':['soft-select','glass-toggle','gentle-hover','menu-open','menu-close','tab-switch','tiny-tick','rounded-tap','double-confirm','low-dismiss'], 'game':['coin-pair','gem-pickup','spring-jump','double-jump','landing-pop','checkpoint','level-up','power-charge','bonus-reveal','life-lost'], 'impact':['soft-thud','deep-hit','hollow-knock','bright-ping','metallic-tap','rubber-pop','woodlike-click','tiny-crack','heavy-drop','short-snap'], 'transition':['air-rise','air-fall','quick-swipe','soft-reverse','sparkle-sweep','low-sweep','wide-wash','flutter-pass','tunnel-pass','short-zip'], 'texture':['soft-air','dark-rumble','fine-sparkles','distant-hum','slow-pulse','digital-rain','windlike-bed','grainy-drift','soft-wobble','space-bed'], 'notification':['message-soft','message-bright','task-done','gentle-reminder','two-note-alert','positive-chime','subtle-error','waiting-pulse','new-event','session-end'], 'magic':['fairy-rise','orb-glow','spell-cast','crystal-dust','shimmer-fall','rune-activate','portal-open','portal-close','energy-pulse','tiny-enchant'], 'scifi':['scanner-sweep','console-beep','robot-question','robot-answer','laser-short','laser-double','shield-on','shield-off','engine-start','data-transmit'], 'mechanical':['latch-click','switch-down','switch-up','ratchet-turn','gear-step','servo-rise','servo-fall','lever-pull','lock-pair','button-spring'], 'retro':['arcade-coin','arcade-jump','arcade-hit','arcade-boost','arcade-bounce','arcade-warp','arcade-win','arcade-fail','arcade-start','arcade-pause'] }; const labels={ui:'UI 입력',game:'게임 이벤트',impact:'합성 타격',transition:'화면 전환',texture:'합성 배경 질감',notification:'알림',magic:'마법 연출',scifi:'SF 연출',mechanical:'합성 기계 동작',retro:'레트로 게임'}; function rng(seed){return ()=>{seed^=seed<<13;seed^=seed>>>17;seed^=seed<<5;return (seed>>>0)/2147483648-1;};} function env(t,len,attack=.004,power=2){return t<0||t>=len?0:Math.min(1,t/attack)*Math.pow(1-t/len,power);} function chirp(t,start,len,f0,f1,amp=.5,harmonic=.1){const u=t-start;if(u<0||u>=len)return 0;const p=f0*u+(f1-f0)*u*u/(2*len);return amp*env(u,len,.004,1.5)*(sin(p)+harmonic*sin(p*2));} function bell(t,start,len,f,amp=.5){const u=t-start;if(u<0||u>=len)return 0;return amp*env(u,len,.003,2)*(sin(f*u)+.23*sin(f*2.71*u)*Math.exp(-8*u)+.08*sin(f*4.17*u)*Math.exp(-12*u));} function stepped(t,notes,step,len,gain=.45){let s=0;for(let k=0;kchirp(t,0,duration*.75,620+j*75,j===9?210:780+j*90,.5,.07)+((j===8||j===1)?bell(t,.09,duration*.5,f*2,.25):0)+random()*.1*env(t,.035,.001,3); }else if(group==='game'){ duration=[.5,.72,.34,.55,.24,.85,1.2,1,.88,.65][j]; fn=t=>{ if(j===2||j===3)return chirp(t,0,.3,180,850,.6,.18)+(j===3?chirp(t,.21,.3,300,1250,.45,.15):0); if(j===4)return chirp(t,0,.21,220,65,.7,.15)+random()*.12*env(t,.1,.001,3); if(j===7)return chirp(t,0,.97,100,1650,.4,.2)*Math.min(1,t*8); const notes=j===9?[f*2,f*1.5,f]:j===6?[f,f*1.25,f*1.5,f*2]:[f,f*1.5,f*2]; return stepped(t,notes,duration/(notes.length+2),duration*.48,.4); }; }else if(group==='impact'){ duration=[.3,.65,.35,.78,.46,.24,.19,.15,.85,.14][j]; fn=t=>{ const n=random();low+=.025*(n-low); if(j===3||j===4)return bell(t,0,duration,500+j*130,.6)+chirp(t,0,.08,120,60,.1); const fundamental=[90,48,150,700,1000,200,330,900,42,1600][j]; const p=fundamental*t+fundamental*.012*(1-Math.exp(-t*40)); return (sin(p)*.6+sin(p*1.83)*.16+(j%2? n*.25:low*2))*env(t,duration,.001,j===8?1.4:3); }; }else if(group==='transition'){ duration=[.8,.75,.25,.65,1.1,.85,1.3,.7,.95,.22][j]; fn=t=>{ const progress=t/duration,amp=Math.sin(Math.PI*progress)**2,n=random(); low+=(.015+.35*(j%2?1-progress:progress))*(n-low); return (low*.8+chirp(t,0,duration,100+j*35,j%2?60:1400,.3,.15))*amp*(j===7?.55+.45*sin(t*18):1); }; }else if(group==='texture'){ duration=4; fn=t=>{ const n=random();low+=.009*(n-low);slow+=.0007*(n-slow); const base=35+j*9; return (j===0?low*4:j===1?slow*9+sin(base*t)*.08:j===2?Math.pow(Math.max(0,random2()),18)*sin(1600*t)*.15:j===3?sin(70*t)*.16+sin(105.2*t)*.09:j===4?sin(80*t)*(.5+.5*sin(1.5*t))*.2:j===5?(n-prev)*.08:j===6?low*4*(.6+.4*sin(.4*t)):j===7?low*2+random2()*.025:j===8?sin(base*t+.8*sin(2.2*t))*.16:slow*5+sin(90*t)*.07)*(0.85+.15*sin(.25*t)); }; }else if(group==='notification'){ duration=[.6,.65,1.1,.8,.7,1,.5,.9,.72,.9][j]; fn=t=>{const notes=j===6?[350,300]:j===9?[700,550,440]:j===2||j===5?[f,f*1.25,f*1.5]:[f,f*(j===4?1.1:1.5)];return stepped(t,notes,.13+j*.006,duration*.6,.38);}; }else if(group==='magic'){ duration=.8+v*.65; const ratios=j===4||j===7?[2,1.5,1.25,1]:[1,1.25,1.5,2]; fn=t=>stepped(t,ratios.map(r=>f*r),.08+v*.045,.52+v*.22,.26)+chirp(t,0,duration*.85,j%2?1200:200,j%2?200:1600,.18,.2)*(.6+.4*sin(t*(6+j))); }else if(group==='scifi'){ duration=[1.05,.25,.65,.65,.32,.55,.8,.7,1.1,.8][j]; fn=t=>{ if(j===1)return chirp(t,0,.22,1100,1120,.5,.2); if(j===4||j===5)return chirp(t,0,.29,1900,120,.6,.2)+(j===5?chirp(t,.2,.3,1500,90,.4,.15):0); phase+=(120+j*90+Math.sin(TAU*t*(j+2))*90)/SR; return (sin(phase+.4*sin((800+j*65)*t))*.38+random()*.035)*env(t,duration,.012,1.3)*(j===9?.4+.6*Math.max(0,sin(t*24)):1); }; }else if(group==='mechanical'){ duration=[.22,.2,.24,.7,.4,.7,.75,.65,.5,.4][j]; fn=t=>{ if(j===5||j===6||j===7)return chirp(t,0,duration,120+j*20,j===6?100:650,.35,.35)+random()*.025*env(t,duration,.01,1); const count=j===3?6:j===8?2:j===4?3:1,step=duration/(count+1); let s=0;for(let k=0;k=0)s+=(sin((420+j*37)*u)*.3+random()*.22)*env(u,.08,.001,3);}return s; }; }else{ duration=[.38,.35,.23,.65,.42,.8,1.25,.8,.6,.4][j]; fn=t=>{ const notes=j===6?[523.25,659.25,783.99,1046.5]:j===7?[660,550,440,220]:[f,f*1.5,f*2]; const k=Math.min(notes.length-1,Math.floor(t/(duration/notes.length))),hz=notes[k]; phase+=hz/SR; const wave=sin(phase)+sin(phase*3)/3+sin(phase*5)/5; return wave*.3*env(t,duration,.002,1.3)+(j===2?random()*.15*env(t,.15,.002,3):0); }; } return {duration,fn}; } function wav(pcm,channels=2){const b=Buffer.alloc(44+pcm.length*2);b.write('RIFF');b.writeUInt32LE(b.length-8,4);b.write('WAVE',8);b.write('fmt ',12);b.writeUInt32LE(16,16);b.writeUInt16LE(1,20);b.writeUInt16LE(channels,22);b.writeUInt32LE(SR,24);b.writeUInt32LE(SR*channels*2,28);b.writeUInt16LE(channels*2,32);b.writeUInt16LE(16,34);b.write('data',36);b.writeUInt32LE(pcm.length*2,40);for(let i=0;i=32767||max<100)throw Error('Duplicate or invalid render');fingerprints.add(sha256); fs.writeFileSync(path.join(destination,filename),bytes); const row={id,category:group,categoryKo:labels[group],name:variants[j],file:'wav/'+group+'/'+filename,durationSeconds:frames/SR,sampleRate:SR,bitDepth:16,channels:2,peakDbFS:20*Math.log10(max/32768),rmsDbFS:20*Math.log10(Math.sqrt(sum/pcm.length)/32768),bytes:bytes.length,sha256,source:{method:'procedural synthesis',externalSamples:false,generator:'generate-originals.cjs',presetGroup:group,presetIndex:j,version:'1.0.0',createdOn:'2026-10-22'}}; manifest.push(row); } } // The second set uses a separate, individually written gesture for each file. const {designs}=require('./diverse-designs.cjs'); for(const [index,d] of designs.entries()){ const fn=d.factory(),frames=Math.round(d.duration*SR),raw=new Float64Array(frames);let peak=0; for(let i=0;i=32767)throw Error('Duplicate or clipped '+d.name);fingerprints.add(sha256); const dir=path.join(ROOT,'wav',d.group);fs.mkdirSync(dir,{recursive:true});fs.writeFileSync(path.join(dir,filename),bytes); manifest.push({id,category:d.group,categoryKo:({foley:'소재·동작',nature:'자연 연출',machine:'장치 동작',percussion:'타악 질감',signal:'통신·신호',motion:'움직임 연출'})[d.group],name:d.name,file:'wav/'+d.group+'/'+filename,durationSeconds:frames/SR,sampleRate:SR,bitDepth:16,channels:2,peakDbFS:20*Math.log10(max/32768),rmsDbFS:20*Math.log10(Math.sqrt(sum/pcm.length)/32768),bytes:bytes.length,sha256,source:{method:'procedural synthesis',externalSamples:false,generator:'diverse-designs.cjs',presetGroup:d.group,presetIndex:index,version:'2.0.0',createdOn:'2026-10-22'}}); } fs.writeFileSync(path.join(ROOT,'manifest.json'),JSON.stringify(manifest,null,2)+'\n'); console.log(JSON.stringify({sounds:manifest.length,uniqueFiles:fingerprints.size,bytes:manifest.reduce((n,m)=>n+m.bytes,0),allFinite:true,clipping:false}));