{"id":13657988,"url":"https://github.com/greggman/html5bytebeat","last_synced_at":"2025-05-15T16:07:03.753Z","repository":{"id":2449298,"uuid":"3420071","full_name":"greggman/html5bytebeat","owner":"greggman","description":"Bytebeats in HTML5","archived":false,"fork":false,"pushed_at":"2025-02-08T06:01:47.000Z","size":2146,"stargazers_count":446,"open_issues_count":8,"forks_count":38,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-05-13T04:11:12.858Z","etag":null,"topics":["audio","bytebeat","sound"],"latest_commit_sha":null,"homepage":"http://greggman.com/downloads/examples/html5bytebeat/html5bytebeat.html","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"android-cn/android-open-project-analysis","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/greggman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2012-02-12T04:42:55.000Z","updated_at":"2025-05-12T15:15:07.000Z","dependencies_parsed_at":"2024-01-14T16:14:36.986Z","dependency_job_id":"3afea895-d623-4b31-a13d-2019bd0e7be8","html_url":"https://github.com/greggman/html5bytebeat","commit_stats":{"total_commits":587,"total_committers":3,"mean_commits":"195.66666666666666","dds":0.4088586030664395,"last_synced_commit":"9cb84f7a1defceb427e883156a53124b3a76f2dd"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greggman%2Fhtml5bytebeat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greggman%2Fhtml5bytebeat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greggman%2Fhtml5bytebeat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greggman%2Fhtml5bytebeat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/greggman","download_url":"https://codeload.github.com/greggman/html5bytebeat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254374475,"owners_count":22060611,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audio","bytebeat","sound"],"created_at":"2024-08-02T05:00:54.848Z","updated_at":"2025-05-15T16:07:03.730Z","avatar_url":"https://github.com/greggman.png","language":"JavaScript","readme":"HTML5 Bytebeat\n==============\n\nBytebeat is the name of type of music made from math.\n\nYou provide a function who's only input is time *t* and from that write some code to generate a sound.\n\nIn this particular case *t* is an 8000hz timer that counts up. For example\n\n    sin(t) * 127 + 127\n\nYou can choose traditional bytebeat where the output of your function is expected to be 0 to 255\nor you can choose floatbeat where the output is expected to be -1 to +1.\n\nFunctions are just plain JavaScript though sin, cos, tan, floor, ceil and int will automatically be converted\nto Math.sin, Math.cos, Math.tan, Math.floor, Math.ceil, and Math.floor respectively.\n\n[Click here to try your hand at Bytebeat](http://greggman.com/downloads/examples/html5bytebeat/html5bytebeat.html).\n\n# Instructions\n\n### Modes\n\nThere 2 modes\n\n* bytebeat: Your expression is expected to generate byte values from 0 to 255\n* floatbeat: Your expression is expected to generate float values from -1.0 to 1.0\n\n### Expression Types\n* Infix: Standard expressions eg. \"`(t * 2) / 4`\"\n* Postfix(rpn): Reverse Polish Notation eg \"`t 2 * 4 /`\"\n* glitch: glitch format or glitch urls.\n* function: Return a function. eg. \"`return t =\u003e (t * 2) / 4`\"\n\n**Infix** is standard JavaScript so all Math functions are available.\nMost math functions you can drop the \"Math.\" part. In other words\n\n    sin(t)\n\nis the same as\n\n    Math.sin(t)\n\n**Postfix** requires that each element have at least one space between it.\n\n    t2*    // BAD!\n    t 2 *  // Good!\n\nIf you're unfamiliar with postfix [see below](#postfix)\n\n**Glitch** is a format used by glitch machine for sharing. Examples\n\n* \u003ca href=\"https://greggman.com/downloads/examples/html5bytebeat/html5bytebeat.html#t=0\u0026e=2\u0026s=8000\u0026bb=5d0000010060000000000000000017e07c68347275b48b8a3e4ae5f2fcf118694f3c5b765c81e4a571018d893ec35ab1c80e51eaadbdb73dbe8af51bf1324d5fc68ca278d3c5fbff8e137344d360a109d789a07673a414f2b2171c4d5de9f1d3f2ecc410e9dfff85520000\"\u003e42_forever!a13880fa400he!a5kma6kn40g!aCk28!a12k1ld!2fladm!43n\u003c/a\u003e\n* \u003ca href=\"https://greggman.com/downloads/examples/html5bytebeat/html5bytebeat.html#t=0\u0026e=2\u0026s=8000\u0026bb=5d000001006b000000000000000017e07ce06937cec415be16c16cd1dc7770bc5386546efdb66845ee0aa7b98eff2ba6e3f457299da2037f6a5ad9e8e38b3611b90fee512d353d0b25fc253191ae89a30e0f7adabb03c956d89bd548392fe27fe4ffe962f8939a5a65ff945a0000\"\u003epipe_symphony!aEk5h5f!a11k2h!a9k3hdf!aDk4hg!ad4e!p5fm!a11k2h1rg!a5kdm\u003c/a\u003e\n\nThese can be prefixed with \"glitch://\". For example\n\n* \u003ca href=\"https://greggman.com/downloads/examples/html5bytebeat/html5bytebeat.html#t=0\u0026e=2\u0026s=8000\u0026bb=5d0000010074000000000000000017e07ce661316231c4f949bffc8dd7660451a2571363cac6697ec8fb0cdb5eb5685ae9f83ad7be74c020fa1efe54e1b53cf571811b40ca41357fd42f73eb9683e086bd4aaf30dc675ee6bb090c9840be59402238c6553b9cc0eea0bdc6ddeac83341fdff033c0000\"\u003eglitch://sadglitch!4.4.9.8.9.6.4.2!aoCk8hq!ad2d!aFk3h1fe!p5d3em!a63hm!a7kFFlp80slf\u003c/a\u003e\n\n\u003ca href=\"https://github.com/erlehmann/libglitch/tree/master/tracks\"\u003eThere's\na bunch more here\u003c/a\u003e. I have a feeling there's a bug or 2 left for full glitch support\n\n### Function\n\nExpects a function body vs infix which expects an expression\n\ninfix: `sin(t)`\n\nfunction: `return t =\u003e sin(t)`\n\nNote thought that \"function\" receives `t` in seconds, not samples.\n\n[See below](#Function)\n\n### Postfix\n\nPostfix in this case I guess can be described as [forth](http://en.wikipedia.org/wiki/Forth_(programming_language))\nlike. It works with a stack. Each command either adds things to the stack or uses what's on the stack to do something. For example\n\n    123       // pushes 123 on the stack               stack = 123\n    456       // pushes 456 on the stack               stack = 123, 456\n    +         // pop the stop 2 things on the stack\n              // adds them, puts the result on the\n              // stack                                 stack = 569\n\nNote the stack is only 256 elements deep. If you push 257 elements it wraps around. Similarly if you use `pick`\nwith a large value your pick will wrap around. The stack is neither cleared nor reset on each iteration\nof your function. Some postfix based bytebeat songs take advantage of this where each iteration leaves\nthings on the stack for the next iteration.\n\n#### operators\n\nThe postfix operators are\n\n`\u003e`, `\u003c` ,`=`\n\nThese take the top two things from the stack, do the comparision, then push 0xFFFFFFFF if the result\nis true or 0x0 if the result is false. Think of it has follows: If the TOP thing on the stack is `\u003e`, `\u003c`, or `=` to \nthe next thing on the stack then 0xFFFFFFFF else 0x0\n\n`drop`\n\nremoves the top thing from the stack\n\n`dup`\n\nduplicates the top thing on the stack.\n\n`swap`\n\nswaps the top 2 things on the stack\n\n`pick`\n\npops the top thing from the stack and duplicates one item that many items back. In other words\nif the stack is `1,2,3,4,5,6,7,3` then `pick` pops the top thing `3` and duplicates\nthe 3rd thing back counting from 0, which is no `4`. The stack is then `1,2,3,4,5,6,7,4`.\n\nAnother way to look at it is `dup` is the same as `0 pick`.\n\n`put`\n\nsets the n'th element from the top of the stack to the current top. In other words if the stack is\n`1,2,3,4,5,6,7,3,100` then put will pull the top `100` and then set the `3` element back. The stack\nwill then be `1,2,3,4,100,6,7,3`.\n\n`abs`, `sqrt`, `round`, `tan`, `log`, `exp`, `sin`, `cos`, `tan`, `floor`, `ceil`, `int`\n`min`, `max`, `pow`\n\nThese operators all pop the top value from the stack, apply the operator, then push the result on\nthe stack\n\n`/`, `+`, `-`, `*`, `%`, `\u003e\u003e`, `\u003c\u003c`, `|`, `\u0026`, `^`, `\u0026\u0026`, `||`:\n\nThese operators pop the top 2 values from the stack, apply the operator, then push the result. The\norder is as follows\n\n    b = pop\n    a = pop\n    push(a op b)\n\nIn other words `4 2 /` is 4 divided by 2.\n\n`~`\n\nPops the top of the stack, applies the binary negate to it, pushes the result.\n\n### Function\n\nSee [Rant](#rant).\n\n\"function\" means you could write code that returns a function. The simplest example\nmight be\n\n```js\nreturn function(t) {\n  sin(t);\n}\n```\n\nor shorter\n\n```js\nreturn t =\u003e sin(t);\n```\n\nThe point being you can write more generic JavaScript. For example\n\n```js\nconst notes = [261.62, 329.628, 391.995, 523.25, 391.995, 329.628, 261.62, 261.62, 1, 1];\n\nfunction getNote(t) {\n  const ndx = (t * 4 | 0) % notes.length;\n  return note = notes[ndx];\n}\n\nreturn function(t) {\n  const note = getNote(t);\n  return sin(t * 10 * note);\n}\n```\n\n[Example](https://greggman.com/downloads/examples/html5bytebeat/html5bytebeat.html#t=1\u0026e=3\u0026s=8000\u0026bb=5d00000100080100000000000000319bca19c63617c05f852678809434c0245718cc973d0784216c18766f89f97417838f624d415ce254f1adfce8a1aa0aca94da7cd23a110b8cb7c5c13d29497b74893a02e812083f504edc25c42ead4ebd79647b868b71508dbcdd834b7a07446239af435da82980ba5f7108aab703421b6143d96834ac872176794e2ba01d8152a4bae0e9e1932f4a3a4a009dd00f27902217477670ef2c0ac8cd96ddf4fe13a4c0)\n\nBut see [Rant](#rant) why this is seems kind of missing the point.\n\n### Stereo\n\nYou can emit an array with 2 values for left and right channels. Eg.\n\n```js\n[sin(t), sin(t / 2)]\n```\n\n### Extra\n\nComments can be both // or /* */ style and I'd personally suggest\nyou use comments for your name, the song's name, etc...\n\nThere are several extra inputs available:\n\nThe mouse position is available as `mouseX` and `mouseY`\n\n```js\nsin(t * mouseX * 0.001) + cos(t * mouseY * 0.003)\n```\n\nThe size of the window is available `width` and `height`\n\nAlso note, using the comma operator you can write fairly arbitrary code. [See this example](https://greggman.com/downloads/examples/html5bytebeat/html5bytebeat.html#t=1\u0026e=0\u0026s=22000\u0026bb=5d0000010058010000000000000017e07ce86fbd1ca9dedaaaf283d5ff76502fd7dadb76e5d882697d441ca3af61153f2f1380cbf89731ae302303c50ef1ebed677ad146c1f124dcf3cc109dd31ddd363d9d15d0d6a631f5f755297df9d98d614a051e4ed8cad8dae98b3b60d98a87f3ef147227e075cf005fc063cb9e4afe0ef1418c10607d6e7748e5c4477a20901c00ef5379b618214e7e2a2c8a538fec32de37b565c288aa49e52f2bcae7c1c9c474fcf1eb149f734180cccc153d360cb13e758ccf5d1eb9bebee221421a05b2a991f07c0b2ee2ed8ffa2ff5fc).\n\nPutting a comment in form of \n\n```\n// vsa: \u003curl\u003e\n```\n\nWill apply a [vertexshaderart](https://vertexshaderart.com) piece. [Example](https://greggman.com/downloads/examples/html5bytebeat/html5bytebeat.html#t=0\u0026e=0\u0026s=8000\u0026bb=5d00000100b9000000000000000017e07c86411ba2a517dacbc183b1477d3c17bd909f859f6ac588a82b934d189a40e82441616f52b3c7192116ea6be66102b438fc3d5e7ca2be7e768c34a949ce70e384f65243670976039bc9ed417d3b4d307c7506468aa5a052be90c656f55857c76626ba542034fe7d4cc6b435dee121ec730c2b0ebd730287a180702ee24e5cfb642a79cf1835917ef095b197cc235e5bee9e023e0f55f263acd5d95412fff91dde60)\n\nRant\n----\n\nThe original bytebeat, or at least the one I saw, was fairly simple. 8bits, stack based,\nfew options. When I built a live JavaScript version I just thought \n\"you get an expression that takes time and returns a value\". **The end**.\n\nA few obvious additions, at least to me, were floatbeat, because the Web Audio API itself\ntakes floats and IIRC some original C based thing that took a function expected floats.\nIn fact I wrote that first. I just fed an expression that returns floats\ninto the Web Audio API. I then manually converted a few beatbyte expressions by just\nputting `(original-bytebeat-expression) / 127 - 1`.\n\nThe reason I didn't just stick with floatbeat is bytebeat expressions already\nexisted and wanted people to be able to use them without having to understand\nhow to convert, even though it's trivial.\n\nBut now I see people have added *signed bytebeat*. What is the point? Any signed\nbytebeat can be turned in to regular bytebeat by just putting `+ 0x80` at the\nend of your expression. The entire point of bytebeat is to be self sufficient,\nto put what you need in the expression itself.\n\nI then found a `funcbeat` in which instead of an expression you pass it a\nfunction body. AFAICT the advantage is you can write code and declare\nother functions and data vs having to squeeze everything into an expression with\ncommas. For example:\n\n```js\nconst notes = [261.62, 329.628, 391.995, 523.25, 391.995, 329.628, 261.62, 261.62, 1, 1];\n\nfunction getNote(t) {\n  const ndx = (t * 4 | 0) % notes.length;\n  return note = notes[ndx];\n}\n\nreturn function(t) {\n  const note = getNote(t);\n  return sin(t * 10 * note);\n}\n```\n\nBut again, What is the point? If you're going to write real code with no limits\nthen why do it this way all? [Just write code](https://jsgist.org/?src=5c0429e50839b546a38ce9dbb66c2ab3),\nno need to try to cram it into a bytebeat player?\n\nThen I found that some people had added a time divisor. For example, instead of\n`t` counting in samples it can count in seconds (fractional values). But again,\nwhat is the point? Why does this option need to exist when you can just divide\n`t` by the sample rate in the expression itself?\n\nIt'd be like if someone added various options for time. `t = sample`,\n`t = sample / sampleRate`, `t = sin(sammple)`, `t = sin(sample / sampleRate)`,\netc... The whole point is to **PUT THE MATH IN YOUR EXPRESSION!!!**. There is\nno need to add these options 😤\n\n\u0026lt;/rant\u0026gt; 😛\n\nFor more info\n-------------\nCheck out \u003chttp://canonical.org/~kragen/bytebeat/\u003e and be sure follow the many links.\n\n\nSpecial thanks to:\n------------------\n\n* Paul Pridham for his [Glitch Machine iOS Bytebeat program](http://madgarden.net/apps/glitch-machine/).\n* Mr.Doob for his [GLSL Sandbox](http://mrdoob.com/projects/glsl_sandbox/) where much of this code was cribbed.\n* Nathan Rugg for his [LZMA-JS library](https://github.com/nmrugg/LZMA-JS).\n* Darius Bacon for his [bytebeat program](https://github.com/darius/bytebeat) and for tips and examples to test it.\n* All the people making awesome bytebeats!\n\n# Library\n\nYou can use this as a library. The library provides a `ByteBeatNode` which is a WebAudio [`AudioNode`](https://developer.mozilla.org/en-US/docs/Web/API/AudioNode).\n\n## Example usage:\n\n```js\nimport ByteBeatNode from 'https://greggman.github.io/html5byteabeat/dist/1.x/ByteBeat.module.js';\n\nasync function start() {\n  const context = new AudioContext();\n  context.resume();  // needed for safari\n  await ByteBeatNode.setup(context);\n  byteBeatNode = new ByteBeatNode(context);\n  byteBeatNode.setType(ByteBeatNode.Type.byteBeat);\n  byteBeatNode.setExpressionType(ByteBeatNode.ExpressionType.infix);\n  byteBeatNode.setDesiredSampleRate(8000);\n  await byteBeatNode.setExpressions(['((t \u003e\u003e 10) \u0026 42) * t']);\n  byteBeatNode.connect(context.destination);\n}\n```\n\n## Live examples:\n\n* [Minimal ESM](https://jsgist.org/?src=668ef93e49417bf0bfafc088edf6b826)\n* [Minimal UMD](https://jsgist.org/?src=b63d9187f8ad3b7ff57831bd6ccd23b3)\n* [Simple visualizer](https://jsgist.org/?src=d1fb987c85cc1cff03f405ed210f04f6)\n* [Visualized based on AnalyserNode](https://jsgist.org/?src=36a61aa554a6da096540c3b7fcce7c78)\n* [npm](examples/npm/README.md)\n\n## API\n\nThere's just one class `ByteBeatNode`. You must call the async function `ByteBeatNode.setup` before using the library.\n\n* `reset()`\n\n   re-starts the time to 0\n\n* `isRunning(): bool`\n\n   true or false if running. The node is considered running if it's connected.\n\n* `async setExpressions(expressions: string[], resetToZero: bool)`\n\n   Pass in array of 1 or 2 expressions.\n   If 2 expressions it is assumed each expression is for a different channel.\n   If a single expression returns an array of\n   2 values that is also also assumed to\n   be 2 channels. Otherwise, it's 1 channel and will be output to both left and right channels.\n\n   Note: this function is async. You can catch expression errors with `try`/`catch`.\n\n* `setDesiredSampleRate(rate: number)`\n\n   Sets the sample rate for the expression\n   (eg 8000, 11000, 22050, 44100, 48000)\n\n* `getDesiredSampleRate(): number`\n\n   Returns the previously set sample rate\n\n* `setExpressionType(expressionType: number)`\n\n    Sets the expression type. Valid expression types\n\n    ```\n    ByteBeatNode.ExpressionType.infix             // sin(t / 50)\n    ByteBeatNode.ExpressionType.postfix           // t 50 / sin\n    ByteBeatNode.ExpressionType.glitch            // see docs\n    ByteBeatNode.ExpressionType.function          // return function() { sin(t / 50); }\n    ```\n\n* `getExpressionType(): number`\n\n   Gets the expression type\n\n* `setType(type: number)`\n\n   Sets the output type.\n   \n   Valid types\n\n   ```\n   ByteBeatNode.Type.byteBeat          // 0 \u003c-\u003e 255\n   ByteBeatNode.Type.floatBeat         // -1.0 \u003c-\u003e +1.0\n   ByteBeatNode.Type.signedByteBeat    // -128 \u003c-\u003e 127\n   ```\n* `getType(): number`\n\n   Gets the type\n\n* `getNumChannels(): number`\n\n   Returns the number of channels output\n   by the current expression.\n\n* `async getSamplesForTimeRange(start: number, end: number: numSamples: number, context, stack, channel: number)`\n\n  Gets a -1 to +1 from the current expression for the given time (time is the `t` value in your expression)\n\n  This function is useful for visualizers.\n  \n  To make a stack call `byteBeat.createStack()`. To create a context call\n  `byteBeat.createContext`.\n  A stack is used for postfix expressions.\n  [See docs on postfix](#postfix). The context\n  is used for keeping expressions state for\n  expressions that try hacks to keep state around like if they build a large note table and assign it to `window`. It won't\n  actually be assigned to `window`, it will\n  be assigned to the context (in theory)\n\n## Development / running locally\n\n```\ngit clone https://github.com/greggman/html5bytebeat.git\ncd html5bytebeat\nnpm i\nnpm start\n```\n\nThe instructions above assume you have node.js installed. If not, if you're\non windows use [nvm-windows](https://github.com/coreybutler/nvm-windows),\nor if you're on mac/linux use [nvm](https://github.com/nvm-sh/nvm).\n\nOr you can just use the installers at [nodejs.org](https://nodejs.org) though\nI'd recommend nvm and nvm-windows personally as once you get into node dev\nyou'll likely need different versions for different projects.\n\n# License\n\n[MIT](LICENSE.md)\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreggman%2Fhtml5bytebeat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgreggman%2Fhtml5bytebeat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreggman%2Fhtml5bytebeat/lists"}