diff --git a/apple2js.html b/apple2js.html
index dce26ec..f1ca7b0 100644
--- a/apple2js.html
+++ b/apple2js.html
@@ -67,6 +67,7 @@
+
@@ -160,12 +161,12 @@
CPU
-
-
diff --git a/apple2jse.html b/apple2jse.html
index b031680..b233188 100644
--- a/apple2jse.html
+++ b/apple2jse.html
@@ -66,6 +66,7 @@
+
@@ -138,11 +139,11 @@
CPU
-
-
+
-
+
Type
diff --git a/js/Makefile b/js/Makefile
index 0de9a8a..1614bfe 100644
--- a/js/Makefile
+++ b/js/Makefile
@@ -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
diff --git a/js/apple2io.js b/js/apple2io.js
index eeec620..2249576 100644
--- a/js/apple2io.js
+++ b/js/apple2io.js
@@ -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) {
diff --git a/js/main2.js b/js/main2.js
index 0795f49..cfe07f6 100644
--- a/js/main2.js
+++ b/js/main2.js
@@ -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);
diff --git a/js/main2e.js b/js/main2e.js
index 814973e..b39be1b 100644
--- a/js/main2e.js
+++ b/js/main2e.js
@@ -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);
diff --git a/js/ui/tape.js b/js/ui/tape.js
new file mode 100644
index 0000000..b782800
--- /dev/null
+++ b/js/ui/tape.js
@@ -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);
+ }
+ };
+}