Refactor tape drive.

This commit is contained in:
Will Scullin 2019-01-09 00:27:31 -08:00
parent 8ee8b01d0a
commit 131db0340a
No known key found for this signature in database
GPG Key ID: 9092A5C0A673416B
7 changed files with 130 additions and 178 deletions

View File

@ -67,6 +67,7 @@
<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/printer.js"></script>
<script type="text/javascript" src="js/ui/tape.js"></script>
<!-- Disk Index -->
<script type="text/javascript" src="json/disks/index.js"></script>
@ -160,12 +161,12 @@
<h3>CPU</h3>
<ul>
<li>
<select id="computer_type" value="apple2plus" onchange="updateCPU()">
<select id="computer_type2" value="apple2plus" onchange="updateCPU()">
<option value="apple2plus">Apple ][+</option>
<option value="apple2">Autostart Apple ][</option>
<option value="original">Apple ][</option>
</select>
<label for="computer_type">
<label for="computer_type2">
Type
</label>
</li>

View File

@ -66,6 +66,7 @@
<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/printer.js"></script>
<script type="text/javascript" src="js/ui/tape.js"></script>
<!-- Disk Index -->
<script type="text/javascript" src="json/disks/index.js"></script>
@ -138,11 +139,11 @@
<h3>CPU</h3>
<ul>
<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="apple2e">Apple //e</option>
</select>
<label for="computer_type">
<label for="computer_type2e">
Type
</label>
</li>

View File

@ -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

View File

@ -46,7 +46,7 @@ function Apple2IO(cpu, callbacks)
var _tape = [];
var _tapeOffset = 0;
var _tapeNext = 0;
var _tapeFlip = false;
var _tapeCurrent = false;
var LOC = {
KEYBOARD: 0x00, // keyboard data (latched) (Read),
@ -285,32 +285,20 @@ function Apple2IO(cpu, callbacks)
_tapeOffset = 0;
_tapeNext = now;
}
if (_tapeOffset < _tape.length) {
_tapeCurrent = _tape[_tapeOffset][1];
while (now >= _tapeNext) {
if ((_tapeOffset % 1000) === 0) {
debug('Read ' + (_tapeOffset / 1000));
}
_tapeFlip = !_tapeFlip;
// flipped = true;
_tapeNext += _tape[_tapeOffset++];
_tapeCurrent = _tape[_tapeOffset][1];
_tapeNext += _tape[_tapeOffset++][0];
}
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) {
@ -461,6 +449,10 @@ function Apple2IO(cpu, callbacks)
_cycles_per_sample = _hz / _rate;
},
getHz: function apple2io_updateHz() {
return _hz;
},
setKeyBuffer: function apple2io_setKeyBuffer(buffer) {
_buffer = buffer.split('');
if (_buffer.length > 0) {

View File

@ -19,6 +19,7 @@
disk_index: false,
Audio: false,
initGamepad: false, processGamepad: false, gamepad: false,
Tape: false,
ApplesoftDump: false, SYMBOLS: false,
multiScreen: true
*/
@ -127,7 +128,7 @@ function DriveLights()
}
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;
@ -204,7 +205,7 @@ function doLoad() {
var files = $('#local_file').prop('files');
if (files.length == 1) {
doLoadLocal(_currentDrive);
doLoadLocal(_currentDrive, files[0]);
} else if (url) {
var filename;
$('#load').dialog('close');
@ -242,20 +243,18 @@ function doDelete(name) {
}
}
function doLoadLocal(drive) {
var files = $('#local_file').prop('files');
if (files.length == 1) {
var file = files[0];
var parts = file.name.split('.');
var ext = parts[parts.length - 1].toLowerCase();
if ($.inArray(ext, DISK_TYPES) >= 0) {
doLoadLocalDisk(drive, file);
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
doLoadLocalTape(file);
} else {
window.alert('Unknown file type: ' + ext);
function doLoadLocal(drive, file) {
var parts = file.name.split('.');
var ext = parts[parts.length - 1].toLowerCase();
if ($.inArray(ext, DISK_TYPES) >= 0) {
doLoadLocalDisk(drive, file);
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
tape.doLoadLocalTape(file, function() {
$('#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();
fileReader.onload = function() {
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)) {
drivelights.label(drive, name);
$('#load').dialog('close');
@ -273,60 +273,6 @@ function doLoadLocalDisk(drive, 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) {
var url = _url || $('#http_url').val();
if (url) {
@ -335,9 +281,11 @@ function doLoadHTTP(drive, _url) {
req.responseType = 'arraybuffer';
req.onload = function() {
var parts = url.split(/[/.]/);
var name = decodeURIComponent(parts[parts.length - 2]);
var ext = parts[parts.length - 1].toLowerCase();
var urlParts = url.split('/');
var file = urlParts.pop();
var fileParts = file.split('.');
var ext = fileParts.pop().toLowerCase();
var name = decodeURIComponent(fileParts.join('.'));
if (disk2.setBinary(drive, name, ext, req.response)) {
drivelights.label(drive, name);
$('#http_load').dialog('close');
@ -429,6 +377,7 @@ var drivelights = new DriveLights();
var io = new Apple2IO(cpu, vm);
var keyboard = new KeyBoard(io);
var audio = new Audio(io);
var tape = new Tape(io);
var lc = new LanguageCard(io, 0, rom);
var parallel = new Parallel(io, 1, new Printer());
var slinky = new RAMFactor(io, 2, 1024 * 1024);

View File

@ -16,6 +16,7 @@
disk_index: false,
Audio: false,
initGamepad: false, processGamepad: false, gamepad: false,
Tape: false,
ApplesoftDump: false, SYMBOLS: false,
multiScreen: true
*/
@ -121,7 +122,7 @@ function DriveLights()
}
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;
@ -198,7 +199,7 @@ function doLoad() {
var files = $('#local_file').prop('files');
if (files.length == 1) {
doLoadLocal(_currentDrive);
doLoadLocal(_currentDrive, files[0]);
} else if (url) {
var filename;
$('#load').dialog('close');
@ -236,20 +237,18 @@ function doDelete(name) {
}
}
function doLoadLocal(drive) {
var files = $('#local_file').prop('files');
if (files.length == 1) {
var file = files[0];
var parts = file.name.split('.');
var ext = parts[parts.length - 1].toLowerCase();
if ($.inArray(ext, DISK_TYPES) >= 0) {
doLoadLocalDisk(drive, file);
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
doLoadLocalTape(file);
} else {
window.alert('Unknown file type: ' + ext);
function doLoadLocal(drive, file) {
var parts = file.name.split('.');
var ext = parts[parts.length - 1].toLowerCase();
if ($.inArray(ext, DISK_TYPES) >= 0) {
doLoadLocalDisk(drive, file);
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
tape.doLoadLocalTape(file, function() {
$('#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();
fileReader.onload = function() {
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)) {
drivelights.label(drive, name);
$('#load').dialog('close');
@ -267,60 +267,6 @@ function doLoadLocalDisk(drive, 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) {
var url = _url || $('#http_url').val();
if (url) {
@ -329,17 +275,15 @@ function doLoadHTTP(drive, _url) {
req.responseType = 'arraybuffer';
req.onload = function() {
var parts = url.split(/[/.]/);
var name = decodeURIComponent(parts[parts.length - 2]);
var ext = parts[parts.length - 1].toLowerCase();
if (req.response.byteLength >= 400 * 1024) {
// smartport.setBinary(drive, req.response);
} else {
if (disk2.setBinary(drive, name, ext, req.response)) {
drivelights.label(drive, name);
$('#http_load').dialog('close');
initGamepad();
}
var urlParts = url.split('/');
var file = urlParts.pop();
var fileParts = file.split('.');
var ext = fileParts.pop().toLowerCase();
var name = decodeURIComponent(fileParts.join('.'));
if (disk2.setBinary(drive, name, ext, req.response)) {
drivelights.label(drive, name);
$('#http_load').dialog('close');
initGamepad();
}
};
req.send(null);
@ -415,6 +359,7 @@ var drivelights = new DriveLights();
var io = new Apple2IO(cpu, vm);
var keyboard = new KeyBoard(io, true);
var audio = new Audio(io);
var tape = new Tape(io);
var mmu = new MMU(cpu, vm, gr, gr2, hgr, hgr2, io, rom);

64
js/ui/tape.js Normal file
View 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);
}
};
}