wip: big refactor
This commit is contained in:
115
AudioSender.js
Normal file
115
AudioSender.js
Normal file
@@ -0,0 +1,115 @@
|
||||
let audioContext;
|
||||
let CHANNELS = [];
|
||||
let DESTINATION;
|
||||
let ON_START;
|
||||
let ON_STOP;
|
||||
let ON_SEND;
|
||||
let CHANNEL_OSCILLATORS = [];
|
||||
let WAVE_FORM;
|
||||
|
||||
let stopOscillatorsTimeoutId;
|
||||
|
||||
export const changeConfiguration = ({
|
||||
channels,
|
||||
destination,
|
||||
startCallback,
|
||||
stopCallback,
|
||||
sendCallback,
|
||||
waveForm
|
||||
}) => {
|
||||
CHANNELS = channels;
|
||||
DESTINATION = destination;
|
||||
ON_START = startCallback;
|
||||
ON_STOP = stopCallback;
|
||||
ON_SEND = sendCallback;
|
||||
WAVE_FORM = waveForm;
|
||||
}
|
||||
|
||||
export const setAudioContext = ctx => audioContext = ctx;
|
||||
|
||||
function getAudioContext() {
|
||||
if(!audioContext) {
|
||||
throw 'Audio context not provided.';
|
||||
}
|
||||
if(audioContext.state === 'suspended') {
|
||||
audioContext.resume();
|
||||
}
|
||||
return audioContext;
|
||||
}
|
||||
|
||||
const getChannels = () => CHANNELS;
|
||||
const getDestination = () => DESTINATION;
|
||||
|
||||
export const now = () => getAudioContext().currentTime;
|
||||
|
||||
export function beginAt(streamStartSeconds) {
|
||||
stopTimeout();
|
||||
const oscillators = getOscillators();
|
||||
if(oscillators.length !== 0) stop();
|
||||
const audioContext = getAudioContext();
|
||||
const channels = getChannels();
|
||||
const channelCount = channels.length;
|
||||
const destination = getDestination();;
|
||||
// create our oscillators
|
||||
for(let i = 0; i < channelCount; i++) {
|
||||
const oscillator = audioContext.createOscillator();
|
||||
oscillator.connect(destination);
|
||||
oscillator.type = WAVE_FORM;
|
||||
oscillator.start(streamStartSeconds);
|
||||
oscillators.push(oscillator);
|
||||
}
|
||||
callFn(ON_START);
|
||||
return oscillators;
|
||||
}
|
||||
function getOscillators() {
|
||||
return CHANNEL_OSCILLATORS;
|
||||
}
|
||||
export function send(bits, startSeconds) {
|
||||
const oscillators = getOscillators();
|
||||
getChannels().forEach((channel, i) => {
|
||||
// send missing bits as zero
|
||||
const isHigh = bits[i] ?? 0;
|
||||
callFn(ON_SEND, isHigh);
|
||||
const oscillator = oscillators[i];
|
||||
// already at correct frequency
|
||||
if(oscillator.on === isHigh) return;
|
||||
oscillator.on = isHigh;
|
||||
const hz = channel[isHigh ? 1 : 0];
|
||||
oscillator.frequency.setValueAtTime(hz, startSeconds);
|
||||
});
|
||||
}
|
||||
const stopTimeout = () => {
|
||||
if(stopOscillatorsTimeoutId) {
|
||||
window.setTimeout(stopOscillatorsTimeoutId);
|
||||
stopOscillatorsTimeoutId = undefined;
|
||||
}
|
||||
}
|
||||
export function stopAt(streamEndSeconds) {
|
||||
const channels = getChannels();
|
||||
const oscillators = getOscillators();
|
||||
const channelCount = channels.length;
|
||||
// silence oscillators when done
|
||||
for(let channel = 0; channel < channelCount; channel++) {
|
||||
const oscillator = oscillators[channel];
|
||||
oscillator?.stop(streamEndSeconds);
|
||||
}
|
||||
stopTimeout();
|
||||
stopOscillatorsTimeoutId = window.setTimeout(
|
||||
stop,
|
||||
(streamEndSeconds - now()) * 1000
|
||||
);
|
||||
}
|
||||
export function stop() {
|
||||
const time = now();
|
||||
const oscillators = getOscillators();
|
||||
oscillators.forEach(
|
||||
oscillator => {
|
||||
oscillator?.stop(time);
|
||||
oscillator?.disconnect();
|
||||
}
|
||||
)
|
||||
oscillators.length = 0;
|
||||
callFn(ON_STOP);
|
||||
stopTimeout();
|
||||
}
|
||||
const callFn = (fn, ...args) => typeof fn === 'function' ? fn(...args) : 0;
|
||||
Reference in New Issue
Block a user