def test_others(self): for test_file in OTHERS: with open(test_file, 'r') as fh: o = jxon.load(fh) self.assertTrue(jxon.jxon_equal(o, jxon.loads(jxon.dumps(o)))) self.assertTrue( jxon.jxon_equal(o, jxon.loads(jxon.dumps(o, indent=2))))
def test_idempotence(self): for test_file in ALL_TESTS: fullpath = 'tests/' + test_file with open(fullpath, 'r') as fh: o = jxon.load(fh) self.assertTrue(jxon.jxon_equal(o, jxon.loads(jxon.dumps(o)))) self.assertTrue( jxon.jxon_equal(o, jxon.loads(jxon.dumps(o, indent=2))))
from functools import cache import jxon from src.ji import Interval, JI MAJOR_EDOS = (5, 7, 12, 15, 17, 19, 22, 24, 31) MAJOR_MINOR_INTERVALS = ["2", "3", "6", "7"] PERFECT_INTERVALS = ["4", "5"] with open("static/consonance/consonances.jxon", "r") as fh: CONSONANCES = jxon.load(fh) with open("static/consonance/dissonances.jxon", "r") as fh: DISSONANCES = jxon.load(fh) class EDOInterval(Interval): __instances = {} def __new__(cls, steps, edo_steps): t = (steps, edo_steps) if t not in cls.__instances: cls.__instances[t] = super(EDOInterval, cls).__new__(cls) return cls.__instances[t] def __init__(self, steps: int, edo_steps: int): self.steps = steps self.edo_steps = edo_steps def octaves(self):
import math import jxon with open("static/ji/intervals.jxon", "r") as fh: NAMED_INTERVALS = jxon.load(fh) class Interval: def octaves(self) -> float: raise NotImplementedError def cents(self): return round(self.octaves() * 1200, 1) def __gt__(self, other): return self.cents() > other.cents() def __lt__(self, other): return self.cents() < other.cents() class JI(Interval): def __init__(self, denom, num): assert num >= denom self.num = num self.denom = denom self.ratio = (denom, num) def octaves(self): return math.log2(self.num / self.denom)
def edo(self): return EDO(self.edo_steps()) def size(self): return len(self.jumps) SCALES_DIR = "static/scales" NAMED_CYCLES = {} for filename in os.listdir(SCALES_DIR): if filename == "scales.jxsd": continue assert (re.fullmatch(r"[0-9]+edo\.jxon", filename)) with open(os.path.join(SCALES_DIR, filename), "r") as fh: cycles = jxon.load(fh) # uniqueness constraint - will hopefully enforce in jxon at some point assert len(set(map(lambda c: c["name"], cycles))) == len(cycles) NAMED_CYCLES[int(filename[:-8])] = cycles class CycleMetaclass(type): __instances = {} def __call__(cls, jumps): modes = [ Mode(jumps[i:] + jumps[:i]) for i in range(len(jumps)) ] canon_mode = min(modes, key=lambda mode: mode.weight())
from .just_interval import JI from functools import cache ORDINALS = [ "0th", "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", ] with open("static/ji/chords.jxon", "r") as fh: NAMED_CHORDS = jxon.load(fh) with open("static/ji/intervals.jxon", "r") as fh: for ivl in jxon.load(fh): NAMED_CHORDS.append({ "name": ivl["name"], "ratio": [ivl["denom"], ivl["num"]] }) class JustChord: def __init__(self, ratio: [int]): if not all(ratio[i] < ratio[i + 1] for i in range(len(ratio) - 1)): raise ValueError(f"JustChord ratio must be increasing: {ratio}") self.ratio = tuple(ratio)