databender 1.0.4 → 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +113 -12
- package/dist/databender.js +221 -2624
- package/index.js +218 -110
- package/package.json +4 -8
- package/rollup.config.js +12 -10
- package/tags +624 -2534
- package/effects/biquad.js +0 -27
- package/effects/bitcrusher.js +0 -7
- package/effects/chorus.js +0 -8
- package/effects/convolver.js +0 -10
- package/effects/detune.js +0 -20
- package/effects/gain.js +0 -5
- package/effects/index.js +0 -13
- package/effects/phaser.js +0 -9
- package/effects/pingPong.js +0 -8
- package/effects/playbackRate.js +0 -14
- package/random.js +0 -4
package/LICENSE.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright
|
|
1
|
+
Copyright 2025 Michael Vattuone
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
4
|
|
package/README.md
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Databender
|
|
2
2
|
|
|
3
|
-
**NOTE: This API may change wildly in v2... use at your own peril!**
|
|
4
|
-
|
|
5
3
|
This module allows for generation interesting visuals by misusing the Web Audio API.
|
|
6
4
|
Inspired by [David Byrne](https://www.youtube.com/watch?v=Gea9SYUdJeY) and [AudioShop](https://github.com/robertfoss/audio_shop/)
|
|
7
5
|
|
|
@@ -11,7 +9,7 @@ Full API documentation and such is _coming soon_.
|
|
|
11
9
|
|
|
12
10
|
The quickest way to get _something_ on the page:
|
|
13
11
|
|
|
14
|
-
- Run `npm i` in your project and make sure you have an image to point to somewhere.
|
|
12
|
+
- Run `npm i databender` in your project and make sure you have an image to point to somewhere.
|
|
15
13
|
- Paste the following snippet into `index.html` and point the image to the location of the image you'd like to bend.
|
|
16
14
|
|
|
17
15
|
```html
|
|
@@ -49,7 +47,7 @@ The quickest way to get _something_ on the page:
|
|
|
49
47
|
value: 0.0
|
|
50
48
|
}
|
|
51
49
|
};
|
|
52
|
-
const databender = new Databender(config);
|
|
50
|
+
const databender = new Databender({ config });
|
|
53
51
|
databender.bend(img, context);
|
|
54
52
|
};
|
|
55
53
|
|
|
@@ -64,22 +62,125 @@ The quickest way to get _something_ on the page:
|
|
|
64
62
|
- Start up a server (e.g. `python -m SimpleHTTPServer`)
|
|
65
63
|
- Behold!
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
Using an ES module aware bundler? You can import straight from npm:
|
|
68
66
|
|
|
69
67
|
```js
|
|
70
|
-
|
|
68
|
+
import Databender from "databender";
|
|
69
|
+
|
|
70
|
+
const databender = new Databender({ config });
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
Need to stick with a classic `<script>` tag that isn't module friendly? `npm run build` will drop an IIFE bundle into `dist/databender.js` that exposes `window.Databender` just like before. Drop that bundle on the page and the snippet above will still work.
|
|
74
74
|
|
|
75
|
-
###
|
|
75
|
+
### Custom effect chains
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
You can inject any Web Audio nodes (Tone.js, Pizzicato, TunaJS, etc.) and they'll be chained in the order you provide.
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
import Databender from 'databender';
|
|
81
|
+
|
|
82
|
+
const databender = new Databender({
|
|
83
|
+
effectsChain: [
|
|
84
|
+
({ context }) => {
|
|
85
|
+
const filter = context.createBiquadFilter();
|
|
86
|
+
filter.type = 'lowpass';
|
|
87
|
+
filter.frequency.value = 400;
|
|
88
|
+
return filter;
|
|
89
|
+
},
|
|
90
|
+
({ context }) => {
|
|
91
|
+
const gain = context.createGain();
|
|
92
|
+
gain.gain.value = 0.8;
|
|
93
|
+
return gain;
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
databender.bend(img, context);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Effect factories can return plain nodes or promises that resolve to nodes. Databender waits on any promises before it starts rendering, which makes it possible to do async setup on the `OfflineAudioContext` (for example, loading an `AudioWorklet` module for each render).
|
|
78
102
|
|
|
79
|
-
|
|
103
|
+
You can also decide how the chain is wired. By default every effect is connected in series. Pass `chainMode: 'parallel'` to fan the source out to each effect and feed each branch directly into the offline destination.
|
|
80
104
|
|
|
81
|
-
|
|
82
|
-
|
|
105
|
+
#### Example: Pizzicato effects
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
import Databender from 'databender';
|
|
109
|
+
import Pizzicato from 'pizzicato';
|
|
110
|
+
|
|
111
|
+
const swapPizzicatoContext = (EffectCtor, options) => ({ context }) => {
|
|
112
|
+
// swap pizzicato internal context=
|
|
113
|
+
const previous = Pizzicato.context;
|
|
114
|
+
Pizzicato.context = context;
|
|
115
|
+
const effect = new EffectCtor(options);
|
|
116
|
+
Pizzicato.context = previous;
|
|
117
|
+
return { input: effect.inputNode, output: effect.outputNode };
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const databender = new Databender({
|
|
121
|
+
effectsChain: [
|
|
122
|
+
swapPizzicatoContext(Pizzicato.Effects.Delay, {
|
|
123
|
+
feedback: 0.6,
|
|
124
|
+
time: 0.4,
|
|
125
|
+
mix: 0.5
|
|
126
|
+
}),
|
|
127
|
+
swapPizzicatoContext(Pizzicato.Effects.LowPassFilter, {
|
|
128
|
+
frequency: 1200,
|
|
129
|
+
peak: 10,
|
|
130
|
+
mix: 0.4
|
|
131
|
+
})
|
|
132
|
+
]
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
databender.bend(img, context);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
(Note: `swapPizzicatoContext` is a tiny helper that swaps Pizzicato's internal context to the offline one Databender uses during rendering, then returns the effect's input/output nodes so Databender can connect it in sequence.)
|
|
139
|
+
|
|
140
|
+
#### Example: AudioWorklet
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
import Databender from 'databender';
|
|
144
|
+
|
|
145
|
+
const useBitcrusher = async ({ context }) => {
|
|
146
|
+
await context.audioWorklet.addModule('/path/to/effects/bitcrusher.js');
|
|
147
|
+
return new AudioWorkletNode(context, 'bitcrusher');
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const databender = new Databender({
|
|
151
|
+
config,
|
|
152
|
+
effectsChain: [useBitcrusher],
|
|
153
|
+
chainMode: 'parallel'
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
databender.bend(img, context);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Because Databender spins up a brand new `OfflineAudioContext` for every render, the worklet module has to be registered on that context before the node is created. Returning a promise from your effect factory ensures the render waits for the module to load.
|
|
160
|
+
|
|
161
|
+
### Source parameters
|
|
162
|
+
|
|
163
|
+
Some tweaks (e.g. `detune` or `playbackRate`) must be applied directly to the `AudioBufferSourceNode` **before** it starts. Pass functions to `sourceParams` and they'll run prior to chaining any effects. Each factory receives the same payload (`{ context, source, config }`) as the regular effect chain.
|
|
164
|
+
|
|
165
|
+
```js
|
|
166
|
+
const databender = new Databender({
|
|
167
|
+
config,
|
|
168
|
+
sourceParams: [
|
|
169
|
+
({ source, config }) => {
|
|
170
|
+
const value = config?.detune?.value ?? 0;
|
|
171
|
+
source.detune.value = value;
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
effectsChain: [
|
|
175
|
+
useDelayEffect(),
|
|
176
|
+
useBitcrusher()
|
|
177
|
+
]
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Prerequisites
|
|
182
|
+
|
|
183
|
+
Google Chrome (ideally) and an open mind!
|
|
83
184
|
|
|
84
185
|
## Contributing
|
|
85
186
|
|