pouët.net

Go to bottom

Experimental music from very short C programs

category: code [glöplog]
Great stuff!

Hmm... I'm not sure. The Filter depends on the usage of floating-point values. It might be possible to convert it to interger math by multiplying all values before and dividing them after the equation.
I'm not really sure how floating-point values are handled by Wurstcaptures, native C and other bytebeat implementations.

However, converting a function from Bytebeat(range 0..256) to Floatbeat(range -1..1) is trivial: (bytebeat_expression%256)/127-1
added on the 2013-10-15 07:31:47 by Qqwy Qqwy
Bytebeat FTW. I'd like to share some of my explorations in a shape of a formula. The language is not C though, but JS (ES5 FTW!) and my simplified bytebeat engine (available here) is hardcoded to generate 8Khz mono 8-bit PCM (and outputs ready-to-use data: URI, I might add).

So, here is the general view of how to generate discrete notes in a compact JS bytebeat expression:
Code:t*.35*("[notes_pattern]".charCodeAt(t*[speed]/8e3%[notes_count])-11)

Don't pay much attention to .35 in t*.35 - this is some fine tuning to get notes sound as they should (I was a pianist so I hate when A is not close to 440 Hz :) ) for this very sawtooth wave case.
[Speed] is... well, the speed, starting from 1.
[notes_pattern] is your notes string (just a moment), and [notes_count] it just the length of this string.
-11 is the real deal. It was selected with trial-and-error in order to fit as many notes into printable (and typable!) low-ASCII characters as possible.
So, what's the note range? It's actually a bit more than 2 octaves of full chromatic scale:

1st octave: #$&()+-/1368
2nd octave: ;=AEGKOSW[ae
3rd octave: kow

As you know, any musical engine should allow to enter the rest character. Unfortunately, it can only be entered as \013 sequence here. That's the price for such an extended note range in such a simple formula, but... not a big deal, really.

This plays all the available notes:
Code:t*.35*("#$&()+-/1368;=AEGKOSW[aekow".charCodeAt(t/1e3%27)-11)


And this plays the interleaved major scale, making a rest after each note:
Code:t*.35*("#\013;\013&\013A\013)\013G\013+\013K\013/\013S\0133\013[\0138\013e\013;\013k\013".charCodeAt(t/1e3%32)-11)


So, I think you've got the point. Everything else depends on the initial tuning and your imagination. :)
added on the 2013-10-18 14:50:34 by Suborg Suborg
Oops... plz remove all the whitespace in the last code snippet (I have absolutely no idea how it appeared there).
added on the 2013-10-18 14:55:08 by Suborg Suborg
This all sound Dead Horsey
added on the 2013-10-18 15:53:19 by p01 p01
p01, how much is the fi... I meant, how wide is the range?
added on the 2013-10-18 18:43:29 by Suborg Suborg
Btw,

Maybe wurstcaptures is feature-rich, but from my UX, it's too slow, glitchy and too serverside-dependent.

BeatM-based (8KHz with math) pure-HTML5 bytebeat player is coming soon. As for now, let me announce the StackBeat esoteric language fir this entire purpose. It also has a bookmarklet version.
added on the 2013-10-18 21:39:55 by Suborg Suborg
The Dead Horse approach looks like this:

Code:oscillator += ASCII_CODE / const


The frequency range is determined by the const and the initial ASCII range. This means 32 to 127 if you limit yourself to the printable characters, Hence this approach goes from a frequency X to a frequency 127 / 32 * X.

It's up to you to fiddle with the const to position your frequency range.
added on the 2013-10-18 22:23:34 by p01 p01
Okay. I'm not talking of frequency range. I'm talking of the semitones range. Not every set of numbers among these 127 can form a consistent chromatic scale of several octaves. That's what I tried to do. 27 semitones is the limit I could pull out of the printable ASCII set. That's why frequency range doesn't really matter here: the notes aren't distributed evenly. The higher they get, the sparser they become.
added on the 2013-10-18 22:43:56 by Suborg Suborg
they are related; a 4x frequency range = 2 octaves. Why did you ask if you knew the answer? :p
added on the 2013-10-19 09:54:29 by p01 p01
I was in doubt.
added on the 2013-10-19 11:18:15 by Suborg Suborg
Anyway, Fort Boyard OST melody:
Code:t*.17*("33AAAAA\013AAKKKGGG;;A\013AK[KSSSSSSSS\013\013[\013[SSSKKGGG;;;GGA\013AK[KAAAAAAAA".charCodeAt(t/1800%64)-11)

Could anyone suggest a method for adding drum line to it? How to mix different lines in 8KHz bytebeat at all?
added on the 2013-10-19 16:58:37 by Suborg Suborg
(and remove all whitespace again in the code, I'm curious what the hell adds them to ready post)
added on the 2013-10-19 16:59:51 by Suborg Suborg
interleaved a "bassline" here.
added on the 2013-10-19 18:07:50 by yumeji yumeji
For now I managed to get only some crazy techno version.
added on the 2013-10-19 18:52:41 by Suborg Suborg
But generally, my question was how to mix 2 independent formulas into one stream.
added on the 2013-10-19 18:54:16 by Suborg Suborg
Shifted drums a little but the question stlll remains.
added on the 2013-10-19 18:59:21 by Suborg Suborg
i guess it's like any other synth mixes waveforms. additive. multiplicative. ored. whatever. you gotta keep track of spectral shit to not loose alotta sound here and there.
added on the 2013-10-19 20:12:13 by yumeji yumeji
Thanx, Cap. o_O

Are there any seamless mixing examples suitable for unsigned 8Khz case?
added on the 2013-10-19 20:25:59 by Suborg Suborg
Hi Suborg,

That's a great description and formula! Very inspiring! Could you explain the \013? How does that convert into a rest?

I've just started working with these equations myself, and here's how I'm approaching drums. First, I use a pattern generator, like this: ((51871 >> ((t>>14)%16))&1)

To break that down:

51871 is decimal for 1100101010011111, which is my 16 step drum pattern in reverse.
I'm bit shifting that to the right at the speed of (t>>14) over and over again.
I'm ANDing the bit-shifted pattern by 1, is how I determine the step's value.

For a kick drum, I'm taking a sound that repeats every beat...

((Math.sqrt(t%16384)<<5)&64)

..and using my pattern generator to filter out the unwanted beats by multiplying them by the 1 or 0 from the pattern generator:

((Math.sqrt(t%16384)<<5)&64)*((51871 >> ((t>>14)%16))&1)

I also ran into trouble with mixing too. I've had some luck simply using a bitwise OR to join two or more sounds. Sounds like whitenoise tend to drown everything else out.

Awesome stuff.
- Bret
added on the 2013-10-20 22:47:08 by clone45 clone45
Hi, thanx for your approach. The \013 converts to zero because its' actually 11 (just in octal notation), so when the formula meets \013 and subtracts 11 from the code 11, it renders no sound.
added on the 2013-10-21 19:27:38 by Suborg Suborg
bartoshe: sounds better with seperation ;)
added on the 2013-10-21 20:01:57 by yumeji yumeji
Telephone: t<<4|t>>6|t>>t
added on the 2013-10-23 12:00:46 by botjao botjao

login

Go to top