mirror of
https://github.com/whscullin/apple2js.git
synced 2024-01-12 14:14:38 +00:00
Audio cleanup.
This commit is contained in:
parent
8a761be9a9
commit
1dfbc0b61b
|
@ -360,7 +360,7 @@ function updateKHz() {
|
|||
}
|
||||
|
||||
/* Audio Handling */
|
||||
initAudio();
|
||||
initAudio(io);
|
||||
|
||||
function updateSound()
|
||||
{
|
||||
|
@ -418,7 +418,7 @@ function run(pc) {
|
|||
}
|
||||
|
||||
var ival = 30;
|
||||
var now, last = Date.now(), lastSample = last;
|
||||
var now, last = Date.now();
|
||||
var runFn = function() {
|
||||
now = Date.now();
|
||||
frames++;
|
||||
|
@ -445,12 +445,7 @@ function run(pc) {
|
|||
cpu.stepCycles(step);
|
||||
running = false;
|
||||
vm.blit();
|
||||
if (now - lastSample >= 200) {
|
||||
if (!audioAPI) {
|
||||
playSample();
|
||||
}
|
||||
lastSample = now;
|
||||
}
|
||||
io.sampleTick();
|
||||
}
|
||||
|
||||
processGamepad(io);
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
<script type="text/javascript" src="js/ramfactor.js"></script>
|
||||
<script type="text/javascript" src="js/thunderclock.js"></script>
|
||||
<script type="text/javascript" src="js/cpu6502.js"></script>
|
||||
<script type="text/javascript" src="js/base64.js"></script><
|
||||
<script type="text/javascript" src="js/base64.js"></script>
|
||||
<script type="text/javascript" src="js/ui/audio.js"></script>
|
||||
<script type="text/javascript" src="js/ui/keyboard2e.js"></script>
|
||||
<script type="text/javascript" src="js/ui/gamepad.js"></script>
|
||||
|
@ -353,7 +353,7 @@ function updateKHz() {
|
|||
}
|
||||
|
||||
/* Audio Handling */
|
||||
initAudio();
|
||||
initAudio(io);
|
||||
|
||||
function updateSound()
|
||||
{
|
||||
|
@ -411,7 +411,7 @@ function run(pc) {
|
|||
}
|
||||
|
||||
var ival = 30;
|
||||
var now, last = Date.now(), lastSample = last;
|
||||
var now, last = Date.now();
|
||||
var runFn = function() {
|
||||
now = Date.now();
|
||||
frames++;
|
||||
|
@ -439,12 +439,7 @@ function run(pc) {
|
|||
cpu.stepCycles(step);
|
||||
running = false;
|
||||
vm.blit();
|
||||
if (now - lastSample >= 200) {
|
||||
if (!audioAPI) {
|
||||
playSample();
|
||||
}
|
||||
lastSample = now;
|
||||
}
|
||||
io.sampleTick();
|
||||
}
|
||||
|
||||
processGamepad(io);
|
||||
|
|
|
@ -18,7 +18,8 @@ function Apple2IO(cpu, callbacks)
|
|||
"use strict";
|
||||
|
||||
var _hz = 1023000;
|
||||
var _rate = 16000;
|
||||
var _rate = 44000;
|
||||
var _sample_size = 4096;
|
||||
|
||||
var _cycles_per_sample = _hz / _rate;
|
||||
|
||||
|
@ -31,9 +32,10 @@ function Apple2IO(cpu, callbacks)
|
|||
var _sample = [];
|
||||
var _sampleTime = 0;
|
||||
|
||||
var _high = "%A0";
|
||||
var _mid = "%80";
|
||||
var _low = "%60";
|
||||
var _high = 0.5;
|
||||
var _low = -0.5;
|
||||
|
||||
var _audioListener = null;
|
||||
|
||||
var _trigger = 0;
|
||||
|
||||
|
@ -94,6 +96,20 @@ function Apple2IO(cpu, callbacks)
|
|||
|
||||
var _locs = [];
|
||||
|
||||
function _tick() {
|
||||
var now = cpu.cycles();
|
||||
var phase = _phase > 0 ? _high : _low;
|
||||
for (; _sampleTime < now; _sampleTime += _cycles_per_sample) {
|
||||
_sample.push(phase);
|
||||
if (_sample.length >= _sample_size) {
|
||||
if (_audioListener) {
|
||||
_audioListener(_sample);
|
||||
}
|
||||
_sample = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _access(off) {
|
||||
var result = 0;
|
||||
var now = cpu.cycles();
|
||||
|
@ -204,13 +220,8 @@ function Apple2IO(cpu, callbacks)
|
|||
if ('doublehires' in callbacks) callbacks.doublehires(true);
|
||||
break;
|
||||
case LOC.SPEAKER:
|
||||
if (_sampleTime) {
|
||||
var phase = _phase > 0 ? _high : _low;
|
||||
for (; _sampleTime < now; _sampleTime += _cycles_per_sample) {
|
||||
_sample.push(phase);
|
||||
}
|
||||
_phase = -_phase;
|
||||
}
|
||||
_phase = -_phase;
|
||||
_tick();
|
||||
break;
|
||||
case LOC.STROBE:
|
||||
_key &= 0x7f;
|
||||
|
@ -342,45 +353,14 @@ function Apple2IO(cpu, callbacks)
|
|||
paddle: function apple2io_paddle(p, v) {
|
||||
_paddle[p] = v;
|
||||
},
|
||||
getSample: function apple2io_getSample() {
|
||||
var result = _sample;
|
||||
var now = cpu.cycles();
|
||||
|
||||
var phase = _mid;
|
||||
if (_sample.length) {
|
||||
phase = _phase > 0 ? _high : _low;
|
||||
}
|
||||
for (; _sampleTime < now; _sampleTime += _cycles_per_sample) {
|
||||
_sample.push(phase);
|
||||
}
|
||||
|
||||
_sample = [];
|
||||
|
||||
return result;
|
||||
},
|
||||
floatAudio: function apple2io_floatAudio(rate) {
|
||||
_rate = rate;
|
||||
_low = -0.5;
|
||||
_mid = 0.0;
|
||||
_high = 0.5;
|
||||
|
||||
_cycles_per_sample = _hz / _rate;
|
||||
},
|
||||
byteAudio: function apple2io_byteAudio(rate) {
|
||||
_rate = rate;
|
||||
_low = 0xa0;
|
||||
_mid = 0x80;
|
||||
_high = 0x60;
|
||||
|
||||
_cycles_per_sample = _hz / _rate;
|
||||
},
|
||||
updateHz: function apple2io_updateHz(hz) {
|
||||
_hz = hz;
|
||||
|
||||
_cycles_per_sample = _hz / _rate;
|
||||
},
|
||||
setKeyBuffer: function apple2io_setKeyBuffer(buffer) {
|
||||
_buffer = buffer.split("");
|
||||
_buffer = buffer.split('');
|
||||
if (_buffer.length > 0) {
|
||||
_keyDown = true;
|
||||
_key = _buffer.shift().charCodeAt(0) | 0x80;
|
||||
|
@ -391,6 +371,19 @@ function Apple2IO(cpu, callbacks)
|
|||
debug('Tape length: ' + tape.length);
|
||||
_tape = tape;
|
||||
_tapeOffset = -1;
|
||||
},
|
||||
|
||||
sampleRate: function sampleRate(rate) {
|
||||
_rate = rate;
|
||||
_cycles_per_sample = _hz / _rate;
|
||||
},
|
||||
|
||||
sampleTick: function sampleTick() {
|
||||
_tick();
|
||||
},
|
||||
|
||||
addSampleListener: function addSampleListener(cb) {
|
||||
_audioListener = cb;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
159
js/ui/audio.js
159
js/ui/audio.js
|
@ -11,132 +11,69 @@
|
|||
*/
|
||||
|
||||
/*jshint jquery: true, browser: true */
|
||||
/*globals io: false, toHex:false, debug: false */
|
||||
/*exported playSample, enableSound, initAudio */
|
||||
/*globals debug: false */
|
||||
/*exported enableSound, initAudio */
|
||||
|
||||
/*
|
||||
* Audio Handling
|
||||
*/
|
||||
|
||||
var sound = true;
|
||||
var sound = true;
|
||||
var _samples = [];
|
||||
|
||||
// 8000 = 0x1f40 = 64, 31
|
||||
// 16000 = 0x3e80 = 128, 62
|
||||
var audioContext;
|
||||
var audioNode;
|
||||
var AC = window.webkitAudioContext || window.AudioContext;
|
||||
|
||||
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 ];
|
||||
if (typeof AC !== 'undefined') {
|
||||
audioContext = new AC();
|
||||
audioNode = audioContext.createScriptProcessor(4096, 1, 1);
|
||||
|
||||
function percentEncode(ary) {
|
||||
var buf = "";
|
||||
for (var idx = 0; idx < ary.length; idx++) {
|
||||
buf += "%" + toHex(ary[idx]);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
audioNode.onaudioprocess = function(event) {
|
||||
var data = event.outputBuffer.getChannelData(0);
|
||||
var sample = _samples.shift();
|
||||
var idx = 0;
|
||||
|
||||
wavHeader = $.map(wavHeader, function(n) {
|
||||
return typeof(n) == "string" ? n.charCodeAt(0) : n;
|
||||
});
|
||||
var len = data.length;
|
||||
if (sample) {
|
||||
len = Math.min(sample.length, len);
|
||||
for (; idx < len; idx++) {
|
||||
data[idx] = sample[idx];
|
||||
}
|
||||
}
|
||||
|
||||
var wavHeaderStr = percentEncode(wavHeader);
|
||||
for (; idx < data.length; idx++) {
|
||||
data[idx] = 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
var audioAPI = false;
|
||||
var audioMoz = false;
|
||||
var audioContext;
|
||||
var audioNode;
|
||||
var audio, audio2;
|
||||
/*
|
||||
// Create and specify parameters for the low-pass filter.
|
||||
var filter = audioContext.createBiquadFilter();
|
||||
filter.type = 'lowpass';
|
||||
filter.frequency.value = 11000;
|
||||
filter.connect(audioContext.destination);
|
||||
audioNode.connect(filter);
|
||||
*/
|
||||
|
||||
function initAudio() {
|
||||
var AC = window.webkitAudioContext || window.AudioContext;
|
||||
if (typeof AC != "undefined") {
|
||||
debug("Using Web Audio API");
|
||||
audioNode.connect(audioContext.destination);
|
||||
}
|
||||
|
||||
audioAPI = true;
|
||||
audioContext = new AC();
|
||||
audioNode = audioContext.createScriptProcessor(4096, 1, 1);
|
||||
io.floatAudio(audioContext.sampleRate);
|
||||
|
||||
audioNode.onaudioprocess = function(event) {
|
||||
var data = event.outputBuffer.getChannelData(0);
|
||||
var sample = io.getSample();
|
||||
|
||||
var delta = 1; // sample.length / data.length;
|
||||
|
||||
var idx, kdx;
|
||||
for (idx = 0, kdx = 0;
|
||||
idx < data.length && parseInt(kdx, 10) < sample.length;
|
||||
kdx += delta, idx++) {
|
||||
data[idx] = sample[parseInt(kdx, 10)];
|
||||
function initAudio(io) {
|
||||
if (audioContext) {
|
||||
debug('Using Webkit Audio');
|
||||
io.sampleRate(audioContext.sampleRate);
|
||||
io.addSampleListener(function(sample) {
|
||||
if (sound) {
|
||||
_samples.push(sample);
|
||||
while (_samples.length > 5) {
|
||||
_samples.shift();
|
||||
}
|
||||
}
|
||||
for (; idx < data.length; idx++) {
|
||||
data[idx] = sample[sample.length - 1];
|
||||
}
|
||||
};
|
||||
} else {
|
||||
audio = document.createElement("audio");
|
||||
|
||||
if (audio.mozSetup) {
|
||||
debug("Using Mozilla Audio API");
|
||||
audio.mozSetup(1, 16000);
|
||||
io.floatAudio(16000);
|
||||
audioMoz = true;
|
||||
} else {
|
||||
debug("Using audio elements");
|
||||
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(enable) {
|
||||
sound = enable;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user