Compare commits

2 Commits

Author SHA1 Message Date
flancian e231242f07 autopushed 2026-07-24 12:58:34 +02:00
flancian 32b10da2db autopushed 2026-07-24 12:46:40 +02:00
2 changed files with 60 additions and 38 deletions
+21 -9
View File
@@ -6,6 +6,7 @@ import click
import math import math
import sys import sys
class AgoraCmd(click.Command): class AgoraCmd(click.Command):
def format_help(self, ctx, formatter): def format_help(self, ctx, formatter):
click.echo("""Usage: click.echo("""Usage:
@@ -27,29 +28,40 @@ class AgoraCmd(click.Command):
except SystemExit: except SystemExit:
sys.exit(exc.exit_code) sys.exit(exc.exit_code)
@click.command(cls=AgoraCmd) @click.command(cls=AgoraCmd)
@click.argument('freq', type=click.FLOAT) @click.argument('freq', type=click.FLOAT)
def hz(freq): 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. # Exact continuous half steps from A4
n = 12 * math.log2(freq / A4) n_exact = 12 * math.log2(freq / A4)
n = round(n) n = round(n_exact)
note_index = n % 12
# 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#"] notes = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]
note_index = n % 12
note = notes[note_index] note = notes[note_index]
octave = 4 + (n // 12) octave = 4 + (n // 12)
if note in ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]: 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 octave += 1
click.echo(f"hz({freq}) is {note}{str(octave)}.") note_name = f"{note}{octave}"
# click.echo(f"hz({freq}) is {note}.") 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__': if __name__ == '__main__':
hz() hz()
+39 -29
View File
@@ -1,20 +1,33 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
#
# https://click.palletsprojects.com/en/8.1.x/arguments/ # https://click.palletsprojects.com/en/8.1.x/arguments/
# https://click.palletsprojects.com/en/8.1.x/options/ # https://click.palletsprojects.com/en/8.1.x/options/
#
# boilerplate shamelessly cloned from prime.py :).
import click import click
import math
import random
import sys import sys
def decompose(n):
"""Decomposes n into chunks of 7, 4, 3, 2, and 1."""
if n <= 0:
return []
ret = []
while n > 7:
ret.append(7)
n -= 7
if n == 6:
ret.extend([3, 3])
elif n == 5:
ret.extend([3, 2])
else:
ret.append(n)
return ret
class AgoraCmd(click.Command): class AgoraCmd(click.Command):
def format_help(self, ctx, formatter): def format_help(self, ctx, formatter):
click.echo("""Usage: click.echo("""Usage:
- Visit anagora.org/tare to execute this file in the Agora of Flancia. - Visit anagora.org/tare to execute this file in the Agora of Flancia.
- Visit e.g. anagora.org/tare/23 to print 23 syllables. - Visit e.g. anagora.org/tare/23 to print 23 syllables of the Tara mantra.
- In general visit anagora.org/foo, anagora.org/foo/bar to execute e.g. <bin/foo.py bar> from your garden. - In general visit anagora.org/foo, anagora.org/foo/bar to execute e.g. <bin/foo.py bar> from your garden.
""") """)
@@ -31,35 +44,32 @@ class AgoraCmd(click.Command):
except SystemExit: except SystemExit:
sys.exit(exc.exit_code) sys.exit(exc.exit_code)
def decompose(n, p):
ret = []
while n > 7:
ret.append(7)
n -= 7
if n == 6:
ret.append(3)
ret.append(3)
elif n == 5:
ret.append(3)
ret.append(2)
else:
ret.append(n)
return ret
@click.command(cls=AgoraCmd) @click.command(cls=AgoraCmd)
@click.argument('n', type=click.INT) @click.argument('n', type=click.INT)
def tare(n): def tare(n):
"""Just for fun, as many of these -- partly inspired by an Asimov story :)""" """Generates [[n]] syllables of the [[Green Tara]] mantra: Om Tare Tuttare Ture Svaha :)"""
parts = { parts = {
1: ['Om'], 1: '[[Om]]',
2: ['Tare', 'Ture'], 2: '[[Tare]] [[Ture]]',
3: ['Tuttare'], 3: '[[Tuttare]]',
4: ['Tare Ture'], 4: '[[Tare]] [[Ture]] [[Svaha]]',
7: ['Tare Tuttare Ture'], 7: '[[Om]] [[Tare]] [[Tuttare]] [[Ture]] [[Svaha]]',
8: ['Tuttare Tuttare Ture'],
} }
click.echo(decompose(n, parts))
chunks = decompose(n)
if not chunks:
click.echo("Please provide a positive integer count of syllables.")
return
mantra_lines = [parts.get(c, f"[[syllables/{c}]]") for c in chunks]
click.echo(f"[[Green Tara]] mantra breakdown for [[{n}]] syllables:")
for i, line in enumerate(mantra_lines, 1):
click.echo(f" {i}. {line}")
click.echo(f"\nTotal syllables: [[{n}]]")
if __name__ == '__main__': if __name__ == '__main__':
tare() tare()