From bcee38bf53f00cb9ad1c547661e9526cea7edccc Mon Sep 17 00:00:00 2001 From: Will Scullin Date: Wed, 5 Mar 2014 20:04:54 -0800 Subject: [PATCH] Refactor audio. --- .gitignore | 1 + apple2js.html | 111 ++-------------------------------------- apple2jse.html | 110 ++-------------------------------------- js/disk2.js | 2 +- js/ui/Makefile | 4 +- js/ui/audio.js | 135 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 148 insertions(+), 215 deletions(-) create mode 100644 js/ui/audio.js diff --git a/.gitignore b/.gitignore index b6261c9..7de43c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .*~ +.checked-*.js diff --git a/apple2js.html b/apple2js.html index 679596c..5dcd06e 100644 --- a/apple2js.html +++ b/apple2js.html @@ -57,6 +57,7 @@ + @@ -286,114 +287,12 @@ function updateKHz() { lastFrames = frames; } -/* - * Audio Handling - */ - -// 8000 = 0x1f40 = 64, 31 -// 16000 = 0x3e80 = 128, 62 - -var wavHeader = - ['R','I','F','F',68 ,3 ,0 ,0 ,'W','A','V','E','f','m','t',' ', - 16 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,128,62 ,0 ,0 ,128,62 ,0 ,0 , - 1 ,0 ,8 ,0 ,'d','a','t','a',32 ,3 ,0 ,0 ]; - -function percentEncode(ary) { - var buf = ""; - for (var idx = 0; idx < ary.length; idx++) { - buf += "%" + toHex(ary[idx]) - } - return buf; -} - -wavHeader = $.map(wavHeader, function(n, i) { - return typeof(n) == "string" ? n.charCodeAt(0) : n; - }); - -wavHeaderStr = percentEncode(wavHeader); - -var audioAPI = false; -var audioMoz = false; -var audioContext; -var audioNode; -var audio, audio2; - -if (typeof webkitAudioContext != "undefined") { - debug("Using Web Audio API"); - - audioAPI = true; - audioContext = new webkitAudioContext(); - audioNode = audioContext.createJavaScriptNode(4096, 1, 1); - io.floatAudio(audioContext.sampleRate); - - audioNode.onaudioprocess = function(event) { - var data = event.outputBuffer.getChannelData(0); - var sample = io.getSample(); - for (var idx = 0; idx < data.length; idx++) { - if (idx < sample.length) { - data[idx] = sample[idx]; - } else { - data[idx] = 0; - } - } - } -} else { - audio = document.createElement("audio"); - - if (audio.mozSetup) { - debug("Using Mozilla Audio API"); - audio.mozSetup(1, 16000); - io.floatAudio(16000); - audioMoz = true; - } else { - audio2 = document.createElement("audio"); - } -} - -function playSample() { - // [audio,audio2] = [audio2,audio]; - - var sample = io.getSample(); - - if (audioMoz) { - audio.mozWriteAudio(sample); - return; - } - - var tmp = audio; - audio = audio2; - audio2 = tmp; - - if (sample && sample.length) { - var len = sample.length, - buf = sample.join(""), - o1 = percentEncode([(len + 36) & 0xff, (len + 36) >> 8]), - o2 = percentEncode([len & 0xff, len >> 8]), - header = wavHeaderStr.replace("%44%03",o1).replace("%20%03", o2); - - audio.src = "data:audio/x-wav," + header + buf; - // debug(audio.src); - audio.play(); - } -} +/* Audio Handling */ +initAudio(); function updateSound() { - var sound = $("#enable_sound").attr("checked"); - if (audioAPI) { - if (sound) { - audioNode.connect(audioContext.destination); - } else { - audioNode.disconnect(); - } - } else { - if (sound) { - if (audio) audio.volume = 0.5; - if (audio2) audio2.volume = 0.5; - } else { - io.getSample(false); - } - } + enableSound($("#enable_sound").attr("checked")); } function dumpDisk(drive) { @@ -478,7 +377,7 @@ function run(pc) { running = false; vm.blit(); if (now - lastSample >= 200) { - if (!audioAPI && sound) { + if (!audioAPI) { playSample(); } lastSample = now; diff --git a/apple2jse.html b/apple2jse.html index d00a611..d7e9cb6 100644 --- a/apple2jse.html +++ b/apple2jse.html @@ -284,114 +284,12 @@ function updateKHz() { lastFrames = frames; } -/* - * Audio Handling - */ - -// 8000 = 0x1f40 = 64, 31 -// 16000 = 0x3e80 = 128, 62 - -var wavHeader = - ['R','I','F','F',68 ,3 ,0 ,0 ,'W','A','V','E','f','m','t',' ', - 16 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,128,62 ,0 ,0 ,128,62 ,0 ,0 , - 1 ,0 ,8 ,0 ,'d','a','t','a',32 ,3 ,0 ,0 ]; - -function percentEncode(ary) { - var buf = ""; - for (var idx = 0; idx < ary.length; idx++) { - buf += "%" + toHex(ary[idx]) - } - return buf; -} - -wavHeader = $.map(wavHeader, function(n, i) { - return typeof(n) == "string" ? n.charCodeAt(0) : n; - }); - -wavHeaderStr = percentEncode(wavHeader); - -var audioAPI = false; -var audioMoz = false; -var audioContext; -var audioNode; -var audio, audio2; - -if (typeof webkitAudioContext != "undefined") { - debug("Using Web Audio API"); - - audioAPI = true; - audioContext = new webkitAudioContext(); - audioNode = audioContext.createJavaScriptNode(4096, 1, 1); - io.floatAudio(audioContext.sampleRate); - - audioNode.onaudioprocess = function(event) { - var data = event.outputBuffer.getChannelData(0); - var sample = io.getSample(); - for (var idx = 0; idx < data.length; idx++) { - if (idx < sample.length) { - data[idx] = sample[idx]; - } else { - data[idx] = 0; - } - } - } -} else { - audio = document.createElement("audio"); - - if (audio.mozSetup) { - debug("Using Mozilla Audio API"); - audio.mozSetup(1, 16000); - io.floatAudio(16000); - audioMoz = true; - } else { - audio2 = document.createElement("audio"); - } -} - -function playSample() { - // [audio,audio2] = [audio2,audio]; - - var sample = io.getSample(); - - if (audioMoz) { - audio.mozWriteAudio(sample); - return; - } - - var tmp = audio; - audio = audio2; - audio2 = tmp; - - if (sample && sample.length) { - var len = sample.length, - buf = sample.join(""), - o1 = percentEncode([(len + 36) & 0xff, (len + 36) >> 8]), - o2 = percentEncode([len & 0xff, len >> 8]), - header = wavHeaderStr.replace("%44%03",o1).replace("%20%03", o2); - - audio.src = "data:audio/x-wav," + header + buf; - // debug(audio.src); - audio.play(); - } -} +/* Audio Handling */ +initAudio(); function updateSound() { - var sound = $("#enable_sound").attr("checked"); - if (audioAPI) { - if (sound) { - audioNode.connect(audioContext.destination); - } else { - audioNode.disconnect(); - } - } else { - if (sound) { - if (audio) audio.volume = 0.5; - if (audio2) audio2.volume = 0.5; - } else { - io.getSample(false); - } - } + enableSound($("#enable_sound").attr("checked")); } function dumpDisk(drive) { @@ -477,7 +375,7 @@ function run(pc) { running = false; vm.blit(); if (now - lastSample >= 200) { - if (!audioAPI && sound) { + if (!audioAPI) { playSample(); } lastSample = now; diff --git a/js/disk2.js b/js/disk2.js index f92e74b..f037472 100644 --- a/js/disk2.js +++ b/js/disk2.js @@ -725,7 +725,7 @@ function DiskII(io, callbacks, slot) if (fmt === "2mg") { // Standard header size is 64 bytes. Make assumptions. var prefix = new Uint8Array(data.slice(0, 64)); - var data = data.slice(64); + data = data.slice(64); // Check image format. // Sure, it's really 64 bits. But only 2 are actually used. diff --git a/js/ui/Makefile b/js/ui/Makefile index 04779d2..bedfe49 100644 --- a/js/ui/Makefile +++ b/js/ui/Makefile @@ -1,8 +1,8 @@ JSLINT = jshint -JSFILES = copyright.js keyboard2.js printer.js +JSFILES = copyright.js audio.js keyboard2.js gamepad.js printer.js -JSFILES2E = copyright.js keyboard2e.js printer.js +JSFILES2E = copyright.js audio.js keyboard2e.js gamepad.js printer.js ALLJS = ${JSFILES} ${JSFILES2E} CHECKEDJS := $(patsubst %.js,.checked-%.js,${ALLJS}) diff --git a/js/ui/audio.js b/js/ui/audio.js new file mode 100644 index 0000000..2bfabfc --- /dev/null +++ b/js/ui/audio.js @@ -0,0 +1,135 @@ +/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* Copyright 2010-2014 Will Scullin + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +/*jshint jquery: true, browser: true */ +/*globals io: false, toHex:false, debug: false */ +/*exported playSample, enableSound, initAudio */ + +/* + * Audio Handling + */ + +var sound = true; + +// 8000 = 0x1f40 = 64, 31 +// 16000 = 0x3e80 = 128, 62 + +var wavHeader = + ['R','I','F','F',68 ,3 ,0 ,0 ,'W','A','V','E','f','m','t',' ', + 16 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,128,62 ,0 ,0 ,128,62 ,0 ,0 , + 1 ,0 ,8 ,0 ,'d','a','t','a',32 ,3 ,0 ,0 ]; + +function percentEncode(ary) { + var buf = ""; + for (var idx = 0; idx < ary.length; idx++) { + buf += "%" + toHex(ary[idx]); + } + return buf; +} + +wavHeader = $.map(wavHeader, function(n) { + return typeof(n) == "string" ? n.charCodeAt(0) : n; + }); + +var wavHeaderStr = percentEncode(wavHeader); + +var audioAPI = false; +var audioMoz = false; +var audioContext; +var audioNode; +var audio, audio2; + +function initAudio() { + if (typeof window.webkitAudioContext != "undefined") { + debug("Using Web Audio API"); + + audioAPI = true; + audioContext = new window.webkitAudioContext(); + audioNode = audioContext.createScriptProcessor(2048, 1, 1); + io.floatAudio(audioContext.sampleRate); + + audioNode.onaudioprocess = function(event) { + var data = event.outputBuffer.getChannelData(0); + var sample = io.getSample(); + for (var idx = 0; idx < data.length; idx++) { + if (idx < sample.length) { + data[idx] = sample[idx]; + } else { + data[idx] = 0; + } + } + }; + } else { + audio = document.createElement("audio"); + + if (audio.mozSetup) { + debug("Using Mozilla Audio API"); + audio.mozSetup(1, 16000); + io.floatAudio(16000); + audioMoz = true; + } else { + audio2 = document.createElement("audio"); + } + } +} + +function playSample() { + // [audio,audio2] = [audio2,audio]; + + var sample = io.getSample(); + + if (!sound) { + return; + } + + if (audioMoz) { + audio.mozWriteAudio(sample); + return; + } + + var tmp = audio; + audio = audio2; + audio2 = tmp; + + if (sample && sample.length) { + var len = sample.length, + buf = sample.join(""), + o1 = percentEncode([(len + 36) & 0xff, (len + 36) >> 8]), + o2 = percentEncode([len & 0xff, len >> 8]), + header = wavHeaderStr.replace("%44%03",o1).replace("%20%03", o2); + + audio.src = "data:audio/x-wav," + header + buf; + // debug(audio.src); + audio.play(); + } +} + +function enableSound(on) +{ + sound = on; + + if (audioAPI) { + if (sound) { + audioNode.connect(audioContext.destination); + } else { + audioNode.disconnect(); + } + } else { + if (sound) { + if (audio) audio.volume = 0.5; + if (audio2) audio2.volume = 0.5; + } else { + io.getSample(true); + } + } +} +