improve prettier and ts config, format files

This commit is contained in:
SArpnt 2024-04-17 01:37:51 -04:00
parent 4907d1f38b
commit 840c35090f
Signed by: SArpnt
SSH key fingerprint: SHA256:iDMeic8KkqqEsN4wODlgsk1d/oW1ojZ/cu/MEWyfLBw
16 changed files with 118 additions and 185 deletions

6
.prettierignore Normal file
View file

@ -0,0 +1,6 @@
pnpm-lock.yaml
package.json5
assets/
*.css
# https://github.com/prettier/prettier/issues/5019
*.md

43
INFO.md
View file

@ -9,14 +9,14 @@ for example lower values could move the speaker inward while higher values move
left to right on the settings bar is:
- time, click button to change unit (t is samples and matches t variable)
- playback controls
- oscillioscope zoom
- oscillioscope draw mode
- playback mode (read info section on webpage for explanations)
- sample rate (samples per second, higher values give higher quality audio to an extent, higher than 48000 is unneccecary)
- sample rate divisor (skips samples for performance, could affect playback quite a bit if static variables are used)
- volume
1. time, click button to change unit (t is samples and matches t variable)
2. playback controls
3. oscillioscope zoom
4. oscillioscope draw mode
5. playback mode (read info section on webpage for explanations)
6. sample rate (samples per second, higher values give higher quality audio to an extent, higher than 48000 is unneccecary)
7. sample rate divisor (skips samples for performance, could affect playback quite a bit if static variables are used)
8. volume
sample rate and playback mode are part of the song itself, others are user preference
@ -37,6 +37,7 @@ start with playback mode Bytebeat, sample rate 8000, and this code:
```js
t
```
you should get a low pitch sawtooth wave (sawtooth being the diagonal spike shape on the oscillioscope, note that one side is diagonal and the other vertical)
the letter `t` here represents the time variable, this code is just outputting the time.
@ -64,14 +65,12 @@ by multiplying t by larger numbers you can get higher pitches.
note that at high values like 34 the wrapping doesn't quite line up anymore and you can both see and hear issues, this is caused by aliasing.
if you go extremely high multiples like 255 the pitch goes down again because it wraps mostly back to where it was before, at 256 it wraps all the way back to the start.
```js
t*t/300
```
last to look at here is just increasing pitch, note that after the pitch gets high enough the pitch starts dropping again due to aliasing.
at this point you may want to read up on [javascript operators](https://www.w3schools.com/jsref/jsref_operators.asp).
important here currently are arithmetic operators, comparison operators, and logical operators.
you may want to also check operator precedence to get an idea of when parenthesis are needed or not
@ -295,20 +294,17 @@ something to note here is that the pitch of the sine wave is so low you can't ev
something you might be wondering is why we're changing the phase and not the pitch, this is for two reasons:
1. changing the phase changes the pitch
pitch is just change of phase, so every part of the sin wave with a steep slope is an increase or decrease in pitch
pitch is just change of phase, so every part of the sin wave with a steep slope is an increase or decrease in pitch
2. trying to change the pitch doesn't even work
```js
(t*2*(1+sin(t/300)/64))%128
```
```js
(t*2*(1+sin(t/300)/64))%128
```
reset the time to 0 and listen to this formula, the vibrato just keeps getting stronger as time goes on.
this is because trying to change the pitch like this does change the speed, but it doesn't keep the phase.
reset the time to 0 and listen to this formula, the vibrato just keeps getting stronger as time goes on.
this is because trying to change the pitch like this does change the speed, but it doesn't keep the phase.
to change the pitch correctly here we would need to either store the phase (annoying and can cause various issues),
or use an infinite series of terms to manage rate of change of pitch, rate of change of rate of change of pitch, and so on (literally impossible) (hint #2 again).
to change the pitch correctly here we would need to either store the phase (annoying and can cause various issues),
or use an infinite series of terms to manage rate of change of pitch, rate of change of rate of change of pitch, and so on (literally impossible) (hint #2 again).
just modulate the phase, not only does it work but it allows doing more than modulating pitch can.
@ -392,13 +388,10 @@ sync with sawtooth fm
inverted sawtooth pulse
wrapping with & operator always wraps in positive range and truncates,
however note that it can only wrap for powers of 2, and operator precedence is different.
this can save on characters in many situations.
arrays, strings, charCodeAt, fromCharCode
variables, comma operator
@ -414,7 +407,7 @@ you'll more likely recognize this from physics
d = cycles (phase)
v = cycles / s (Hz)
a = cycles / s**2 (rate of change of Hz)
a = cycles / s\*\*2 (rate of change of Hz)
this allows pitch shifting without messing up phase (which often messes up the pitch shifting in the first place)

View file

@ -1,23 +1,26 @@
# bytebeat-composer
modern bytebeat player with a library of many formulas from around the internet.
originally forked from [StephanShi's website](https://github.com/SthephanShinkufag/bytebeat-composer) to fix bugs and add features, now maintained independently.
afaik this was the first bytebeat program that didn't have any major playback bugs (the two common ones are being unable to access functions like `escape`, and editing strings like `"sin"`).
this program also works well with storing persistent variables, in this example `b` is used to store persistent variables
this program also works well with storing persistent variables, in this example `b` is used to store persistent variables:
```js
this.b??={a:0,b:0}, // this, window, and globalThis are all the same in this context
w=((t/(+"8654"[t>>11&3]+(t>>15&1))/10%1>.5)+1.5)*64,
c=sin(t/2e3)/6+.3,
b.b+=c*((b.a+=c*(w-b.a+(b.a-b.b)/.7))-b.b)
```
all iterable variables are deleted when the bytebeat is input, so variables between bytebeats don't conflict
Longline Theory and Information Theory are played correctly since a signed bytebeat mode has been added
all iterable variables are deleted when the bytebeat is input, so variables between bytebeats don't conflict.
syntax highlighting has been added, with a good amount of useful settings but nothing intrusive
Longline Theory and Information Theory are played correctly since a signed bytebeat mode has been added.
stereo is supported by returning an array
syntax highlighting has been added, with a good amount of useful settings but nothing intrusive.
stereo is supported by returning an array.
## warning
@ -25,25 +28,28 @@ this website runs arbitrary code!
i've taken many security measures, but i can't guarantee what i've done is foolproof.
as far as i can tell, this website should be secure, but this doesn't prevent:
- taking advantage of browser security vulnerabilities
- locking up the audio thread, making controls not work (volume still works, and the page can be refreshed)
- anything else an AudioWorklet could do that i don't know about (i really don't know that much about security)
on a secure browser the website _should_ be safe, but i can't guarantee anything.
If i've messed up anywhere then results could be much worse
If i've messed up anywhere then results could be much worse.
to judge yourself, these are the security measures i've taken:
- input code is ran in an audio worklet (note that the code has access to the global scope)
- most iterable global variables are deleted
- objects and prototypes of objects on the global scope are frozen
- variables remaining on the global scope are made unwritable and unconfigurable
- variables remaining on the global scope are made unwritable and unconfigurable
## embedding
https://bytebeat.ficial.io/embed is an embeddable version of the page, designed to be used in other projects.
it doesn't have the library, doesn't save settings, and can recieve commands via `postMessage`
it doesn't have the library, doesn't save settings, and can recieve commands via `postMessage`.
command format:
```js
{
show: { // show / hide webpage elements
@ -68,6 +74,7 @@ command format:
```
any messages recieved will be in this format:
```js
{
song: { // sent on getSong
@ -84,10 +91,10 @@ if any previously working links stop working, LET ME KNOW. link compatibility is
if i'm unavalible or you're in a hurry, you can decode the links manually:
- links prefixed with `#v3b64` are the oldest, to decode:
1. remove the prefix
2. convert from base 64 with atob
4. inflate to string with deflate (you can use a tool like fflate or pako)
5. parse with JSON
1. remove the prefix
2. convert from base 64 with atob
3. inflate to string with deflate (you can use a tool like fflate or pako)
4. parse with JSON
- links prefixed with `#v4` have essentially the same process. the only differences are the prefix and the absence of base64 padding.
newer formats are complicated, so i'll only provide commit hashes and the code locations.
@ -96,16 +103,13 @@ newer formats are complicated, so i'll only provide commit hashes and the code l
- `#6` commit a36406d, src/url/mod.ts. this version was reverted because the urls broke markdown
- `#5` after commit a36406d, src/url/mod.ts
## building
install pnpm
```sh
pnpm i --prod
pnpm run build
```
- install pnpm
- ```sh
pnpm i --prod
pnpm run build
```
output is in \_site, you can start a webserver there.

View file

@ -20,11 +20,7 @@ module.exports = eleventyConfig => {
eleventyConfig.on("eleventy.after", async ({ dir, results, runMode, outputMode }) => {
await Promise.all([
esbuild.build({
entryPoints: [
`src/style.css`,
`src/bytebeat.ts`,
`src/embed.ts`,
],
entryPoints: [`src/style.css`, `src/bytebeat.ts`, `src/embed.ts`],
outdir: output,
format: "esm",
bundle: true,
@ -34,9 +30,7 @@ module.exports = eleventyConfig => {
//write: serve,
}),
esbuild.build({
entryPoints: [
`src/audio-worklet/audio-worklet.ts`,
],
entryPoints: [`src/audio-worklet/audio-worklet.ts`],
outdir: output,
format: "esm",
bundle: true,

View file

@ -6,6 +6,7 @@ no player has all of these features yet but i considered everything that seemed
i will not change anything already defined in the format because i already made my urls and backwards compatibility should stay forever.
some pseudo javascript to show how the format works:
```js
mode & 0x80 ? /* code is statements */ : /* code is an expression */
mode & 0x40 ? /* returns a function */ : /* returns a number */

View file

@ -5,12 +5,12 @@ import type { DrawSample } from "../oscillioscope.ts";
declare abstract class AudioWorkletProcessor {
readonly port: MessagePort;
constructor(options?: {
numberOfInputs?: number,
numberOfOutputs?: number,
outputChannelCount: number[],
numberOfInputs?: number;
numberOfOutputs?: number;
outputChannelCount: number[];
// i don't understand these ones
parameterData?: unknown,
processorOptions?: unknown,
parameterData?: unknown;
processorOptions?: unknown;
});
abstract process(
_inputs: Float32Array[][],

View file

@ -1,12 +1,18 @@
import { EditorState } from "@codemirror/state";
import { EditorView, keymap, highlightSpecialChars } from "@codemirror/view";
import { history, historyKeymap, defaultKeymap, insertNewline, indentLess } from "@codemirror/commands";
import {
history,
historyKeymap,
defaultKeymap,
insertNewline,
indentLess,
} from "@codemirror/commands";
import { searchKeymap, highlightSelectionMatches } from "@codemirror/search";
import { indentUnit, bracketMatching, syntaxHighlighting } from "@codemirror/language";
import { javascript } from "@codemirror/lang-javascript";
import { classHighlighter } from "@lezer/highlight";
function createCodemirror(inputListener?: (() => void)) {
function createCodemirror(inputListener?: () => void) {
const editor = new EditorView({
state: EditorState.create({
extensions: [

View file

@ -9,15 +9,18 @@ class CodeEditor {
const textarea = document.getElementById("code-editor") as HTMLTextAreaElement;
initTextarea(editCallback, textarea);
this.getCode = () => textarea.value;
this.setCode = v => {textarea.value = v as string};
this.setCode = v => {
textarea.value = v as string;
};
// codemirror takes a long time to load, so import it late, then replace the textarea
import("./codemirror.ts").then(c => {
const codemirror = c.replace(editCallback, textarea);
this.getCode = () => codemirror.state.doc.toString();
this.setCode = v => codemirror.dispatch({
changes: { from: 0, to: codemirror.state.doc.length, insert: v },
});
this.setCode = v =>
codemirror.dispatch({
changes: { from: 0, to: codemirror.state.doc.length, insert: v },
});
});
}
}

View file

@ -1,15 +1,15 @@
function f32ToRound10(value: number): number {
// this is stupid but it works for numbers less
// than 10 digits on one side of the decimal point
const p7 = +(value.toPrecision(7));
// this is stupid but it works for numbers less
// than 10 digits on one side of the decimal point
const p7 = +value.toPrecision(7);
if (Math.fround(p7) === value) {
return p7
return p7;
}
const p8 = +(value.toPrecision(8));
const p8 = +value.toPrecision(8);
if (Math.fround(p8) === value) {
return p8
return p8;
}
return +(value.toPrecision(9));
return +value.toPrecision(9);
// for the range that sampleRate uses:
// 62677722 numbers needs precision 7

View file

@ -23,11 +23,7 @@
<main id="content">
<section class="container-fixed">
<div id="code-editor-container">
<textarea
id="code-editor"
aria-label="Code editor"
spellcheck="false"
></textarea>
<textarea id="code-editor" aria-label="Code editor" spellcheck="false"></textarea>
</div>
<div id="controls">
<span class="control-group control-time" id="control-time">
@ -36,11 +32,7 @@
id="control-time-unit"
onclick="bytebeat.changeTimeUnit();"
>
<label
id="control-time-unit-label"
for="control-time-value"
>t</label
>
<label id="control-time-unit-label" for="control-time-value">t</label>
</button>
<input
title="Time value"
@ -52,11 +44,7 @@
/>
</span>
<span class="control-group control-time buttons">
<button
title="Restart"
id="control-restart"
onclick="bytebeat.resetTime();"
>
<button title="Restart" id="control-restart" onclick="bytebeat.resetTime();">
&#x23ee;&#xfe0e;
</button>
<button
@ -73,11 +61,7 @@
>
&#x23f4;&#xfe0e;
</button>
<button
title="Pause"
id="control-pause"
onclick="bytebeat.togglePlay(false);"
>
<button title="Pause" id="control-pause" onclick="bytebeat.togglePlay(false);">
&#x23f8;&#xfe0e;
</button>
<button
@ -115,11 +99,7 @@
>
+
</button>
<button
title="Zoom out"
id="control-scaleup"
onclick="bytebeat.changeScale(1);"
>
<button title="Zoom out" id="control-scaleup" onclick="bytebeat.changeScale(1);">
-
</button>
</span>
@ -156,12 +136,8 @@
onblur="this.value||=this.placeholder;this.placeholder=''"
onchange="bytebeat.setSampleRate(+this.value); bytebeat.refreshCode();"
/><span class="text"
><label for="control-sample-rate" class="control-song"
>Hz</label
>
<label
for="control-sample-rate-divisor"
class="control-playback"
><label for="control-sample-rate" class="control-song">Hz</label>
<label for="control-sample-rate-divisor" class="control-playback"
>/</label
></span
><input
@ -207,10 +183,7 @@
<!-- SVG BUTTONS -->
<!-- TODO: create svgs for all controls-->
<div id="svg-icons" style="height: 0; width: 0; overflow: hidden">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol viewBox="0 0 32 32" id="symbol-play">
<path
d="m23 14.3-9-5.2c-1.3-.8-3 .2-3 1.7v10.4c0 1.5 1.7 2.5 3 1.7l9-5.2c1.3-.7 1.3-2.7 0-3.4z"

View file

@ -22,10 +22,7 @@ html(data-embed lang="en")
textarea#code-editor(spellcheck="false" aria-label="Code editor")
#controls
span#control-time.control-group.control-time
button#control-time-unit(
onclick="bytebeat.changeTimeUnit();"
title="Time unit"
)
button#control-time-unit(onclick="bytebeat.changeTimeUnit();" title="Time unit")
label#control-time-unit-label(for="control-time-value") t
input#control-time-value(
onchange="bytebeat.setByteSample(bytebeat.convertFromUnit(+this.value)); this.value = '';"
@ -64,14 +61,8 @@ html(data-embed lang="en")
title="Volume"
)
span.control-group.control-view.buttons.buttons-zoom
button#control-scaledown(
onclick="bytebeat.changeScale(-1);"
title="Zoom in"
) +
button#control-scaleup(
onclick="bytebeat.changeScale(1);"
title="Zoom out"
) -
button#control-scaledown(onclick="bytebeat.changeScale(-1);" title="Zoom in") +
button#control-scaleup(onclick="bytebeat.changeScale(1);" title="Zoom out") -
//
<span class="control-group control-record buttons">
<button title="Share" onclick="">&#x1f517;&#xfe0e;</button>
@ -135,10 +126,7 @@ html(data-embed lang="en")
// SVG BUTTONS
// TODO: create svgs for all controls
#svg-icons(style="height: 0; width: 0; overflow: hidden")
svg(
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
)
svg(xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg")
symbol#symbol-play(viewBox="0 0 32 32")
path(
d="m23 14.3-9-5.2c-1.3-.8-3 .2-3 1.7v10.4c0 1.5 1.7 2.5 3 1.7l9-5.2c1.3-.7 1.3-2.7 0-3.4z"

View file

@ -18,46 +18,37 @@ html(lang="en")
| (t*(1+(5&t>>10))*(3+(t>>17&1?(2^2&t>>14)/3:3&(t>>13)+1))>>(3&t>>9))&(t&4096?(t*(t^t%9)|t>>3)>>1:255)
#controls
span#control-time.control-group.control-time
button#control-time-unit(
title="Time unit"
onclick="bytebeat.changeTimeUnit();"
)
button#control-time-unit(title="Time unit" onclick="bytebeat.changeTimeUnit()")
label#control-time-unit-label(for="control-time-value") t
input#control-time-value(
onchange="bytebeat.setByteSample(bytebeat.convertFromUnit(+this.value)); this.value = '';"
onchange="bytebeat.setByteSample(bytebeat.convertFromUnit(+this.value)); this.value = ''"
style="width: 8em"
placeholder="0"
type="number"
title="Time value"
)
span.control-group.control-time.buttons
button#control-restart(
onclick="bytebeat.resetTime();"
title="Restart"
) &#9198;&#65038;
button#control-restart(onclick="bytebeat.resetTime()" title="Restart") &#9198;&#65038;
button#control-fr(
onclick="bytebeat.setPlaySpeed(-4); bytebeat.togglePlay(true);"
onclick="bytebeat.setPlaySpeed(-4); bytebeat.togglePlay(true)"
title="Fast reverse"
) &#9194;&#65038;
button#control-reverse(
onclick="bytebeat.setPlaySpeed(-1); bytebeat.togglePlay(true);"
onclick="bytebeat.setPlaySpeed(-1); bytebeat.togglePlay(true)"
title="Reverse"
) &#9204;&#65038;
button#control-pause(
onclick="bytebeat.togglePlay(false);"
title="Pause"
) &#9208;&#65038;
button#control-pause(onclick="bytebeat.togglePlay(false)" title="Pause") &#9208;&#65038;
button#control-play(
onclick="bytebeat.setPlaySpeed(1); bytebeat.togglePlay(true);"
onclick="bytebeat.setPlaySpeed(1); bytebeat.togglePlay(true)"
title="Play"
) &#9205;&#65038;
button#control-ff(
onclick="bytebeat.setPlaySpeed(4); bytebeat.togglePlay(true);"
onclick="bytebeat.setPlaySpeed(4); bytebeat.togglePlay(true)"
title="Fast Forward"
) &#9193;&#65038;
span.control-group.control-playback
input#control-volume(
oninput="bytebeat.setVolume();"
oninput="bytebeat.setVolume()"
value="0.6"
step="any"
max="1"
@ -67,14 +58,8 @@ html(lang="en")
style="width: 8em"
)
span.control-group.control-view.buttons
button#control-scaledown(
onclick="bytebeat.changeScale(-1);"
title="Zoom in"
) +
button#control-scaleup(
onclick="bytebeat.changeScale(1);"
title="Zoom out"
) -
button#control-scaledown(onclick="bytebeat.changeScale(-1)" title="Zoom in") +
button#control-scaleup(onclick="bytebeat.changeScale(1)" title="Zoom out") -
//
span.control-group.control-record.buttons
button(title="Share" onclick="") &#x1f517;&#xfe0e;
@ -83,7 +68,7 @@ html(lang="en")
button(title="Record" onclick="") &#x23fa;&#xfe0e;
span.control-group.control-song
select#control-song-mode(
onchange="bytebeat.setPlaybackMode(this.value);"
onchange="bytebeat.setPlaybackMode(this.value)"
title="Playback mode"
)
option(value="Bytebeat" selected) Bytebeat
@ -92,7 +77,7 @@ html(lang="en")
option(value="Funcbeat") Funcbeat
span.control-group
input#control-sample-rate.control-song.control-round-right(
onchange="bytebeat.setSampleRate(+this.value); bytebeat.refreshCode();"
onchange="bytebeat.setSampleRate(+this.value); bytebeat.refreshCode()"
onblur="this.value||=this.placeholder;this.placeholder=''"
onfocus="this.placeholder=this.value;this.value=''"
style="width: 6em"
@ -107,7 +92,7 @@ html(lang="en")
label.control-song(for="control-sample-rate") Hz
label.control-playback(for="control-sample-rate-divisor") /
input#control-sample-rate-divisor.control-playback.control-round-left.control-round-right(
onchange="bytebeat.setSampleRateDivisor(+this.value); bytebeat.refreshCode();"
onchange="bytebeat.setSampleRateDivisor(+this.value); bytebeat.refreshCode()"
style="width: 3em"
value="1"
step="1"
@ -124,9 +109,7 @@ html(lang="en")
option(value="44100")
option(value="48000")
#error
#canvas-container(
onclick="bytebeat.setPlaySpeed(1); bytebeat.togglePlay()"
)
#canvas-container(onclick="bytebeat.setPlaySpeed(1); bytebeat.togglePlay()")
canvas#canvas-main(height="256" width="1024" aria-label="Oscillioscope")
#canvas-timecursor
#canvas-toggleplay.canvas-toggleplay-show
@ -174,20 +157,11 @@ html(lang="en")
href="https://countercomplex.blogspot.com.au/search/label/algorithmic%20music"
) Blog posts #2
li
a(
target="_blank"
href="https://www.youtube.com/watch?v=GtQdIYUtAHg"
) YouTube video #1
a(target="_blank" href="https://www.youtube.com/watch?v=GtQdIYUtAHg") YouTube video #1
li
a(
target="_blank"
href="https://www.youtube.com/watch?v=qlrs2Vorw2Y"
) YouTube video #2
a(target="_blank" href="https://www.youtube.com/watch?v=qlrs2Vorw2Y") YouTube video #2
li
a(
target="_blank"
href="https://www.youtube.com/watch?v=tCRPUv8V22o"
) YouTube video #3
a(target="_blank" href="https://www.youtube.com/watch?v=tCRPUv8V22o") YouTube video #3
figure.figure-list
figcaption Online JavaScript players:
ul
@ -201,10 +175,7 @@ html(lang="en")
li
a(target="_blank" href="https://entropedia.co.uk/generative_music") by Paul Hayes
li
a(
target="_blank"
href="https://wurstcaptures.untergrund.net/music"
) by Bemmu and Rarefluid
a(target="_blank" href="https://wurstcaptures.untergrund.net/music") by Bemmu and Rarefluid
section
p
| This webpage has a collection of bytebeat music found by
@ -282,17 +253,11 @@ html(lang="en")
footer
a.link(target="_blank" href="https://dollchan.net/btb") Dollchan Discussion board
br
a.link(
target="_blank"
href="https://git.disroot.org/SArpnt/bytebeat-composer"
) Source code
a.link(target="_blank" href="https://git.disroot.org/SArpnt/bytebeat-composer") Source code
// SVG BUTTONS
// TODO: create svgs for all controls
#svg-icons(style="height: 0; width: 0; overflow: hidden")
svg(
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
)
svg(xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg")
symbol#symbol-play(viewBox="0 0 32 32")
path(
d="m23 14.3-9-5.2c-1.3-.8-3 .2-3 1.7v10.4c0 1.5 1.7 2.5 3 1.7l9-5.2c1.3-.7 1.3-2.7 0-3.4z"

View file

@ -5,10 +5,7 @@ function stripEntryToSong(entry: Entry) {
const { sampleRate, mode } = entry;
return { sampleRate, mode };
}
function stripInlineEntryToSong(
entry: Readonly<InlineEntry>,
codeType: keyof InlineEntry,
) {
function stripInlineEntryToSong(entry: Readonly<InlineEntry>, codeType: keyof InlineEntry) {
const { sampleRate, mode } = entry;
return { code: entry[codeType], sampleRate, mode };
}

View file

@ -18,7 +18,7 @@ const lbl = Array(20)
* converts data into base89, using all the valid characters for a url anchor.
* this allows incredibly small urls, but many of these characters
* break markdown and other common post formatting.
*
*
* bitIndex is the first bit that into89 will read from and encode,
* and it'll continue until the end of the array.
* use bitIndex if you want to trim less than 8 bits off the data.

View file

@ -142,7 +142,7 @@ async function setUrlData({ code, mode, sampleRate }: Song) {
* samplerates out of the range won't get stored correctly at all
* you can do Math.min(Math.max(Math.fround(sampleRate), 2), 2 ** 24 - 1)
* to get any number within the correct range
*
*
* this function sets the window hash directly, it doesn't return a string
*/
async function setUrlData({ code, mode, sampleRate }: Song) {

View file

@ -7,6 +7,9 @@
"noEmit": true,
"target": "esnext",
"strict": true,
"exactOptionalPropertyTypes": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"types": ["jest"]