mirror of
https://github.com/whscullin/apple2js.git
synced 2024-01-12 14:14:38 +00:00
Refactor tape drive.
This commit is contained in:
parent
8ee8b01d0a
commit
131db0340a
|
@ -67,6 +67,7 @@
|
||||||
<script type="text/javascript" src="js/ui/keyboard.js"></script>
|
<script type="text/javascript" src="js/ui/keyboard.js"></script>
|
||||||
<script type="text/javascript" src="js/ui/gamepad.js"></script>
|
<script type="text/javascript" src="js/ui/gamepad.js"></script>
|
||||||
<script type="text/javascript" src="js/ui/printer.js"></script>
|
<script type="text/javascript" src="js/ui/printer.js"></script>
|
||||||
|
<script type="text/javascript" src="js/ui/tape.js"></script>
|
||||||
|
|
||||||
<!-- Disk Index -->
|
<!-- Disk Index -->
|
||||||
<script type="text/javascript" src="json/disks/index.js"></script>
|
<script type="text/javascript" src="json/disks/index.js"></script>
|
||||||
|
@ -160,12 +161,12 @@
|
||||||
<h3>CPU</h3>
|
<h3>CPU</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<select id="computer_type" value="apple2plus" onchange="updateCPU()">
|
<select id="computer_type2" value="apple2plus" onchange="updateCPU()">
|
||||||
<option value="apple2plus">Apple ][+</option>
|
<option value="apple2plus">Apple ][+</option>
|
||||||
<option value="apple2">Autostart Apple ][</option>
|
<option value="apple2">Autostart Apple ][</option>
|
||||||
<option value="original">Apple ][</option>
|
<option value="original">Apple ][</option>
|
||||||
</select>
|
</select>
|
||||||
<label for="computer_type">
|
<label for="computer_type2">
|
||||||
Type
|
Type
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
<script type="text/javascript" src="js/ui/keyboard.js"></script>
|
<script type="text/javascript" src="js/ui/keyboard.js"></script>
|
||||||
<script type="text/javascript" src="js/ui/gamepad.js"></script>
|
<script type="text/javascript" src="js/ui/gamepad.js"></script>
|
||||||
<script type="text/javascript" src="js/ui/printer.js"></script>
|
<script type="text/javascript" src="js/ui/printer.js"></script>
|
||||||
|
<script type="text/javascript" src="js/ui/tape.js"></script>
|
||||||
|
|
||||||
<!-- Disk Index -->
|
<!-- Disk Index -->
|
||||||
<script type="text/javascript" src="json/disks/index.js"></script>
|
<script type="text/javascript" src="json/disks/index.js"></script>
|
||||||
|
@ -138,11 +139,11 @@
|
||||||
<h3>CPU</h3>
|
<h3>CPU</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<select id="computer_type" value="apple2enh" onchange="updateCPU()">
|
<select id="computer_type2e" value="apple2enh" onchange="updateCPU()">
|
||||||
<option value="apple2enh">Enhanced Apple //e</option>
|
<option value="apple2enh">Enhanced Apple //e</option>
|
||||||
<option value="apple2e">Apple //e</option>
|
<option value="apple2e">Apple //e</option>
|
||||||
</select>
|
</select>
|
||||||
<label for="computer_type">
|
<label for="computer_type2e">
|
||||||
Type
|
Type
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
JSLINT = jshint
|
JSLINT = eslint
|
||||||
|
|
||||||
JSFILES = copyright.js util.js prefs.js ram.js langcard.js fpbasic.js apple2char.js canvas2.js apple2io.js parallel.js ramfactor.js disk2.js cpu6502.js base64.js
|
JSFILES = copyright.js util.js prefs.js ram.js langcard.js fpbasic.js apple2char.js canvas2.js apple2io.js parallel.js ramfactor.js disk2.js cpu6502.js base64.js
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ function Apple2IO(cpu, callbacks)
|
||||||
var _tape = [];
|
var _tape = [];
|
||||||
var _tapeOffset = 0;
|
var _tapeOffset = 0;
|
||||||
var _tapeNext = 0;
|
var _tapeNext = 0;
|
||||||
var _tapeFlip = false;
|
var _tapeCurrent = false;
|
||||||
|
|
||||||
var LOC = {
|
var LOC = {
|
||||||
KEYBOARD: 0x00, // keyboard data (latched) (Read),
|
KEYBOARD: 0x00, // keyboard data (latched) (Read),
|
||||||
|
@ -285,32 +285,20 @@ function Apple2IO(cpu, callbacks)
|
||||||
_tapeOffset = 0;
|
_tapeOffset = 0;
|
||||||
_tapeNext = now;
|
_tapeNext = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_tapeOffset < _tape.length) {
|
if (_tapeOffset < _tape.length) {
|
||||||
|
_tapeCurrent = _tape[_tapeOffset][1];
|
||||||
while (now >= _tapeNext) {
|
while (now >= _tapeNext) {
|
||||||
if ((_tapeOffset % 1000) === 0) {
|
if ((_tapeOffset % 1000) === 0) {
|
||||||
debug('Read ' + (_tapeOffset / 1000));
|
debug('Read ' + (_tapeOffset / 1000));
|
||||||
}
|
}
|
||||||
_tapeFlip = !_tapeFlip;
|
_tapeCurrent = _tape[_tapeOffset][1];
|
||||||
// flipped = true;
|
_tapeNext += _tape[_tapeOffset++][0];
|
||||||
_tapeNext += _tape[_tapeOffset++];
|
|
||||||
}
|
}
|
||||||
result = _tapeFlip ? 0x80 : 0x00;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if (flipped) {
|
|
||||||
debug('now=' + now + ' next=' + _tapeNext + ' (' + (_tapeNext - now) + ')');
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
var progress =
|
|
||||||
Math.round(_tapeOffset / _tapeBuffer.length * 100) / 100;
|
|
||||||
|
|
||||||
if (_progress != progress) {
|
|
||||||
_progress = progress;
|
|
||||||
cb.progress(_progress);
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
result = _tapeCurrent ? 0x80 : 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val !== undefined) {
|
if (val !== undefined) {
|
||||||
|
@ -461,6 +449,10 @@ function Apple2IO(cpu, callbacks)
|
||||||
_cycles_per_sample = _hz / _rate;
|
_cycles_per_sample = _hz / _rate;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getHz: function apple2io_updateHz() {
|
||||||
|
return _hz;
|
||||||
|
},
|
||||||
|
|
||||||
setKeyBuffer: function apple2io_setKeyBuffer(buffer) {
|
setKeyBuffer: function apple2io_setKeyBuffer(buffer) {
|
||||||
_buffer = buffer.split('');
|
_buffer = buffer.split('');
|
||||||
if (_buffer.length > 0) {
|
if (_buffer.length > 0) {
|
||||||
|
|
95
js/main2.js
95
js/main2.js
|
@ -19,6 +19,7 @@
|
||||||
disk_index: false,
|
disk_index: false,
|
||||||
Audio: false,
|
Audio: false,
|
||||||
initGamepad: false, processGamepad: false, gamepad: false,
|
initGamepad: false, processGamepad: false, gamepad: false,
|
||||||
|
Tape: false,
|
||||||
ApplesoftDump: false, SYMBOLS: false,
|
ApplesoftDump: false, SYMBOLS: false,
|
||||||
multiScreen: true
|
multiScreen: true
|
||||||
*/
|
*/
|
||||||
|
@ -127,7 +128,7 @@ function DriveLights()
|
||||||
}
|
}
|
||||||
|
|
||||||
var DISK_TYPES = ['dsk','d13','do','po','raw','nib','2mg'];
|
var DISK_TYPES = ['dsk','d13','do','po','raw','nib','2mg'];
|
||||||
var TAPE_TYPES = ['wav','aiff','aif','mp3'];
|
var TAPE_TYPES = ['wav','aiff','aif','mp3','m4a'];
|
||||||
|
|
||||||
var _currentDrive = 1;
|
var _currentDrive = 1;
|
||||||
|
|
||||||
|
@ -204,7 +205,7 @@ function doLoad() {
|
||||||
|
|
||||||
var files = $('#local_file').prop('files');
|
var files = $('#local_file').prop('files');
|
||||||
if (files.length == 1) {
|
if (files.length == 1) {
|
||||||
doLoadLocal(_currentDrive);
|
doLoadLocal(_currentDrive, files[0]);
|
||||||
} else if (url) {
|
} else if (url) {
|
||||||
var filename;
|
var filename;
|
||||||
$('#load').dialog('close');
|
$('#load').dialog('close');
|
||||||
|
@ -242,20 +243,18 @@ function doDelete(name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function doLoadLocal(drive) {
|
function doLoadLocal(drive, file) {
|
||||||
var files = $('#local_file').prop('files');
|
var parts = file.name.split('.');
|
||||||
if (files.length == 1) {
|
var ext = parts[parts.length - 1].toLowerCase();
|
||||||
var file = files[0];
|
if ($.inArray(ext, DISK_TYPES) >= 0) {
|
||||||
var parts = file.name.split('.');
|
doLoadLocalDisk(drive, file);
|
||||||
var ext = parts[parts.length - 1].toLowerCase();
|
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
|
||||||
if ($.inArray(ext, DISK_TYPES) >= 0) {
|
tape.doLoadLocalTape(file, function() {
|
||||||
doLoadLocalDisk(drive, file);
|
|
||||||
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
|
|
||||||
doLoadLocalTape(file);
|
|
||||||
} else {
|
|
||||||
window.alert('Unknown file type: ' + ext);
|
|
||||||
$('#load').dialog('close');
|
$('#load').dialog('close');
|
||||||
}
|
});
|
||||||
|
} else {
|
||||||
|
window.alert('Unknown file type: ' + ext);
|
||||||
|
$('#load').dialog('close');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +262,8 @@ function doLoadLocalDisk(drive, file) {
|
||||||
var fileReader = new FileReader();
|
var fileReader = new FileReader();
|
||||||
fileReader.onload = function() {
|
fileReader.onload = function() {
|
||||||
var parts = file.name.split('.');
|
var parts = file.name.split('.');
|
||||||
var name = parts[0], ext = parts[parts.length - 1].toLowerCase();
|
var ext = parts.pop().toLowerCase();
|
||||||
|
var name = parts.join('.');
|
||||||
if (disk2.setBinary(drive, name, ext, this.result)) {
|
if (disk2.setBinary(drive, name, ext, this.result)) {
|
||||||
drivelights.label(drive, name);
|
drivelights.label(drive, name);
|
||||||
$('#load').dialog('close');
|
$('#load').dialog('close');
|
||||||
|
@ -273,60 +273,6 @@ function doLoadLocalDisk(drive, file) {
|
||||||
fileReader.readAsArrayBuffer(file);
|
fileReader.readAsArrayBuffer(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
function doLoadLocalTape(file) {
|
|
||||||
// Audio Buffer Source
|
|
||||||
var context;
|
|
||||||
if (typeof window.AudioContext != 'undefined') {
|
|
||||||
context = new window.AudioContext();
|
|
||||||
} else {
|
|
||||||
window.alert('Not supported by your browser');
|
|
||||||
$('#load').dialog('close');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function(ev) {
|
|
||||||
context.decodeAudioData(ev.target.result, function(buffer) {
|
|
||||||
var buf = [];
|
|
||||||
var data = buffer.getChannelData(0), datum = data[0];
|
|
||||||
var old = (datum > 0.0), current;
|
|
||||||
var last = 0, delta, ival;
|
|
||||||
debug('Sample Count: ' + data.length);
|
|
||||||
debug('Sample rate: ' + buffer.sampleRate);
|
|
||||||
for (var idx = 1; idx < data.length; idx++) {
|
|
||||||
datum = data[idx];
|
|
||||||
if ((datum > 0.1) || (datum < -0.1)) {
|
|
||||||
current = (datum > 0.0);
|
|
||||||
if (current != old) {
|
|
||||||
delta = idx - last;
|
|
||||||
if (delta > 2000000) {
|
|
||||||
delta = 2000000;
|
|
||||||
}
|
|
||||||
ival = delta / buffer.sampleRate * 1000;
|
|
||||||
if (ival >= 0.550 && ival < 0.750) {
|
|
||||||
ival = 0.650; // Header
|
|
||||||
} else if (ival >= 0.175 && ival < 0.225) {
|
|
||||||
ival = 0.200; // sync 1
|
|
||||||
} else if (ival >= 0.225 && ival < 0.275) {
|
|
||||||
ival = 0.250; // 0 / sync 2
|
|
||||||
} else if (ival >= 0.450 && ival < 0.550) {
|
|
||||||
ival = 0.500; // 1
|
|
||||||
} else {
|
|
||||||
// debug(idx + ' ' + buf.length + ' ' + ival);
|
|
||||||
}
|
|
||||||
buf.push(parseInt(ival * kHz));
|
|
||||||
old = current;
|
|
||||||
last = idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
io.setTape(buf);
|
|
||||||
$('#load').dialog('close');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
fileReader.readAsArrayBuffer(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
function doLoadHTTP(drive, _url) {
|
function doLoadHTTP(drive, _url) {
|
||||||
var url = _url || $('#http_url').val();
|
var url = _url || $('#http_url').val();
|
||||||
if (url) {
|
if (url) {
|
||||||
|
@ -335,9 +281,11 @@ function doLoadHTTP(drive, _url) {
|
||||||
req.responseType = 'arraybuffer';
|
req.responseType = 'arraybuffer';
|
||||||
|
|
||||||
req.onload = function() {
|
req.onload = function() {
|
||||||
var parts = url.split(/[/.]/);
|
var urlParts = url.split('/');
|
||||||
var name = decodeURIComponent(parts[parts.length - 2]);
|
var file = urlParts.pop();
|
||||||
var ext = parts[parts.length - 1].toLowerCase();
|
var fileParts = file.split('.');
|
||||||
|
var ext = fileParts.pop().toLowerCase();
|
||||||
|
var name = decodeURIComponent(fileParts.join('.'));
|
||||||
if (disk2.setBinary(drive, name, ext, req.response)) {
|
if (disk2.setBinary(drive, name, ext, req.response)) {
|
||||||
drivelights.label(drive, name);
|
drivelights.label(drive, name);
|
||||||
$('#http_load').dialog('close');
|
$('#http_load').dialog('close');
|
||||||
|
@ -429,6 +377,7 @@ var drivelights = new DriveLights();
|
||||||
var io = new Apple2IO(cpu, vm);
|
var io = new Apple2IO(cpu, vm);
|
||||||
var keyboard = new KeyBoard(io);
|
var keyboard = new KeyBoard(io);
|
||||||
var audio = new Audio(io);
|
var audio = new Audio(io);
|
||||||
|
var tape = new Tape(io);
|
||||||
var lc = new LanguageCard(io, 0, rom);
|
var lc = new LanguageCard(io, 0, rom);
|
||||||
var parallel = new Parallel(io, 1, new Printer());
|
var parallel = new Parallel(io, 1, new Printer());
|
||||||
var slinky = new RAMFactor(io, 2, 1024 * 1024);
|
var slinky = new RAMFactor(io, 2, 1024 * 1024);
|
||||||
|
|
107
js/main2e.js
107
js/main2e.js
|
@ -16,6 +16,7 @@
|
||||||
disk_index: false,
|
disk_index: false,
|
||||||
Audio: false,
|
Audio: false,
|
||||||
initGamepad: false, processGamepad: false, gamepad: false,
|
initGamepad: false, processGamepad: false, gamepad: false,
|
||||||
|
Tape: false,
|
||||||
ApplesoftDump: false, SYMBOLS: false,
|
ApplesoftDump: false, SYMBOLS: false,
|
||||||
multiScreen: true
|
multiScreen: true
|
||||||
*/
|
*/
|
||||||
|
@ -121,7 +122,7 @@ function DriveLights()
|
||||||
}
|
}
|
||||||
|
|
||||||
var DISK_TYPES = ['dsk','d13','do','po','raw','nib','2mg'];
|
var DISK_TYPES = ['dsk','d13','do','po','raw','nib','2mg'];
|
||||||
var TAPE_TYPES = ['wav','aiff','aif','mp3'];
|
var TAPE_TYPES = ['wav','aiff','aif','mp3','m4a'];
|
||||||
|
|
||||||
var _currentDrive = 1;
|
var _currentDrive = 1;
|
||||||
|
|
||||||
|
@ -198,7 +199,7 @@ function doLoad() {
|
||||||
|
|
||||||
var files = $('#local_file').prop('files');
|
var files = $('#local_file').prop('files');
|
||||||
if (files.length == 1) {
|
if (files.length == 1) {
|
||||||
doLoadLocal(_currentDrive);
|
doLoadLocal(_currentDrive, files[0]);
|
||||||
} else if (url) {
|
} else if (url) {
|
||||||
var filename;
|
var filename;
|
||||||
$('#load').dialog('close');
|
$('#load').dialog('close');
|
||||||
|
@ -236,20 +237,18 @@ function doDelete(name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function doLoadLocal(drive) {
|
function doLoadLocal(drive, file) {
|
||||||
var files = $('#local_file').prop('files');
|
var parts = file.name.split('.');
|
||||||
if (files.length == 1) {
|
var ext = parts[parts.length - 1].toLowerCase();
|
||||||
var file = files[0];
|
if ($.inArray(ext, DISK_TYPES) >= 0) {
|
||||||
var parts = file.name.split('.');
|
doLoadLocalDisk(drive, file);
|
||||||
var ext = parts[parts.length - 1].toLowerCase();
|
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
|
||||||
if ($.inArray(ext, DISK_TYPES) >= 0) {
|
tape.doLoadLocalTape(file, function() {
|
||||||
doLoadLocalDisk(drive, file);
|
|
||||||
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
|
|
||||||
doLoadLocalTape(file);
|
|
||||||
} else {
|
|
||||||
window.alert('Unknown file type: ' + ext);
|
|
||||||
$('#load').dialog('close');
|
$('#load').dialog('close');
|
||||||
}
|
});
|
||||||
|
} else {
|
||||||
|
window.alert('Unknown file type: ' + ext);
|
||||||
|
$('#load').dialog('close');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,7 +256,8 @@ function doLoadLocalDisk(drive, file) {
|
||||||
var fileReader = new FileReader();
|
var fileReader = new FileReader();
|
||||||
fileReader.onload = function() {
|
fileReader.onload = function() {
|
||||||
var parts = file.name.split('.');
|
var parts = file.name.split('.');
|
||||||
var name = parts[0], ext = parts[parts.length - 1].toLowerCase();
|
var ext = parts.pop().toLowerCase();
|
||||||
|
var name = parts.join('.');
|
||||||
if (disk2.setBinary(drive, name, ext, this.result)) {
|
if (disk2.setBinary(drive, name, ext, this.result)) {
|
||||||
drivelights.label(drive, name);
|
drivelights.label(drive, name);
|
||||||
$('#load').dialog('close');
|
$('#load').dialog('close');
|
||||||
|
@ -267,60 +267,6 @@ function doLoadLocalDisk(drive, file) {
|
||||||
fileReader.readAsArrayBuffer(file);
|
fileReader.readAsArrayBuffer(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
function doLoadLocalTape(file) {
|
|
||||||
// Audio Buffer Source
|
|
||||||
var context;
|
|
||||||
if (typeof window.AudioContext != 'undefined') {
|
|
||||||
context = new window.AudioContext();
|
|
||||||
} else {
|
|
||||||
window.alert('Not supported by your browser');
|
|
||||||
$('#load').dialog('close');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function(ev) {
|
|
||||||
context.decodeAudioData(ev.target.result, function(buffer) {
|
|
||||||
var buf = [];
|
|
||||||
var data = buffer.getChannelData(0), datum = data[0];
|
|
||||||
var old = (datum > 0.0), current;
|
|
||||||
var last = 0, delta, ival;
|
|
||||||
debug('Sample Count: ' + data.length);
|
|
||||||
debug('Sample rate: ' + buffer.sampleRate);
|
|
||||||
for (var idx = 1; idx < data.length; idx++) {
|
|
||||||
datum = data[idx];
|
|
||||||
if ((datum > 0.1) || (datum < -0.1)) {
|
|
||||||
current = (datum > 0.0);
|
|
||||||
if (current != old) {
|
|
||||||
delta = idx - last;
|
|
||||||
if (delta > 2000000) {
|
|
||||||
delta = 2000000;
|
|
||||||
}
|
|
||||||
ival = delta / buffer.sampleRate * 1000;
|
|
||||||
if (ival >= 0.550 && ival < 0.750) {
|
|
||||||
ival = 0.650; // Header
|
|
||||||
} else if (ival >= 0.175 && ival < 0.225) {
|
|
||||||
ival = 0.200; // sync 1
|
|
||||||
} else if (ival >= 0.225 && ival < 0.275) {
|
|
||||||
ival = 0.250; // 0 / sync 2
|
|
||||||
} else if (ival >= 0.450 && ival < 0.550) {
|
|
||||||
ival = 0.500; // 1
|
|
||||||
} else {
|
|
||||||
// debug(idx + ' ' + buf.length + ' ' + ival);
|
|
||||||
}
|
|
||||||
buf.push(parseInt(ival * kHz));
|
|
||||||
old = current;
|
|
||||||
last = idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
io.setTape(buf);
|
|
||||||
$('#load').dialog('close');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
fileReader.readAsArrayBuffer(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
function doLoadHTTP(drive, _url) {
|
function doLoadHTTP(drive, _url) {
|
||||||
var url = _url || $('#http_url').val();
|
var url = _url || $('#http_url').val();
|
||||||
if (url) {
|
if (url) {
|
||||||
|
@ -329,17 +275,15 @@ function doLoadHTTP(drive, _url) {
|
||||||
req.responseType = 'arraybuffer';
|
req.responseType = 'arraybuffer';
|
||||||
|
|
||||||
req.onload = function() {
|
req.onload = function() {
|
||||||
var parts = url.split(/[/.]/);
|
var urlParts = url.split('/');
|
||||||
var name = decodeURIComponent(parts[parts.length - 2]);
|
var file = urlParts.pop();
|
||||||
var ext = parts[parts.length - 1].toLowerCase();
|
var fileParts = file.split('.');
|
||||||
if (req.response.byteLength >= 400 * 1024) {
|
var ext = fileParts.pop().toLowerCase();
|
||||||
// smartport.setBinary(drive, req.response);
|
var name = decodeURIComponent(fileParts.join('.'));
|
||||||
} else {
|
if (disk2.setBinary(drive, name, ext, req.response)) {
|
||||||
if (disk2.setBinary(drive, name, ext, req.response)) {
|
drivelights.label(drive, name);
|
||||||
drivelights.label(drive, name);
|
$('#http_load').dialog('close');
|
||||||
$('#http_load').dialog('close');
|
initGamepad();
|
||||||
initGamepad();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
req.send(null);
|
req.send(null);
|
||||||
|
@ -415,6 +359,7 @@ var drivelights = new DriveLights();
|
||||||
var io = new Apple2IO(cpu, vm);
|
var io = new Apple2IO(cpu, vm);
|
||||||
var keyboard = new KeyBoard(io, true);
|
var keyboard = new KeyBoard(io, true);
|
||||||
var audio = new Audio(io);
|
var audio = new Audio(io);
|
||||||
|
var tape = new Tape(io);
|
||||||
|
|
||||||
var mmu = new MMU(cpu, vm, gr, gr2, hgr, hgr2, io, rom);
|
var mmu = new MMU(cpu, vm, gr, gr2, hgr, hgr2, io, rom);
|
||||||
|
|
||||||
|
|
64
js/ui/tape.js
Normal file
64
js/ui/tape.js
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*globals debug */
|
||||||
|
/*exported Tape */
|
||||||
|
|
||||||
|
function Tape(io) {
|
||||||
|
var AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||||
|
|
||||||
|
return {
|
||||||
|
doLoadLocalTape: function(file, done) {
|
||||||
|
var kHz = io.getHz() / 1000;
|
||||||
|
|
||||||
|
// Audio Buffer Source
|
||||||
|
var context;
|
||||||
|
if (AudioContext) {
|
||||||
|
context = new AudioContext();
|
||||||
|
} else {
|
||||||
|
window.alert('Not supported by your browser');
|
||||||
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileReader = new FileReader();
|
||||||
|
fileReader.onload = function(ev) {
|
||||||
|
context.decodeAudioData(ev.target.result, function(buffer) {
|
||||||
|
var buf = [];
|
||||||
|
var data = buffer.getChannelData(0), datum = data[0];
|
||||||
|
var old = (datum > 0.0), current;
|
||||||
|
var last = 0, delta, ival;
|
||||||
|
debug('Sample Count: ' + data.length);
|
||||||
|
debug('Sample rate: ' + buffer.sampleRate);
|
||||||
|
for (var idx = 1; idx < data.length; idx++) {
|
||||||
|
datum = data[idx];
|
||||||
|
if ((datum > 0.1) || (datum < -0.1)) {
|
||||||
|
current = (datum > 0.0);
|
||||||
|
if (current != old) {
|
||||||
|
delta = idx - last;
|
||||||
|
if (delta > 2000000) {
|
||||||
|
delta = 2000000;
|
||||||
|
}
|
||||||
|
ival = delta / buffer.sampleRate * 1000;
|
||||||
|
if (ival >= 0.550 && ival < 0.750) {
|
||||||
|
ival = 0.650; // Header
|
||||||
|
} else if (ival >= 0.175 && ival < 0.225) {
|
||||||
|
ival = 0.200; // sync 1
|
||||||
|
} else if (ival >= 0.225 && ival < 0.275) {
|
||||||
|
ival = 0.250; // 0 / sync 2
|
||||||
|
} else if (ival >= 0.450 && ival < 0.550) {
|
||||||
|
ival = 0.500; // 1
|
||||||
|
} else {
|
||||||
|
// debug(idx + ' ' + buf.length + ' ' + ival);
|
||||||
|
}
|
||||||
|
buf.push([parseInt(ival * kHz), current]);
|
||||||
|
old = current;
|
||||||
|
last = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
io.setTape(buf);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
fileReader.readAsArrayBuffer(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user