summaryrefslogtreecommitdiff
path: root/js/vendor
diff options
context:
space:
mode:
authorJules Laplace <jules@okfoc.us>2016-11-18 19:08:50 -0500
committerJules Laplace <jules@okfoc.us>2016-11-18 19:08:50 -0500
commit1d6e01a44ea9f23b2a7fcc63de12c132e74fc0bb (patch)
tree712c7f5ec3f3d9d567c9b67e33499b6dcb8f5589 /js/vendor
parentebaf585e2e0b1efb7e7d6b9841ea5d949b8394c7 (diff)
hiding broken stuff
Diffstat (limited to 'js/vendor')
-rw-r--r--js/vendor/intonation.js163
1 files changed, 163 insertions, 0 deletions
diff --git a/js/vendor/intonation.js b/js/vendor/intonation.js
new file mode 100644
index 0000000..b660fee
--- /dev/null
+++ b/js/vendor/intonation.js
@@ -0,0 +1,163 @@
+var Intonation = (function(){
+ var Intonation = function(opt){
+ opt = this.opt = Object.assign({
+ name: "",
+ 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.scl) {
+ this.generate_scl()
+ }
+ else 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.name = this.opt.name || "interval list"
+ this.intervals = interval_list
+ this.interval = 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.interval = this.opt.interval
+ var ratio = Math.pow( interval, 1/tet )
+ var n = root
+ scale.push(n)
+ for (var i = 0; i < tet-1; i++) {
+ n *= ratio
+ scale.push(n)
+ }
+ this.name = this.opt.name || tet + "-tone equal temperament"
+ this.intervals = null
+ }
+ Intonation.prototype.generate_scl = function(){
+ var root = this.opt.root
+ var scl = this.parse_scl( this.opt.scl )
+ this.intervals = scl.notes
+ this.interval = scl.notes.pop()
+ this.name = this.opt.name || scl.description
+ this.scale = scl.notes.map(function(v){
+ return v * root
+ })
+ }
+ Intonation.prototype.parse_scl = function(s){
+ var scl = {}
+ scl.comments = []
+ scl.notes = []
+ s.trim().split("\n").forEach(function(line){
+ // Lines beginning with an exclamation mark are regarded as comments
+ // and are to be ignored.
+ if ( line.indexOf("!") !== -1 ) {
+ scl.comments.push(line)
+ }
+ // The first (non comment) line contains a short description of the scale.
+ // If there is no description, there should be an empty line. (nb: which is falsey)
+ else if ( ! ('description' in scl) ) {
+ scl.description = line
+ }
+ // The second line contains the number of notes.
+ // The first note of 1/1 or 0.0 cents is implicit and not in the files.
+ else if ( ! scl.notes.length) {
+ scl.notes.push(1)
+ }
+ else {
+ // If the value contains a period, it is a cents value, otherwise a ratio.
+ var note = line.replace(/^[^-\.0-9]+/,"").replace(/[^-\/\.0-9]+$/,"")
+ if ( note.indexOf(".") !== -1 ) {
+ note = Math.pow( 2, (parseFloat(note) / 1200) )
+ }
+ else {
+ note = parseInterval(note)
+ }
+ if (note) {
+ scl.notes.push(note)
+ }
+ }
+ })
+ return scl
+ }
+ 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.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.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
+})()
+