Coder Social home page Coder Social logo

greggman / html5bytebeat Goto Github PK

View Code? Open in Web Editor NEW
413.0 18.0 36.0 1.77 MB

Bytebeats in HTML5

Home Page: http://greggman.com/downloads/examples/html5bytebeat/html5bytebeat.html

License: MIT License

JavaScript 93.06% HTML 6.64% CSS 0.30%
bytebeat audio sound

html5bytebeat's Introduction

HTML5 Bytebeat

Bytebeat is the name of type of music made from math.

You provide a function who's only input is time t and from that write some code to generate a sound.

In this particular case t is an 8000hz timer that counts up. For example

sin(t) * 127 + 127

You can choose traditional bytebeat where the output of your function is expected to be 0 to 255 or you can choose floatbeat where the output is expected to be -1 to +1.

Functions are just plain JavaScript though sin, cos, tan, floor, ceil and int will automatically be converted to Math.sin, Math.cos, Math.tan, Math.floor, Math.ceil, and Math.floor respectively.

Click here to try your hand at Bytebeat.

Instructions

Modes

There 2 modes

  • bytebeat: Your expression is expected to generate byte values from 0 to 255
  • floatbeat: Your expression is expected to generate float values from -1.0 to 1.0

Expression Types

  • Infix: Standard expressions eg. "(t * 2) / 4"
  • Postfix(rpn): Reverse Polish Notation eg "t 2 * 4 /"
  • glitch: glitch format or glitch urls.
  • function: Return a function. eg. "return t => (t * 2) / 4"

Infix is standard JavaScript so all Math functions are available. Most math functions you can drop the "Math." part. In other words

sin(t)

is the same as

Math.sin(t)

Postfix requires that each element have at least one space between it.

t2*    // BAD!
t 2 *  // Good!

If you're unfamiliar with postfix see below

Glitch is a format used by glitch machine for sharing. Examples

These can be prefixed with "glitch://". For example

There's a bunch more here. I have a feeling there's a bug or 2 left for full glitch support

Function

Expects a function body vs infix which expects an expression

infix: sin(t)

function: return t => sin(t)

Note thought that "function" receives t in seconds, not samples.

See below

Postfix

Postfix in this case I guess can be described as forth like. 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

123       // pushes 123 on the stack               stack = 123
456       // pushes 456 on the stack               stack = 123, 456
+         // pop the stop 2 things on the stack
          // adds them, puts the result on the
          // stack                                 stack = 569

Note the stack is only 256 elements deep. If you push 257 elements it wraps around. Similarly if you use pick with a large value your pick will wrap around. The stack is neither cleared nor reset on each iteration of your function. Some postfix based bytebeat songs take advantage of this where each iteration leaves things on the stack for the next iteration.

operators

The postfix operators are

>, < ,=

These take the top two things from the stack, do the comparision, then push 0xFFFFFFFF if the result is true or 0x0 if the result is false. Think of it has follows: If the TOP thing on the stack is >, <, or = to the next thing on the stack then 0xFFFFFFFF else 0x0

drop

removes the top thing from the stack

dup

duplicates the top thing on the stack.

swap

swaps the top 2 things on the stack

pick

pops the top thing from the stack and duplicates one item that many items back. In other words if the stack is 1,2,3,4,5,6,7,3 then pick pops the top thing 3 and duplicates the 3rd thing back counting from 0, which is no 4. The stack is then 1,2,3,4,5,6,7,4.

Another way to look at it is dup is the same as 0 pick.

put

sets the n'th element from the top of the stack to the current top. In other words if the stack is 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 will then be 1,2,3,4,100,6,7,3.

abs, sqrt, round, tan, log, exp, sin, cos, tan, floor, ceil, int min, max, pow

These operators all pop the top value from the stack, apply the operator, then push the result on the stack

/, +, -, *, %, >>, <<, |, &, ^, &&, ||:

These operators pop the top 2 values from the stack, apply the operator, then push the result. The order is as follows

b = pop
a = pop
push(a op b)

In other words 4 2 / is 4 divided by 2.

~

Pops the top of the stack, applies the binary negate to it, pushes the result.

Function

See Rant.

"function" means you could write code that returns a function. The simplest example might be

return function(t) {
  sin(t);
}

or shorter

return t => sin(t);

The point being you can write more generic JavaScript. For example

const notes = [261.62, 329.628, 391.995, 523.25, 391.995, 329.628, 261.62, 261.62, 1, 1];

function getNote(t) {
  const ndx = (t * 4 | 0) % notes.length;
  return note = notes[ndx];
}

return function(t) {
  const note = getNote(t);
  return sin(t * 10 * note);
}

Example

But see Rant why this is seems kind of missing the point.

Stereo

You can emit an array with 2 values for left and right channels. Eg.

[sin(t), sin(t / 2)]

Extra

Comments can be both // or /* */ style and I'd personally suggest you use comments for your name, the song's name, etc...

There are several extra inputs available:

The mouse position is available as mouseX and mouseY

sin(t * mouseX * 0.001) + cos(t * mouseY * 0.003)

The size of the window is available width and height

Also note, using the comma operator you can write fairly arbitrary code. See this example.

Putting a comment in form of

// vsa: <url>

Will apply a vertexshaderart piece. Example

Rant

The original bytebeat, or at least the one I saw, was fairly simple. 8bits, stack based, few options. When I built a live JavaScript version I just thought "you get an expression that takes time and returns a value". The end.

A few obvious additions, at least to me, were floatbeat, because the Web Audio API itself takes floats and IIRC some original C based thing that took a function expected floats. In fact I wrote that first. I just fed an expression that returns floats into the Web Audio API. I then manually converted a few beatbyte expressions by just putting (original-bytebeat-expression) / 127 - 1.

The reason I didn't just stick with floatbeat is bytebeat expressions already existed and wanted people to be able to use them without having to understand how to convert, even though it's trivial.

But now I see people have added signed bytebeat. What is the point? Any signed bytebeat can be turned in to regular bytebeat by just putting + 0x80 at the end of your expression. The entire point of bytebeat is to be self sufficient, to put what you need in the expression itself.

I then found a funcbeat in which instead of an expression you pass it a function body. AFAICT the advantage is you can write code and declare other functions and data vs having to squeeze everything into an expression with commas. For example:

const notes = [261.62, 329.628, 391.995, 523.25, 391.995, 329.628, 261.62, 261.62, 1, 1];

function getNote(t) {
  const ndx = (t * 4 | 0) % notes.length;
  return note = notes[ndx];
}

return function(t) {
  const note = getNote(t);
  return sin(t * 10 * note);
}

But again, What is the point? If you're going to write real code with no limits then why do it this way all? Just write code, no need to try to cram it into a bytebeat player?

Then I found that some people had added a time divisor. For example, instead of t counting in samples it can count in seconds (fractional values). But again, what is the point? Why does this option need to exist when you can just divide t by the sample rate in the expression itself?

It'd be like if someone added various options for time. t = sample, t = sample / sampleRate, t = sin(sammple), t = sin(sample / sampleRate), etc... The whole point is to PUT THE MATH IN YOUR EXPRESSION!!!. There is no need to add these options ๐Ÿ˜ค

</rant> ๐Ÿ˜›

For more info

Check out http://canonical.org/~kragen/bytebeat/ and be sure follow the many links.

Special thanks to:

Library

You can use this as a library. The library provides a ByteBeatNode which is a WebAudio AudioNode.

Example usage:

import ByteBeatNode from 'https://greggman.github.io/html5byteabeat/dist/1.x/ByteBeat.module.js';

async function start() {
  const context = new AudioContext();
  context.resume();  // needed for safari
  await ByteBeatNode.setup(context);
  byteBeatNode = new ByteBeatNode(context);
  byteBeatNode.setType(ByteBeatNode.Type.byteBeat);
  byteBeatNode.setExpressionType(ByteBeatNode.ExpressionType.infix);
  byteBeatNode.setDesiredSampleRate(8000);
  await byteBeatNode.setExpressions(['((t >> 10) & 42) * t']);
  byteBeatNode.connect(context.destination);
}

Live examples:

API

There's just one class ByteBeatNode. You must call the async function ByteBeatNode.setup before using the library.

  • reset()

    re-starts the time to 0

  • isRunning(): bool

    true or false if running. The node is considered running if it's connected.

  • async setExpressions(expressions: string[], resetToZero: bool)

    Pass in array of 1 or 2 expressions. If 2 expressions it is assumed each expression is for a different channel. If a single expression returns an array of 2 values that is also also assumed to be 2 channels. Otherwise, it's 1 channel and will be output to both left and right channels.

    Note: this function is async. You can catch expression errors with try/catch.

  • setDesiredSampleRate(rate: number)

    Sets the sample rate for the expression (eg 8000, 11000, 22050, 44100, 48000)

  • getDesiredSampleRate(): number

    Returns the previously set sample rate

  • setExpressionType(expressionType: number)

    Sets the expression type. Valid expression types

    ByteBeatNode.ExpressionType.infix             // sin(t / 50)
    ByteBeatNode.ExpressionType.postfix           // t 50 / sin
    ByteBeatNode.ExpressionType.glitch            // see docs
    ByteBeatNode.ExpressionType.function          // return function() { sin(t / 50); }
    
  • getExpressionType(): number

    Gets the expression type

  • setType(type: number)

    Sets the output type.

    Valid types

    ByteBeatNode.Type.byteBeat          // 0 <-> 255
    ByteBeatNode.Type.floatBeat         // -1.0 <-> +1.0
    ByteBeatNode.Type.signedByteBeat    // -128 <-> 127
    
  • getType(): number

    Gets the type

  • getNumChannels(): number

    Returns the number of channels output by the current expression.

  • async getSamplesForTimeRange(start: number, end: number: numSamples: number, context, stack, channel: number)

    Gets a -1 to +1 from the current expression for the given time (time is the t value in your expression)

    This function is useful for visualizers.

    To make a stack call byteBeat.createStack(). To create a context call byteBeat.createContext. A stack is used for postfix expressions. See docs on postfix. The context is used for keeping expressions state for expressions that try hacks to keep state around like if they build a large note table and assign it to window. It won't actually be assigned to window, it will be assigned to the context (in theory)

Development / running locally

git clone https://github.com/greggman/html5bytebeat.git
cd html5bytebeat
npm i
npm start

The instructions above assume you have node.js installed. If not, if you're on windows use nvm-windows, or if you're on mac/linux use nvm.

Or you can just use the installers at nodejs.org though I'd recommend nvm and nvm-windows personally as once you get into node dev you'll likely need different versions for different projects.

License

MIT

html5bytebeat's People

Contributors

actions-user avatar greggman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

html5bytebeat's Issues

better documentation

Some better documentation like wiki, or quick helps on main page about usage and functionality about some commands, like DUP and binary operators (some musicians can not understand the functionality)

my song "boots in bed" is just labelled "??"

          * [??](https://greggman.com/downloads/examples/html5bytebeat/html5bytebeat.html#t=1&e=3&s=44100&bb=5d00000100f2010000000000000039194af031b445aedd75309df43c408c46627877a0cc4921c1c85e15b418b6426811708ef659be64d728efadc2ced4be0d68b9dea9e9f29e4ee93aef5595dd502f778c3b79c0687de279cf1f5db996aeeefd518ef358c592dd47c384db99dc011e5ef13349532959dc72591798b8126155272085e104d10091738ac1594a916d9cd2c2412c2b97fcb12df4ca14fa8d7484946f386f5a661efe8a43bcc21cd3dc35931be1222767262b6bb764fc20e109fd4acfe9a5357ca57b79707697feaf8ea7a6eba874296da0e6caeab81b2c4fb4838cce0e1303e5aef8c409db3e1f334a6f10b4179fc8e8cbe5582eab061bb30cfcb8c99deb187822efc10851234647579a43124b7cb53b95629a1fce3a2f6df9a34ddd4a660fd762e9626b13f4816c3382fdcde20ecdb75fbab028066aefee7c3b2476fd0e5de69e9306130000a0a78dfa6ecba33e10342e3cf66d916ffeec14686deb970df1b4a3ad7741d23a1c4a9a36b9a8d38ef3e4ff88fd2b0cc3035cc362b57b7b2f38e568fcf846e8)

Originally posted by @greggman in #17 (comment)

Hi!

Please add sound recorder, With.
If i record, it will record.
And if i STOP. so it will save a .WAV file

XSS exploit

I've found an exploit that lets you get window.
So, 0 is a number, I think we can agree on that. So 0["constructor"] returns the function Number. Now Number is a function, and we can use 0["constructor"]["constructor"] to get the function Function. The problem is, that we can do Function("return this")(), and get window, because it's running as window.
window also has more useful keys inside of it, like document
There's also the fact that you can't type in the code without it automatically running when it checks for errors. This can be solved, by setting it to glitch, where "return this" causes an error due to the space. Then, in the URL, you can change e to 0 to create an automatically running link. There's also a limitation where "https://" is automatically escaped or something, so you have to split links into two strings, or encode it somehow
Here's an example

Add Audio Data API support

I don't personally want to do this. I looked for a sample and it was ugly but I'm happy to take a patch of someone wants to work it in.

Blue Background Inaccuracies

I found out that I could put arbitrary images in the blue background by using an array. As I was doing so, I discovered a few errors with the blue background rendering. Specifically, numbers 20, 36, 37, 52, and 53, modulo 256, get rendered as each minus 1.
image

Request: .wav export

It would be nice having a way to export a .wav file to upload to SoundCloud, or use in videos, or...well, anything that requires an audio file.
It could be something as simple as an alert asking for the desired length of the audio in seconds, and then exporting from (t = 0) while (t < selected sample rate * desired length in seconds), I don't know how easy it'd be to implement it but it'd be really helpful.
Thanks

Innacurate 't' value inside code

First, I apologize in advance for not being able to name this properly, hopefully the examples make it clear.

Sometimes, when running the code, the t value is different than what it should be (what is shown in the interface). This can be seen in this video.
(A brief explanation: t/16 % 8 is just so I have an audio output that doesn't sound loud, and tt=t is just so I'm able to log t's value in the console. Most of the times that I do that - but not all - the value shown in the console is different than the one shown in the interface.

This affects codes that rely on 't' as an accurate timing source. This does NOT happen on saved .wav files, though, the issue only happens on browser playback.
An actual example:

Thanks for reading!

Song from YouTube

extra is not defined when using mouseX, etc

I tried importing the example underneath the extra section of the documentation
(sin(t * mouseX * 0.001) + cos(t * mouseY * 0.003))
to find ReferenceError: extra is not defined

I have no clue else to say, except that it used to work in older versions.

HELLO

Please add Sinmode. Bitbeat. 2048. Sinfreq. Logmode, Logmode10. and RAW.

No 16 khz/16000 hz option, realy helpfull with some byteabeat

So like i said there is no any 16khz option onlt 11 and we jump to 22 instantky idk why, is it because its not posible on HTML 5 ?
Because yeah it completly destruct the chosen byteabeat if it need to be ran in a specific range of khz/hz.

I tried to modificate the html myselft because everything is clientside, atleast for the music composition and the graphics maybe ? idk

But yeah that prety much it, apart of that i love this bytebeat composer and with his unique graphics

Yeah i forgor to say that its with the Website

License

Hello

Could you throw in a license file of your choosing?
(I see MIT on some of the files, but helpful to have on on the main repo page)

Thanks

website doesn't work anymore

Hi since few days I get this error on the website: "SyntaxError: missing variable name"
no more sound. I tried Firefox, Chrome. I tried to delete cache, coockies etc... no change

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.