From e231242f0715eec51acb199baa508f7c109c2531 Mon Sep 17 00:00:00 2001 From: Flancian <0@flancia.org> Date: Fri, 24 Jul 2026 12:58:34 +0200 Subject: [PATCH] autopushed --- bin/hz.py | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/bin/hz.py b/bin/hz.py index 0c4ba624c..d5415c00c 100755 --- a/bin/hz.py +++ b/bin/hz.py @@ -6,6 +6,7 @@ import click import math import sys + class AgoraCmd(click.Command): def format_help(self, ctx, formatter): click.echo("""Usage: @@ -27,29 +28,40 @@ class AgoraCmd(click.Command): except SystemExit: sys.exit(exc.exit_code) + @click.command(cls=AgoraCmd) @click.argument('freq', type=click.FLOAT) def hz(freq): - """Calculates the closest note to input hz :)""" + """Calculates the closest musical note to an input frequency in Hz.""" + if freq <= 0: + click.echo("Frequency must be positive.") + return - A4 = 440 + A4 = 440.0 - # Number of half steps away. - n = 12 * math.log2(freq / A4) - n = round(n) - note_index = n % 12 + # Exact continuous half steps from A4 + n_exact = 12 * math.log2(freq / A4) + n = round(n_exact) + + # Pitch deviation in cents (100 cents = 1 semitone) + cents = round((n_exact - n) * 100) notes = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"] + note_index = n % 12 note = notes[note_index] octave = 4 + (n // 12) if note in ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]: - # compensate for the fact that octaves are counted from C + # compensate for octave starting at C octave += 1 - click.echo(f"hz({freq}) is {note}{str(octave)}.") - # click.echo(f"hz({freq}) is {note}.") + note_name = f"{note}{octave}" + cents_str = f" ({'+' if cents > 0 else ''}{cents} cents)" if cents != 0 else " (perfect pitch)" + + click.echo(f"[[hz/{freq}]] is closest to [[{note_name}]] at [[{freq}]] Hz{cents_str}.") + click.echo(f"Note class: [[{note}]], Octave: [[octave/{octave}]].") if __name__ == '__main__': hz() +