|
1 | | -# rescript-tonejs |
2 | | -Bindings for ToneJS |
| 1 | +# rescript-tone |
| 2 | + |
| 3 | +ReScript bindings for [Tone.js](https://tonejs.github.io/), a Web Audio framework for creating interactive music in the browser. |
| 4 | + |
| 5 | +## Installation |
| 6 | + |
| 7 | +```bash |
| 8 | +npm install rescript-tone tone |
| 9 | +``` |
| 10 | + |
| 11 | +Add to your `rescript.json`: |
| 12 | + |
| 13 | +```json |
| 14 | +{ |
| 15 | + "bs-dependencies": ["rescript-tone"] |
| 16 | +} |
| 17 | +``` |
| 18 | + |
| 19 | +## Quick Start |
| 20 | + |
| 21 | +```rescript |
| 22 | +open RescriptTone |
| 23 | +
|
| 24 | +// Create a synth and connect it to the speakers |
| 25 | +let synth = ToneJs_Synth.make() |
| 26 | +let node = synth->ToneJs_Synth.asAudioNode->ToneJs_AudioNode.toDestination |
| 27 | +
|
| 28 | +// Play a note |
| 29 | +let _ = synth->ToneJs_Synth.triggerAttackRelease(440.0, ToneJs_Types.Time.seconds(0.5)) |
| 30 | +
|
| 31 | +// Start the audio context (required by browsers) |
| 32 | +let _ = ToneJs_Tone.start() |
| 33 | +``` |
| 34 | + |
| 35 | +## Usage Examples |
| 36 | + |
| 37 | +### Playing Notes with a Synth |
| 38 | + |
| 39 | +```rescript |
| 40 | +open RescriptTone |
| 41 | +
|
| 42 | +let synth = ToneJs_Synth.makeWithOptions({ |
| 43 | + oscillator: ?Some({\"type": ?Some(ToneJs_Types.Sawtooth)}), |
| 44 | + envelope: ?Some({ |
| 45 | + attack: ?Some(ToneJs_Types.Time.seconds(0.1)), |
| 46 | + decay: ?Some(ToneJs_Types.Time.seconds(0.2)), |
| 47 | + sustain: ?Some(0.5), |
| 48 | + release: ?Some(ToneJs_Types.Time.seconds(0.8)), |
| 49 | + }), |
| 50 | +}) |
| 51 | +
|
| 52 | +let _ = synth->ToneJs_Synth.asAudioNode->ToneJs_AudioNode.toDestination |
| 53 | +let _ = synth->ToneJs_Synth.triggerAttackRelease(440.0, ToneJs_Types.Time.seconds(0.5)) |
| 54 | +``` |
| 55 | + |
| 56 | +### Chaining Effects |
| 57 | + |
| 58 | +```rescript |
| 59 | +open RescriptTone |
| 60 | +
|
| 61 | +let synth = ToneJs_Synth.make() |
| 62 | +let reverb = ToneJs_Reverb.makeWithDecay(1.5) |
| 63 | +let delay = ToneJs_FeedbackDelay.makeWithTimeFeedback(ToneJs_Types.Time.notation("8n"), 0.5) |
| 64 | +let dest = ToneJs_Tone.getDestination() |
| 65 | +
|
| 66 | +// Chain: synth -> delay -> reverb -> destination |
| 67 | +let _ = synth |
| 68 | + ->ToneJs_Synth.asAudioNode |
| 69 | + ->ToneJs_AudioNode.chain([ |
| 70 | + delay->ToneJs_FeedbackDelay.asAudioNode, |
| 71 | + reverb->ToneJs_Reverb.asAudioNode, |
| 72 | + dest->ToneJs_Destination.asAudioNode, |
| 73 | + ]) |
| 74 | +``` |
| 75 | + |
| 76 | +### Scheduling with Transport |
| 77 | + |
| 78 | +```rescript |
| 79 | +open RescriptTone |
| 80 | +
|
| 81 | +let synth = ToneJs_Synth.make() |
| 82 | +let _ = synth->ToneJs_Synth.asAudioNode->ToneJs_AudioNode.toDestination |
| 83 | +
|
| 84 | +let transport = ToneJs_Tone.getTransport() |
| 85 | +
|
| 86 | +// Set BPM |
| 87 | +let bpm = transport->ToneJs_Transport.bpm |
| 88 | +ToneJs_Param.setValue(bpm, 120.0) |
| 89 | +
|
| 90 | +// Schedule a repeating note |
| 91 | +let _ = transport->ToneJs_Transport.scheduleRepeat( |
| 92 | + _time => { |
| 93 | + let _ = synth->ToneJs_Synth.triggerAttackRelease(440.0, ToneJs_Types.Time.notation("8n")) |
| 94 | + }, |
| 95 | + ToneJs_Types.Time.notation("4n"), |
| 96 | +) |
| 97 | +
|
| 98 | +// Start the transport |
| 99 | +let _ = transport->ToneJs_Transport.start |
| 100 | +``` |
| 101 | + |
| 102 | +### Looping Patterns |
| 103 | + |
| 104 | +```rescript |
| 105 | +open RescriptTone |
| 106 | +
|
| 107 | +let synth = ToneJs_Synth.make() |
| 108 | +let _ = synth->ToneJs_Synth.asAudioNode->ToneJs_AudioNode.toDestination |
| 109 | +
|
| 110 | +let notes = ["C4", "E4", "G4", "B4"] |
| 111 | +
|
| 112 | +let seq = ToneJs_Sequence.makeWithSubdivision( |
| 113 | + (time, note) => { |
| 114 | + let _ = synth->ToneJs_Synth.triggerAttackReleaseAt( |
| 115 | + ToneJs_Types.Frequency.fromNotation(note), |
| 116 | + ToneJs_Types.Time.notation("8n"), |
| 117 | + ~time=ToneJs_Types.Time.fromFloat(time), |
| 118 | + ) |
| 119 | + }, |
| 120 | + notes, |
| 121 | + ToneJs_Types.Time.notation("4n"), |
| 122 | +) |
| 123 | +
|
| 124 | +let _ = seq->ToneJs_Sequence.start |
| 125 | +let _ = ToneJs_Tone.getTransport()->ToneJs_Transport.start |
| 126 | +``` |
| 127 | + |
| 128 | +### Polyphonic Synth |
| 129 | + |
| 130 | +```rescript |
| 131 | +open RescriptTone |
| 132 | +
|
| 133 | +let poly = ToneJs_PolySynth.makeWithOptions({maxPolyphony: ?Some(4)}) |
| 134 | +let _ = poly->ToneJs_PolySynth.asAudioNode->ToneJs_AudioNode.toDestination |
| 135 | +
|
| 136 | +// Play a chord |
| 137 | +let _ = poly->ToneJs_PolySynth.triggerAttackRelease( |
| 138 | + [261.63, 329.63, 392.0], |
| 139 | + ToneJs_Types.Time.seconds(1.0), |
| 140 | +) |
| 141 | +``` |
| 142 | + |
| 143 | +## API Reference |
| 144 | + |
| 145 | +See [docs/API.md](docs/API.md) for the complete API reference. |
| 146 | + |
| 147 | +## Architecture |
| 148 | + |
| 149 | +The library is organized into modules that mirror Tone.js's structure: |
| 150 | + |
| 151 | +| Category | Modules | |
| 152 | +|----------|---------| |
| 153 | +| **Core** | `Tone`, `Context`, `Transport`, `Destination`, `Param`, `AudioNode`, `Types` | |
| 154 | +| **Instruments** | `Synth`, `AMSynth`, `FMSynth`, `MonoSynth`, `PolySynth` | |
| 155 | +| **Sources** | `Oscillator`, `Player`, `Noise` | |
| 156 | +| **Effects** | `Reverb`, `FeedbackDelay`, `Chorus`, `Distortion`, `AutoFilter`, `AutoPanner`, `AutoWah`, `BitCrusher`, `Chebyshev`, `Freeverb`, `JCReverb`, `Phaser`, `PingPongDelay`, `PitchShift`, `Tremolo`, `Vibrato`, `FrequencyShifter`, `StereoWidener` | |
| 157 | +| **Components** | `Compressor`, `Limiter`, `Gate`, `Filter`, `EQ3`, `Panner` | |
| 158 | +| **Signal & Channel** | `Signal`, `Volume`, `Gain`, `Channel`, `CrossFade` | |
| 159 | +| **Scheduling** | `Loop`, `Event`, `Part`, `Sequence` | |
| 160 | + |
| 161 | +Each Tone.js class maps to a ReScript module with an abstract `type t`. Modules expose: |
| 162 | +- `make` / `makeWithOptions` constructors |
| 163 | +- `@send` methods for instance operations |
| 164 | +- `@get` / `@set` for properties |
| 165 | +- `asAudioNode` for casting to the base `ToneJs_AudioNode.t` type (for `connect`, `chain`, etc.) |
| 166 | + |
| 167 | +## Requirements |
| 168 | + |
| 169 | +- ReScript >= 12.0.0 |
| 170 | +- Tone.js >= 15.0.0 |
| 171 | +- A browser environment with Web Audio API support |
| 172 | + |
| 173 | +## License |
| 174 | + |
| 175 | +MIT |
0 commit comments