-
Notifications
You must be signed in to change notification settings - Fork 0
/
nklang.py
82 lines (60 loc) · 1.78 KB
/
nklang.py
1
2
3
4
5
6
7
8
9
10
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
import math
from copy import copy
import numpy as np
from util import *
class Nklang(object):
'''
"Abstract" base class for all types of nklang.
'''
def get_number(self):
raise NotImplementedError()
def get_name(self):
raise NotImplementedError()
class Nullklang(Nklang):
'''
Used for silent sections.
'''
def __init__(self):
pass
def get_name(self):
return '-'
def get_number(self):
return -1
def transpose(self, _):
return Nullklang()
def __repr__(self):
return '<Nullklang>'
class Anyklang(object):
'''
An nklang, where n > 0.
Numerically represented as sum_{i = 0}^{n - 1} k_i * 12^i, where
k_i is the i:th note in the klang.
'''
def __init__(self, notes, n):
self.original_notes = copy(notes)
self.notes = notes
if len(notes) < n:
self.notes += [self.notes[-1]] * (n - len(self.notes))
def get_name(self):
return ', '.join(map(lambda n: note_names[n], self.original_notes))
def get_number(self):
return np.dot(np.array(self.notes), (12 ** np.arange(len(self.notes))))
def transpose(self, delta):
transposed_notes = map(lambda n: (n + delta) % 12, self.original_notes)
return Anyklang(transposed_notes, len(self.notes))
def get_n(self):
return len(self.original_notes)
def __repr__(self):
return '<%d-klang: %s>' % (self.get_n(), self.get_name())
def klang_number_to_name(number, n):
'''
Helper that returns the name of an nklang.
'''
if number == -1:
return 'Silence'
else:
names = []
for i in range(n):
names.append('%-2s' % note_names[number % 12])
number /= 12
return ', '.join(names)