crossbrowdy
Version:
A Multimedia JavaScript framework to create real cross-platform and hybrid game engines, games, emulators, multimedia libraries and apps.
442 lines (384 loc) • 10.1 kB
HTML
<head>
<meta charset="utf-8">
<meta http-eqv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>jsfx</title>
<script>
window.onerror = function(msg, url, linenumber) {
alert('Error message: '+msg+'\nURL: '+url+'\nLine Number: '+linenumber);
return true;
}
</script>
<script src="jsfx.js"></script>
</head>
<body>
<div id="jsfx">
<h1 class="title">jsfx</h1>
<div class="description">See <a href="https://github.com/loov/jsfx">github.com/loov/jsfx</a> for more information.</div>
<div></div>
<div id="control" class="panel">
<div class="panel-title">Control</div>
<input type="checkbox" id="use-audiocontext" title="Use AudioContext." onclick="ChangePlayMode()">
<button onclick="PlayCurrent()">Play</button>
<button onclick="AddToLibrary()">Add</button>
<a class="button" id="download" href="#" onmousedown="UpdateDownloadLink()" download="sound.wav">Download</a>
<div id="last-time" title="Time it took to generate."></div>
<div class="clear"></div>
</div>
<div id="presets" class="panel">
<div class="panel-title">Presets</div>
</div>
<div class="clear"></div>
<div id="panels">
</div>
<div class="clear"></div>
<div class="panel wide">
<div class="panel-title">Library</div>
<input type="text" readonly id="library-content" title="Paramset for the current Library.">
<div id="library"></div>
</div>
</div>
</body>
<script>var Library = {};
var CurrentParams = {};
function PlayCurrent(){ Play(CurrentParams); }
var PlayAudio = function(params){
var start = (new Date())|0;
jsfx.Sound(params).play();
var stop = (new Date())|0;
var time = (stop - start) + "ms"
console.log("Generated in", time);
document.getElementById("last-time").innerText = time;
};
var Play = PlayAudio;
var PlayContext;
if(typeof AudioContext !== "undefined"){
var Live = jsfx.Live();
PlayContext = function(params){
Live._play(params);
};
} else {
document.getElementById("use-audiocontext").hidden = true;
}
function ChangePlayMode(){
if(document.getElementById("use-audiocontext").checked){
Play = PlayContext;
} else {
Play = PlayAudio;
}
}
function AddToLibrary(){
var name = prompt("Please enter name for the sound:");
if((name == null) || (name == "")){
return;
}
var params = JSON.parse(JSON.stringify(CurrentParams));
jsfx._RemoveEmptyParams(params);
Library[name] = params;
UpdateHash();
UpdateCurrentView();
}
function SelectPreset(preset){
CurrentParams = preset();
UpdateCurrentView();
PlayCurrent();
}
var LastHash = "";
function UpdateHash(){
var json = JSON.stringify(Library);
document.getElementById("library-content").value = json;
LastHash = "#" + btoa(json);
window.location.hash = LastHash;
}
function LoadFromHash(){
var json = window.location.hash.substr(1);
try{
json = atob(json)
document.getElementById("library-content").value = json;
Library = JSON.parse(json);
}catch(e){ console.log(e); }
}
if(window.location.hash != ""){ LoadFromHash(); }
window.onhashchange = function(ev){
if(window.location.hash != LastHash){
LoadFromHash();
UpdateCurrentView();
}
};
function UpdateDownloadLink(){
var sound = jsfx.Sound(CurrentParams);
var el = document.getElementById("download");
el.href = sound.src;
}
function UpdateCurrentView(){
// create a copy of params
var params = JSON.parse(JSON.stringify(CurrentParams));
jsfx.InitDefaultParams(params, jsfx.DefaultModules);
list(params, function(moduleName, params){
list(params, function(paramName, paramValue){
var element = document.getElementById(moduleName + "$" + paramName);;
if(element){
element.value = paramValue;
}
var element = document.getElementById(moduleName + "_" + paramName + "_" + paramValue);
if(element){
element.checked = true;
}
});
});
var library = document.getElementById("library");
library.innerHTML = "";
var els = list(Library, function(name, params){
var load = E("button", "item-load", "#");
load.title = "Load";
load.onclick = function(){
CurrentParams = JSON.parse(JSON.stringify(params));
UpdateCurrentView();
};
var del = E("button", "item-delete", "X");
del.title = "Delete";
del.onclick = function(){
delete Library[name];
UpdateHash();
UpdateCurrentView();
}
var el = E("div", "library-item", [
load,
E("span", "item-name", name),
del
]);
el.title = "play";
el.onclick = function(){
Play(params);
};
library.appendChild(el);
});
}
document.getElementById("library-content").click = function(ev){
ev.currentTarget.select();
}
function ModifyValue(moduleName, paramName, newValue){
// console.log("CHANGE", moduleName, paramName, newValue);
if(CurrentParams[moduleName] == null){
CurrentParams[moduleName] = {};
}
CurrentParams[moduleName][paramName] = newValue;
PlayCurrent();
}
function CreateParam(name, def, module){
var sel;
if(def.C){
sel = E("form", "", list(def.C, function(value){
var input = E("input", "", []);
input.type = "radio";
input.id = module.name + "_" + name + "_" + value;
input.name = module.name + "_" + name;
input.value = value;
input.onchange = function(ev){
ModifyValue(module.name, name, input.value);
};
var label = E("label", "", value);
label.htmlFor = input.id;
return E("span", "radio-option", [input, label]);
}));
} else {
sel = E("input", "", []);
sel.type = "range";
sel.min = def.L;
sel.max = def.H;
sel.value = def.D;
sel.step = 0.01;
sel.onchange = function(ev){
ModifyValue(module.name, name, parseFloat(sel.value));
};
if(def.H - def.L > 10){
sel.step = 1;
}
}
sel.id = module.name + "$" + name;
return E("tr", "", [
E("td", "", name),
E("td", "", [sel])
]);
}
function CreatePanel(module){
return E("div", "panel", [
E("div", "panel-title", module.name),
E("table", "", list(module.params, CreateParam, module))
]);
}
function Add(module){
document.getElementById("panels").appendChild(CreatePanel(module));
}
Add(jsfx.Module.Generator);
Add(jsfx.Module.Frequency);
Add(jsfx.Module.Volume);
Add(jsfx.Module.Vibrato);
Add(jsfx.Module.Filter);
Add(jsfx.Module.Phaser);
document.getElementById("panels").appendChild(E("div", "clear", []));
list(jsfx.Preset, function(name, preset){
var button = E("button", "", name);
button.onclick = function(){ SelectPreset(preset); };
document.getElementById("presets").appendChild(button);
});
document.getElementById("presets").appendChild(E("div", "clear", []));
function E(tag, className, content){
var el = document.createElement(tag);
if(className !== ''){
el.className = className;
}
if(typeof content == 'object'){
for(var i = 0; i < content.length; i += 1){
el.appendChild(content[i]);
}
} else if (typeof content == 'string'){
el.innerHTML = content;
}
return el;
}
function list(obj, fn, X){
var r = [];
for(var name in obj){
if(obj.hasOwnProperty(name)){
r.push(fn(name, obj[name], X));
}
}
return r;
}
UpdateCurrentView();
;
</script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body, html {
font-family: RobotoDraft,Roboto,Helvetica Neue,Helvetica,Arial,sans-serif;
font-weight: 300;
line-height: 1.2;
color: #333333;
}
.clear { clear: both; }
#jsfx {
margin: 16px auto;
max-width: 650px;
}
#jsfx .title {
font-size: 2em;
color: #444;
clear: both;
}
#jsfx .description {
margin-bottom: 8px;
}
#jsfx .panel {
float: left;
clear: left;
position: relative;
margin: 8px;
padding: 4px;
width: 300px;
background: #FFF;
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.37);
}
#jsfx .panel:nth-child(2n) {
float: right;
clear: right;
}
#jsfx .panel.wide {
float: none; clear: none;
width: 100%;
}
@media(max-width: 650px){
#jsfx {
width: 100%;
margin: 0;
}
#jsfx .panel {
float: none !important;
clear: none !important;
margin: 8px 0;
width: 100%;
}
}
#jsfx .panel .panel-title {
padding: 4px;
font-size: 12px;
color: #666;
}
#jsfx .panel button, #jsfx .panel .button {
float: left;
}
#jsfx button, #jsfx .button {
font-family: RobotoDraft,Roboto,Helvetica Neue,Helvetica,Arial,sans-serif;
font-weight: 300;
font-size: 14px;
margin: 2px;
border: 1px solid #AAA;
background: #FFF;
cursor: pointer;
padding: 4px 8px;
text-decoration: none;
color: inherit;
}
#jsfx button:hover, #jsfx .button:hover {
border: 1px solid #7DC6FF;
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.37);
}
#jsfx .panel table {
font-size: 0.8em;
width: 100%;
}
#jsfx #use-audiocontext {
float: left;
}
#jsfx .panel table input[type="range"] { width: 100%; }
#jsfx .panel table tr td:first-child { width: 80px; }
#jsfx .panel .radio-option {
display: inline-block;
margin-left: 2px;
line-height: 10px;
border: 1px solid #eee;
margin: 2px 4px;
padding: 2px 4px;
width: 40%;
}
#jsfx .panel .radio-option input {
height: 10px;
}
#jsfx #last-time {
position: absolute;
bottom: 4px;
right: 8px;
}
#jsfx #library-content {
position: absolute;
top: 4px;
right: 4px;
}
#jsfx #library .library-item {
position: relative;
cursor: pointer;
line-height: 24px;
}
#jsfx #library .library-item:hover {
background: #eee;
}
#jsfx #library .library-item .item-name {
margin-left: 8px;
vertical-align: middle;
font-size: 14px;
}
#jsfx #library .library-item button {
padding: 0px 4px;
width: 32px;
text-align: center;
}
#jsfx #library .library-item .item-delete {
display: block;
position: absolute;
right: 1px; bottom: 1px; top: 1px;
border: 1px solid #F88;
}
</style>