diff --git a/compiler/package-lock.json b/compiler/package-lock.json index 73b9422..d097314 100644 --- a/compiler/package-lock.json +++ b/compiler/package-lock.json @@ -1,12 +1,12 @@ { "name": "@js2eel/compiler", - "version": "0.11.0", + "version": "0.11.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@js2eel/compiler", - "version": "0.11.0", + "version": "0.11.1", "license": "GPL-3.0", "dependencies": { "acorn": "8.12.1", diff --git a/compiler/package.json b/compiler/package.json index 3d3424c..38d3792 100644 --- a/compiler/package.json +++ b/compiler/package.json @@ -1,6 +1,6 @@ { "name": "@js2eel/compiler", - "version": "0.11.0", + "version": "0.11.1", "description": "Write REAPER JSFX/EEL2 plugins in JavaScript", "engines": { "node": ">=20.0.0" diff --git a/desktop/package-lock.json b/desktop/package-lock.json index b7cebaa..ef8046f 100644 --- a/desktop/package-lock.json +++ b/desktop/package-lock.json @@ -1,12 +1,12 @@ { "name": "js2eel-desktop", - "version": "0.11.0", + "version": "0.11.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "js2eel-desktop", - "version": "0.11.0", + "version": "0.11.1", "license": "GPL-3.0", "dependencies": { "@js2eel/compiler": "file:../compiler", diff --git a/desktop/package.json b/desktop/package.json index 9a8848c..bc2c5b0 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -1,6 +1,6 @@ { "name": "js2eel-desktop", - "version": "0.11.0", + "version": "0.11.1", "homepage": "https://js2eel.org", "description": "JS2EEL", "engines": { diff --git a/gui/package-lock.json b/gui/package-lock.json index ad2c9d1..5a493bf 100644 --- a/gui/package-lock.json +++ b/gui/package-lock.json @@ -1,12 +1,12 @@ { "name": "@js2eel/gui", - "version": "0.11.0", + "version": "0.11.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@js2eel/gui", - "version": "0.11.0", + "version": "0.11.1", "dependencies": { "@codemirror/lang-javascript": "6.2.2", "@codemirror/lang-json": "6.0.1", diff --git a/gui/package.json b/gui/package.json index ee44eb8..9fcf76b 100644 --- a/gui/package.json +++ b/gui/package.json @@ -1,7 +1,7 @@ { "name": "@js2eel/gui", "private": true, - "version": "0.11.0", + "version": "0.11.1", "engines": { "node": ">=20.0.0" }, diff --git a/gui/src/components/js2eel/examples/08_cab_sim.ts b/gui/src/components/js2eel/examples/08_cab_sim.ts new file mode 100644 index 0000000..0c1de8e --- /dev/null +++ b/gui/src/components/js2eel/examples/08_cab_sim.ts @@ -0,0 +1,171 @@ +export const EXAMPLE_CAB_SIM = { + path: 'example://cab_sim.js', + src: `config({ description: 'cab_sim', inChannels: 2, outChannels: 2, extTailSize: 32768 }); + +let fftSize = -1; +let needsReFft = true; +let convolutionSource = new EelBuffer(1, 131072); // 128 * 1024; +let lastAmpModel = -1; +let importedBuffer = new EelBuffer(1, 131072); // 128 * 1024; +let importedBufferChAmount = 0; +let importedBufferSize; +let chunkSize; +let chunkSize2x; +let bufferPosition; +let lastBlock = new EelBuffer(1, 65536); // 64 * 1024 +let currentBlock = new EelBuffer(1, 65536); // 64 * 1024 +let inverseFftSize; +const interpolationStepCount = 1.0; + +let ampModel; + +fileSelector(1, ampModel, 'amp_models', 'none', 'Impulse Response'); + +onSlider(() => { + if (ampModel !== lastAmpModel) { + lastAmpModel = ampModel; + + const fileHandle = file_open(ampModel); + + let importedBufferSampleRate = 0; + + if (fileHandle > 0) { + file_riff( + fileHandle, + importedBufferChAmount, + importedBufferSampleRate + ); + + if (importedBufferChAmount) { + importedBufferSize = + file_avail(fileHandle) / importedBufferChAmount; + + needsReFft = true; + + // FIXME multi dim buffer? + file_mem( + fileHandle, + importedBuffer.start(), + importedBufferSize * importedBufferChAmount + ); + } + + file_close(fileHandle); + } + } +}); + +onBlock(() => { + if (needsReFft) { + if (importedBufferSize > 16384) { + importedBufferSize = 16384; + } + + fftSize = 32; + + while (importedBufferSize > fftSize * 0.5) { + fftSize += fftSize; + } + + chunkSize = fftSize - importedBufferSize - 1; + chunkSize2x = chunkSize * 2; + bufferPosition = 0; + + inverseFftSize = 1 / fftSize; + + let i = 0; + let i2 = 0; + + let interpolationCounter = 0; + + while (interpolationCounter < min(fftSize, importedBufferSize)) { + const ipos = i; + const ipart = i - ipos; + + convolutionSource[0][i2] = + importedBuffer[0][ipos * importedBufferChAmount] * (1 - ipart) + + importedBuffer[0][(ipos + 1) * importedBufferChAmount - 1] * + ipart; + + convolutionSource[0][i2 + 1] = + importedBuffer[0][ipos * importedBufferChAmount - 1] * + (1 - ipart) + + importedBuffer[0][(ipos + 2) * importedBufferChAmount - 1] * + ipart; + + i += interpolationStepCount; + i2 += 2; + + interpolationCounter++; + } + + let zeroPadCounter = 0; + + while (zeroPadCounter < fftSize - importedBufferSize) { + convolutionSource[0][i2] = 0; + convolutionSource[0][i2 + 1] = 0; + i2 += 2; + + zeroPadCounter++; + } + + fft(convolutionSource.start(), fftSize); + + i = 0; + + let normalizeCounter = 0; + + while (normalizeCounter < fftSize * 2) { + convolutionSource[0][i] *= inverseFftSize; + i += 1; + + normalizeCounter++; + } + + needsReFft = false; + } +}); + +onSample(() => { + if (importedBufferSize > 0) { + if (bufferPosition >= chunkSize) { + lastBlock.swap(currentBlock); + + memset( + currentBlock.start() + chunkSize * 2, + 0, + (fftSize - chunkSize) * 2 + ); + + // Perform FFT on currentBlock, convolve, and perform inverse FFT + fft(currentBlock.start(), fftSize); + convolve_c( + currentBlock.start(), + convolutionSource.start(), + fftSize + ); + ifft(currentBlock.start(), fftSize); + + bufferPosition = 0; + } + + // Save sample + const bufferPosition2x = bufferPosition * 2; + + lastBlock[0][bufferPosition2x] = spl0; + lastBlock[0][bufferPosition2x + 1] = 0; + + spl0 = currentBlock[0][bufferPosition2x]; + spl1 = currentBlock[0][bufferPosition2x + 1]; + + // Apply overlap-and-add for block continuity + if (bufferPosition < fftSize - chunkSize) { + spl0 += lastBlock[0][chunkSize2x + bufferPosition2x]; + spl1 += lastBlock[0][chunkSize2x + bufferPosition2x + 1]; + } + + bufferPosition += 1; + } +}); +` +}; diff --git a/gui/src/constants.ts b/gui/src/constants.ts index 7fca51b..6a6a2c7 100644 --- a/gui/src/constants.ts +++ b/gui/src/constants.ts @@ -5,6 +5,7 @@ import { EXAMPLE_STEREO_DELAY_JS } from './components/js2eel/examples/04_stereo_ import { EXAMPLE_LOWPASS_JS } from './components/js2eel/examples/05_lowpass'; import { EXAMPLE_SATURATION_JS } from './components/js2eel/examples/06_saturation'; import { EXAMPLE_4BAND_EQ_JS } from './components/js2eel/examples/07_4band_eq'; +import { EXAMPLE_CAB_SIM } from './components/js2eel/examples/08_cab_sim'; import type { Js2EelLeftTab, Js2EelRightTab } from './types'; @@ -34,7 +35,8 @@ export const examples = [ EXAMPLE_STEREO_DELAY_JS, EXAMPLE_LOWPASS_JS, EXAMPLE_SATURATION_JS, - EXAMPLE_4BAND_EQ_JS + EXAMPLE_4BAND_EQ_JS, + EXAMPLE_CAB_SIM ]; export const COLORS = {