initial commit, first workable version
This commit is contained in:
commit
0abcd235c9
3 changed files with 173 additions and 0 deletions
26
index.html
Normal file
26
index.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Zoom Marks Analyzer</title>
|
||||
<link rel="stylesheet" href="main.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div id="dropmark">Click or drop file here</div>
|
||||
<div id="label"></div>
|
||||
<div id="cuelist-outer">
|
||||
<div>MARKS</div>
|
||||
<ol id="cuelist"></ol>
|
||||
</div>
|
||||
<button id="export-button" disabled>Export as TSV...
|
||||
<span class="subtitle">(For Adobe Audition)</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/wavefile@11.0.0/dist/wavefile.min.js"
|
||||
integrity="sha384-W3PirarYaOAUEL6KdD+DTxgNwNV2WjP01eFWsWWBBzy4goLvqOd//bovJESrq043"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
</html>
|
61
main.css
Normal file
61
main.css
Normal file
|
@ -0,0 +1,61 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
font-family: monospace;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
#dropmark {
|
||||
font-size: 16pt;
|
||||
border: 4px dashed gray;
|
||||
padding: 2em 3em;
|
||||
|
||||
background: #f5f5f5;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#label {
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
#cuelist-outer {
|
||||
visibility: hidden;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#cuelist-outer div {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#cuelist li {
|
||||
margin: .5em;
|
||||
}
|
||||
|
||||
#export-button {
|
||||
font-size: 16pt;
|
||||
border: 4px solid gray;
|
||||
|
||||
padding: 1.5em 3em;
|
||||
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
#export-button .subtitle {
|
||||
display: block;
|
||||
font-size: 12pt;
|
||||
}
|
86
main.js
Normal file
86
main.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
const dropElement = document.getElementById("dropmark");
|
||||
const label = document.getElementById("label");
|
||||
const infoElement = document.getElementById("cuelist-outer");
|
||||
const cueListElement = document.getElementById("cuelist");
|
||||
const exportButton = document.getElementById("export-button");
|
||||
|
||||
|
||||
function processFile (file) {
|
||||
window.currentFile = file;
|
||||
console.debug(window.currentFile);
|
||||
file.arrayBuffer().then((arrayBuffer) => {
|
||||
const buffer = new Uint8Array(arrayBuffer);
|
||||
window.resultWav = new wavefile.WaveFile(buffer);
|
||||
console.debug(window.resultWav);
|
||||
window.cuePoints = window.resultWav.listCuePoints().map((point) => {
|
||||
return new Date(point.position).toISOString().substr(11, 12);
|
||||
});
|
||||
console.debug(window.cuePoints);
|
||||
displayMarks();
|
||||
});
|
||||
}
|
||||
|
||||
function displayMarks () {
|
||||
const length = window.resultWav.data.chunkSize / window.resultWav.fmt.byteRate;
|
||||
label.innerText = `${window.currentFile.name}: ${length.toFixed(2)}s`;
|
||||
|
||||
while (cueListElement.lastElementChild) {
|
||||
cueListElement.removeChild(cueListElement.lastElementChild);
|
||||
}
|
||||
|
||||
window.cuePoints.forEach((point) => {
|
||||
const row = document.createElement("li");
|
||||
row.innerText = point;
|
||||
cueListElement.appendChild(row);
|
||||
});
|
||||
|
||||
infoElement.style.visibility = "inherit";
|
||||
exportButton.disabled = false;
|
||||
}
|
||||
|
||||
function exportAsTSV () {
|
||||
const filename = `${window.currentFile.name.replace(/\.(wav|WAV)$/, "")}_marks.csv`;
|
||||
let text = "Name\tStart\tDuration\tTime Format\tType\tDescription\n";
|
||||
window.cuePoints.forEach((point, idx) => {
|
||||
text += `Mark ${idx}\t${point}\t0:00.000\tdecimal\tCue\n`;
|
||||
});
|
||||
|
||||
console.debug(text);
|
||||
|
||||
const aElement = document.createElement("a");
|
||||
aElement.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(text));
|
||||
aElement.setAttribute("download", filename);
|
||||
aElement.click();
|
||||
}
|
||||
|
||||
function handleFileSelect (evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
|
||||
processFile(evt.dataTransfer.files.item(0));
|
||||
}
|
||||
|
||||
function handleDragOver (evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}
|
||||
|
||||
function handleClick (evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
|
||||
const fileInput = document.createElement("input");
|
||||
fileInput.type = "file";
|
||||
fileInput.accept = ".wav";
|
||||
fileInput.onchange = () => {
|
||||
if (fileInput.files !== null) {
|
||||
processFile(fileInput.files.item(0));
|
||||
}
|
||||
};
|
||||
fileInput.click();
|
||||
}
|
||||
|
||||
dropElement.addEventListener("dragover", handleDragOver, false);
|
||||
dropElement.addEventListener("drop", handleFileSelect, false);
|
||||
dropElement.addEventListener("click", handleClick, false);
|
||||
exportButton.addEventListener("click", exportAsTSV, false);
|
Loading…
Reference in a new issue