bpm-finder-tools 0.1.0

Lightweight Rust utilities and CLI for audio-file BPM analysis, tap tempo, and tempo conversion.
Documentation
# bpm-finder-tools

`bpm-finder-tools` is a lightweight Rust utility package for audio-file BPM analysis, tap tempo analysis, BPM conversion, and practical tempo normalization. It is maintained by [BPM Finder](https://bpm-finder.net/), the browser-based tool for fast and privacy-first BPM workflows.

## Why this crate exists

Many music and workflow tools only need a few reliable tempo primitives:

- Detect BPM from supported audio files
- Estimate BPM from tap intervals
- Convert BPM into milliseconds per beat or bar
- Normalize half-time and double-time readings into a practical range

This crate keeps those utilities small, dependency-light, and easy to embed in Rust applications or command-line workflows.

Supported file decoding currently includes WAV, MP3, FLAC, OGG/Vorbis, and common MP4/M4A AAC or ALAC audio files.

## Installation

Add the crate to your project:

```toml
[dependencies]
bpm-finder-tools = "0.1.0"
```

Or install the CLI from source:

```bash
cargo install bpm-finder-tools
```

## Library usage

### Tap tempo

```rust
use bpm_finder_tools::tap;

let analysis = tap::analyze_intervals(&[500.0, 480.0, 495.0, 505.0])?;

assert_eq!(analysis.average_interval_ms, 495.0);
assert_eq!(analysis.bpm, 121.212);
assert_eq!(analysis.rounded_bpm, 121);
# Ok::<(), bpm_finder_tools::TapTempoError>(())
```

### Analyze an audio file

```rust
use bpm_finder_tools::file;

let analysis = file::analyze_path("fixtures/loop.wav", 70.0, 180.0)?;

println!("Detected BPM: {}", analysis.bpm);
println!("Normalized BPM: {}", analysis.normalized_bpm);
# Ok::<(), bpm_finder_tools::TapTempoError>(())
```

### BPM and milliseconds conversion

```rust
use bpm_finder_tools::convert;

let beat_ms = convert::bpm_to_ms_per_beat(128.0)?;
let bar_ms = convert::bpm_to_ms_per_bar(128.0, 4)?;
let bpm = convert::ms_per_bar_to_bpm(1875.0, 4)?;

assert_eq!(beat_ms, 468.75);
assert_eq!(bar_ms, 1875.0);
assert_eq!(bpm, 128.0);
# Ok::<(), bpm_finder_tools::TapTempoError>(())
```

### Normalize into a practical range

```rust
use bpm_finder_tools::range;

assert_eq!(range::normalize(72.0, 90.0, 180.0)?, 144.0);
assert_eq!(range::double_time(87.5)?, 175.0);
assert_eq!(range::half_time(174.0)?, 87.0);
assert!(range::is_within(128.0, 90.0, 180.0)?);
# Ok::<(), bpm_finder_tools::TapTempoError>(())
```

## CLI usage

```bash
bpm-finder-tools file ./loop.wav
bpm-finder-tools tap 500 480 495 505
bpm-finder-tools ms 128
bpm-finder-tools bpm 468.75
bpm-finder-tools normalize 72 --min 90 --max 180
```

Example output:

```text
$ bpm-finder-tools file ./loop.wav
File: ./loop.wav
Detected BPM: 120
Rounded BPM: 120
Normalized BPM: 120
Confidence: 0.742
Duration: 8
Sample rate: 44100 Hz
```

```text
$ bpm-finder-tools tap 500 480 495 505
Tap intervals: 500, 480, 495, 505
Average interval: 495 ms
Exact BPM: 121.212
Rounded BPM: 121
```

## Public API

### `TapTempoAnalysis`

- `average_interval_ms: f64`
- `bpm: f64`
- `rounded_bpm: u32`

### `AudioFileAnalysis`

- `bpm: f64`
- `rounded_bpm: u32`
- `normalized_bpm: f64`
- `confidence: f64`
- `duration_seconds: f64`
- `analyzed_seconds: f64`
- `sample_rate: u32`

### `file`

- `analyze_path(path, min_bpm, max_bpm) -> Result<AudioFileAnalysis, TapTempoError>`
- `analyze_samples(samples, sample_rate, min_bpm, max_bpm) -> Result<AudioFileAnalysis, TapTempoError>`

### `tap`

- `analyze_intervals(intervals_ms: &[f64]) -> Result<TapTempoAnalysis, TapTempoError>`
- `bpm_from_intervals(intervals_ms: &[f64]) -> Result<f64, TapTempoError>`

### `convert`

- `bpm_to_ms_per_beat(bpm: f64) -> Result<f64, TapTempoError>`
- `bpm_to_ms_per_bar(bpm: f64, beats_per_bar: u32) -> Result<f64, TapTempoError>`
- `ms_per_beat_to_bpm(milliseconds: f64) -> Result<f64, TapTempoError>`
- `ms_per_bar_to_bpm(milliseconds: f64, beats_per_bar: u32) -> Result<f64, TapTempoError>`

### `range`

- `normalize(bpm: f64, min: f64, max: f64) -> Result<f64, TapTempoError>`
- `is_within(bpm: f64, min: f64, max: f64) -> Result<bool, TapTempoError>`
- `half_time(bpm: f64) -> Result<f64, TapTempoError>`
- `double_time(bpm: f64) -> Result<f64, TapTempoError>`

## Development

```bash
cargo test
cargo package --list
cargo publish --dry-run
```

## Release notes

Current version: `0.1.0`

- First public release
- Library API plus CLI
- Basic audio-file BPM analysis for supported formats

## License

MIT