# StringPitcher
Ultra low-latency pitch detection library for guitar and bass instruments. Built in Rust with bindings for multiple platforms.
[](https://crates.io/crates/stringpitcher)
[](https://www.npmjs.com/package/stringpitcher)
[](https://opensource.org/licenses/MIT)
## Features
- **Ultra Low Latency**: < 20ms pitch detection using McLeod Pitch Method (MPM)
- **Multi-Instrument Support**: 6-string guitar, 4-string bass, 5-string bass
- **12 Built-in Tunings**: Standard, Drop D, Drop C, Open G, DADGAD, and more
- **Chromatic Mode**: Detect any note, not just string frequencies
- **Configurable Reference Pitch**: A4 = 432-448 Hz
- **Cross-Platform**: iOS, Android, Web (WASM), Node.js, and native Rust
## Installation
| **Rust** | `cargo add stringpitcher` |
| **npm** | `npm install stringpitcher` |
| **iOS (SPM)** | Add `https://github.com/pablocalofatti/stringpitcher` |
| **Android** | `implementation 'com.github.pablocalofatti:stringpitcher:0.1.0'` |
## Platform Documentation
- [iOS Integration Guide](docs/ios-integration.md)
- [Android Integration Guide](docs/android-integration.md)
- [Web/Node.js Integration Guide](docs/web-integration.md)
- [Rust API Documentation](https://docs.rs/stringpitcher)
## Quick Start
### Rust
```rust
use stringpitcher::{TunerInstance, InstrumentType};
let mut tuner = TunerInstance::default();
tuner.set_callback(|result| {
println!("{}{}: {:.1} cents",
result.note_name(), result.octave, result.cent_deviation);
});
// In your audio callback:
tuner.process_audio(&audio_samples);
```
### JavaScript / TypeScript
```typescript
import { StringPitcher, Instrument, TuningPreset } from 'stringpitcher';
const tuner = new StringPitcher(48000);
tuner.setInstrument(Instrument.Guitar6String);
const result = tuner.processAudio(audioSamples);
if (result?.confidence > 0.5) {
console.log(`${result.noteName}${result.octave}: ${result.centDeviation} cents`);
}
```
### Swift (iOS)
```swift
import StringPitcherLib
let tuner = StringPitcher(sampleRate: 48000)
tuner.onPitchDetected = { result in
print("\(result.noteName)\(result.octave): \(result.centDeviation) cents")
}
tuner.processAudio(samples: audioBuffer)
```
### Kotlin (Android)
```kotlin
val tuner = StringPitcher(sampleRate = 48000)
lifecycleScope.launch {
tuner.pitchResults.collect { result ->
Log.d("Tuner", "${result.noteName}${result.octave}: ${result.centDeviation}")
}
}
tuner.processAudio(samples, sampleCount)
```
## API Reference
### PitchResult
| `frequency` | Float | Detected frequency in Hz |
| `confidence` | Float | Detection confidence (0.0 - 1.0) |
| `noteName` | String | Note name (C, C#, D, etc.) |
| `octave` | Int | Octave number (0-8) |
| `centDeviation` | Float | Cents off from target (-50 to +50) |
| `isInTune` | Bool | True if within tuning threshold |
| `tuningDirection` | Int | -1: flat, 0: in tune, 1: sharp |
| `matchedString` | Int | Matched string index (0-5) or -1 |
| `signalLevel` | Float | Input signal level (0.0 - 1.0) |
### Tuning Presets
| 0 | Standard | E A D G B E |
| 1 | Half Step Down | Eb Ab Db Gb Bb Eb |
| 5 | Drop D | D A D G B E |
| 6 | Drop C | C G C F A D |
| 9 | Open G | D G D G B D |
| 11 | DADGAD | D A D G A D |
## Architecture
```
┌─────────────────────────────────────────┐
│ Rust Core Library │
│ McLeod Pitch Detection + Tuning │
└─────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐
│ FFI │ │ WASM │ │ JNI │
│(Swift)│ │ (JS) │ │(Kotlin)│
└───────┘ └───────┘ └───────┘
│ │ │
▼ ▼ ▼
iOS Browser Android
Node.js
```
## Performance
| Latency | < 20ms |
| Frequency Range | 20Hz - 5kHz |
| Accuracy | ±1 cent |
| WASM Size | ~300KB |
## License
MIT License