# `Xenia.Adapters.WaveSurfer`
[🔗](https://github.com/uzaydurdu/xenia/blob/v0.1.1/lib/xenia/adapters/wave_surfer.ex#L1)

`<.wavesurfer>`: an audio waveform (WaveSurfer.js), through Xenia's official adapter.

## Setup

Install the library in your app:

    npm install wavesurfer.js --prefix assets

Pass it to the adapter, and register it, in `assets/js/app.js`:

```js
import { createWaveSurfer } from "xenia/wavesurfer"

const wavesurfer = createWaveSurfer({
    load: async () => {
      const [ws, regions, timeline, minimap, hover, spectrogram] = await Promise.all([
        import("wavesurfer.js"),
        import("wavesurfer.js/dist/plugins/regions.esm.js"),
        import("wavesurfer.js/dist/plugins/timeline.esm.js"),
        import("wavesurfer.js/dist/plugins/minimap.esm.js"),
        import("wavesurfer.js/dist/plugins/hover.esm.js"),
        import("wavesurfer.js/dist/plugins/spectrogram.esm.js"),
      ])
      return {
        WaveSurfer: ws.default,
        RegionsPlugin: regions.default,
        TimelinePlugin: timeline.default,
        MinimapPlugin: minimap.default,
        HoverPlugin: hover.default,
        SpectrogramPlugin: spectrogram.default,
      }
    },
})

hooks: { ...colocatedHooks, ...createHooks({ WaveSurfer: wavesurfer }) },
```

Then `import Xenia.Adapters.WaveSurfer` in `html_helpers`, and render
`<.wavesurfer id="...">` with the props below. Every event becomes an
`on_<event>` attribute; commands go through `Xenia.push_to/4`.

The factory returns a plain adapter object: spread it to add or change
props, commands and events, without copying the adapter.

The tag uses the adapter name `"WaveSurfer"`. To register it under
another name, render `<.xenia adapter="...">` or declare your own tag.

## Reference

  Xenia's official adapter for WaveSurfer.js (v7/v8): one audio file as an interactive
  waveform, with regions, markers, timeline, minimap, hover and spectrogram.
  For several synchronized tracks and recording, see wavesurfer_multitrack.js.

  Props:
    url           audio URL. Changing it loads the new file.
    peaks         precomputed peaks (list of channels) for instant drawing of
                  long files; needs `duration` too
    duration      seconds, with `peaks`
    options       any WaveSurfer option, camelCase or snake_case, applied in
                  place: wave_color, progress_color, cursor_color, height,
                  bar_width, bar_gap, bar_radius, normalize, split_channels,
                  drag_to_seek, auto_scroll, auto_center, ...
    zoom          pixels per second (0 = fit the container)
    volume        0..1
    muted         boolean
    playback_rate 0.25..4 (pitch preserved)
    regions       [%{id, start, end?, color?, content?, drag?, resize?}]
                  The server owns the list: regions are added, updated and
                  removed to match it. A region without `end` is a marker.
    region_editing  true lets the user drag on the waveform to create
                  regions (sent as region_created; add them to `regions`)
    timeline      true or %{height, time_interval, primary_label_interval, ...}
    minimap       true or %{height, wave_color, ...}
    hover         true or %{line_color, label_color, ...}
    spectrogram   true or %{height, fft_samples, frequency_min, frequency_max,
                  labels, scale, color_map, ...}
    Plugin props: false or nil removes the plugin; a changed map rebuilds it.

  Commands:
    play %{start?, end?}, pause, play_pause, stop
    seek %{seconds}, skip %{seconds}
    play_region %{id}
    download_image %{filename?}   the waveform as PNG

  Events:
    ready            %{duration}
    loading          %{percent}             at most every 250 ms
    playback         %{state: "playing" | "paused", seconds}
    position         %{seconds}             while playing, at most every 250 ms
    seek             %{seconds}             the user clicked or dragged
    finish           %{}
    zoom             %{px_per_sec}          at most every 250 ms
    region_created   %{region}              the user drew a region
    region_updated   %{region}              the user moved/resized one
    region_clicked   %{region}
    region_in, region_out  %{region}        playback entered/left a region
    error            %{source, message, code}
    `region` is %{id, start, end, color, content}.

# `wavesurfer`

## Attributes

* `id` (`:string`) (required) - Stable DOM id used for adapter commands.
* `url` (`:string`)
* `peaks` (`:list`)
* `duration` (`:any`)
* `options` (`:map`)
* `zoom` (`:any`)
* `volume` (`:any`)
* `muted` (`:boolean`)
* `playback_rate` (`:any`)
* `regions` (`:list`)
* `region_editing` (`:boolean`)
* `timeline` (`:any`)
* `minimap` (`:any`)
* `hover` (`:any`)
* `spectrogram` (`:any`)
* `on_ready` (`:string`) - LiveView event triggered when the adapter emits :ready. Defaults to `nil`.
* `on_loading` (`:string`) - LiveView event triggered when the adapter emits :loading. Defaults to `nil`.
* `on_playback` (`:string`) - LiveView event triggered when the adapter emits :playback. Defaults to `nil`.
* `on_position` (`:string`) - LiveView event triggered when the adapter emits :position. Defaults to `nil`.
* `on_seek` (`:string`) - LiveView event triggered when the adapter emits :seek. Defaults to `nil`.
* `on_finish` (`:string`) - LiveView event triggered when the adapter emits :finish. Defaults to `nil`.
* `on_zoom` (`:string`) - LiveView event triggered when the adapter emits :zoom. Defaults to `nil`.
* `on_region_created` (`:string`) - LiveView event triggered when the adapter emits :region_created. Defaults to `nil`.
* `on_region_updated` (`:string`) - LiveView event triggered when the adapter emits :region_updated. Defaults to `nil`.
* `on_region_clicked` (`:string`) - LiveView event triggered when the adapter emits :region_clicked. Defaults to `nil`.
* `on_region_in` (`:string`) - LiveView event triggered when the adapter emits :region_in. Defaults to `nil`.
* `on_region_out` (`:string`) - LiveView event triggered when the adapter emits :region_out. Defaults to `nil`.
* `on_error` (`:string`) - LiveView event triggered when the adapter emits :error. Defaults to `nil`.
* `shortcuts` (`:map`) - Key combination => LiveView event, while focus is inside (see Xenia.Shortcuts). Defaults to `%{}`.
* `on_crash` (`:string`) - LiveView event sent if the adapter throws (see Xenia.Component). Defaults to `nil`.
* Global attributes are accepted.
## Slots

* `loading` - Shown until the island's first mount finishes.
* `error` - Shown if the adapter throws; data-xenia-retry starts it again.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
