//  Salience:

c = 60.midicps; 

//e = 71.midicps; 

e = c * 8/5; e.asNote

f = Array.series(5, c, c) ++ Array.series(5, e, e);

~vp = {|freqs| Array.series(9, 1, 2).collect{|n| freqs /n }}; // subharmonics


g = ~vp.(f)

h = g.flop;

h[0].asNote;

w = [1, 0.5, 0.3, 0.2, 0.1, 0.06, 0.03, 0.015, 0.0075]; // weights


x = h.collect{|hx,i| hx.collect{|hy, j| [hy, w[j]]}};

p = ();

x.do{|xx| xx.do{|xxx| p[xxx[0]] = 0}};

x.do{|x0, i| x0.do{|x1, j| p[x1.first] = p[x1.first] + x1.last}};


p.keys.size

p.keys.asArray.asNote

d = p.values.select{|h| h >= 0.5}.removeDuplicates;

r = d.collect{|dd| [p.findKeyForValue(dd), dd]}

r.do{|rr| [rr[0].asNote, rr[1]].postln}




////////////////////


c = 60.midicps; 

e = c * 5/4; e.asNote

g = 67.midicps; 

f = c.series(c * 2, c * 5) ++ e.series(e * 2, e * 5) ++ g.series(g * 2,g * 5);

a = (1..5).reciprocal.ampdb + 90;

~m1 = [f[0..4], a].flop.compensateMasking;

~m2 = [f[5..9], a].flop.compensateMasking;

~m3 = [f[10..14], a].flop.compensateMasking;


[f[0..4], ~m1].flop.asSone.round(0.01);

[f[5..9], ~m1].flop.asSone.round(0.01);

[f[10..14], ~m1].flop.asSone.round(0.01);


a = Salience.calc(f);

a.pitches.values;

a.pitches.scanFor(f[1]);

a.pitches[f[0]]; // the salience value for the first note of the chord

a.pitches.includesKey(f[0]);

l = a.select(1.5); // shows the pitches with a salience of 1.5 or higher



a.spectral; // list of spectral pitches and their salience value

a.virtual; // the list of virtual pitches and their salience

a.virtual




z = Dissonance.make(Array.series(10, c, c), {1}!10, method:\parncutt)

z.harmonicAnalysis

z.play