@react-synth/synth 0.0.6-alpha → 0.1.0-alpha
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/README.md +256 -82
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -7,10 +7,20 @@ Should you use it? I don't know, you are an adult.
|
|
|
7
7
|
|
|
8
8
|
## How It Works
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Init new repository and install react-synth and its dependencies:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm init
|
|
14
|
+
npm i @react-synth/synth react
|
|
15
|
+
npm i -D @types/react
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then create new `.tsx` file. React-synth requires created file to have default
|
|
19
|
+
export with ReactNode. For example, you can paste below code:
|
|
11
20
|
|
|
12
21
|
```tsx
|
|
13
22
|
// song.tsx
|
|
23
|
+
import React from "react";
|
|
14
24
|
import {
|
|
15
25
|
Chord,
|
|
16
26
|
Loop,
|
|
@@ -58,129 +68,293 @@ Then run it with:
|
|
|
58
68
|
npx react-synth song.tsx
|
|
59
69
|
```
|
|
60
70
|
|
|
71
|
+
Now any change made to the code will cause hot reload without disruption.
|
|
72
|
+
|
|
61
73
|
## Components
|
|
62
74
|
|
|
63
|
-
### `<Track
|
|
75
|
+
### `<Track>`
|
|
76
|
+
|
|
77
|
+
Root component that sets the tempo and provides audio context. All other
|
|
78
|
+
components must be nested inside a Track.
|
|
64
79
|
|
|
65
|
-
|
|
80
|
+
| Prop | Type | Default | Description |
|
|
81
|
+
| ---------- | ----------- | ------- | --------------------------------------- |
|
|
82
|
+
| `bpm` | `number` | — | **Required.** Tempo in beats per minute |
|
|
83
|
+
| `children` | `ReactNode` | — | Child components to render |
|
|
66
84
|
|
|
67
|
-
|
|
85
|
+
```tsx
|
|
86
|
+
<Track bpm={120}>
|
|
87
|
+
{/* Your music components here */}
|
|
88
|
+
</Track>;
|
|
89
|
+
```
|
|
68
90
|
|
|
69
|
-
|
|
91
|
+
---
|
|
70
92
|
|
|
71
|
-
### `<
|
|
93
|
+
### `<Loop>`
|
|
72
94
|
|
|
73
|
-
|
|
95
|
+
Repeats its children at a specified beat interval. Use this for drum patterns,
|
|
96
|
+
repeating melodies, or any cyclical musical phrase.
|
|
74
97
|
|
|
75
|
-
|
|
76
|
-
|
|
98
|
+
| Prop | Type | Default | Description |
|
|
99
|
+
| ---------- | ----------- | ------- | --------------------------------------------------- |
|
|
100
|
+
| `id` | `string` | — | **Required.** Unique identifier for this loop |
|
|
101
|
+
| `interval` | `number` | — | **Required.** Interval in beats between repetitions |
|
|
102
|
+
| `children` | `ReactNode` | — | Content to play on each loop iteration |
|
|
77
103
|
|
|
78
|
-
|
|
104
|
+
```tsx
|
|
105
|
+
{/* Kick drum every beat */}
|
|
106
|
+
<Loop id="kick" interval={1}>
|
|
107
|
+
<Sample name="bd_haus" />
|
|
108
|
+
</Loop>;
|
|
109
|
+
|
|
110
|
+
{/* Chord progression every 4 beats */}
|
|
111
|
+
<Loop id="chords" interval={4}>
|
|
112
|
+
<Chord notes="Am7" />
|
|
113
|
+
</Loop>;
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
79
117
|
|
|
80
|
-
|
|
118
|
+
### `<Sequence>`
|
|
81
119
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
- `attack`, `decay`, `sustain`, `release` - ADSR envelope in beats
|
|
85
|
-
- `oscillator` - Override synth oscillator type
|
|
86
|
-
- `filter` - Override filter settings `{ cutoff, resonance, type }`
|
|
87
|
-
- `voices` - Override voice settings `{ count, detune, spread }`
|
|
120
|
+
Plays children one after another with a specified interval between each. Each
|
|
121
|
+
child is played at its index position × interval beats.
|
|
88
122
|
|
|
89
|
-
|
|
123
|
+
| Prop | Type | Default | Description |
|
|
124
|
+
| ---------- | ----------- | ------- | --------------------------------------------- |
|
|
125
|
+
| `interval` | `number` | — | **Required.** Time between each step in beats |
|
|
126
|
+
| `children` | `ReactNode` | — | Steps to play in order |
|
|
90
127
|
|
|
91
|
-
|
|
128
|
+
```tsx
|
|
129
|
+
{/* Arpeggio: C-E-G-C played as 16th notes */}
|
|
130
|
+
<Sequence interval={0.25}>
|
|
131
|
+
<Note note="C4" />
|
|
132
|
+
<Note note="E4" />
|
|
133
|
+
<Note note="G4" />
|
|
134
|
+
<Note note="C5" />
|
|
135
|
+
</Sequence>;
|
|
136
|
+
|
|
137
|
+
{/* Drum pattern */}
|
|
138
|
+
<Sequence interval={0.5}>
|
|
139
|
+
<Sample name="bd_haus" />
|
|
140
|
+
<Sample name="drum_snare_soft" />
|
|
141
|
+
<Sample name="bd_haus" />
|
|
142
|
+
<Sample name="drum_snare_soft" />
|
|
143
|
+
</Sequence>;
|
|
144
|
+
```
|
|
92
145
|
|
|
93
|
-
|
|
94
|
-
- Same ADSR and synth overrides as `<Note>`
|
|
146
|
+
---
|
|
95
147
|
|
|
96
|
-
### `<
|
|
148
|
+
### `<Synth>`
|
|
97
149
|
|
|
98
|
-
|
|
150
|
+
Defines the synthesizer configuration for child `Note` and `Chord` components.
|
|
151
|
+
Provides preset sounds and allows customization of oscillator, filter, and voice
|
|
152
|
+
parameters.
|
|
99
153
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
154
|
+
| Prop | Type | Default | Description |
|
|
155
|
+
| ------------ | ----------------------- | ------- | --------------------------------------------------------------------- |
|
|
156
|
+
| `type` | `SynthType` | — | **Required.** Synth preset name (see below) |
|
|
157
|
+
| `oscillator` | `OscillatorType` | — | Override oscillator: `"sine"`, `"square"`, `"sawtooth"`, `"triangle"` |
|
|
158
|
+
| `filter` | `Partial<FilterConfig>` | — | Override filter settings |
|
|
159
|
+
| `voices` | `Partial<VoiceConfig>` | — | Override voice/unison settings |
|
|
160
|
+
| `children` | `ReactNode` | — | Note/Chord components to apply this synth to |
|
|
105
161
|
|
|
106
|
-
|
|
162
|
+
**Available Synth Presets:**
|
|
107
163
|
|
|
108
|
-
|
|
164
|
+
| Preset | Description |
|
|
165
|
+
| ----------------- | ---------------------------------------------------- |
|
|
166
|
+
| `"sine"` | Pure sine wave - clean, fundamental tone |
|
|
167
|
+
| `"saw"` | Sawtooth wave - bright, harmonically rich |
|
|
168
|
+
| `"square"` | Square wave - hollow, clarinet-like |
|
|
169
|
+
| `"tri"` | Triangle wave - soft, flute-like |
|
|
170
|
+
| `"prophet"` | Prophet-5 inspired - warm with detuned voices |
|
|
171
|
+
| `"hollow"` | Ethereal pad - filtered square, atmospheric |
|
|
172
|
+
| `"dark_ambience"` | Deep atmospheric pad - low-passed with many voices |
|
|
173
|
+
| `"bass"` | Punchy bass - filtered sawtooth |
|
|
174
|
+
| `"pluck"` | Bright plucked string - square wave with high cutoff |
|
|
109
175
|
|
|
110
|
-
|
|
176
|
+
**Filter Config:**
|
|
111
177
|
|
|
112
|
-
|
|
113
|
-
|
|
178
|
+
| Property | Type | Description |
|
|
179
|
+
| ----------- | ------------------ | --------------------------------------------- |
|
|
180
|
+
| `type` | `FilterType` | `"lowpass"`, `"highpass"`, `"bandpass"`, etc. |
|
|
181
|
+
| `cutoff` | `number` or `Line` | Cutoff frequency in Hz, or a Line pattern |
|
|
182
|
+
| `resonance` | `number` | Filter resonance/Q factor |
|
|
183
|
+
|
|
184
|
+
**Voice Config:**
|
|
185
|
+
|
|
186
|
+
| Property | Type | Description |
|
|
187
|
+
| -------- | -------- | ------------------------------------ |
|
|
188
|
+
| `count` | `number` | Number of oscillator voices (unison) |
|
|
189
|
+
| `detune` | `number` | Detune spread in cents |
|
|
190
|
+
| `spread` | `number` | Stereo spread 0-1 |
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
{/* Using a preset */}
|
|
194
|
+
<Synth type="prophet">
|
|
195
|
+
<Note note="C4" />
|
|
196
|
+
</Synth>;
|
|
197
|
+
|
|
198
|
+
{/* Overriding filter settings */}
|
|
199
|
+
<Synth type="saw" filter={{ cutoff: 2000, resonance: 8 }}>
|
|
200
|
+
<Chord notes="Am7" />
|
|
201
|
+
</Synth>;
|
|
202
|
+
|
|
203
|
+
{/* Thick unison lead */}
|
|
204
|
+
<Synth type="saw" voices={{ count: 4, detune: 15, spread: 0.8 }}>
|
|
205
|
+
<Note note="A4" />
|
|
206
|
+
</Synth>;
|
|
114
207
|
```
|
|
115
208
|
|
|
116
|
-
|
|
209
|
+
---
|
|
117
210
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
211
|
+
### `<Note>`
|
|
212
|
+
|
|
213
|
+
Plays a single note using Web Audio oscillators with ADSR envelope. Inherits
|
|
214
|
+
synth settings from parent `<Synth>` component, or uses defaults.
|
|
215
|
+
|
|
216
|
+
| Prop | Type | Default | Description |
|
|
217
|
+
| --------------- | ----------------------- | --------------- | ------------------------------------------------------------ |
|
|
218
|
+
| `note` | `string` or `number` | — | **Required.** Note name (`"C4"`, `"A#3"`) or frequency in Hz |
|
|
219
|
+
| `amp` | `number` | `0.3` | Amplitude/volume 0-1 |
|
|
220
|
+
| `attack` | `number` | `0` | Attack time in beats |
|
|
221
|
+
| `attack_level` | `number` | `1` | Peak level at end of attack (multiplied by amp) |
|
|
222
|
+
| `decay` | `number` | `0` | Decay time in beats |
|
|
223
|
+
| `decay_level` | `number` | `sustain_level` | Level at end of decay |
|
|
224
|
+
| `sustain` | `number` | `0` | Sustain time in beats |
|
|
225
|
+
| `sustain_level` | `number` | `1` | Sustained level (multiplied by amp) |
|
|
226
|
+
| `release` | `number` | `1` | Release time in beats |
|
|
227
|
+
| `oscillator` | `OscillatorType` | — | Override synth oscillator type |
|
|
228
|
+
| `filter` | `Partial<FilterConfig>` | — | Override filter settings |
|
|
229
|
+
| `voices` | `Partial<VoiceConfig>` | — | Override voice settings |
|
|
230
|
+
|
|
231
|
+
**Note Duration:** Total duration = `attack` + `decay` + `sustain` + `release`
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
{/* Simple note */}
|
|
235
|
+
<Note note="A4" />;
|
|
236
|
+
|
|
237
|
+
{/* Note with envelope */}
|
|
238
|
+
<Note note="C4" amp={0.5} attack={0.1} sustain={0.5} release={0.3} />;
|
|
239
|
+
|
|
240
|
+
{/* Note with frequency in Hz */}
|
|
241
|
+
<Note note={440} />;
|
|
121
242
|
|
|
122
|
-
|
|
123
|
-
|
|
243
|
+
{/* Note with filter override */}
|
|
244
|
+
<Note note="E4" filter={{ cutoff: 800, resonance: 5 }} />;
|
|
124
245
|
```
|
|
125
246
|
|
|
126
|
-
|
|
247
|
+
---
|
|
127
248
|
|
|
128
|
-
|
|
249
|
+
### `<Chord>`
|
|
129
250
|
|
|
130
|
-
|
|
251
|
+
Plays multiple notes simultaneously. Supports chord name notation (powered by
|
|
252
|
+
Tonal) or explicit note arrays.
|
|
131
253
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
254
|
+
| Prop | Type | Default | Description |
|
|
255
|
+
| --------------- | -------------------------------- | --------------- | ------------------------------------------ |
|
|
256
|
+
| `notes` | `string` or `(string\|number)[]` | — | **Required.** Chord name or array of notes |
|
|
257
|
+
| `amp` | `number` | `0.3` | Amplitude/volume 0-1 |
|
|
258
|
+
| `attack` | `number` | `0` | Attack time in beats |
|
|
259
|
+
| `attack_level` | `number` | `1` | Peak level at end of attack |
|
|
260
|
+
| `decay` | `number` | `0` | Decay time in beats |
|
|
261
|
+
| `decay_level` | `number` | `sustain_level` | Level at end of decay |
|
|
262
|
+
| `sustain` | `number` | `0` | Sustain time in beats |
|
|
263
|
+
| `sustain_level` | `number` | `1` | Sustained level |
|
|
264
|
+
| `release` | `number` | `1` | Release time in beats |
|
|
265
|
+
| `oscillator` | `OscillatorType` | — | Override synth oscillator type |
|
|
266
|
+
| `filter` | `Partial<FilterConfig>` | — | Override filter settings |
|
|
267
|
+
| `voices` | `Partial<VoiceConfig>` | — | Override voice settings |
|
|
268
|
+
|
|
269
|
+
**Chord Name Format:**
|
|
270
|
+
|
|
271
|
+
- Basic: `"C"`, `"Am"`, `"F#m"`, `"Bb"`
|
|
272
|
+
- Extended: `"Cmaj7"`, `"Dm7"`, `"G7"`, `"Am9"`
|
|
273
|
+
- With octave: `"Cmaj7:4"` (plays in octave 4, default is octave 3)
|
|
274
|
+
- Slash chords: `"Dm7/F"`, `"C/E"`
|
|
135
275
|
|
|
136
|
-
|
|
137
|
-
|
|
276
|
+
```tsx
|
|
277
|
+
{/* Chord name */}
|
|
278
|
+
<Chord notes="Am7" />;
|
|
279
|
+
|
|
280
|
+
{/* Chord in specific octave */}
|
|
281
|
+
<Chord notes="Cmaj7:4" />;
|
|
282
|
+
|
|
283
|
+
{/* Note array */}
|
|
284
|
+
<Chord notes={["C4", "E4", "G4"]} />;
|
|
138
285
|
|
|
139
|
-
|
|
140
|
-
|
|
286
|
+
{/* Frequency array */}
|
|
287
|
+
<Chord notes={[261.63, 329.63, 392.00]} />;
|
|
141
288
|
|
|
142
|
-
|
|
143
|
-
|
|
289
|
+
{/* With envelope for pad sound */}
|
|
290
|
+
<Chord notes="Em7" amp={0.4} attack={0.5} sustain={2} release={1} />;
|
|
144
291
|
```
|
|
145
292
|
|
|
146
|
-
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
### `<Sample>`
|
|
296
|
+
|
|
297
|
+
Plays an audio sample file with optional effects. Samples are loaded from a
|
|
298
|
+
built-in sample library.
|
|
299
|
+
|
|
300
|
+
| Prop | Type | Default | Description |
|
|
301
|
+
| -------- | ------------------ | ------- | -------------------------------------------------- |
|
|
302
|
+
| `name` | `SampleName` | — | **Required.** Sample name (without file extension) |
|
|
303
|
+
| `amp` | `number` | `1` | Amplitude/volume multiplier |
|
|
304
|
+
| `cutoff` | `number` or `Line` | `20000` | Lowpass filter cutoff (MIDI note or Hz) |
|
|
305
|
+
| `rate` | `number` | `1` | Playback rate multiplier |
|
|
306
|
+
| `pan` | `number` | `0` | Stereo pan position: -1 (left) to 1 (right) |
|
|
147
307
|
|
|
308
|
+
**Cutoff Values (MIDI note → Hz):**
|
|
309
|
+
|
|
310
|
+
- `60` → ~262 Hz (C4)
|
|
311
|
+
- `80` → ~831 Hz
|
|
312
|
+
- `100` → ~2637 Hz
|
|
313
|
+
- `110` → ~4699 Hz
|
|
314
|
+
- `130` → ~20kHz (no filtering)
|
|
315
|
+
|
|
316
|
+
```tsx
|
|
317
|
+
{/* Basic kick drum */}
|
|
318
|
+
<Sample name="bd_haus" />;
|
|
319
|
+
|
|
320
|
+
{/* Louder with filter */}
|
|
321
|
+
<Sample name="bd_haus" amp={2} cutoff={100} />;
|
|
322
|
+
|
|
323
|
+
{/* Hi-hat with pitch shift and panning */}
|
|
324
|
+
<Sample name="drum_cymbal_closed" rate={1.2} pan={0.3} />;
|
|
325
|
+
|
|
326
|
+
{/* Snare with lowpass filter */}
|
|
327
|
+
<Sample name="drum_snare_soft" cutoff={80} amp={0.8} />;
|
|
148
328
|
```
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
│ └── utils/
|
|
166
|
-
│ ├── envelope.ts # ADSR envelope
|
|
167
|
-
│ ├── line.ts # Value interpolation
|
|
168
|
-
│ └── notes.ts # Note/chord utilities
|
|
169
|
-
├── cli/
|
|
170
|
-
│ └── cli.ts # CLI entry point (includes React + JSDOM setup)
|
|
171
|
-
├── examples/
|
|
172
|
-
│ └── simple/
|
|
173
|
-
│ └── simple.tsx # Demo song
|
|
174
|
-
├── dist/ # Build output
|
|
175
|
-
├── package.json
|
|
176
|
-
├── tsconfig.json
|
|
177
|
-
└── vite.config.ts
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Line Patterns
|
|
333
|
+
|
|
334
|
+
The `cutoff` prop on `<Note>`, `<Chord>`, and `<Sample>` components supports
|
|
335
|
+
Line patterns for dynamic filter sweeps within a `<Sequence>`:
|
|
336
|
+
|
|
337
|
+
```tsx
|
|
338
|
+
<Sequence interval={0.25}>
|
|
339
|
+
{/* Filter sweeps from 60 to 120 over 8 steps */}
|
|
340
|
+
<Note note="C4" filter={{ cutoff: { from: 60, to: 120, steps: 8 } }} />
|
|
341
|
+
<Note note="E4" filter={{ cutoff: { from: 60, to: 120, steps: 8 } }} />
|
|
342
|
+
<Note note="G4" filter={{ cutoff: { from: 60, to: 120, steps: 8 } }} />
|
|
343
|
+
{/* ... */}
|
|
344
|
+
</Sequence>;
|
|
178
345
|
```
|
|
179
346
|
|
|
347
|
+
| Property | Type | Description |
|
|
348
|
+
| -------- | --------- | --------------------------------- |
|
|
349
|
+
| `from` | `number` | Starting cutoff value (MIDI note) |
|
|
350
|
+
| `to` | `number` | Ending cutoff value (MIDI note) |
|
|
351
|
+
| `steps` | `number` | Number of interpolation steps |
|
|
352
|
+
| `mirror` | `boolean` | If true, goes up then back down |
|
|
353
|
+
| `step` | `number` | Manual step index override |
|
|
354
|
+
|
|
180
355
|
## Inspired By
|
|
181
356
|
|
|
182
357
|
- [Sonic Pi](https://sonic-pi.net/) - The original live coding synth
|
|
183
|
-
- React's declarative component model
|
|
184
358
|
|
|
185
359
|
## License
|
|
186
360
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-synth/synth",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0-alpha",
|
|
4
4
|
"description": "Live coding music with React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"@types/react": "^19.0.2",
|
|
48
48
|
"@types/react-dom": "^19.0.2",
|
|
49
49
|
"tsx": "^4.19.2",
|
|
50
|
-
"typescript": "^5.
|
|
51
|
-
"vite-plugin-dts": "^4.4
|
|
50
|
+
"typescript": "^5.9.3",
|
|
51
|
+
"vite-plugin-dts": "^4.5.4"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -75,6 +75,6 @@
|
|
|
75
75
|
],
|
|
76
76
|
"repository": {
|
|
77
77
|
"type": "git",
|
|
78
|
-
"url": "https://github.com/
|
|
78
|
+
"url": "https://github.com/rafalsz98/react-synth.git"
|
|
79
79
|
}
|
|
80
80
|
}
|