# tone-visualizer

Simple and customizable audio visualizer for [Tone.js](https://tonejs.github.io/) with [p5.js](https://p5js.org/).

## Installation

```bash
npm install tone-visualizer tone
```

**Important:** 
- p5.js must be loaded globally via `<script>` tag
- Tone.js can be passed in config: `new ToneVisualizer(element, source, { Tone })` or exposed globally as `window.Tone`

```bash
npm install p5
```

## Quick Start

### Using CDN (CodePen, JSFiddle, etc.)

```html
<!DOCTYPE html>
<html>
<head>
  <style>
    #visualizer {
      width: 100%;
      height: 200px;
      background: #000;
    }
  </style>
</head>
<body>
  <div id="visualizer"></div>
  
  <!-- Load p5.js globally (must be a <script> tag, NOT an import) -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
  
  <!-- Your code -->
  <script type="module">
    import * as Tone from 'https://cdn.skypack.dev/tone@15.1.22';
    import { ToneVisualizer } from 'https://unpkg.com/tone-visualizer@latest/dist/visualizer.esm.js';

    // Create an audio source
    const synth = new Tone.FMSynth().toDestination();

    // Create a visualizer - pass Tone in config
    const visualizer = new ToneVisualizer('#visualizer', synth, {
      Tone, // Pass Tone here
      type: 'oscilloscope',
      strokeColor: [0, 255, 255],
      strokeWeight: 2
    });

    // Start visualization
    document.body.addEventListener('click', async () => {
      await Tone.start();
      visualizer.start();
      synth.triggerAttackRelease("C3", "4n");
    }, { once: true });
  </script>
</body>
</html>
```

## API

### Constructor

```javascript
new ToneVisualizer(element, audioSource, config)
```

**Parameters:**

- `element` (string | HTMLElement) - querySelector string or DOM element where the canvas will be created
- `audioSource` (Tone.ToneAudioNode) - Any Tone.js audio source (synth, player, sampler, etc.)
- `config` (Object) - Optional configuration object

**Config Options:**

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `width` | number | 100% of element | Canvas width in pixels |
| `height` | number | 100% of element | Canvas height in pixels |
| `type` | string | `'fft'` | Visualization type: `'fft'` or `'oscilloscope'` |
| `fftSize` | number | `1024` | FFT analyzer size |
| `waveformSize` | number | `512` | Waveform analyzer size |
| `fillColor` | Array | `[0, 255, 255, 200]` | Fill color for FFT (RGBA) |
| `strokeColor` | Array | `[0, 255, 255]` | Stroke color for oscilloscope (RGB/RGBA) |
| `strokeWeight` | number | `2` | Line thickness for oscilloscope |

### Methods

#### `start()`
Start the visualization.

```javascript
visualizer.start();
```

#### `stop()`
Stop the visualization.

```javascript
visualizer.stop();
```

#### `setType(type)`
Change visualization type.

```javascript
visualizer.setType('fft');        // Frequency spectrum
visualizer.setType('oscilloscope'); // Waveform
```

#### `setFillColor(color)`
Change fill color for FFT visualization.

```javascript
visualizer.setFillColor([255, 0, 0, 150]); // Red semi-transparent
```

#### `setStrokeColor(color)`
Change stroke color for oscilloscope.

```javascript
visualizer.setStrokeColor([0, 255, 0]); // Green
```

#### `setStrokeWeight(weight)`
Change line thickness.

```javascript
visualizer.setStrokeWeight(5);
```

## Examples

### FFT Visualizer

```javascript
import * as Tone from 'tone';
import { ToneVisualizer } from 'tone-visualizer';

const player = new Tone.Player({
  url: "audio.mp3",
  loop: true
}).toDestination();

const visualizer = new ToneVisualizer('#visualizer', player, {
  Tone,
  type: 'fft',
  fillColor: [255, 100, 0, 200],
  height: 200
});

await Tone.start();
visualizer.start();
player.start();
```

### Oscilloscope with Synth

```javascript
import * as Tone from 'tone';
import { ToneVisualizer } from 'tone-visualizer';

const synth = new Tone.PolySynth(Tone.Synth).toDestination();

const visualizer = new ToneVisualizer('#visualizer', synth, {
  Tone,
  type: 'oscilloscope',
  strokeColor: [0, 255, 255],
  strokeWeight: 3
});

await Tone.start();
visualizer.start();

// Play notes
synth.triggerAttackRelease(["C4", "E4", "G4"], "2n");
```

### Dynamic Type Switching

```javascript
const visualizer = new ToneVisualizer('#visualizer', synth);

visualizer.start();

// Switch to oscilloscope after 3 seconds
setTimeout(() => {
  visualizer.setType('oscilloscope');
}, 3000);
```

## Using with a Bundler

If you're using a bundler (Vite, Webpack, etc.):

```html
<!-- In your HTML, load p5 globally -->
<script src="node_modules/p5/lib/p5.min.js"></script>
```

```javascript
import * as Tone from 'tone';
import { ToneVisualizer } from 'tone-visualizer';

const synth = new Tone.FMSynth().toDestination();
const visualizer = new ToneVisualizer('#visualizer', synth, {
  Tone, // Pass Tone here
  type: 'oscilloscope',
  strokeColor: [0, 255, 255],
  strokeWeight: 2
});

await Tone.start();
visualizer.start();
synth.triggerAttackRelease("C3", "4n");
```

## Browser Support

Requires ES6+ support and WebGL. Works in all modern browsers.
