Skip to content

File: ShaderFlow/Common/Notes.py

ShaderFlow.Common.Notes

PIANO_NOTES

PIANO_NOTES = 'C C# D D# E F F# G G# A A# B'.split()

BrokenPianoNote

Bases: BrokenFluent

Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
@define(eq=False)
class BrokenPianoNote(BrokenFluent):
    note:     int   = 60
    start:    float = 0
    end:      float = 0
    channel:  int   = 0
    velocity: int   = 100
    tuning:   float = 440

    def __hash__(self):
        return hash((self.note, self.start, self.end, self.channel, self.velocity))

    def idk_hash(self):
        return hash((self.note, self.channel))

    def __eq__(self, other):
        return hash(self) == hash(other)

    # # Initialization

    @classmethod
    @functools.lru_cache
    def from_index(cls, note: int, **kwargs) -> "BrokenPianoNote":
        return cls(note=note, **kwargs)

    @classmethod
    @functools.lru_cache
    def from_name(cls, name: str, **kwargs) -> "BrokenPianoNote":
        return cls(note=BrokenPianoNote.name_to_index(name), **kwargs)

    @classmethod
    @functools.lru_cache
    def from_frequency(cls, frequency: float, **kwargs) -> "BrokenPianoNote":
        return cls(note=BrokenPianoNote.frequency_to_index(frequency), **kwargs)

    @classmethod
    @functools.lru_cache
    def get(cls, object: Any, **kwargs) -> Self:
        if isinstance(object, BrokenPianoNote):
            return object(**kwargs)
        elif isinstance(object, int):
            return cls.from_index(object, **kwargs)
        elif isinstance(object, str):
            return cls.from_name(object, **kwargs)
        elif isinstance(object, float):
            return cls.from_frequency(object, **kwargs)
        return cls(**kwargs)

    # # Conversion

    @staticmethod
    @functools.lru_cache
    def index_to_name(index: int) -> str:
        return f"{PIANO_NOTES[index % 12]}{index//12 - 1}"

    @staticmethod
    @functools.lru_cache
    def index_to_frequency(index: int, *, tuning: float=440) -> float:
        return tuning * 2**((index - 69)/12)

    @staticmethod
    @functools.lru_cache
    def name_to_index(name: str) -> int:
        note, octave = name[:-1].upper(), int(name[-1])
        return PIANO_NOTES.index(note) + 12*(octave + 1)

    @staticmethod
    @functools.lru_cache
    def name_to_frequency(name: str, *, tuning: float=440) -> float:
        return BrokenPianoNote.index_to_frequency(BrokenPianoNote.name_to_index(name), tuning=tuning)

    @staticmethod
    @functools.lru_cache
    def frequency_to_index(frequency: float, *, tuning: float=440) -> int:
        return round(12*math.log2(frequency/tuning) + 69)

    @staticmethod
    @functools.lru_cache
    def frequency_to_name(frequency: float, *, tuning: float=440) -> str:
        return BrokenPianoNote.index_to_name(BrokenPianoNote.frequency_to_index(frequency, tuning=tuning))

    # # Utilities

    @property
    def frequency(self) -> float:
        return BrokenPianoNote.index_to_frequency(self.note, tuning=self.tuning)

    @frequency.setter
    def frequency(self, value: float):
        self.note = BrokenPianoNote.frequency_to_index(value, tuning=self.tuning)

    @property
    def name(self) -> str:
        return BrokenPianoNote.index_to_name(self.note)

    @name.setter
    def name(self, value: str):
        self.note = BrokenPianoNote.name_to_index(value)

    # Black and White

    def is_white(note: int) -> bool:
        return (note % 12) in {0, 2, 4, 5, 7, 9, 11}

    def is_black(note: int) -> bool:
        return (note % 12) in {1, 3, 6, 8, 10}

    @property
    def white(self) -> bool:
        return BrokenPianoNote.is_white(self.note)

    @property
    def black(self) -> bool:
        return BrokenPianoNote.is_black(self.note)

    # Temporal

    @property
    def duration(self):
        return self.end - self.start

    @duration.setter
    def duration(self, value: float):
        self.end = self.start + value

note

note: int = 60

start

start: float = 0

end

end: float = 0

channel

channel: int = 0

velocity

velocity: int = 100

tuning

tuning: float = 440

__hash__

__hash__()
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
20
21
def __hash__(self):
    return hash((self.note, self.start, self.end, self.channel, self.velocity))

idk_hash

idk_hash()
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
23
24
def idk_hash(self):
    return hash((self.note, self.channel))

__eq__

__eq__(other)
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
26
27
def __eq__(self, other):
    return hash(self) == hash(other)

from_index

from_index(note: int, **kwargs) -> BrokenPianoNote
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
31
32
33
34
@classmethod
@functools.lru_cache
def from_index(cls, note: int, **kwargs) -> "BrokenPianoNote":
    return cls(note=note, **kwargs)

from_name

from_name(name: str, **kwargs) -> BrokenPianoNote
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
36
37
38
39
@classmethod
@functools.lru_cache
def from_name(cls, name: str, **kwargs) -> "BrokenPianoNote":
    return cls(note=BrokenPianoNote.name_to_index(name), **kwargs)

from_frequency

from_frequency(
    frequency: float, **kwargs
) -> BrokenPianoNote
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
41
42
43
44
@classmethod
@functools.lru_cache
def from_frequency(cls, frequency: float, **kwargs) -> "BrokenPianoNote":
    return cls(note=BrokenPianoNote.frequency_to_index(frequency), **kwargs)

get

get(object: Any, **kwargs) -> Self
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
46
47
48
49
50
51
52
53
54
55
56
57
@classmethod
@functools.lru_cache
def get(cls, object: Any, **kwargs) -> Self:
    if isinstance(object, BrokenPianoNote):
        return object(**kwargs)
    elif isinstance(object, int):
        return cls.from_index(object, **kwargs)
    elif isinstance(object, str):
        return cls.from_name(object, **kwargs)
    elif isinstance(object, float):
        return cls.from_frequency(object, **kwargs)
    return cls(**kwargs)

index_to_name

index_to_name(index: int) -> str
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
61
62
63
64
@staticmethod
@functools.lru_cache
def index_to_name(index: int) -> str:
    return f"{PIANO_NOTES[index % 12]}{index//12 - 1}"

index_to_frequency

index_to_frequency(
    index: int, *, tuning: float = 440
) -> float
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
66
67
68
69
@staticmethod
@functools.lru_cache
def index_to_frequency(index: int, *, tuning: float=440) -> float:
    return tuning * 2**((index - 69)/12)

name_to_index

name_to_index(name: str) -> int
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
71
72
73
74
75
@staticmethod
@functools.lru_cache
def name_to_index(name: str) -> int:
    note, octave = name[:-1].upper(), int(name[-1])
    return PIANO_NOTES.index(note) + 12*(octave + 1)

name_to_frequency

name_to_frequency(
    name: str, *, tuning: float = 440
) -> float
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
77
78
79
80
@staticmethod
@functools.lru_cache
def name_to_frequency(name: str, *, tuning: float=440) -> float:
    return BrokenPianoNote.index_to_frequency(BrokenPianoNote.name_to_index(name), tuning=tuning)

frequency_to_index

frequency_to_index(
    frequency: float, *, tuning: float = 440
) -> int
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
82
83
84
85
@staticmethod
@functools.lru_cache
def frequency_to_index(frequency: float, *, tuning: float=440) -> int:
    return round(12*math.log2(frequency/tuning) + 69)

frequency_to_name

frequency_to_name(
    frequency: float, *, tuning: float = 440
) -> str
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
87
88
89
90
@staticmethod
@functools.lru_cache
def frequency_to_name(frequency: float, *, tuning: float=440) -> str:
    return BrokenPianoNote.index_to_name(BrokenPianoNote.frequency_to_index(frequency, tuning=tuning))

frequency

frequency: float

name

name: str

is_white

is_white(note: int) -> bool
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
112
113
def is_white(note: int) -> bool:
    return (note % 12) in {0, 2, 4, 5, 7, 9, 11}

is_black

is_black(note: int) -> bool
Source code in Projects/ShaderFlow/ShaderFlow/Common/Notes.py
115
116
def is_black(note: int) -> bool:
    return (note % 12) in {1, 3, 6, 8, 10}

white

white: bool

black

black: bool

duration

duration