Skip to content

Instantly share code, notes, and snippets.

@Eiyeron
Last active February 10, 2019 17:03
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Eiyeron/0f3d49082308389e9a17d1e650f3453d to your computer and use it in GitHub Desktop.
Save Eiyeron/0f3d49082308389e9a17d1e650f3453d to your computer and use it in GitHub Desktop.
Haxe/Heaps custom Sound/Data class pair to generate sound on the fly. Beware, it's experimental and prone to crash if you tweak the wrong knobs.
import hxd.snd.Data;
import hxd.res.Sound;
// This class should work like a Sound. Jsut create one and call play and a lo-fi generated tune should ring.
// You can check out a bit more about bytebeat there : http://countercomplex.blogspot.com/2011/10/algorithmic-symphonies-from-one-line-of.html
class CustomSound extends Sound {
public function new() {
super(null);
data = new SoundDataGenerator();
}
public override function toString():String {
return "Custom generator";
}
public override function getData():Data {
return super.getData();
}
}
import hxd.snd.Data.SampleFormat;
import haxe.io.Bytes;
class SoundDataGenerator extends hxd.snd.Data
{
private var t:Int = 0;
private var frequency = 880;
public function new() {
samplingRate = 8000;
sampleFormat = SampleFormat.UI8;
samples = 20*samplingRate;
channels = 1;
}
// Long Line Theory.
// Source : http://www.pouet.net/topic.php?which=8357&page=13
var backgroundWaveNotes:Array<Int> = [15, 15, 23, 8];
var mainInstrumentNotes:Array<Array<Float>> = [
[ 15, 18, 17, 17, 17, 17, 999, 999, 22, 22, 999, 18, 999, 15,
20, 22 ],
[ 20, 18, 17, 17, 10, 10, 999, 999, 20, 22, 20, 18, 17, 18, 17,
10 ]];
private function LLT(t:Int) {
var sb:Float;
var y:Float;
var h:Float;
var a:Float;
var d:Float;
var g:Float;
sb = (t > 0xffff ? 1 : 0);
y = Math.pow(2, backgroundWaveNotes[t >> 14 & 3] / 12.);
a = 1. - ((t & 0x7ff) / cast(0x7ff, Float));
d = ((Std.int (14.) * t * t ^ t) & 0x7ff);
g = (t & 0x7ff) / cast(0x7ff, Float);
g = 1. - (g * g);
h = Math.pow(2.,
mainInstrumentNotes[((t >> 14 & 3) > 2 ? 1 : 0) & 1][t >> 10 & 15] / 12);
var wave:Float = (Std.int(y * t * 0.241) & 127 - 64)
+ (Std.int(y * t * 0.25) & 127 - 64) * 1.2;
var drum:Float = (
(Std.int((Std.int(5. * t) & 0x7ff) * a) & 255 - 127)
* ((0x53232323 >> (t >> 11 & 31)) & 1) * a * 1.0
+ (Std.int(d * a) & 255 - 128)
* ((0xa444c444 >> (t >> 11 & 31)) & 1) * a * 1.5 + (Std.int((a
* a * d * (t >> 9 & 1))) & 0xff - 0x80) * 0.1337)
* sb;
var instrument:Float =
((Std.int(h * t) & 31) + (Std.int(h * t * 1.992) & 31)
+ (Std.int(h * t * .497) & 31) + (Std.int(h * t * 0.977) & 31))
* g * sb;
return Math.max(Math.min((wave + drum + instrument) / 3., 127), -128);
}
// End of LLT magic
public override function decodeBuffer(out:Bytes, outPos:Int, sampleStart:Int, sampleCount:Int) {
var sampleRate:Float = samplingRate;
for (i in outPos...out.length) {
var t = t + i - outPos;
// That was a simpler bytebeat formula
// var v = ((t >> 10) & 42) * t;
var v = Std.int(LLT(t));
out.set(i, v);
}
// I haven't figured the difference between sampleStart/sampleCount and out/outPos variable couples
t += sampleCount;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment