Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: audio input gain control #800

Merged
merged 10 commits into from
Jan 3, 2023
13 changes: 6 additions & 7 deletions src/application/setup-media.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,15 @@ async function setupMedia({ audioId, videoId, useDefaultDevices = false }) {
// Set up arrays for analyser
floatFrequencyDataArray = new Float32Array(analyserNode.frequencyBinCount);
byteFrequencyDataArray = new Uint8Array(analyserNode.frequencyBinCount);
byteTimeDomainDataArray = new Uint8Array(analyserNode.frequencyBinCount / 2);
byteTimeDomainDataArray = new Uint8Array(
analyserNode.frequencyBinCount / 2
);

// Create a gain node
this.gainNode = this.audioContext.createGain();

// Mute the node
this.gainNode.gain.value = 0;
// Default gain
this.gainNode.gain.value = 1;

// Create the audio input stream (audio)
this.audioStream = this.audioContext.createMediaStreamSource(
Expand All @@ -176,14 +178,11 @@ async function setupMedia({ audioId, videoId, useDefaultDevices = false }) {
// Connect the audio stream to the gain node (audio->(analyser)->gain)
this.audioStream.connect(this.gainNode);

// Connect the gain node to the output (audio->(analyser)->gain->destination)
this.gainNode.connect(this.audioContext.destination);

// Set up Meyda
// eslint-disable-next-line new-cap
this.meyda = new Meyda.createMeydaAnalyzer({
audioContext: this.audioContext,
source: this.audioStream,
source: this.gainNode,
bufferSize: constants.AUDIO_BUFFER_SIZE,
windowingFunction: "rect",
featureExtractors: ["complexSpectrum"]
Expand Down
55 changes: 16 additions & 39 deletions src/components/Controls/RangeControl.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
<template>
<div class="range-control" ref="container">
<canvas
v-tooltip
@mousedown.left="requestPointerLock"
@mouseup.left="exitPointerLock"
@click.right="toggleEditMode"
v-show="!editMode"
ref="canvas"
></canvas>
<Number
v-model="inputValue"
type="number"
:step="step"
@keypress.enter="toggleEditMode"
@click.right="toggleEditMode"
@input="numberInputHandler"
v-show="editMode"
ref="input"
/>
</div>
<RightClickNumberInput
v-bind="$props"
v-model="inputValue"
@input="numberInputHandler"
>
<div class="range-control" ref="container">
<canvas
@mousedown.left="requestPointerLock"
@mouseup.left="exitPointerLock"
ref="canvas"
></canvas>
</div>
</RightClickNumberInput>
</template>

<script>
import RightClickNumberInput from "../inputs/RightClickNumberInput.vue";
export default {
components: { RightClickNumberInput },
props: {
min: {
type: Number,
Expand All @@ -49,7 +44,6 @@ export default {
context: null,
active: false,
position: 0,
editMode: false,
inputValue: 0,
lastCursor: "",
spacingModifier: 1,
Expand Down Expand Up @@ -302,15 +296,6 @@ export default {
this.$emit("input", this.inputValue);
},

toggleEditMode(e) {
e.preventDefault();
this.editMode = !this.editMode;

if (this.editMode) {
this.$refs.input.focus();
}
},

keyDown(e) {
if (!this.mouseIsDown) {
return;
Expand Down Expand Up @@ -396,14 +381,6 @@ div {
width: 100%;
height: 16px;
display: inline-block;
}

input {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
vertical-align: top;
}
</style>
43 changes: 39 additions & 4 deletions src/components/InputDeviceConfig/AudioVideo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@
</grid>
</c>

<c span="1..">
<grid columns="4">
<c span="1">
Audio Gain
</c>
<c span="2">
<Range
:min="minGain"
:max="maxGain"
step="0.01"
v-model="gainRangeValue"
/>
</c>
<c>({{ gainRangeValue.toFixed(2) }})</c>
</grid>
</c>

<c span="1..">
<grid columns="4">
<c span="1">
Expand All @@ -57,7 +74,7 @@
<c span="1..">
<grid columns="4">
<c span="2+3">
<Button class="light" @click="renumerate">Re-scan devices</Button>
<Button class="light" @click="renumerate">Re-scan Devices</Button>
</c>
</grid>
</c>
Expand All @@ -71,13 +88,17 @@ export default {
data() {
return {
iVTitle: "Media Input Config",
iVBody:
"Configure your audio and video inputs here. Click Renumerate Devices to scan for new sources.",
iVBody: `Configure your audio and video inputs here. Click "Re-scan Devices" to scan for new sources.`,
2xAA marked this conversation as resolved.
Show resolved Hide resolved
switchingAudio: false,
switchingVideo: false
switchingVideo: false,
gainRangeValue: 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a value on data so we can keep track of what the value is doing.
Vue wasn't aware of the value before this.

We also update the value when the component is created below in the created function.

};
},

created() {
this.gainRangeValue = this.$modV.gainNode.gain.value ?? 1;
},

computed: {
audioInputs() {
const audioInputs = Object.values(
Expand Down Expand Up @@ -117,13 +138,27 @@ export default {
this.$modV.setupMedia({ videoId: value });
this.switchingVideo = false;
}
},

maxGain() {
return this.$modV.gainNode.gain.maxValue.toPrecision(1 + 2).split("e")[0];
2xAA marked this conversation as resolved.
Show resolved Hide resolved
},

minGain() {
return 0;
2xAA marked this conversation as resolved.
Show resolved Hide resolved
}
},

methods: {
renumerate() {
this.$modV.enumerateDevices();
}
},

watch: {
gainRangeValue(value) {
this.$modV.gainNode.gain.value = value;
}
}
};
</script>
Expand Down
49 changes: 37 additions & 12 deletions src/components/directives/ValueTooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ let tooltip = null;
let pre = null;
let vnode = null;
let setTooltipFromValue = true;
let isVisible = false;

function createTooltip() {
const existingTooltip = document.getElementById(TOOLTIP_ID);

if (existingTooltip) {
tooltip = existingTooltip;
pre = existingTooltip.querySelector("pre");
tooltip.style.display = "initial";
setTooltipVisibility();
return;
}

Expand Down Expand Up @@ -51,18 +52,27 @@ function setTooltipPosition(e) {
});
}

function setPreValue() {
function setPreValue(e) {
if (!vnode || !vnode.__vue__) {
return;
}

const value = parseFloat(vnode.__vue__.value, 10);

if (typeof value === "undefined") {
return;
let value = e;
if (!e) {
value = vnode.__vue__.value;
} else if (typeof e === "object" && e.target) {
value = e.target.value;
}

pre.innerHTML = value.toFixed(3);
vnode.__vue__.$nextTick(() => {
const parsedValue = parseFloat(value, 10);

if (typeof parsedValue === "undefined") {
return;
}

pre.innerHTML = parsedValue.toFixed(3);
});
}

function cleanUp() {
Expand All @@ -74,9 +84,7 @@ function cleanUp() {
window.removeEventListener("mousemove", mouseMove);
window.removeEventListener("mouseup", mouseUp);

if (tooltip) {
tooltip.style.display = "none";
}
setTooltipVisibility(false);
}

function mouseUp() {
Expand All @@ -92,6 +100,8 @@ function mouseMove(e) {
}

function mouseDown(e) {
window.addEventListener("mouseup", mouseUp);

if (e.button > 0) {
return;
}
Expand All @@ -107,7 +117,6 @@ function mouseDown(e) {

vnode.__vue__.$on("input", setPreValue);
window.addEventListener("mousemove", mouseMove);
window.addEventListener("mouseup", mouseUp);

createTooltip();
setTooltipPosition(e);
Expand Down Expand Up @@ -135,8 +144,18 @@ function mouseOver(e, message) {
pre.innerHTML = message;
}

function setTooltipVisibility(visible) {
const visibility = visible ?? isVisible;

if (tooltip) {
tooltip.style.display = visibility ? "initial" : "none";
}
}

Vue.directive("tooltip", {
inserted(el, { value: { mouseover, message } = {} }) {
inserted(el, { value: { visible, mouseover, message } = {} }) {
isVisible = visible ?? true;

if (!mouseover) {
el.addEventListener("mousedown", mouseDown);
} else {
Expand All @@ -145,6 +164,12 @@ Vue.directive("tooltip", {
}
},

update(el, { value: { visible } }) {
if (isVisible !== visible) {
isVisible = visible;
}
},

unbind() {
cleanUp();
}
Expand Down
1 change: 1 addition & 0 deletions src/components/inputs/Number.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ input {
padding: 0 4px;
box-sizing: border-box;
width: 100%;
vertical-align: top;
}
</style>
27 changes: 21 additions & 6 deletions src/components/inputs/Range.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
<template>
<input
type="range"
@input="$emit('input', parseFloat($event.target.value, 10))"
v-bind="$props"
v-tooltip
/>
<RightClickNumberInput v-bind="$props" @input="handleNumberInput">
<input
type="range"
@input="$emit('input', parseFloat($event.target.value, 10))"
v-bind="$props"
/>
</RightClickNumberInput>
</template>

<script>
import RightClickNumberInput from "./RightClickNumberInput.vue";

export default {
components: { RightClickNumberInput },
props: {
min: {},
max: {},
step: {},
value: {
default: 0
}
},

methods: {
handleNumberInput(value) {
let valueOut = parseFloat(value, 10);
if (isNaN(valueOut)) {
valueOut = 0;
}

this.$emit("input", valueOut);
}
}
};
</script>
Expand Down
Loading