Audio cleanup.
This commit is contained in:
parent
8a761be9a9
commit
1dfbc0b61b
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html><!-- -*- mode: HTML; indent-tabs-mode: nil -*- -->
|
||||
<!--
|
||||
<!--
|
||||
Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this software and its
|
||||
documentation for any purpose is hereby granted without fee, provided that
|
||||
the above copyright notice appear in all copies and that both that
|
||||
|
@ -27,7 +27,7 @@
|
|||
<link rel="apple-touch-icon" size="72x72" href="img/webapp-ipad.png" />
|
||||
<link rel="shortcut icon" href="logoicon.png" />
|
||||
<link rel="stylesheet" type="text/css" href="css/apple2.css" />
|
||||
<link rel="stylesheet" type="text/css"
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://code.jquery.com/ui/1.10.3/themes/mint-choc/jquery-ui.css" />
|
||||
|
||||
<meta property="og:title" content="Apple ][js" />
|
||||
|
@ -88,8 +88,8 @@ function DriveLights()
|
|||
{
|
||||
return {
|
||||
driveLight: function(drive, on) {
|
||||
$("#disk" + drive).css("background-image",
|
||||
on ? "url(css/red-on-16.png)" :
|
||||
$("#disk" + drive).css("background-image",
|
||||
on ? "url(css/red-on-16.png)" :
|
||||
"url(css/red-off-16.png)");
|
||||
},
|
||||
dirty: function(drive, dirty) {
|
||||
|
@ -277,7 +277,7 @@ function loadHTTP(url) {
|
|||
var req = new XMLHttpRequest();
|
||||
req.open("GET", url, true);
|
||||
req.responseType = "arraybuffer";
|
||||
|
||||
|
||||
req.onload = function(event) {
|
||||
var parts = url.split(/[\/\.]/);
|
||||
var name = decodeURIComponent(parts[parts.length - 2]);
|
||||
|
@ -360,7 +360,7 @@ function updateKHz() {
|
|||
}
|
||||
|
||||
/* Audio Handling */
|
||||
initAudio();
|
||||
initAudio(io);
|
||||
|
||||
function updateSound()
|
||||
{
|
||||
|
@ -403,9 +403,9 @@ function updateSpeed()
|
|||
}
|
||||
|
||||
var _requestAnimationFrame =
|
||||
window.requestAnimationFrame ||
|
||||
window.requestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame;
|
||||
|
||||
function run(pc) {
|
||||
|
@ -418,8 +418,8 @@ function run(pc) {
|
|||
}
|
||||
|
||||
var ival = 30;
|
||||
var now, last = Date.now(), lastSample = last;
|
||||
var runFn = function() {
|
||||
var now, last = Date.now();
|
||||
var runFn = function() {
|
||||
now = Date.now();
|
||||
frames++;
|
||||
|
||||
|
@ -439,18 +439,13 @@ function run(pc) {
|
|||
loadAjax("json/disks/" + filename + ".json");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!loading) {
|
||||
running = true;
|
||||
cpu.stepCycles(step);
|
||||
running = false;
|
||||
vm.blit();
|
||||
if (now - lastSample >= 200) {
|
||||
if (!audioAPI) {
|
||||
playSample();
|
||||
}
|
||||
lastSample = now;
|
||||
}
|
||||
io.sampleTick();
|
||||
}
|
||||
|
||||
processGamepad(io);
|
||||
|
@ -510,7 +505,7 @@ function selectDisk(event) {
|
|||
}
|
||||
|
||||
function clickDisk(event) {
|
||||
doLoad();
|
||||
doLoad();
|
||||
}
|
||||
|
||||
function loadDisk(data) {
|
||||
|
@ -540,10 +535,10 @@ function loadJSON(data) {
|
|||
loading = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* LocalStorage Disk Storage
|
||||
/*
|
||||
* LocalStorage Disk Storage
|
||||
*/
|
||||
|
||||
|
||||
function updateLocalStorage() {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
var names = [], name, cat;
|
||||
|
@ -555,38 +550,38 @@ function updateLocalStorage() {
|
|||
}
|
||||
|
||||
cat = disk_categories['Local Saves'] = [];
|
||||
$("#manage").empty();
|
||||
$("#manage").empty();
|
||||
|
||||
names.forEach(function(name) {
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': name,
|
||||
'filename': 'local:' + name});
|
||||
$("#manage").append("<span class='local_save'>" +
|
||||
name +
|
||||
" <a href='#' onclick='doDelete(\"" +
|
||||
name +
|
||||
'filename': 'local:' + name});
|
||||
$("#manage").append("<span class='local_save'>" +
|
||||
name +
|
||||
" <a href='#' onclick='doDelete(\"" +
|
||||
name +
|
||||
"\")'>Delete</a><br /></span>");
|
||||
});
|
||||
cat.push({'category': 'Local Saves',
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': 'Manage Saves...',
|
||||
'filename': 'local:__manage'});
|
||||
}
|
||||
|
||||
function saveLocalStorage(drive, name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
|
||||
|
||||
var json = disk2.getJSON(drive);
|
||||
diskIndex[name] = json;
|
||||
|
||||
|
||||
window.localStorage.diskIndex = JSON.stringify(diskIndex);
|
||||
|
||||
|
||||
window.alert("Saved");
|
||||
|
||||
|
||||
drivelights.label(drive, name);
|
||||
drivelights.dirty(drive, false);
|
||||
updateLocalStorage();
|
||||
}
|
||||
|
||||
|
||||
function deleteLocalStorage(name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
if (diskIndex[name]) {
|
||||
|
@ -640,7 +635,7 @@ function _keydown(evt) {
|
|||
keyboard.controlKey(true);
|
||||
} else if (!focused && (!evt.metaKey || evt.ctrlKey)) {
|
||||
evt.preventDefault();
|
||||
|
||||
|
||||
var key = keyboard.mapKeyEvent(evt);
|
||||
if (key != 0xff) {
|
||||
io.keyDown(key);
|
||||
|
@ -754,12 +749,12 @@ $(function() {
|
|||
$("input,textarea").blur(function() { focused = false; });
|
||||
|
||||
keyboard.create($("#keyboard"));
|
||||
|
||||
|
||||
if (prefs.havePrefs()) {
|
||||
$("input[type=checkbox]").each(function() {
|
||||
var val = prefs.readPref(this.id);
|
||||
if (val != null)
|
||||
this.checked = JSON.parse(val);
|
||||
this.checked = JSON.parse(val);
|
||||
});
|
||||
$("input[type=checkbox]").change(function() {
|
||||
prefs.writePref(this.id, JSON.stringify(this.checked));
|
||||
|
@ -794,7 +789,7 @@ $(function() {
|
|||
buttons: {"Close": cancel }});
|
||||
|
||||
if (window.localStorage !== undefined) {
|
||||
$("button.disksave").show();
|
||||
$("button.disksave").show();
|
||||
}
|
||||
|
||||
var oldcat = "";
|
||||
|
@ -806,11 +801,11 @@ $(function() {
|
|||
$("<option />").val(cat).text(cat).appendTo("#category_select");
|
||||
disk_categories[cat] = [];
|
||||
oldcat = cat;
|
||||
}
|
||||
}
|
||||
disk_categories[cat].push(file);
|
||||
if (disk) {
|
||||
if (!disk_sets[name]) {
|
||||
disk_sets[name] = []
|
||||
disk_sets[name] = []
|
||||
}
|
||||
disk_sets[name].push(file);
|
||||
}
|
||||
|
@ -887,7 +882,7 @@ $(function() {
|
|||
<div style="float: right">
|
||||
<input type="button" onclick="window.open('about.html','_html')"
|
||||
name="About" value="About">
|
||||
<input type="button" onclick="$('#options').dialog('open')"
|
||||
<input type="button" onclick="$('#options').dialog('open')"
|
||||
name="Options" value="Options">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -911,21 +906,21 @@ $(function() {
|
|||
<h3>Joystick</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<input type="checkbox" id="flip_x"
|
||||
<input type="checkbox" id="flip_x"
|
||||
onclick="updateJoystick()" />
|
||||
<label for="flip_x">
|
||||
Flip X-Axis
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="flip_y"
|
||||
<input type="checkbox" id="flip_y"
|
||||
onclick="updateJoystick()" />
|
||||
<label for="flip_y">
|
||||
Flip Y-Axis
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="swap_x_y"
|
||||
<input type="checkbox" id="swap_x_y"
|
||||
onclick="updateJoystick()" />
|
||||
<label for="swap_x_y">
|
||||
Swap X-Y Axis
|
||||
|
@ -935,14 +930,14 @@ $(function() {
|
|||
<h3>Monitor</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<input type="checkbox" id="green_screen"
|
||||
<input type="checkbox" id="green_screen"
|
||||
onclick="updateScreen()" />
|
||||
<label for="green_screen">
|
||||
Green Screen
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="show_scanlines"
|
||||
<input type="checkbox" id="show_scanlines"
|
||||
onclick="updateScreen()" />
|
||||
<label for="show_scanlines">
|
||||
Show Scanlines
|
||||
|
@ -952,7 +947,7 @@ $(function() {
|
|||
<h3>Sound</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<input type="checkbox" id="enable_sound"
|
||||
<input type="checkbox" id="enable_sound"
|
||||
onclick="updateSound()" checked="checked" />
|
||||
<label for="enable_sound">
|
||||
Enable (Experimental)
|
||||
|
@ -962,7 +957,7 @@ $(function() {
|
|||
</div>
|
||||
<div id="save" title="Save Disk">
|
||||
<form action="#" onsubmit="return false;">
|
||||
Save Name: <input type="text" name="name" id="save_name"
|
||||
Save Name: <input type="text" name="name" id="save_name"
|
||||
style="width: 200px" />
|
||||
</form>
|
||||
</div>
|
||||
|
@ -972,7 +967,7 @@ $(function() {
|
|||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<select id="category_select" multiple="multiple"
|
||||
<select id="category_select" multiple="multiple"
|
||||
class="ui-widget ui-state-default"
|
||||
onchange="selectCategory(event)" >
|
||||
</select>
|
||||
|
@ -981,7 +976,7 @@ $(function() {
|
|||
<select id="disk_select" multiple="multiple"
|
||||
class="ui-widget ui-state-default"
|
||||
onchange="selectDisk(event)"
|
||||
ondblclick="clickDisk(event)">
|
||||
ondblclick="clickDisk(event)">
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
101
apple2jse.html
101
apple2jse.html
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html><!-- -*- mode: HTML; indent-tabs-mode: nil -*- -->
|
||||
<!--
|
||||
<!--
|
||||
Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
|
||||
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this software and its
|
||||
documentation for any purpose is hereby granted without fee, provided that
|
||||
the above copyright notice appear in all copies and that both that
|
||||
|
@ -27,7 +27,7 @@
|
|||
<link rel="apple-touch-icon" size="72x72" href="img/webapp-ipad.png" />
|
||||
<link rel="shortcut icon" href="logoicon.png" />
|
||||
<link rel="stylesheet" type="text/css" href="css/apple2.css" />
|
||||
<link rel="stylesheet" type="text/css"
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://code.jquery.com/ui/1.10.3/themes/mint-choc/jquery-ui.css" />
|
||||
|
||||
<meta property="og:title" content="Apple //js" />
|
||||
|
@ -59,7 +59,7 @@
|
|||
<script type="text/javascript" src="js/ramfactor.js"></script>
|
||||
<script type="text/javascript" src="js/thunderclock.js"></script>
|
||||
<script type="text/javascript" src="js/cpu6502.js"></script>
|
||||
<script type="text/javascript" src="js/base64.js"></script><
|
||||
<script type="text/javascript" src="js/base64.js"></script>
|
||||
<script type="text/javascript" src="js/ui/audio.js"></script>
|
||||
<script type="text/javascript" src="js/ui/keyboard2e.js"></script>
|
||||
<script type="text/javascript" src="js/ui/gamepad.js"></script>
|
||||
|
@ -89,8 +89,8 @@ function DriveLights()
|
|||
{
|
||||
return {
|
||||
driveLight: function(drive, on) {
|
||||
$("#disk" + drive).css("background-image",
|
||||
on ? "url(css/red-on-16.png)" :
|
||||
$("#disk" + drive).css("background-image",
|
||||
on ? "url(css/red-on-16.png)" :
|
||||
"url(css/red-off-16.png)");
|
||||
},
|
||||
dirty: function(drive, dirty) {
|
||||
|
@ -278,7 +278,7 @@ function loadHTTP(url) {
|
|||
var req = new XMLHttpRequest();
|
||||
req.open("GET", url, true);
|
||||
req.responseType = "arraybuffer";
|
||||
|
||||
|
||||
req.onload = function(event) {
|
||||
var parts = url.split(/[\/\.]/);
|
||||
var name = decodeURIComponent(parts[parts.length - 2]);
|
||||
|
@ -353,7 +353,7 @@ function updateKHz() {
|
|||
}
|
||||
|
||||
/* Audio Handling */
|
||||
initAudio();
|
||||
initAudio(io);
|
||||
|
||||
function updateSound()
|
||||
{
|
||||
|
@ -396,9 +396,9 @@ function updateSpeed()
|
|||
}
|
||||
|
||||
var _requestAnimationFrame =
|
||||
window.requestAnimationFrame ||
|
||||
window.requestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame;
|
||||
|
||||
function run(pc) {
|
||||
|
@ -411,8 +411,8 @@ function run(pc) {
|
|||
}
|
||||
|
||||
var ival = 30;
|
||||
var now, last = Date.now(), lastSample = last;
|
||||
var runFn = function() {
|
||||
var now, last = Date.now();
|
||||
var runFn = function() {
|
||||
now = Date.now();
|
||||
frames++;
|
||||
|
||||
|
@ -432,19 +432,14 @@ function run(pc) {
|
|||
loadAjax("json/disks/" + filename + ".json");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!loading) {
|
||||
mmu.resetVB();
|
||||
running = true;
|
||||
cpu.stepCycles(step);
|
||||
running = false;
|
||||
vm.blit();
|
||||
if (now - lastSample >= 200) {
|
||||
if (!audioAPI) {
|
||||
playSample();
|
||||
}
|
||||
lastSample = now;
|
||||
}
|
||||
io.sampleTick();
|
||||
}
|
||||
|
||||
processGamepad(io);
|
||||
|
@ -504,7 +499,7 @@ function selectDisk(event) {
|
|||
}
|
||||
|
||||
function clickDisk(event) {
|
||||
doLoad();
|
||||
doLoad();
|
||||
}
|
||||
|
||||
function loadDisk(data) {
|
||||
|
@ -534,10 +529,10 @@ function loadJSON(data) {
|
|||
loading = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* LocalStorage Disk Storage
|
||||
/*
|
||||
* LocalStorage Disk Storage
|
||||
*/
|
||||
|
||||
|
||||
function updateLocalStorage() {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
var names = [], name, cat;
|
||||
|
@ -549,38 +544,38 @@ function updateLocalStorage() {
|
|||
}
|
||||
|
||||
cat = disk_categories['Local Saves'] = [];
|
||||
$("#manage").empty();
|
||||
$("#manage").empty();
|
||||
|
||||
names.forEach(function(name) {
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': name,
|
||||
'filename': 'local:' + name});
|
||||
$("#manage").append("<span class='local_save'>" +
|
||||
name +
|
||||
" <a href='#' onclick='doDelete(\"" +
|
||||
name +
|
||||
'filename': 'local:' + name});
|
||||
$("#manage").append("<span class='local_save'>" +
|
||||
name +
|
||||
" <a href='#' onclick='doDelete(\"" +
|
||||
name +
|
||||
"\")'>Delete</a><br /></span>");
|
||||
});
|
||||
cat.push({'category': 'Local Saves',
|
||||
cat.push({'category': 'Local Saves',
|
||||
'name': 'Manage Saves...',
|
||||
'filename': 'local:__manage'});
|
||||
}
|
||||
|
||||
function saveLocalStorage(drive, name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
|
||||
|
||||
var json = disk2.getJSON(drive);
|
||||
diskIndex[name] = json;
|
||||
|
||||
|
||||
window.localStorage.diskIndex = JSON.stringify(diskIndex);
|
||||
|
||||
|
||||
window.alert("Saved");
|
||||
|
||||
|
||||
drivelights.label(drive, name);
|
||||
drivelights.dirty(drive, false);
|
||||
updateLocalStorage();
|
||||
}
|
||||
|
||||
|
||||
function deleteLocalStorage(name) {
|
||||
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
|
||||
if (diskIndex[name]) {
|
||||
|
@ -638,7 +633,7 @@ function _keydown(evt) {
|
|||
keyboard.optionKey(true);
|
||||
} else if (!focused) {
|
||||
evt.preventDefault();
|
||||
|
||||
|
||||
var key = keyboard.mapKeyEvent(evt);
|
||||
if (key != 0xff) {
|
||||
io.keyDown(key);
|
||||
|
@ -754,17 +749,17 @@ $(function() {
|
|||
$("input,textarea").focus(function() { focused = true; })
|
||||
.blur(function() { focused = false; });
|
||||
|
||||
$("body > div").hover(function() { focused = false; },
|
||||
$("body > div").hover(function() { focused = false; },
|
||||
function() { focused = true; });
|
||||
|
||||
|
||||
keyboard.create($("#keyboard"));
|
||||
|
||||
|
||||
if (prefs.havePrefs()) {
|
||||
$("input[type=checkbox]").each(function() {
|
||||
var val = prefs.readPref(this.id);
|
||||
if (val != null)
|
||||
this.checked = JSON.parse(val);
|
||||
this.checked = JSON.parse(val);
|
||||
});
|
||||
$("input[type=checkbox]").change(function() {
|
||||
prefs.writePref(this.id, JSON.stringify(this.checked));
|
||||
|
@ -799,7 +794,7 @@ $(function() {
|
|||
buttons: {"Close": cancel }});
|
||||
|
||||
if (window.localStorage !== undefined) {
|
||||
$("button.disksave").show();
|
||||
$("button.disksave").show();
|
||||
}
|
||||
|
||||
var oldcat = "";
|
||||
|
@ -811,11 +806,11 @@ $(function() {
|
|||
$("<option />").val(cat).text(cat).appendTo("#category_select");
|
||||
disk_categories[cat] = [];
|
||||
oldcat = cat;
|
||||
}
|
||||
}
|
||||
disk_categories[cat].push(file);
|
||||
if (disk) {
|
||||
if (!disk_sets[name]) {
|
||||
disk_sets[name] = []
|
||||
disk_sets[name] = []
|
||||
}
|
||||
disk_sets[name].push(file);
|
||||
}
|
||||
|
@ -852,7 +847,7 @@ $(function() {
|
|||
<table id="display">
|
||||
<tr>
|
||||
<td style="vertical-align: top">
|
||||
<div role="textbox" class="overscan"
|
||||
<div role="textbox" class="overscan"
|
||||
onKeyDown="_keydown(event);"
|
||||
onKeyUp="_keyup(event);">
|
||||
<canvas id="screen" width="560" height="384"></canvas>
|
||||
|
@ -894,7 +889,7 @@ $(function() {
|
|||
<div style="float: right">
|
||||
<input type="button" onclick="window.open('about.html','_html')"
|
||||
name="About" value="About">
|
||||
<input type="button" onclick="$('#options').dialog('open')"
|
||||
<input type="button" onclick="$('#options').dialog('open')"
|
||||
name="Options" value="Options">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -918,21 +913,21 @@ $(function() {
|
|||
<h3>Joystick</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<input type="checkbox" id="flip_x"
|
||||
<input type="checkbox" id="flip_x"
|
||||
onclick="updateJoystick()" />
|
||||
<label for="flip_x">
|
||||
Flip X-Axis
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="flip_y"
|
||||
<input type="checkbox" id="flip_y"
|
||||
onclick="updateJoystick()" />
|
||||
<label for="flip_y">
|
||||
Flip Y-Axis
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="swap_x_y"
|
||||
<input type="checkbox" id="swap_x_y"
|
||||
onclick="updateJoystick()" />
|
||||
<label for="swap_x_y">
|
||||
Swap X-Y Axis
|
||||
|
@ -942,14 +937,14 @@ $(function() {
|
|||
<h3>Monitor</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<input type="checkbox" id="green_screen"
|
||||
<input type="checkbox" id="green_screen"
|
||||
onclick="updateScreen()" />
|
||||
<label for="green_screen">
|
||||
Green Screen
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="show_scanlines"
|
||||
<input type="checkbox" id="show_scanlines"
|
||||
onclick="updateScreen()" />
|
||||
<label for="show_scanlines">
|
||||
Show Scanlines
|
||||
|
@ -959,7 +954,7 @@ $(function() {
|
|||
<h3>Sound</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<input type="checkbox" id="enable_sound"
|
||||
<input type="checkbox" id="enable_sound"
|
||||
onclick="updateSound()" checked="checked" />
|
||||
<label for="enable_sound">
|
||||
Enable (Experimental)
|
||||
|
@ -969,7 +964,7 @@ $(function() {
|
|||
</div>
|
||||
<div id="save" title="Save Disk">
|
||||
<form action="#" onsubmit="return false;">
|
||||
Save Name: <input type="text" name="name" id="save_name"
|
||||
Save Name: <input type="text" name="name" id="save_name"
|
||||
style="width: 200px" />
|
||||
</form>
|
||||
</div>
|
||||
|
@ -979,7 +974,7 @@ $(function() {
|
|||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<select id="category_select" multiple="multiple"
|
||||
<select id="category_select" multiple="multiple"
|
||||
class="ui-widget ui-state-default"
|
||||
onchange="selectCategory(event)" >
|
||||
</select>
|
||||
|
@ -988,7 +983,7 @@ $(function() {
|
|||
<select id="disk_select" multiple="multiple"
|
||||
class="ui-widget ui-state-default"
|
||||
onchange="selectDisk(event)"
|
||||
ondblclick="clickDisk(event)">
|
||||
ondblclick="clickDisk(event)">
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -18,7 +18,8 @@ function Apple2IO(cpu, callbacks)
|
|||
"use strict";
|
||||
|
||||
var _hz = 1023000;
|
||||
var _rate = 16000;
|
||||
var _rate = 44000;
|
||||
var _sample_size = 4096;
|
||||
|
||||
var _cycles_per_sample = _hz / _rate;
|
||||
|
||||
|
@ -31,10 +32,11 @@ function Apple2IO(cpu, callbacks)
|
|||
var _sample = [];
|
||||
var _sampleTime = 0;
|
||||
|
||||
var _high = "%A0";
|
||||
var _mid = "%80";
|
||||
var _low = "%60";
|
||||
var _high = 0.5;
|
||||
var _low = -0.5;
|
||||
|
||||
var _audioListener = null;
|
||||
|
||||
var _trigger = 0;
|
||||
|
||||
var _tape = [];
|
||||
|
@ -94,6 +96,20 @@ function Apple2IO(cpu, callbacks)
|
|||
|
||||
var _locs = [];
|
||||
|
||||
function _tick() {
|
||||
var now = cpu.cycles();
|
||||
var phase = _phase > 0 ? _high : _low;
|
||||
for (; _sampleTime < now; _sampleTime += _cycles_per_sample) {
|
||||
_sample.push(phase);
|
||||
if (_sample.length >= _sample_size) {
|
||||
if (_audioListener) {
|
||||
_audioListener(_sample);
|
||||
}
|
||||
_sample = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _access(off) {
|
||||
var result = 0;
|
||||
var now = cpu.cycles();
|
||||
|
@ -204,13 +220,8 @@ function Apple2IO(cpu, callbacks)
|
|||
if ('doublehires' in callbacks) callbacks.doublehires(true);
|
||||
break;
|
||||
case LOC.SPEAKER:
|
||||
if (_sampleTime) {
|
||||
var phase = _phase > 0 ? _high : _low;
|
||||
for (; _sampleTime < now; _sampleTime += _cycles_per_sample) {
|
||||
_sample.push(phase);
|
||||
}
|
||||
_phase = -_phase;
|
||||
}
|
||||
_phase = -_phase;
|
||||
_tick();
|
||||
break;
|
||||
case LOC.STROBE:
|
||||
_key &= 0x7f;
|
||||
|
@ -342,45 +353,14 @@ function Apple2IO(cpu, callbacks)
|
|||
paddle: function apple2io_paddle(p, v) {
|
||||
_paddle[p] = v;
|
||||
},
|
||||
getSample: function apple2io_getSample() {
|
||||
var result = _sample;
|
||||
var now = cpu.cycles();
|
||||
|
||||
var phase = _mid;
|
||||
if (_sample.length) {
|
||||
phase = _phase > 0 ? _high : _low;
|
||||
}
|
||||
for (; _sampleTime < now; _sampleTime += _cycles_per_sample) {
|
||||
_sample.push(phase);
|
||||
}
|
||||
|
||||
_sample = [];
|
||||
|
||||
return result;
|
||||
},
|
||||
floatAudio: function apple2io_floatAudio(rate) {
|
||||
_rate = rate;
|
||||
_low = -0.5;
|
||||
_mid = 0.0;
|
||||
_high = 0.5;
|
||||
|
||||
_cycles_per_sample = _hz / _rate;
|
||||
},
|
||||
byteAudio: function apple2io_byteAudio(rate) {
|
||||
_rate = rate;
|
||||
_low = 0xa0;
|
||||
_mid = 0x80;
|
||||
_high = 0x60;
|
||||
|
||||
_cycles_per_sample = _hz / _rate;
|
||||
},
|
||||
|
||||
updateHz: function apple2io_updateHz(hz) {
|
||||
_hz = hz;
|
||||
|
||||
_cycles_per_sample = _hz / _rate;
|
||||
},
|
||||
setKeyBuffer: function apple2io_setKeyBuffer(buffer) {
|
||||
_buffer = buffer.split("");
|
||||
_buffer = buffer.split('');
|
||||
if (_buffer.length > 0) {
|
||||
_keyDown = true;
|
||||
_key = _buffer.shift().charCodeAt(0) | 0x80;
|
||||
|
@ -391,6 +371,19 @@ function Apple2IO(cpu, callbacks)
|
|||
debug('Tape length: ' + tape.length);
|
||||
_tape = tape;
|
||||
_tapeOffset = -1;
|
||||
},
|
||||
|
||||
sampleRate: function sampleRate(rate) {
|
||||
_rate = rate;
|
||||
_cycles_per_sample = _hz / _rate;
|
||||
},
|
||||
|
||||
sampleTick: function sampleTick() {
|
||||
_tick();
|
||||
},
|
||||
|
||||
addSampleListener: function addSampleListener(cb) {
|
||||
_audioListener = cb;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
161
js/ui/audio.js
161
js/ui/audio.js
|
@ -11,132 +11,69 @@
|
|||
*/
|
||||
|
||||
/*jshint jquery: true, browser: true */
|
||||
/*globals io: false, toHex:false, debug: false */
|
||||
/*exported playSample, enableSound, initAudio */
|
||||
/*globals debug: false */
|
||||
/*exported enableSound, initAudio */
|
||||
|
||||
/*
|
||||
* Audio Handling
|
||||
*/
|
||||
|
||||
var sound = true;
|
||||
var sound = true;
|
||||
var _samples = [];
|
||||
|
||||
// 8000 = 0x1f40 = 64, 31
|
||||
// 16000 = 0x3e80 = 128, 62
|
||||
var audioContext;
|
||||
var audioNode;
|
||||
var AC = window.webkitAudioContext || window.AudioContext;
|
||||
|
||||
var wavHeader =
|
||||
['R','I','F','F',68 ,3 ,0 ,0 ,'W','A','V','E','f','m','t',' ',
|
||||
16 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,128,62 ,0 ,0 ,128,62 ,0 ,0 ,
|
||||
1 ,0 ,8 ,0 ,'d','a','t','a',32 ,3 ,0 ,0 ];
|
||||
if (typeof AC !== 'undefined') {
|
||||
audioContext = new AC();
|
||||
audioNode = audioContext.createScriptProcessor(4096, 1, 1);
|
||||
|
||||
function percentEncode(ary) {
|
||||
var buf = "";
|
||||
for (var idx = 0; idx < ary.length; idx++) {
|
||||
buf += "%" + toHex(ary[idx]);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
audioNode.onaudioprocess = function(event) {
|
||||
var data = event.outputBuffer.getChannelData(0);
|
||||
var sample = _samples.shift();
|
||||
var idx = 0;
|
||||
|
||||
wavHeader = $.map(wavHeader, function(n) {
|
||||
return typeof(n) == "string" ? n.charCodeAt(0) : n;
|
||||
});
|
||||
var len = data.length;
|
||||
if (sample) {
|
||||
len = Math.min(sample.length, len);
|
||||
for (; idx < len; idx++) {
|
||||
data[idx] = sample[idx];
|
||||
}
|
||||
}
|
||||
|
||||
for (; idx < data.length; idx++) {
|
||||
data[idx] = 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
var wavHeaderStr = percentEncode(wavHeader);
|
||||
/*
|
||||
// Create and specify parameters for the low-pass filter.
|
||||
var filter = audioContext.createBiquadFilter();
|
||||
filter.type = 'lowpass';
|
||||
filter.frequency.value = 11000;
|
||||
filter.connect(audioContext.destination);
|
||||
audioNode.connect(filter);
|
||||
*/
|
||||
|
||||
var audioAPI = false;
|
||||
var audioMoz = false;
|
||||
var audioContext;
|
||||
var audioNode;
|
||||
var audio, audio2;
|
||||
audioNode.connect(audioContext.destination);
|
||||
}
|
||||
|
||||
function initAudio() {
|
||||
var AC = window.webkitAudioContext || window.AudioContext;
|
||||
if (typeof AC != "undefined") {
|
||||
debug("Using Web Audio API");
|
||||
|
||||
audioAPI = true;
|
||||
audioContext = new AC();
|
||||
audioNode = audioContext.createScriptProcessor(4096, 1, 1);
|
||||
io.floatAudio(audioContext.sampleRate);
|
||||
|
||||
audioNode.onaudioprocess = function(event) {
|
||||
var data = event.outputBuffer.getChannelData(0);
|
||||
var sample = io.getSample();
|
||||
|
||||
var delta = 1; // sample.length / data.length;
|
||||
|
||||
var idx, kdx;
|
||||
for (idx = 0, kdx = 0;
|
||||
idx < data.length && parseInt(kdx, 10) < sample.length;
|
||||
kdx += delta, idx++) {
|
||||
data[idx] = sample[parseInt(kdx, 10)];
|
||||
function initAudio(io) {
|
||||
if (audioContext) {
|
||||
debug('Using Webkit Audio');
|
||||
io.sampleRate(audioContext.sampleRate);
|
||||
io.addSampleListener(function(sample) {
|
||||
if (sound) {
|
||||
_samples.push(sample);
|
||||
while (_samples.length > 5) {
|
||||
_samples.shift();
|
||||
}
|
||||
}
|
||||
for (; idx < data.length; idx++) {
|
||||
data[idx] = sample[sample.length - 1];
|
||||
}
|
||||
};
|
||||
} else {
|
||||
audio = document.createElement("audio");
|
||||
|
||||
if (audio.mozSetup) {
|
||||
debug("Using Mozilla Audio API");
|
||||
audio.mozSetup(1, 16000);
|
||||
io.floatAudio(16000);
|
||||
audioMoz = true;
|
||||
} else {
|
||||
debug("Using audio elements");
|
||||
audio2 = document.createElement("audio");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function playSample() {
|
||||
// [audio,audio2] = [audio2,audio];
|
||||
|
||||
var sample = io.getSample();
|
||||
|
||||
if (!sound) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (audioMoz) {
|
||||
audio.mozWriteAudio(sample);
|
||||
return;
|
||||
}
|
||||
|
||||
var tmp = audio;
|
||||
audio = audio2;
|
||||
audio2 = tmp;
|
||||
|
||||
if (sample && sample.length) {
|
||||
var len = sample.length,
|
||||
buf = sample.join(""),
|
||||
o1 = percentEncode([(len + 36) & 0xff, (len + 36) >> 8]),
|
||||
o2 = percentEncode([len & 0xff, len >> 8]),
|
||||
header = wavHeaderStr.replace("%44%03",o1).replace("%20%03", o2);
|
||||
|
||||
audio.src = "data:audio/x-wav," + header + buf;
|
||||
// debug(audio.src);
|
||||
audio.play();
|
||||
}
|
||||
function enableSound(enable) {
|
||||
sound = enable;
|
||||
}
|
||||
|
||||
function enableSound(on)
|
||||
{
|
||||
sound = on;
|
||||
|
||||
if (audioAPI) {
|
||||
if (sound) {
|
||||
audioNode.connect(audioContext.destination);
|
||||
} else {
|
||||
audioNode.disconnect();
|
||||
}
|
||||
} else {
|
||||
if (sound) {
|
||||
if (audio) audio.volume = 0.5;
|
||||
if (audio2) audio2.volume = 0.5;
|
||||
} else {
|
||||
io.getSample(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue