let harmony = Engine.new(Palestrina);
fn detect_pitch(buf) -> Note
const MAX_VOICES: usize = 4;
voice_leading.reject_parallels()
struct GuitarInput { onset }
engine.harmonize(note, scale)
fn detect_pitch(
  buf: &[f32]
) -> Option<Note>
let voices =
  counterpoint::
    generate(line, mode);
if interval == Fifth
  && motion == Parallel
  { reject() }
#[inline(always)]
fn onset(
  frame: &Frame
) -> bool
block_size: 128
sample_rate: 48_000
latency_ms: 7.2
// Palestrina
// counterpoint
// rules.rs
COMMUNITY · OPEN SOURCE · GITHUB

MADE TOGETHER.

Guitarists, theorists, DSP engineers, and bedroom producers. Read the code, open an issue, send a PR.

"

The Jazz mode voicings are better than I am. I mean that as a compliment to the code.

KE
@kenji_osaka
JAZZ GUITARIST
"

I make my species-counterpoint students check their homework against Palestrina mode. Beats my red pen.

LE
@lena.strings
COMPOSITION PROF
"

Random-below-no-2nds into a Rhodes plugin hosted in-app. Instant ECM record.

DR
@drifter_7
AMBIENT PRODUCER
"

Looked under the hood expecting hacks. Found a voice-leading solver with comments. Read the whole thing on a flight.

BO
@boris.k
DSP ENGINEER
"

We run two guitars into two instances, quantize to different modes. Feels like a third band member.

SU
@sunday_kids
POST-ROCK BAND
"

Parallel-fifths rejection on by default is a value statement. Ship more value statements.

MA
@mara.note
MUSIC THEORIST
◆ ◇ ◆ ◇ ◆ RECENT COMMITS
  1. 2226a83 feat(audio): synth crossfade + dry-path compressor + lookahead scheduling (Tier 2) Vibhav Bobade · 2m ago
  2. 7ac77fb feat(audio): expose getAudioContext() for Companion tick clock Vibhav Bobade · 2h ago
  3. 249a0b3 fix(harmony,companion): preserve V_K species FSM during cascade clone (Tier 1) Vibhav Bobade · 2h ago
  4. 20f9956 chore(wasm): rebuild bundle for v1.2.0 cascade-shared-state + CompanionWasm Vibhav Bobade · 1d ago
  5. 7da7d4b fix(ui): align companion entry timeline grid with track-rail dots Vibhav Bobade · 1d ago
  6. 71a26a1 fix(companion): truly shared CounterpointState across cascade mini-engines Vibhav Bobade · 1d ago
  7. 0addd5e debug(wasm): companion + per-voice state introspection on note events Vibhav Bobade · 1d ago
  8. f8675f3 fix(wasm): close the remaining synth/FX parity TODOs — ADSR + filter + reverb shape Vibhav Bobade · 1d ago
  9. 625e835 fix(wasm): wire synth waveform / master gain + reverb mix + delay (time / feedback / mix) through embedAudio Vibhav Bobade · 1d ago
  10. 721d8d9 fix(wasm): companion-emitted notes show up in ActiveNotes + Piano + Fretboard Vibhav Bobade · 1d ago
  11. 66888e9 fix(wasm): real-MIDI input feeds Companion + engine state sync + chord-name layout stable Vibhav Bobade · 1d ago
  12. 57a8f61 feat(wasm): web parity for Companion · Canon · Counterpoint lanes Vibhav Bobade · 1d ago
  13. 68fd733 ci(windows): trigger on tags + attach installers to GitHub Release Vibhav Bobade · 1d ago
  14. ba492c0 chore(release-name): add Renaissance composers to the codename pool Vibhav Bobade · 1d ago
  15. ed16580 release: v1.2.0 — Lanes & Voice Library Vibhav Bobade · 1d ago
  16. 753971f fix(companion): consistent beat-within-bar labels on the entry timeline Vibhav Bobade · 1d ago
  17. 912233e feat(defaults): CounterpointLane enabled by default · matches canon Vibhav Bobade · 1d ago
  18. 482165b fix(counterpoint): cancel unfired NoteOns on player NoteOff · no more stuck notes Vibhav Bobade · 1d ago
  19. 7c2efcb feat(companion): restructure into peer Lane cards · canon + counterpoint side-by-side Vibhav Bobade · 1d ago
  20. e6cc242 fix(companion): promote CounterpointLane card to top of right column Vibhav Bobade · 1d ago
GET CONTRAPUNK

THREE WAYS IN.
ALL FREE.

Browser at app.contrapunk.com. macOS DMG from GitHub Releases. Build from source with cargo tauri dev.