Last active
February 10, 2019 17:03
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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