-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit. Previously developed as part of mvls.
- Loading branch information
Nicholas Schreiber
authored and
Nicholas Schreiber
committed
Feb 25, 2024
0 parents
commit 4d92387
Showing
334 changed files
with
26,994 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
node_modules | ||
build | ||
npm-debug.log | ||
.DS_Store | ||
*.code-workspace |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# AWSM | ||
This is the second Version of the *AwesomeWaveSplineMachine*. It is a quite unique modular software synthesizer that utilizes dynamic *WaveSpline* synthesis. | ||
|
||
Click the link below to try the AWSM in your browser. | ||
|
||
🚀 [AWSM - AwesomeWaveSplineMachine](https://rnd7.github.io/awsm/dist/index.html) | ||
|
||
For more information consider one of the following links. | ||
|
||
📚 [User Guide](#user-guide) | ||
|
||
🏗 [Developer Guide](#developer-guide) | ||
|
||
🏛 [License](#license) | ||
|
||
# User guide | ||
|
||
[Back to top](#awsm) | ||
|
||
## Modes | ||
Toggle between Database | ||
|
||
## Views | ||
|
||
|
||
# Developer guide | ||
|
||
[Back to top](#awsm) | ||
|
||
|
||
```bash | ||
npm install | ||
``` | ||
|
||
```bash | ||
npm run build | ||
``` | ||
|
||
```bash | ||
npm run serve | ||
``` | ||
|
||
|
||
# License | ||
|
||
[Back to top](#awsm) | ||
|
||
Feel free to use this tool to make music or to test the limits of your speakers. I encourage this. When redistributing the software, be sure to understand the underlying license. Since I'm donating a considerable amount of my time to the opensource community, it's important to me that everything that builds on this is also available to everyone. | ||
|
||
This project is licensed under the GNU General Public License v3.0 | ||
|
||
Copyright (C) 2024 C. Nicholas Schreiber | ||
|
||
See [COPYING](https://rnd7.github.io/awsm-mkii/COPYING) for the license text or contact me for more information. | ||
|
||
The license applies to every file within this repository even if not explicitly stated within the source code of every module. | ||
|
||
Official GNU license page: [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.html) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
|
||
export default class AudioMetricsAnalyzer { | ||
|
||
#audioContext | ||
#analyserNode | ||
#audioMetrics | ||
#source | ||
#lastFrame = 0 | ||
constructor(audioContext) { | ||
this.#audioContext = audioContext | ||
this.#analyserNode = this.#audioContext.createAnalyser() | ||
this.#analyserNode.fftSize = 2048 | ||
this.#analyserNode.smoothingTimeConstant = 0.8 | ||
} | ||
|
||
connect(source) { | ||
if (this.#source) this.#source.disconnect(this.#analyserNode) | ||
this.#source = source | ||
this.#source.connect(this.#analyserNode) | ||
} | ||
|
||
update() { | ||
const now = Date.now() | ||
if (!this.#audioMetrics || this.#lastFrame >= now-10) return | ||
this.#lastFrame = now | ||
this.#analyserNode.getByteTimeDomainData(this.#audioMetrics.frame) | ||
} | ||
|
||
set audioMetrics(value) { | ||
this.#audioMetrics = value | ||
this.#audioMetrics.frame = new Uint8Array(this.#analyserNode.frequencyBinCount) | ||
this.#audioMetrics.callback = this.update.bind(this) | ||
} | ||
|
||
get audioMetrics() { | ||
return this.#audioMetrics | ||
} | ||
|
||
destroy() { | ||
this.#source.disconnect(this.#analyserNode) | ||
this.#audioMetrics = null | ||
this.#audioContext = null | ||
this.#analyserNode = null | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import interpolateLinear from "../math/interpolate-linear.js" | ||
|
||
class AudioSqueezeProcessor extends AudioWorkletProcessor { | ||
static get parameterDescriptors() { | ||
return [{ | ||
name: 'threshold', // threshold (0-1 normalized) | ||
defaultValue: 0.5, | ||
minValue: 0.0, | ||
maxValue: 1.0, | ||
automationRate: "a-rate", | ||
}, { | ||
name: 'scale', // scale | ||
defaultValue: 1, | ||
minValue: 0, | ||
maxValue: 10, | ||
automationRate: "a-rate", | ||
}, { | ||
name: 'potential', // loudness factor | ||
defaultValue: 0.0, | ||
minValue: 0, | ||
maxValue: 1, | ||
automationRate: "a-rate", | ||
}, { | ||
name: 'inputs', | ||
defaultValue: 0, | ||
minValue: 0, | ||
maxValue: 128, | ||
automationRate: "k-rate", | ||
}] | ||
} | ||
|
||
#bufferIndex = 0 | ||
|
||
#targetPeak = 0 | ||
#peak = 0 | ||
#peakIncrement = 0 | ||
#peakTime = 0 | ||
|
||
#buffer = new Float32Array(512) | ||
#output = new Float32Array(128) | ||
#delay = 512 | ||
|
||
constructor(...args) { | ||
super(...args) | ||
this.port.onmessage = (message) => { | ||
if (message.data.type === "destroy") { | ||
this.onDestroy() | ||
} | ||
} | ||
} | ||
|
||
onDestroy() { | ||
this.port.onmessage = null | ||
this.port.close() | ||
} | ||
|
||
process(inputs, outputs, parameters) { | ||
for (let outputIndex = 0; outputIndex < outputs.length; outputIndex++) { | ||
const output = outputs[outputIndex] | ||
for (let channelIndex = 0; channelIndex < output.length; channelIndex++) { | ||
const channel = output[channelIndex] | ||
if (outputIndex == 0 && channelIndex == 0) { | ||
if (channel.length != this.#buffer.length) { | ||
this.#output = new Float32Array(channel.length) | ||
} | ||
if (this.#buffer.length != this.#delay) { | ||
this.#buffer = new Float32Array(this.#delay) | ||
} | ||
} | ||
for (let sample = 0; sample < channel.length; sample++) { | ||
if (channelIndex == 0 && outputIndex == 0) { | ||
|
||
let amplitude = 0 | ||
for (let inputIndex = 0; inputIndex < inputs.length; inputIndex++) { | ||
const input = inputs[inputIndex] | ||
if (input.length) amplitude += input[channelIndex][sample] | ||
} | ||
|
||
this.#buffer[this.#bufferIndex] = amplitude | ||
|
||
let magnitude = Math.abs(amplitude) | ||
|
||
if (magnitude >= this.#targetPeak *.9) { | ||
this.#peakTime = 0 | ||
} | ||
if (magnitude >= this.#targetPeak) { | ||
this.#targetPeak = magnitude | ||
} | ||
this.#peakIncrement = (8 * this.#targetPeak) / this.#delay // min value to get from -peak to peak within delay | ||
|
||
if (this.#peak - this.#peakIncrement > this.#targetPeak) { | ||
this.#peak -= this.#peakIncrement | ||
} else if (this.#peak + this.#peakIncrement < this.#targetPeak) { | ||
this.#peak += this.#peakIncrement | ||
} else { | ||
this.#peak = this.#targetPeak | ||
} | ||
|
||
let liveAmplitude = this.#buffer[(this.#bufferIndex+1)%this.#buffer.length] || 0 | ||
let liveMagnitude = Math.abs(liveAmplitude) | ||
let liveSign = Math.sign(liveAmplitude) | ||
const overdrive = parameters.potential.length>1?parameters.potential[sample]:parameters.potential[0] | ||
const threshold = (parameters.threshold.length>1?parameters.threshold[sample]:parameters.threshold[0]) * .99 | ||
const scale = parameters.scale.length>1?parameters.scale[sample]:parameters.scale[0] | ||
let out = 0 | ||
let scaledMax = Math.max( | ||
threshold + (1-threshold) * scale, | ||
threshold + (1-threshold) * .5 | ||
) | ||
|
||
if (this.#peak > 0) { | ||
out = liveMagnitude / this.#peak | ||
if (out > threshold) { | ||
let rel = out - threshold | ||
let scaledRel = rel * scale | ||
out = threshold + interpolateLinear(rel, scaledRel, rel/(1-threshold)) | ||
} | ||
} | ||
out /= scaledMax | ||
if (this.#peak < 1) out = interpolateLinear(out * this.#peak, out, overdrive) | ||
|
||
this.#output[sample] = out * liveSign * .9999 | ||
|
||
if (this.#peakTime > this.#delay ) { | ||
this.#targetPeak = this.#targetPeak * .99999 | ||
} | ||
|
||
this.#bufferIndex = (this.#bufferIndex+1)%this.#buffer.length | ||
this.#peakTime++ | ||
|
||
} | ||
channel[sample] = this.#output[sample] | ||
|
||
|
||
} | ||
} | ||
} | ||
return true | ||
} | ||
} | ||
registerProcessor("audio-squeeze-processor", AudioSqueezeProcessor); |
Oops, something went wrong.