Bitcrushers!
Added bit-crusher-sr8, bit-crusher-res, and bit-crusher-both Added a spacer so you can see the waveform better :)
This commit is contained in:
3 files changed
+107
-8
No files matched your search
Vendored
+1
-1
@@ -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];Math.pow(.5,8);for(let e=0;e<t.length;e++)for(let r=0;r<t[e].length;r++)o[e][r]=t[e][r];return!0}}registerProcessor("bit-crusher",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[0][r]+=(e%2==0?1:-1)*t[e][r];0!==e&&o[e].set(o[0])}return!0}}registerProcessor("subtract-overlap",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++)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",i)}]);
|
||||
!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)}]);
|
||||
+30
@@ -23,6 +23,7 @@
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
color: white;
|
||||
background-color: black;
|
||||
}
|
||||
body { display: flex; }
|
||||
a[href] { color: var(--accent); }
|
||||
@@ -73,6 +74,10 @@
|
||||
border-color: #448aff;
|
||||
}
|
||||
|
||||
button, select {
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: fixed;
|
||||
top: 0; left: 0; bottom: 0; right: 0;
|
||||
@@ -88,6 +93,12 @@
|
||||
padding: 1em;
|
||||
z-index: 1;
|
||||
}
|
||||
.spacer {
|
||||
/* height: 90vh; */
|
||||
height: 1000px;
|
||||
height: 90vh;
|
||||
height: calc(100vh - 6rem);
|
||||
}
|
||||
.credits {
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
@@ -124,6 +135,9 @@
|
||||
<option value="integral">integral</option>
|
||||
<option value="subtract-overlap">subtract-overlap</option>
|
||||
<option value="isolate-overlap" disabled>isolate-overlap</option>
|
||||
<option value="bit-crusher-sr8">bit-crusher-sr8 (Sample-rate reduction)</option>
|
||||
<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>
|
||||
</select>
|
||||
</label>
|
||||
@@ -163,6 +177,20 @@
|
||||
<code>isolate-overlap</code>
|
||||
<p>The opposite of subtract-overlap. You think it'd be simple but I can't get it to work :/</p>
|
||||
</li>
|
||||
<!-- bit-crusher-sr8
|
||||
bit-crusher-res -->
|
||||
<li>
|
||||
<code>bit-crusher-sr8</code>
|
||||
<p>Bitcrusher. Works by taking the average of 8 samples of the input and setting that average as the output for those 8 samples, effectively <strong>reducing the sampling rate</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<code>bit-crusher-res</code>
|
||||
<p>Bitcrusher. Works by <strong>reducing the resolution of each sample</strong> from a 32-bit float to a 8-bit float.</p>
|
||||
</li>
|
||||
<li>
|
||||
<code>bit-crusher-both</code>
|
||||
<p>Bitcrusher. Combines the output of bit-crusher-sr8 and bit-crusher-res.</p>
|
||||
</li>
|
||||
<li>
|
||||
<code>mono</code>
|
||||
<p>
|
||||
@@ -176,6 +204,8 @@
|
||||
•
|
||||
<a href="https://github.com/MindfulMinun/d-flat">Source code</a>
|
||||
</p>
|
||||
|
||||
<div class="spacer"></div>
|
||||
|
||||
</div>
|
||||
<input id="file" type="file" hidden>
|
||||
|
||||
@@ -102,8 +102,10 @@ class IntegralProcessor extends AudioWorkletProcessor {
|
||||
}
|
||||
registerProcessor('integral', IntegralProcessor)
|
||||
|
||||
|
||||
class BitCrusher extends AudioWorkletProcessor {
|
||||
/**
|
||||
* Sample-rate reduction
|
||||
*/
|
||||
class BitCrusher_Sr8 extends AudioWorkletProcessor {
|
||||
/**
|
||||
* @param {Float32Array[][]} inputs
|
||||
* @param {Float32Array[][]} outputs
|
||||
@@ -112,20 +114,87 @@ class BitCrusher extends AudioWorkletProcessor {
|
||||
const input = inputs[0]
|
||||
const output = outputs[0]
|
||||
|
||||
let phase = 1
|
||||
const step = 2 * Math.pow(.5, 8)
|
||||
const chunkSize = 1 << 3
|
||||
|
||||
for (let channel = 0; channel < input.length; channel++) {
|
||||
for (let sample = 0; sample < input[channel].length; sample++) {
|
||||
output[channel][sample] = input[channel][sample]
|
||||
for (let sample = 0; sample < input[channel].length; sample += chunkSize) {
|
||||
// Take the average of a few samples
|
||||
let sum = 0
|
||||
for (let i = 0; i < chunkSize; i++) {
|
||||
sum += input[channel][sample + i]
|
||||
}
|
||||
const avg = sum / chunkSize
|
||||
|
||||
// Set the output to the average, effectively reducing the sampling rate
|
||||
for (let i = 0; i < chunkSize; i++) {
|
||||
output[channel][sample + i] = avg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
registerProcessor('bit-crusher', BitCrusher)
|
||||
registerProcessor('bit-crusher-sr8', BitCrusher_Sr8)
|
||||
|
||||
/**
|
||||
* Resolution reduction
|
||||
*/
|
||||
class BitCrusher_Res extends AudioWorkletProcessor {
|
||||
/**
|
||||
* @param {Float32Array[][]} inputs
|
||||
* @param {Float32Array[][]} outputs
|
||||
*/
|
||||
process(inputs, outputs) {
|
||||
const input = inputs[0]
|
||||
const output = outputs[0]
|
||||
|
||||
const res = 16
|
||||
|
||||
// Resolution reduction
|
||||
for (let channel = 0; channel < input.length; channel++) {
|
||||
for (let sample = 0; sample < input[channel].length; sample++) {
|
||||
output[channel][sample] = Math.round(input[channel][sample] * res) / res
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
registerProcessor('bit-crusher-res', BitCrusher_Res)
|
||||
|
||||
class BitCrusher_Both extends AudioWorkletProcessor {
|
||||
/**
|
||||
* @param {Float32Array[][]} inputs
|
||||
* @param {Float32Array[][]} outputs
|
||||
*/
|
||||
process(inputs, outputs) {
|
||||
const input = inputs[0]
|
||||
const output = outputs[0]
|
||||
|
||||
const chunkSize = 1 << 3
|
||||
const res = 16
|
||||
|
||||
for (let channel = 0; channel < input.length; channel++) {
|
||||
for (let sample = 0; sample < input[channel].length; sample += chunkSize) {
|
||||
// Take the average of a few samples
|
||||
let sum = 0
|
||||
for (let i = 0; i < chunkSize; i++) {
|
||||
sum += Math.round(input[channel][sample] * res) / res
|
||||
}
|
||||
const avg = sum / chunkSize
|
||||
|
||||
// Set the output to the average, effectively reducing the sampling rate
|
||||
for (let i = 0; i < chunkSize; i++) {
|
||||
output[channel][sample + i] = avg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
registerProcessor('bit-crusher-both', BitCrusher_Both)
|
||||
|
||||
/**
|
||||
* Inverts the amplitude of every even-numbered channel and merges them to mono.
|
||||
|
||||
Reference in new issue
Block a user