Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Binary file not shown.
@@ -0,0 +1,115 @@
var audio = new Audio();
var data = [];
var theme;
var compile;
var wave = new RIFFWAVE();
audio.loop = true;

const getQParam = (param) =>
decodeURI(atob(new URL(window.location).searchParams.get(param)));

const setQParam = (param, val) => {
let url = new URL(window.location);
url.searchParams.set(param, encodeURI(btoa(val)));
window.history.pushState({ path: url.href }, "", url.href);
};

window.onload = () => {
theme = new Theme();
theme.install(document.body);
theme.start();

Module.onRuntimeInitialized = (_) => {
window.read = () => {
tableFrews = document.getElementById("freqs").value;
tableData = document.getElementById("index").value;
waveformsData = document.getElementById("waveforms").value;
vec = Module.gen(tableFrews, tableData, waveformsData);

for (var i = 0; i < vec.size(); i++) {
// TODO: figure out correct type over wasm->js embind
data[i] = vec.get(i);
}

wave.header.bitsPerSample = 16;
wave.header.sampleRate = 44100;
wave.header.numChannels = 1;
wave.Make(data);
var continuePlaying;
if (!audio.paused) {
continuePlaying = true;
audio.pause();
}
audio.src = wave.dataURI;
if (continuePlaying) audio.play();
};
init();
};

window.setFreqs = (e) => {
setQParam("frequencies", e.value);
read();
};

window.init = () => {
let f = (document.getElementById("freqs").value = getQParam("frequencies")),
i = (document.getElementById("dslIndex").value = getQParam("index")),
w = (document.getElementById("dslWaveforms").value = getQParam(
"waveforms"
));
compile(i, "index");
compile(f, "waveforms");
draw();
};

window.compile = (txt, destination) => {
setQParam(destination, txt);
let seq = wave_dsl.parser.parse__GT_js(txt);
document.getElementById(destination).value = seq.join(" ");
read();
};
};

audio.onpause = () => {
document.getElementById("playButton").className = "off";
};

const play = (e) => {
e.className = !audio.paused ? "off" : "";
if (!audio.paused) {
audio.pause();
} else {
audio.play();
}
};

const loopToggle = (e) => {
audio.loop = !audio.loop;
e.className = audio.loop ? "" : "off";
};

const dataURItoBlob = (dataURI) => {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(",")[0].indexOf("base64") >= 0)
byteString = atob(dataURI.split(",")[1]);
else byteString = unescape(dataURI.split(",")[1]);

// separate out the mime component
let mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];

// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}

return new Blob([ia], { type: mimeString });
};

const download = () => saveAs(dataURItoBlob(wave.dataURI), "segmod.wav");

const share = () => {
navigator.clipboard.writeText(window.location.href);
alert("link copied to clipboard!");
};
@@ -0,0 +1,43 @@
var ctx = document.getElementById("scope").getContext("2d");

function hexToRGB(hex, alpha) {
var r = parseInt(hex.slice(1, 3), 16),
g = parseInt(hex.slice(3, 5), 16),
b = parseInt(hex.slice(5, 7), 16);

if (alpha) {
return "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")";
} else {
return "rgb(" + r + ", " + g + ", " + b + ")";
}
}

function draw() {
var width = ctx.canvas.width;
var height = ctx.canvas.height;
var scaling = 30 / 32768; //(height + 32768) / (32768 * 2);
var timeData = data;
var risingEdge = 0;
var edgeThreshold = 5;

ctx.fillStyle = hexToRGB(theme.active.background);
ctx.fillRect(0, 0, width, height);

ctx.lineWidth = 4;
ctx.strokeStyle = hexToRGB(theme.active.f_high);
ctx.beginPath();

// No buffer overrun protection
while (timeData[risingEdge++] - 16000 > 0 && risingEdge <= width);
if (risingEdge >= width) risingEdge = 0;

while (timeData[risingEdge++] - 16000 < edgeThreshold && risingEdge <= width);
if (risingEdge >= width) risingEdge = 0;

for (var x = risingEdge; x < timeData.length && x - risingEdge < width; x++)
ctx.lineTo(x - risingEdge, (height - timeData[x] * scaling) / 2);

ctx.stroke();

requestAnimationFrame(draw);
}
@@ -0,0 +1,125 @@
:root {
--font-fam: JetBrainsMono, monospace;
--line-height: 30px;
--font-size: 14px;
--line-width: 1px;
}

@font-face {
font-family: JetBrainsMono;
src: url(vendors/JetBrainsMono-Regular-40b288a985bc90e34d3260d92b8f4515.woff2)
format("woff2"),
url(vendors/JetBrainsMono-Regular-edaecf9876afc052ec1a241d9443d594.woff)
format("woff"),
url(vendors/JetBrainsMono-Regular-6664e867457f3dc3d7ee961775261e80.ttf)
format("truetype");
font-weight: 400;
font-style: normal;
}

body {
font-family: var(--font-fam);
font-size: var(--font-size);
line-height: var(--line-height);
}

* {
padding: 0;
margin: 0;
box-sizing: border-box;
text-rendering: geometricPrecision;
}

::selection {
background: var(--f_med);
}

input,
textarea,
button {
font-family: var(--font-fam);
font-size: var(--font-size);
color: var(--f_high);
background-color: var(--background);
border: none;
line-height: var(--line-height);
resize: none;
height: 100%;
caret-color: var(--f_med);
outline: none;
}

h1 {
font-size: var(--font-size);
font-weight: normal;
min-height: var(--line-height);
color: var(--f_med);
text-transform: lowercase;
line-height: var(--line-height);
position: relative;
}
h1 span {
background-color: var(--background);
z-index: 3;
position: relative;
padding-right: 10px;
}

h1:after {
content: "";
width: calc(100% - 30px);
margin-left: 10px;
border-bottom: solid var(--line-width) var(--f_low);
z-index: 1;
position: absolute;
left: 0;
top: 50%;
}

.col:last-child h1:after {
width: 100%;
}

button {
margin-right: 10px;
cursor: pointer;
}

button.off {
color: var(--f_low);
}

.container {
display: flex;
flex-direction: column;
height: 70vh;
max-width: 70rem;
transform: translate(25%, 25%);
}

.row {
display: flex;
flex-direction: row;
flex: auto;
}
.col {
display: flex;
flex-direction: column;
flex: 1;
}

.col:not(:last-child) > *:nth-child(2n) {
border-right: solid var(--line-width) var(--f_low);
padding-right: 10xp;
margin-right: 5px;
height: 100%;
}

.col:not(:first-child) > * {
padding-left: 10px;
}

canvas {
width: 100%;
height: 30px;
}
@@ -0,0 +1,197 @@
/* Blob.js
* A Blob implementation.
* 2014-07-24
*
* By Eli Grey, http://eligrey.com
* By Devin Samarin, https://github.com/dsamarin
* License: X11/MIT
* See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md
*/

/*global self, unescape */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true */

/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */

(function (view) {
"use strict";

view.URL = view.URL || view.webkitURL;

if (view.Blob && view.URL) {
try {
new Blob;
return;
} catch (e) {}
}

// Internally we use a BlobBuilder implementation to base Blob off of
// in order to support older browsers that only have BlobBuilder
var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
var
get_class = function(object) {
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
}
, FakeBlobBuilder = function BlobBuilder() {
this.data = [];
}
, FakeBlob = function Blob(data, type, encoding) {
this.data = data;
this.size = data.length;
this.type = type;
this.encoding = encoding;
}
, FBB_proto = FakeBlobBuilder.prototype
, FB_proto = FakeBlob.prototype
, FileReaderSync = view.FileReaderSync
, FileException = function(type) {
this.code = this[this.name = type];
}
, file_ex_codes = (
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
).split(" ")
, file_ex_code = file_ex_codes.length
, real_URL = view.URL || view.webkitURL || view
, real_create_object_URL = real_URL.createObjectURL
, real_revoke_object_URL = real_URL.revokeObjectURL
, URL = real_URL
, btoa = view.btoa
, atob = view.atob

, ArrayBuffer = view.ArrayBuffer
, Uint8Array = view.Uint8Array

, origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/
;
FakeBlob.fake = FB_proto.fake = true;
while (file_ex_code--) {
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
}
// Polyfill URL
if (!real_URL.createObjectURL) {
URL = view.URL = function(uri) {
var
uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
, uri_origin
;
uri_info.href = uri;
if (!("origin" in uri_info)) {
if (uri_info.protocol.toLowerCase() === "data:") {
uri_info.origin = null;
} else {
uri_origin = uri.match(origin);
uri_info.origin = uri_origin && uri_origin[1];
}
}
return uri_info;
};
}
URL.createObjectURL = function(blob) {
var
type = blob.type
, data_URI_header
;
if (type === null) {
type = "application/octet-stream";
}
if (blob instanceof FakeBlob) {
data_URI_header = "data:" + type;
if (blob.encoding === "base64") {
return data_URI_header + ";base64," + blob.data;
} else if (blob.encoding === "URI") {
return data_URI_header + "," + decodeURIComponent(blob.data);
} if (btoa) {
return data_URI_header + ";base64," + btoa(blob.data);
} else {
return data_URI_header + "," + encodeURIComponent(blob.data);
}
} else if (real_create_object_URL) {
return real_create_object_URL.call(real_URL, blob);
}
};
URL.revokeObjectURL = function(object_URL) {
if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
real_revoke_object_URL.call(real_URL, object_URL);
}
};
FBB_proto.append = function(data/*, endings*/) {
var bb = this.data;
// decode data to a binary string
if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
var
str = ""
, buf = new Uint8Array(data)
, i = 0
, buf_len = buf.length
;
for (; i < buf_len; i++) {
str += String.fromCharCode(buf[i]);
}
bb.push(str);
} else if (get_class(data) === "Blob" || get_class(data) === "File") {
if (FileReaderSync) {
var fr = new FileReaderSync;
bb.push(fr.readAsBinaryString(data));
} else {
// async FileReader won't work as BlobBuilder is sync
throw new FileException("NOT_READABLE_ERR");
}
} else if (data instanceof FakeBlob) {
if (data.encoding === "base64" && atob) {
bb.push(atob(data.data));
} else if (data.encoding === "URI") {
bb.push(decodeURIComponent(data.data));
} else if (data.encoding === "raw") {
bb.push(data.data);
}
} else {
if (typeof data !== "string") {
data += ""; // convert unsupported types to strings
}
// decode UTF-16 to binary string
bb.push(unescape(encodeURIComponent(data)));
}
};
FBB_proto.getBlob = function(type) {
if (!arguments.length) {
type = null;
}
return new FakeBlob(this.data.join(""), type, "raw");
};
FBB_proto.toString = function() {
return "[object BlobBuilder]";
};
FB_proto.slice = function(start, end, type) {
var args = arguments.length;
if (args < 3) {
type = null;
}
return new FakeBlob(
this.data.slice(start, args > 1 ? end : this.data.length)
, type
, this.encoding
);
};
FB_proto.toString = function() {
return "[object Blob]";
};
FB_proto.close = function() {
this.size = 0;
delete this.data;
};
return FakeBlobBuilder;
}(view));

view.Blob = function(blobParts, options) {
var type = options ? (options.type || "") : "";
var builder = new BlobBuilder();
if (blobParts) {
for (var i = 0, len = blobParts.length; i < len; i++) {
builder.append(blobParts[i]);
}
}
return builder.getBlob(type);
};
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,131 @@
/*
* RIFFWAVE.js v0.03 - Audio encoder for HTML5 <audio> elements.
* Copyleft 2011 by Pedro Ladaria <pedro.ladaria at Gmail dot com>
*
* Public Domain
*
* Changelog:
*
* 0.01 - First release
* 0.02 - New faster base64 encoding
* 0.03 - Support for 16bit samples
*
* Notes:
*
* 8 bit data is unsigned: 0..255
* 16 bit data is signed: −32,768..32,767
*
*/

var FastBase64 = {

chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
encLookup: [],

Init: function() {
for (var i=0; i<4096; i++) {
this.encLookup[i] = this.chars[i >> 6] + this.chars[i & 0x3F];
}
},

Encode: function(src) {
var len = src.length;
var dst = '';
var i = 0;
while (len > 2) {
n = (src[i] << 16) | (src[i+1]<<8) | src[i+2];
dst+= this.encLookup[n >> 12] + this.encLookup[n & 0xFFF];
len-= 3;
i+= 3;
}
if (len > 0) {
var n1= (src[i] & 0xFC) >> 2;
var n2= (src[i] & 0x03) << 4;
if (len > 1) n2 |= (src[++i] & 0xF0) >> 4;
dst+= this.chars[n1];
dst+= this.chars[n2];
if (len == 2) {
var n3= (src[i++] & 0x0F) << 2;
n3 |= (src[i] & 0xC0) >> 6;
dst+= this.chars[n3];
}
if (len == 1) dst+= '=';
dst+= '=';
}
return dst;
} // end Encode

}

FastBase64.Init();

var RIFFWAVE = function(data) {

this.data = []; // Array containing audio samples
this.wav = []; // Array containing the generated wave file
this.dataURI = ''; // http://en.wikipedia.org/wiki/Data_URI_scheme

this.header = { // OFFS SIZE NOTES
chunkId : [0x52,0x49,0x46,0x46], // 0 4 "RIFF" = 0x52494646
chunkSize : 0, // 4 4 36+SubChunk2Size = 4+(8+SubChunk1Size)+(8+SubChunk2Size)
format : [0x57,0x41,0x56,0x45], // 8 4 "WAVE" = 0x57415645
subChunk1Id : [0x66,0x6d,0x74,0x20], // 12 4 "fmt " = 0x666d7420
subChunk1Size: 16, // 16 4 16 for PCM
audioFormat : 1, // 20 2 PCM = 1
numChannels : 1, // 22 2 Mono = 1, Stereo = 2...
sampleRate : 8000, // 24 4 8000, 44100...
byteRate : 0, // 28 4 SampleRate*NumChannels*BitsPerSample/8
blockAlign : 0, // 32 2 NumChannels*BitsPerSample/8
bitsPerSample: 8, // 34 2 8 bits = 8, 16 bits = 16
subChunk2Id : [0x64,0x61,0x74,0x61], // 36 4 "data" = 0x64617461
subChunk2Size: 0 // 40 4 data size = NumSamples*NumChannels*BitsPerSample/8
};

function u32ToArray(i) {
return [i&0xFF, (i>>8)&0xFF, (i>>16)&0xFF, (i>>24)&0xFF];
}

function u16ToArray(i) {
return [i&0xFF, (i>>8)&0xFF];
}

function split16bitArray(data) {
var r = [];
var j = 0;
var len = data.length;
for (var i=0; i<len; i++) {
r[j++] = data[i] & 0xFF;
r[j++] = (data[i]>>8) & 0xFF;
}
return r;
}

this.Make = function(data) {
if (data instanceof Array) this.data = data;
this.header.blockAlign = (this.header.numChannels * this.header.bitsPerSample) >> 3;
this.header.byteRate = this.header.blockAlign * this.sampleRate;
this.header.subChunk2Size = this.data.length * (this.header.bitsPerSample >> 3);
this.header.chunkSize = 36 + this.header.subChunk2Size;

this.wav = this.header.chunkId.concat(
u32ToArray(this.header.chunkSize),
this.header.format,
this.header.subChunk1Id,
u32ToArray(this.header.subChunk1Size),
u16ToArray(this.header.audioFormat),
u16ToArray(this.header.numChannels),
u32ToArray(this.header.sampleRate),
u32ToArray(this.header.byteRate),
u16ToArray(this.header.blockAlign),
u16ToArray(this.header.bitsPerSample),
this.header.subChunk2Id,
u32ToArray(this.header.subChunk2Size),
(this.header.bitsPerSample == 16) ? split16bitArray(this.data) : this.data
);
this.dataURI = 'data:audio/wav;base64,'+FastBase64.Encode(this.wav);
};

if (data instanceof Array) this.Make(data);

}; // end RIFFWAVE

@@ -0,0 +1,19 @@
body { background:var(--background) !important; color:var(--f_med); }
.bg { background:var(--background) !important }
.f_high { color:var(--f_high) !important; stroke:var(--f_high) !important }
.f_med { color:var(--f_med) !important ; stroke:var(--f_med) !important }
.f_low { color:var(--f_low) !important ; stroke:var(--f_low) !important }
.f_inv { color:var(--f_inv) !important ; stroke:var(--f_inv) !important }
.b_high { background:var(--b_high) !important; fill:var(--b_high) !important }
.b_med { background:var(--b_med) !important ; fill:var(--b_med) !important }
.b_low { background:var(--b_low) !important ; fill:var(--b_low) !important }
.b_inv { background:var(--b_inv) !important ; fill:var(--b_inv) !important }

#debug { color:var(--f_high); }

#dis_f_high { background: var(--f_high) !important }
#dis_f_med { background: var(--f_med) !important }
#dis_f_low { background: var(--f_low) !important }
#dis_b_high { background: var(--b_high) !important }
#dis_b_med { background: var(--b_med) !important }
#dis_b_low { background: var(--b_low) !important }
@@ -0,0 +1,170 @@
'use strict'

/* global localStorage */
/* global FileReader */
/* global DOMParser */

function Theme (client) {
this.el = document.createElement('style')
this.el.type = 'text/css'

this.active = {}
this.default = {
background: "#111111",
f_high: "#efefef",
f_med: "#ff4444",
f_low: "#333333",
f_inv: "#000000",
b_high: "#666666",
b_med: "#444444",
b_low: "#222222",
b_inv: "#ff4444"
}

// Callbacks
this.onLoad = () => {}

this.install = (host = document.body) => {
window.addEventListener('dragover', this.drag)
window.addEventListener('drop', this.drop)
host.appendChild(this.el)
}

this.start = () => {
console.log('Theme', 'Starting..')
if (isJson(localStorage.theme)) {
const storage = JSON.parse(localStorage.theme)
if (isValid(storage)) {
console.log('Theme', 'Loading theme in localStorage..')
this.load(storage)
return
}
}
this.load(this.default)
}

this.open = () => {
console.log('Theme', 'Open theme..')
const input = document.createElement('input')
input.type = 'file'
input.onchange = (e) => {
this.read(e.target.files[0], this.load)
}
input.click()
}

this.load = (data) => {
const theme = this.parse(data)
if (!isValid(theme)) { console.warn('Theme', 'Invalid format'); return }
console.log('Theme', 'Loaded theme!')
this.el.innerHTML = `:root {
--background: ${theme.background};
--f_high: ${theme.f_high};
--f_med: ${theme.f_med};
--f_low: ${theme.f_low};
--f_inv: ${theme.f_inv};
--b_high: ${theme.b_high};
--b_med: ${theme.b_med};
--b_low: ${theme.b_low};
--b_inv: ${theme.b_inv};
}`
localStorage.setItem('theme', JSON.stringify(theme))
this.active = theme
if (this.onLoad) {
this.onLoad(data)
}
}

this.reset = () => {
this.load(this.default)
}

this.set = (key, val) => {
if (!val) { return }
const hex = (`${val}`.substr(0, 1) !== '#' ? '#' : '') + `${val}`
if (!isColor(hex)) { console.warn('Theme', `${hex} is not a valid color.`); return }
this.active[key] = hex
}

this.get = (key) => {
return this.active[key]
}

this.parse = (any) => {
if (isValid(any)) { return any }
if (isJson(any)) { return JSON.parse(any) }
if (isHtml(any)) { return extract(any) }
}

// Drag

this.drag = (e) => {
e.stopPropagation()
e.preventDefault()
e.dataTransfer.dropEffect = 'copy'
}

this.drop = (e) => {
e.preventDefault()
const file = e.dataTransfer.files[0]
if (file.name.indexOf('.svg') > -1) {
this.read(file, this.load)
}
e.stopPropagation()
}

this.read = (file, callback) => {
const reader = new FileReader()
reader.onload = (event) => {
callback(event.target.result)
}
reader.readAsText(file, 'UTF-8')
}

// Helpers

function extract (xml) {
const svg = new DOMParser().parseFromString(xml, 'text/xml')
try {
return {
background: svg.getElementById('background').getAttribute('fill'),
f_high: svg.getElementById('f_high').getAttribute('fill'),
f_med: svg.getElementById('f_med').getAttribute('fill'),
f_low: svg.getElementById('f_low').getAttribute('fill'),
f_inv: svg.getElementById('f_inv').getAttribute('fill'),
b_high: svg.getElementById('b_high').getAttribute('fill'),
b_med: svg.getElementById('b_med').getAttribute('fill'),
b_low: svg.getElementById('b_low').getAttribute('fill'),
b_inv: svg.getElementById('b_inv').getAttribute('fill')
}
} catch (err) {
console.warn('Theme', 'Incomplete SVG Theme', err)
}
}

function isValid (json) {
if (!json) { return false }
if (!json.background || !isColor(json.background)) { return false }
if (!json.f_high || !isColor(json.f_high)) { return false }
if (!json.f_med || !isColor(json.f_med)) { return false }
if (!json.f_low || !isColor(json.f_low)) { return false }
if (!json.f_inv || !isColor(json.f_inv)) { return false }
if (!json.b_high || !isColor(json.b_high)) { return false }
if (!json.b_med || !isColor(json.b_med)) { return false }
if (!json.b_low || !isColor(json.b_low)) { return false }
if (!json.b_inv || !isColor(json.b_inv)) { return false }
return true
}

function isColor (hex) {
return /^#([0-9A-F]{3}){1,2}$/i.test(hex)
}

function isJson (text) {
try { JSON.parse(text); return true } catch (error) { return false }
}

function isHtml (text) {
try { new DOMParser().parseFromString(text, 'text/xml'); return true } catch (error) { return false }
}
}