Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Bytebeat renderer
- You'll need node.js. If you don't have it, install it at https://nodejs.org/
- find the flag list below
- */
- const fs = require('fs');
- const chyx = {
- /*bit*/ "bitC": function (x, y, z) { return x & y ? z : 0 },
- /*bit reverse*/"br": function (x, size = 8) {
- if (size > 32) { throw new Error("br() Size cannot be greater than 32") } else {
- let result = 0;
- for (let idx = 0; idx < (size - 0); idx++) {
- result += chyx.bitC(x, 2 ** idx, 2 ** (size - (idx + 1)))
- }
- return result
- }
- },
- /*sin that loops every 128 "steps", instead of every pi steps*/"sinf": function (x) { return Math.sin(x / (128 / Math.PI)) },
- /*cos that loops every 128 "steps", instead of every pi steps*/"cosf": function (x) { return Math.cos(x / (128 / Math.PI)) },
- /*tan that loops every 128 "steps", instead of every pi steps*/"tanf": function (x) { return Math.tan(x / (128 / Math.PI)) },
- /*converts t into a string composed of it's bits, regex's that*/"regG": function (t, X) { return X.test(t.toString(2)) }
- /*corrupt sound"crpt": function(x,y=8) {return chyx.br(chyx.br(x,y)+t,y)^chyx.br(t,y)},
- decorrupt sound"decrpt": function(x,y=8) {return chyx.br(chyx.br(x^chyx.br(t,y),y)-t,y)},*/
- }
- const outputFile = './output.wav';
- const inputFile = './input.txt';
- const bitsPerSample = 8;
- function number32to4chars(input) {
- const buffer = Buffer.alloc(4);
- buffer.writeUInt32LE(input, 0);
- return buffer;
- }
- function number16to2chars(input) {
- const buffer = Buffer.alloc(2);
- buffer.writeUInt16LE(input, 0);
- return buffer;
- }
- function indicator(val, max, barSize = 20) {
- const first = `[${''.padStart(Math.floor((val / max) * barSize), '#').padEnd(barSize, ' ')}]`
- const second = `(${String(val).padStart(12, ".")} / ${String(max).padEnd(12, ".")})`;
- return first + second
- }
- function main() {
- if (process.argv.indexOf('--usage') !== -1) {
- const filePath = require('path').dirname(__filename).replace(/^\w:\\Users\\(.+?)(?:\\OneDrive)?\\Desktop/i, '($1\'s desktop)').replace(/^\w:\\Users\\(.+?)/i, '($1\'s folder)')
- console.log(` Flag list\r
- --rate <samplerate>\r
- --length <seconds>\r
- --mode <float, byte, or signed. case sensitive>\r
- --stereo to specify the code is stereo. Double check this is used correctly!\r
- --chyx to include the chyxPack extension from the CHYX composer. Non-standard!\r
- Instructions
- The program takes in an input.txt file fom the directory it's in. If it can't find this file,\r
- it will probably crash. Ensure you have an input.txt file in: \r
- \x1b[96m${filePath}\x1b[0m\r
- and it has valid bytebeat JS code.\r
- the program will throw an error if the sample rate or length flags are not specified.\r
- Mode does not need to be specified, as it defaults to bytebeat ("byte")\r
- --chyx adds the custom functions found on https://chasyxx.github.io/EnBeat_NEW .\r
- These functions are exotic and non standard.`)
- return 0;
- }
- console.log("\x1b[92mUse flag --usage to see usage information. The discord may not be up to date, so be sure to check!\x1b[0m")
- const modeIndex = process.argv.indexOf('--mode');
- let getvalues = function () { };
- const lengthIndex = process.argv.indexOf('--length');
- const rateIndex = process.argv.indexOf('--rate');
- const sizeIndex = process.argv.indexOf('--size');
- const stereo = process.argv.indexOf('--stereo') !== -1;
- const useChyx = process.argv.indexOf('--chyx') !== -1;
- let bufferSize = null; // Number of samples to buffer before flushing to the main buffer
- let rateValue, lengthValue, trueLength;
- if (rateIndex !== -1) {
- rateValue = parseInt(parseInt(process.argv[rateIndex + 1]));
- console.log('Sample rate: %d', rateValue);
- } else {
- throw new Error("Required samplerate parameter. Flag is --rate (number)");
- }
- if (sizeIndex !== -1) {
- bufferSize = parseInt(parseInt(process.argv[sizeIndex + 1]));
- console.log("buffer size %d", bufferSize)
- }
- if (modeIndex !== -1) {
- switch (process.argv[modeIndex + 1]) {
- case 'byte':
- getvalues = (x) => (x & 255);
- break;
- case 'signed':
- getvalues = (x) => ((x + 128) & 255);
- break;
- case 'float':
- getvalues = (x) => Math.max(Math.min((x * 128 + 128), 255), 0);
- break;
- default: throw new Error("Invalid mode. Use byte, signed, or float")
- }
- } else {
- getvalues = (x) => (x & 255)
- }
- if (lengthIndex !== -1) {
- lengthValue = parseFloat(process.argv[lengthIndex + 1]);
- trueLength = Math.floor(lengthValue * rateValue);
- bufferSize ??= Math.min(Math.floor(trueLength / 40), 5e4);
- console.log('Length in seconds: %d', lengthValue);
- console.log('Samples to generate: %d', trueLength);
- } else {
- throw new Error("Required length parameter. Flag is --length (number)");
- }
- if (stereo) {
- console.log("Code is marked as stereo.")
- }
- const globalVars = {};
- const codeString = fs.readFileSync(inputFile, { encoding: "ascii" });
- const codeLength = codeString.length;
- let codeFunc = null;
- let lastValue = stereo ? [0, 0] : 0;
- let buffer = Buffer.alloc(0);
- let tempBuffer = Buffer.alloc(0);
- const params = Object.getOwnPropertyNames(Math);
- const values = params.map(k => Math[k]);
- const chyxNames = Object.getOwnPropertyNames(chyx);
- const chyxFuncs = chyxNames.map(k => chyx[k]);
- params.push('int', 'window');
- values.push(Math.floor, globalVars);
- if (useChyx) {
- console.log("ChyxPak library included. \x1b[33mThis is non-standard!\x1b[0m")
- params.push(...chyxNames)
- values.push(...chyxFuncs)
- }
- let i;
- console.log(codeLength > 256 ? `Code squelched, ${codeLength > 1000 ? `${codeLength / 1000} KB` : `${codeLength}b`}` : `Code: ${codeString}`);
- console.log(`\nsong progress: [$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$](------------ / ------------)\nsubBuffer progress:[$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$](------------ / ------------)`);
- try {
- codeFunc = new Function(...params, 't', `return 0,\n${codeString || 0};`).bind(globalVars, ...values);
- try {
- codeFunc(0)
- } catch (e) {
- console.log(`\x1b[3A\x1b[91mRuntime error at t=0: ${e.message}\x1b[0m\x1b[2B`)
- const exec = /^(.+) is not defined$/.exec(e.message)
- if (exec!==null && !useChyx) {
- if(chyxNames.indexOf(exec[0].replace(/ is not defined$/,""))!==-1) {
- console.log("Maybe try using the --chyx flag?")
- return 1;
- }
- }
- }
- } catch (e) {
- console.error("Creation error: " + e.message);
- const exec = /^(.+) is not defined$/.exec(e.message)
- if (exec!==null && !useChyx) {
- if(chyxNames.indexOf(exec[0].replace(/ is not defined$/,""))!==-1) {
- console.log("Maybe try using the --chyx flag?")
- }
- }
- return 1;
- }
- if (stereo) {
- for (i = 0; i <= trueLength; i++) {
- if ((i % 100) == 0) console.log("\x1b[2Asong progress: %s\nsubBuffer progess: %s", indicator(i, trueLength, 40), indicator(tempBuffer.length, bufferSize, 40));
- let result = NaN;
- try {
- result = codeFunc(i)
- } catch (e) {
- if(e instanceof Error) {
- console.log(`\x1b[3A\x1b[91mRuntime error at t=${i}: ${e.message}\x1b[0m\x1b[2B`)
- }else{
- console.log(`\x1b[3A\x1b[93mThrown at t=${i}: ${e}\x1b[0m\x1b[2B`)
- }
- }
- lastValue[0] = isNaN(result[0]) ? lastValue[0] : getvalues(result[0]) & 255;
- lastValue[1] = isNaN(result[1]) ? lastValue[1] : getvalues(result[1]) & 255;
- tempBuffer = Buffer.concat([tempBuffer, Buffer.from([lastValue[0]]), Buffer.from([lastValue[1]])]);
- // Flush the tempBuffer to the main buffer when it reaches the bufferSize
- if (tempBuffer.length >= bufferSize) {
- buffer = Buffer.concat([buffer, tempBuffer]);
- tempBuffer = Buffer.alloc(0);
- }
- }
- } else {
- for (i = 0; i <= trueLength; i++) {
- if ((i % 100) == 0) console.log("\x1b[2Asong progress: %s\nsubBuffer progess: %s", indicator(i, trueLength, 40), indicator(tempBuffer.length, bufferSize, 40));
- let result = NaN;
- try {
- result = getvalues(codeFunc(i))
- } catch (e) {
- if(e instanceof Error) {
- console.log(`\x1b[3A\x1b[91mRuntime error at t=${i}: ${e.message}\x1b[0m\x1b[2B`)
- }else{
- console.log(`\x1b[3A\x1b[93mThrown at t=${i}: ${e}\x1b[0m\x1b[2B`)
- }
- }
- lastValue = isNaN(result) ? lastValue : result & 255;
- tempBuffer = Buffer.concat([tempBuffer, Buffer.from([lastValue])]);
- // Flush the tempBuffer to the main buffer when it reaches the bufferSize
- if (tempBuffer.length >= bufferSize) {
- buffer = Buffer.concat([buffer, tempBuffer]);
- tempBuffer = Buffer.alloc(0);
- }
- }
- }
- // Flush any remaining samples in the tempBuffer to the main buffer
- buffer = Buffer.concat([buffer, tempBuffer]);
- console.log('\x1b[1AProcessing complete. Generating file. ');
- const header = Buffer.concat([
- Buffer.from('RIFF', 'ascii'), // RIFF
- number32to4chars(buffer.length + 36), // filesize - 8
- Buffer.from('WAVEfmt ', 'ascii'), // .wav file, begin formatting info
- number32to4chars(16), // length of formatting info
- number16to2chars(1), // Marker for PCM data
- number16to2chars(stereo ? 2 : 1), // Channel No.
- number32to4chars(rateValue), // Sample rate
- number32to4chars(rateValue * (stereo ? 2 : 1) * (bitsPerSample / 8)), // (Sample rate * Number of channels * Bits per sample) / 8
- number16to2chars((bitsPerSample * (stereo ? 2 : 1)) / 8), // (Bits per sample * Number of channels) / 8
- number16to2chars(bitsPerSample), // bits per sample
- Buffer.from('data', 'ascii'), // Begin data block
- number32to4chars(buffer.length), // How long is this block?
- ]);
- const final = Buffer.concat([header, buffer]);
- fs.writeFileSync(outputFile, final);
- console.log('Done, wrote %d samples.', trueLength);
- return 0;
- }
- main();
Advertisement
Add Comment
Please, Sign In to add comment