databender 1.0.3 → 2.0.0-alpha.0

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 CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2018 Michael Vattuone
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,105 @@ 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
- You might also prefer using this in a CommonJS manner:
65
+ Using an ES module aware bundler? You can import straight from npm:
68
66
 
69
67
  ```js
70
- const Databender = require("databender");
68
+ import Databender from "databender";
69
+
70
+ const databender = new Databender({ config });
71
71
  ```
72
72
 
73
- Since I am lazy, you'll need to deduce what config you want for each effect that is included by looking in the `effects` directory. At some point, this may be removed from the app, and it will be up to you to include whatever effects and dependencies you would like to use with your bent data.
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
- ### Prerequisites
75
+ ### Custom effect chains
76
76
 
77
- Google Chrome (ideally) and an open mind!
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).
102
+
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.
104
+
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
+ };
78
149
 
79
- ## Built With
150
+ const databender = new Databender({
151
+ config,
152
+ effectsChain: [useBitcrusher],
153
+ chainMode: 'parallel'
154
+ });
80
155
 
81
- - [TunaJS](https://github.com/Theodeus/tuna) - A splendid audio effects library.
82
- - [Rollup](https://github.com/rollup/rollup) - Module bundling
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
+ ### Prerequisites
162
+
163
+ Google Chrome (ideally) and an open mind!
83
164
 
84
165
  ## Contributing
85
166