UNPKG

sus-io

Version:

A SUS (Sliding Universal Score) converter (parser and stringifier).

3 lines (2 loc) 6.74 kB
"use strict";function e(e){return e.replace(/^"(.*(?="$))"$/,"$1")}function t(e){const t=[];let r;for(const s of e.sort(((e,t)=>e.tick-t.tick)))r||(r=[],t.push(r)),r.push(s),2===s.type&&(r=void 0);return t}function r(e,t){const[r]=e,n=Number.parseInt(r[4],36);return s(e,t).map((([e,t])=>{const r=Number.parseInt(t[1],36);return{tick:e,lane:n,width:r,type:Number.parseInt(t[0],36)}}))}function s([e,t],r){const s=+e.substring(0,3);return(t.match(/.{2}/g)||[]).map(((e,t,n)=>"00"!==e&&[r(s,t,n.length),e])).filter((e=>!!e))}function n(n){var a,o;const i=function(t){const r=[],s=[];for(const n of t.split(/\r\n|(?!\r\n)[\n-\r\x85\u2028\u2029]/)){if(!n.startsWith("#"))continue;const t=n.match(/^#([^:]+): *(.*)$/);if(t){const[s,n]=t.slice(1);r.push([s,e(n)]);continue}const a=n.match(/^#(.+?) (.*)$/);if(a){const[t,r]=a.slice(1);s.push([t,e(r)])}else console.warn(`Unknown SUS data line: "${n}"`)}return{score:r,metadata:s}}(n),c=function(e){const t={};for(const[r,s]of e)switch(r){case"TITLE":t.title=s;break;case"SUBTITLE":t.subtitle=s;break;case"ARTIST":t.artist=s;break;case"GENRE":t.genre=s;break;case"DESIGNER":t.designer=s;break;case"DIFFICULTY":t.difficulty=s;break;case"PLAYLEVEL":t.playlevel=s;break;case"SONGID":t.songid=s;break;case"WAVE":t.wave=s;break;case"JACKET":t.jacket=s;break;case"BACKGROUND":t.background=s;break;case"MOVIE":t.movie=s;break;case"WAVEOFFSET":t.waveoffset=Number.parseInt(s);break;case"MOVIEOFFSET":t.movieoffset=Number.parseInt(s);break;case"BASEBPM":t.basebpm=Number.parseInt(s);break;case"REQUEST":{const e=t.requests||[];e.push(s),t.requests=e;break}default:console.log("Unknown metadata header: ",r)}return t}(i.metadata),u=null===(a=c.requests)||void 0===a?void 0:a.find((e=>e.startsWith("ticks_per_beat")));u||console.warn("Missing ticks_per_beat request, defaulting to 480.");const l=Number.parseInt(null!==(o=null==u?void 0:u.split(" ")[1])&&void 0!==o?o:"")||480;return Object.assign({metadata:c},function(e,n){var a;const o=e.filter((([e])=>5===e.length&&e.endsWith("02")&&!Number.isNaN(Number.parseInt(e)))).map((([e,t])=>[Number.parseInt(e.substring(0,3)),Number.parseInt(t)]));0===o.length&&(console.warn("No barLengths found, adding default 4/4 time signature (#00002:4)..."),o.push([0,4]));let i=0;const c=[...o].sort((([e],[t])=>e-t)).map((([e,t],r,s)=>{const a=s[r-1];return a&&(i+=(e-a[0])*a[1]*n),{measure:e,ticksPerMeasure:t*n,ticks:i}})).reverse(),u=(e,t,r)=>{const s=c.find((t=>e>=t.measure));if(!s)throw"Unexpected missing bar";return s.ticks+(e-s.measure)*s.ticksPerMeasure+t*s.ticksPerMeasure/r},l=new Map,p=[],f=[],h=[],d=new Map;for(const t of e){const[e,n]=t;if(5===e.length&&e.startsWith("BPM"))l.set(e.substring(3),+n);else if(5===e.length&&e.endsWith("08"))p.push(...s(t,u));else if(5!==e.length||"1"!==e[3])if(6!==e.length||"3"!==e[3])5===e.length&&"5"===e[3]&&h.push(...r(t,u));else{const s=e[5],n=null!==(a=d.get(s))&&void 0!==a?a:[];n.push(...r(t,u)),d.set(s,n)}else f.push(...r(t,u))}return{taps:f,directionals:h,slides:[...d.values()].flatMap(t),bpms:p.sort(((e,t)=>e[0]-t[0])).map((([e,t])=>[e,l.get(t)||0])).reverse(),barLengths:o}}(i.score,l))}Object.defineProperty(exports,"__esModule",{value:!0}),"function"==typeof SuppressedError&&SuppressedError;class a extends Error{constructor(e,t){super(`Notes are not aligned correctly, with gcd ${e}. Note ticks: ${t.join(", ")}`),this.name="InvalidAlignmentError",this.gcdValue=e,this.noteTicks=t}}var o;function i(e,t){return e<t?i(t,e):0===t?e:i(t,e%t)}class c extends Map{constructor(e){super(),this.generateDefault=e}get(e){const t=super.get(e);if(void 0===t){const t=this.generateDefault();return super.set(e,t),t}return t}}class u{constructor(){o.set(this,void 0),function(e,t,r,s,n){if("m"===s)throw new TypeError("Private method is not writable");if("a"===s&&!n)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!n:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");"a"===s?n.call(e,r):n?n.value=r:t.set(e,r)}(this,o,[...Array(36).keys()].map((e=>[e,[0,0]])),"f")}generateChannel(e,t){const r=function(e,t,r,s){if("a"===r&&!s)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!s:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?s:"a"===r?s.call(e):s?s.value:t.get(e)}(this,o,"f").find((([,[r,s]])=>0===r&&0===s||t<r||s<e));if(!r)throw new Error("No more channel available.");return r[1]=[e,t],r[0]}}function l(e,t="This file was generated by sus-js v1.1.0"){var r;const{metadata:s,bpms:n,taps:o,directionals:l,slides:p,barLengths:f}=e;let h=480;const d=[];d.push(t);for(const[e,t]of Object.entries(s))if("requests"!==e)d.push(`#${e.toUpperCase()} ${"number"==typeof t?t:(g=t,`"${g}"`)}`);else{d.push("");for(const e of t)d.push(`#REQUEST "${e}"`),e.startsWith("ticks_per_beat")&&(h=+e.split(" ")[1])}var g;d.push("");const b=new c((()=>({raws:[],ticksPerMeasure:0})));for(const[e,t]of f)d.push(`#${e.toString().padStart(3,"0")}02:${t}`);d.push("");let m=0;const k=f.map((([e,t],r,s)=>{var n;const[a]=null!==(n=s[r+1])&&void 0!==n?n:[Number.POSITIVE_INFINITY],o=m;return m+=(a-e)*t*h,{tick:o,measure:e,value:t}})).reverse(),w=(e,t,r)=>{var s;const{tick:n,measure:a,value:o}=null!==(s=k.find((({tick:t})=>e>=t)))&&void 0!==s?s:{tick:0,measure:0,value:4},i=Math.floor(a+(e-n)/h/o),c=b.get(`${i.toString().padStart(3,"0")}${t}`);c.raws.push({tick:e-n,value:r}),c.ticksPerMeasure=o*h};if(n.length>=Math.pow(36,2)-1)throw new Error(`Too much BPMS (${n.length} >= 36^2 -1 = ${Math.pow(36,2)-1})`);const v=new Map;for(const[e,t]of n){const s=(v.size+1).toString(36).padStart(2,"0");v.has(t)||(v.set(t,s),d.push(`#BPM${v.get(t)}:${t}`)),w(e,"08",null!==(r=v.get(t))&&void 0!==r?r:s)}for(const{tick:e,lane:t,width:r,type:s}of o)w(e,`1${t.toString(36)}`,`${s}${r.toString(36)}`);for(const{tick:e,lane:t,width:r,type:s}of l)w(e,`5${t.toString(36)}`,`${s}${r.toString(36)}`);const E=new u;for(const e of p){const t=e[0].tick,r=e[e.length-1].tick,s=E.generateChannel(t,r).toString(36);for(const{tick:t,lane:r,width:n,type:a}of e)w(t,`3${r.toString(36)}${s}`,`${a}${n.toString(36)}`)}return b.forEach((({raws:e,ticksPerMeasure:t},r)=>{var s;const n=e.reduce(((e,t)=>i(t.tick,e)),t);if(!Number.isInteger(n))throw new a(n,e.map((({tick:e})=>e)));const o=new Map(e.sort((({tick:e},{tick:t})=>e-t)).map((({tick:e,value:r})=>[e%t,r]))),c=[];for(let e=0;e*n<t;e++){const t=e*n;c.push(null!==(s=o.get(t))&&void 0!==s?s:"00")}d.push(`#${r}:${c.join("")}`)})),d.join("\n")}o=new WeakMap;var p={parse:n,stringify:l};exports.default=p,exports.parse=n,exports.stringify=l; //# sourceMappingURL=index.cjs.js.map