Fixed a handful of audio glitches!!

Glitches mainly caused by assuming output array is empty.
It's not empty, it contains the samples of the previous chunk

- Integral and derivative processors no longer "click"
- Overlap no longer screams.
- Zero processor
This commit is contained in:
MindfulMinun
2020-08-05 01:18:21 -05:00
parent 6201f33d61
commit d4fcdb5f12
3 changed files with 62 additions and 15 deletions
+1 -1
View File
@@ -1 +1 @@
!function(e){var r={};function t(o){if(r[o])return r[o].exports;var s=r[o]={i:o,l:!1,exports:{}};return e[o].call(s.exports,s,s.exports,t),s.l=!0,s.exports}t.m=e,t.c=r,t.d=function(e,r,o){t.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:o})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,r){if(1&r&&(e=t(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(t.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var s in e)t.d(o,s,function(r){return e[r]}.bind(null,s));return o},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.p="",t(t.s=0)}([function(e,r){const t=Symbol();class o extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++)o[e].set(t[e]);return!0}}registerProcessor("noop",o);class s extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++){for(let r=0;r<t[0].length;r++)o[0][r]+=t[e][r]*(1/t.length);0!==e&&o[e].set(o[0])}return!0}}registerProcessor("mono",s);class n extends AudioWorkletProcessor{constructor(e){super(),this[t]=new Float32Array(e.processorOptions.maxChannels)}process(e,r){const o=e[0],s=r[0];for(let e=0;e<o.length;e++){s[e][0]=this[t][e];for(let r=1;r<o[e].length;r++)s[e][r]=o[e][r]-o[e][r-1];this[t][e]=o[e][o.length-1]}return!0}}registerProcessor("derivative",n);class l extends AudioWorkletProcessor{constructor(e){super(),this[t]=new Float32Array(e.processorOptions.maxChannels)}process(e,r){const o=e[0],s=r[0];for(let e=0;e<o.length;e++){s[e][0]=(this[t][e]+o[e][0])/2;for(let r=1;r<o[e].length;r++)s[e][r]=(o[e][r-1]+o[e][r])/2;this[t][e]=o[e][o.length-1]}return!0}}registerProcessor("integral",l);class c extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++)for(let r=0;r<t[e].length;r+=8){let s=0;for(let o=0;o<8;o++)s+=t[e][r+o];const n=s/8;for(let t=0;t<8;t++)o[e][r+t]=n}return!0}}registerProcessor("bit-crusher-sr8",c);class u extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++)for(let r=0;r<t[e].length;r++)o[e][r]=Math.round(16*t[e][r])/16;return!0}}registerProcessor("bit-crusher-res",u);class i extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++)for(let r=0;r<t[e].length;r+=8){let s=0;for(let o=0;o<8;o++)s+=Math.round(16*t[e][r])/16;const n=s/8;for(let t=0;t<8;t++)o[e][r+t]=n}return!0}}registerProcessor("bit-crusher-both",i);class f extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++){for(let r=0;r<t[e].length;r++)o[0][r]+=(e%2==0?1:-1)*t[e][r];0!==e&&o[e].set(o[0])}return!0}}registerProcessor("subtract-overlap",f);class a extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++)for(let r=0;r<t[e].length;r++)o[0][r]+=(e%2==0?1:-1)*t[e][r];for(let e=t.length-1;0<=e;e--)for(let r=0;r<t[e].length;r++)o[e][r]=t[e][r]-o[0][r];return!0}}registerProcessor("isolate-overlap",a)}]);
!function(e){var r={};function t(o){if(r[o])return r[o].exports;var s=r[o]={i:o,l:!1,exports:{}};return e[o].call(s.exports,s,s.exports,t),s.l=!0,s.exports}t.m=e,t.c=r,t.d=function(e,r,o){t.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:o})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,r){if(1&r&&(e=t(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(t.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var s in e)t.d(o,s,function(r){return e[r]}.bind(null,s));return o},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.p="",t(t.s=0)}([function(e,r){const t=Symbol();class o extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++)o[e].set(t[e]);return!0}}registerProcessor("noop",o);class s extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];o[0].set(t[0]);for(let e=1;e<t.length;e++)for(let r=0;r<t[0].length;r++)o[0][r]+=t[e][r]*(1/t.length);for(let e=1;e<o.length;e++)o[e].set(o[0]);return!0}}registerProcessor("mono",s);class n extends AudioWorkletProcessor{constructor(e){super(),this[t]=new Float32Array(e.processorOptions.maxChannels)}process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++){o[e][0]=o[e][o[e].length-1];for(let r=1;r<t[e].length;r++)o[e][r]=t[e][r]-t[e][r-1]}return!0}}registerProcessor("derivative",n);class l extends AudioWorkletProcessor{constructor(e){super(),this[t]=new Float32Array(e.processorOptions.maxChannels)}process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++){o[e][0]=o[e][o[e].length-1];for(let r=1;r<t[e].length;r++)o[e][r]=(t[e][r-1]+t[e][r])/2}return!0}}registerProcessor("integral",l);class c extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++)for(let r=0;r<t[e].length;r+=8){let s=0;for(let o=0;o<8;o++)s+=t[e][r+o];const n=s/8;for(let t=0;t<8;t++)o[e][r+t]=n}return!0}}registerProcessor("bit-crusher-sr8",c);class u extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++)for(let r=0;r<t[e].length;r++)o[e][r]=Math.round(16*t[e][r])/16;return!0}}registerProcessor("bit-crusher-res",u);class i extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];for(let e=0;e<t.length;e++)for(let r=0;r<t[e].length;r+=8){let s=0;for(let o=0;o<8;o++)s+=Math.round(16*t[e][r])/16;const n=s/8;for(let t=0;t<8;t++)o[e][r+t]=n}return!0}}registerProcessor("bit-crusher-both",i);class f extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];o[0].set(t[0]);for(let e=1;e<t.length;e++)for(let r=0;r<t[e].length;r++)o[0][r]+=t[e][r]*(e%2==0?1:-1);for(let e=1;e<o.length;e++)o[e].set(o[0]);return!0}}registerProcessor("subtract-overlap",f);class a extends AudioWorkletProcessor{process(e,r){const t=e[0],o=r[0];o[0].set(t[0]);for(let e=1;e<t.length;e++)for(let r=0;r<t[e].length;r++)o[0][r]+=(e%2==0?1:-1)*t[e][r];for(let e=t.length-1;0<=e;e--)for(let r=0;r<t[e].length;r++)o[e][r]=t[e][r]-o[0][r];return!0}}registerProcessor("isolate-overlap",a);class g extends AudioWorkletProcessor{process(e,r){for(let e=0;e<r.length;e++)for(let t=0;e<r.length;e++)for(let o=0;e<r.length;e++)r[e][t][o]=0;return!0}}registerProcessor("zeroes",g)}]);
+16
View File
@@ -93,6 +93,10 @@
padding: 1em;
z-index: 1;
}
.warn {
border: 2px solid red;
padding: 0 1em;
}
.spacer {
/* height: 90vh; */
height: 1000px;
@@ -123,6 +127,13 @@
<body>
<canvas></canvas>
<div class="container">
<div class="warn">
<p>
There’s currently a bug in Chrome that causes the <code>subtract-overlap</code> filter to glitch and scream.
Refrain from using it, it’ll hurt your years X(
</p>
<p>(This glitch doesn’t occur in Firefox, so maybe try that instead :) )</p>
</div>
<p>
Drag and drop an audio file anywhere or <button id="choose">choose one from your filesystem.</button>
</p>
@@ -139,6 +150,7 @@
<option value="bit-crusher-res">bit-crusher-res (bit-depth reduction)</option>
<option value="bit-crusher-both">bit-crusher-both</option>
<option value="mono">mono</option>
<option value="zeroes">zeroes</option>
</select>
</label>
<label>
@@ -197,6 +209,10 @@
Converts the audio to mono by taking the arithmetic average of the samples of each channel.
</p>
</li>
<li>
<code>zeroes</code>
<p>Outputs no sound.</p>
</li>
</ul>
<p class="credits">
+45 -14
View File
@@ -29,15 +29,16 @@ class Mono extends AudioWorkletProcessor {
const input = inputs[0]
const output = outputs[0]
for (let channel = 0; channel < input.length; channel++) {
output[0].set(input[0])
for (let channel = 1; channel < input.length; channel++) {
for (let sample = 0; sample < input[0].length; sample++) {
// Mono: (L + R) / 2
// More generally: 1/n * (\sum_{i = 0}^n C_i)
output[0][sample] += input[channel][sample] * (1 / input.length)
}
if (channel !== 0) {
output[channel].set(output[0])
}
}
for (let channel = 1; channel < output.length; channel++) {
output[channel].set(output[0])
}
return true
@@ -60,12 +61,12 @@ class DerivativeProcessor extends AudioWorkletProcessor {
const output = outputs[0]
for (let channel = 0; channel < input.length; channel++) {
output[channel][0] = this[carry][channel]
// Carry
output[channel][0] = output[channel][output[channel].length - 1]
for (let sample = 1; sample < input[channel].length; sample++) {
// dy/dx: (s2 - s1) / time
output[channel][sample] = input[channel][sample] - input[channel][sample - 1]
}
this[carry][channel] = input[channel][input.length - 1]
}
return true
@@ -89,12 +90,12 @@ class IntegralProcessor extends AudioWorkletProcessor {
const output = outputs[0]
for (let channel = 0; channel < input.length; channel++) {
output[channel][0] = (this[carry][channel] + input[channel][0]) / 2
// Carry
output[channel][0] = output[channel][output[channel].length - 1]
for (let sample = 1; sample < input[channel].length; sample++) {
// Integral of two samples: (time * (s1 + s2)) / 2
output[channel][sample] = (input[channel][sample - 1] + input[channel][sample]) / 2
}
this[carry][channel] = input[channel][input.length - 1]
}
return true
@@ -210,14 +211,20 @@ class SubtractOverlap extends AudioWorkletProcessor {
const input = inputs[0]
const output = outputs[0]
for (let channel = 0; channel < input.length; channel++) {
// OK, I think i figured out the problem.
// I can't assume that the output samples are zeroed out,
// they probably still have the previous chunk's samples.
output[0].set(input[0])
for (let channel = 1; channel < input.length; channel++) {
for (let sample = 0; sample < input[channel].length; sample++) {
output[0][sample] += (channel % 2 === 0 ? 1 : -1) * input[channel][sample]
}
if (channel !== 0) {
output[channel].set(output[0])
output[0][sample] += input[channel][sample] * (channel % 2 === 0 ? 1 : -1)
}
}
for (let channel = 1; channel < output.length; channel++) {
output[channel].set(output[0])
}
return true
}
@@ -239,8 +246,9 @@ class IsolateOverlap extends AudioWorkletProcessor {
const output = outputs[0]
// FIXME: I can't get this filter to work :/
output[0].set(input[0])
for (let channel = 0; channel < input.length; channel++) {
for (let channel = 1; channel < input.length; channel++) {
for (let sample = 0; sample < input[channel].length; sample++) {
output[0][sample] += (channel % 2 === 0 ? 1 : -1) * input[channel][sample]
}
@@ -257,3 +265,26 @@ class IsolateOverlap extends AudioWorkletProcessor {
}
}
registerProcessor('isolate-overlap', IsolateOverlap)
/**
* Plays nothing. Chrome fucks this up for some reason.
*/
class Zeroes extends AudioWorkletProcessor {
/**
* @param {Float32Array[][]} inputs
* @param {Float32Array[][]} outputs
*/
process(inputs, outputs) {
for (let i = 0; i < outputs.length; i++) {
for (let j = 0; i < outputs.length; i++) {
for (let k = 0; i < outputs.length; i++) {
outputs[i][j][k] = 0
}
}
}
return true
}
}
registerProcessor('zeroes', Zeroes)