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
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
|
var Intonation = (function(){
var Intonation = function(opt){
opt = this.opt = Object.assign({
root: 440,
octave: 0,
interval: 2,
tet: 0,
intervals: null,
}, opt || {})
this.generate()
}
Intonation.prototype.generate = function(opt){
opt = Object.assign(this.opt, opt || {})
if (opt.tet) {
this.generate_tet()
}
else if (opt.intervals) {
this.generate_intervals()
}
}
Intonation.prototype.generate_intervals = function(){
var root = this.opt.root
var interval_list = this.opt.intervals
if (typeof interval_list == "string") {
interval_list = interval_list.split(" ")
}
this.intervals = interval_list
this.opt.interval = parseInterval.call(this, interval_list.pop() )
this.scale = interval_list.map( parseIntervalString.bind(this) ).filter(function(v){
return !! v
})
}
Intonation.prototype.generate_tet = function(){
var scale = this.scale = []
var root = this.opt.root
var tet = this.opt.tet
var interval = this.opt.interval
var ratio = Math.pow( interval, 1/tet )
var n = root
scale.push(n)
for (var i = 0; i < tet; i++) {
n *= ratio
scale.push(n)
}
this.intervals = null
}
Intonation.prototype.index = function(i, octave){
octave = octave || this.opt.octave
var f = this.scale[ mod(i, this.scale.length)|0 ]
var pow = Math.floor(norm(i, 0, this.scale.length)) + octave
f *= Math.pow(this.opt.interval, pow)
return f
}
Intonation.prototype.range = function(min, max){
var a = []
for (var i = min; i < max; i++) {
a.push( this.index(i) )
}
return a
}
Intonation.prototype.set_root = function(f){
this.opt.root = f
this.generate()
}
Intonation.prototype.quantize_frequency = function(f){
if (f == 0) return 0
var scale_f = f
var pow = 0
var interval = this.opt.interval
var scale = this.scale
while (scale_f < root) {
scale_f *= interval
pow -= 1
}
while (scale_f > root * interval) {
scale_f /= interval
pow += 1
}
for (var i = 0; i < scale.length; i++) {
if (scale_f > scale[i]) continue
scale_f = scale[i]
break
}
scale_f *= Math.pow(2, pow)
return scale_f
}
Intonation.prototype.quantize_index = function(i){
return mod(index-1, this.scale.length)|0
}
var parseInterval = Intonation.prototype.parse_interval = function (s) {
if (typeof s == "number") return s
if (! s.indexOf("/") == -1) return parseInt(s)
var pp = s.split("/")
var num = parseInt(pp[0])
var den = parseInt(pp[1])
if (isNaN(num)) return 1
if (isNaN(den) || den == 0) return num
if (num == den) return 1
return num / den
}
var parseIntervalString = Intonation.prototype.parse_interval_string = function(s){
if (s.indexOf("/") !== -1) return parseInterval(s) * this.opt.root // intervals
if (s.indexOf("f") !== -1) return parseFloat(s) // pure frequencies
return parseFloat(s)
}
function norm(n,a,b){ return (n-a) / (b-a) }
function mod(n,m){ return n-(m * Math.floor(n/m)) }
return Intonation
})()
|