-
Notifications
You must be signed in to change notification settings - Fork 7
/
interface.js
executable file
·128 lines (109 loc) · 4.62 KB
/
interface.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// PlayUEF
// Copyright (c) 2017 8bitkick
//
// www.8bitkick.cc
//
// Web-based UEF to WAV conversion and player
// Loads cassette-based games to Acorn Electron and BBC micro
// Cassette & console interface
// -----------------------------
function userInterface(wavfile, chunks, UEFNAME, BAUD, SAMPLE_RATE, TEXTFILE) {
var warning = "";
var player = document.getElementById('audio');
var fps = 30;
var thischunk = 0;
// resize cassette on browser resize
function resize(){
var c = document.getElementById("cassette");
var newwidth = window.innerWidth-10;
if (newwidth>480){newwidth=480};
c.width=newwidth;
c.height=260*newwidth/400;
var ctx = c.getContext("2d");
var scalefactor = newwidth / 400;
ctx.scale(scalefactor,scalefactor);}
window.addEventListener('resize', function(event){
resize();
});
function binarySearch(array, key) {
var samplesPerCycle = SAMPLE_RATE / BAUD;
var lo = 0, hi = array.length - 1, mid, element;
while (lo <= hi) {
mid = ((lo + hi) >> 1);
element = array[mid];
if ((element.timestamp+(element.cycles*samplesPerCycle)) < key) {
lo = mid + 1;
} else if (element.timestamp > key) {
hi = mid - 1;
} else {
return mid;
}
}
return -1;
}
// set up animation of cassette
function draw() {
setTimeout(function() {
requestAnimationFrame(draw);
// Get position of audio player
var duration = player.duration;
var currentTime = player.currentTime;
var bytesPerSample = (BAUD/SAMPLE_RATE)/10; // # tape bytes transmitted per WAV sample, assuming 10 bit packets
// Render cassette frame
cassette(duration,currentTime,UEFNAME,BAUD,VERSION);
// Console animation
// If playing
if (currentTime!=0){
// convert audio time to sample position and get associated UEF chunk
var samplepos = currentTime * SAMPLE_RATE;
thischunk = binarySearch(chunks,samplepos);
// For UEF data chunks display contents in the console in 'real time'
switch (chunks[thischunk].type){
case "dataBlock":
document.getElementById("console").style.color = "#00aa00";
var delta = Math.floor((samplepos-chunks[thischunk].timestamp)*bytesPerSample); // how much data to display
var str = String.fromCharCode.apply(null,chunks[thischunk].data.slice(delta & 0xfe00,delta));
document.getElementById("console").innerHTML = str+"|";
document.getElementById("header").innerHTML = chunks[thischunk].header;
break;
case "definedDataBlock":
document.getElementById("console").style.color = "#00aaaa";
var delta = Math.floor((samplepos-chunks[thischunk].timestamp)*bytesPerSample); // how much data to display
var str = String.fromCharCode.apply(null,chunks[thischunk].data.slice(delta & 0xfe00,delta));
document.getElementById("console").innerHTML = str+"|";
document.getElementById("header").innerHTML = chunks[thischunk].header;
break;
// Clear console for integerGap
case "integerGap":
document.getElementById("console").innerHTML ="";
document.getElementById("header").innerHTML = "";
break;
// Bright green for carrierTone, it just looks cooler
case "carrierTone":
document.getElementById("console").style.color = "#00ff22";
break;
}
// Otherwise stick in text file and warnings if you're at the beginning
} else {document.getElementById("console").innerHTML = TEXTFILE;document.getElementById("header").innerHTML = warning;}
}, 1000 / fps);
}
// Set up audio player
var wavname = UEFNAME.split('.').shift();
if (BAUD!=1200) {wavname+=BAUD};
const blob = new Blob([wavfile], { type: 'audio/wav' });
const url = window.URL.createObjectURL(blob);
// Connect WAV to the audio player
const audio = document.getElementById('audio');
const source = document.getElementById('source');
// Insert blob object URL into audio element & play.
source.src = url;
audio.load();
// Swap loader for cassette in web page
document.getElementById('container').innerHTML = '<canvas id="cassette" height="260px" width="400px"></canvas>';
// Set up listener for WAV save on clicking casssette
document.getElementById("cassette").addEventListener('click',function ()
{saveAs(blob, wavname+'.wav')});
// Start animations
resize();
draw();
}