( 変更履歴:
v0.3 ['16/10/11]
セント値のグラフからインハーモニシティ値を加え無くしました。
v0.2 ['11/10/30] c2fの計算式を変更しました。)
Javaの run部分
tuningの計算を取り出してみました。
mwdファイルとうなり数を
>> tuning('design.mwd', 1.0)
とする事で tuning後のセント値のグラフが表示されます。
function毎に別ファイルにする事で計算速度は早くなります。
827.98 -> 39.638[sec]
function tuning(fname, beat) global SM KM NG WM AA DC W head is_fortepiano; SM = 7.85; # 芯線密度 g/cm^3 KM = 6.9906; # 銅と空気の混合密度 g/cm^3 NG = 9.80665204821; # 重力加速度 kgw WM = 9.0; # 巻線密度 g/cm^3 DC = 0.1; # Δcent値 if (nargin < 1 || nargin > 2) usage("tuning('mwd_file_name' [, beats (1.0)])"); elseif (nargin < 2) beat = 1.0; end [head, wire] = ReadWire(fname); W = Wire(wire); if (length(head) > 3) # フォルテピアノ is_fortepiano = true; start_key = head(4)+1; AA = 415; else # ピアノ is_fortepiano = false; start_key = 1; AA = 440; end lenw = length(wire); bee = zeros(1, lenw); SetWire(start_key, AA); k2k = 24; # 2octave tune inte = Interval(k2k); wi36 = k2w(36); wi37 = k2w(37); wi61 = k2w(61); wi62 = k2w(62); up = sa = sb = ds = 0; do ds = up/(wi61-wi37); set2octave(up, wi37, wi61); tune(true, wi62, inte, beat); sa = W(wi62).cnt-W(wi61).cnt; tune(false, wi36, inte, beat); sb = W(wi37).cnt-W(wi36).cnt; if (sa-ds > 0.3) d = DC*10; else d = DC; end up = up+d; until (sa <= ds && sb >= ds) up = up-d; set2octave(up, wi37, wi61); for i=wi36:-1:start_key tune(false, i, inte, beat); end for i=wi62:lenw tune(true, i, inte, beat); end cent = zeros(1, lenw); for i=start_key:lenw cent(i) = W(i).cnt; end plot(cent, '@;Cent;'); end #-----
function set2octave(up, i_start, i_end) global W; ds = up/(i_end-i_start); dd = up/2; n = 0; for i=i_start:i_end W(i).cnt = ds*(n++)-dd; ResetWire(i); end end # 2octave分のセント値を加えます #-----
function beat = tune(sw, wi, inte, max) global W DC; if (sw == true) # 上行 dc = DC; wh = wi; wl = itvl2wire(wi, -inte(1)); else # 下行 dc = -DC; wl = wi; wh = itvl2wire(wi, inte(1)); end sa = 0.2; % 差がsa以内でdcを1/10に変更 beat = GetWbeats(wh, wl, inte); while (beat < max) if (max-beat > sa) d = dc*10; else d = dc; end; W(wi).cnt = W(wi).cnt+d; ResetWire(wi); beat = GetWbeats(wh, wl, inte); end while (beat > max) if (max-beat > sa) d = dc*10; else d = dc; end W(wi).cnt = W(wi).cnt-d; ResetWire(wi); beat = GetWbeats(wh, wl, inte); end end # 一定のうなりになるまでセント値を増減します #-----
function beats = GetWbeats(wh, wl, inte) global W; beats = c2f(W(wh).frq*inte(3), W(wh).inh*inte(3)*inte(3)+W(wh).cnt)-\ c2f(W(wl).frq*inte(2), W(wl).inh*inte(2)*inte(2)+W(wl).cnt); end # 音程間のうなりを計算します #-----
function [header, wire] = ReadWire(fname) wire = dlmread(fname); len = length(wire(1, :)); if (len <= 3) header = [wire(1,1) wire(1,2) wire(1,3)]; elseif (len > 3) header = [wire(1,1) wire(1,2) wire(1,3) wire(1,4) wire(1,5)]; else error('Not Wire data.'); end wire(1,:) = []; end # mwdファイルを読み込みます #-----
function w = Wire(x) [row, col] = size(x); for i=1:row if (col > 3) w(i) = struct('length', x(i,1), 'bante', x(i,2), 'copper', x(i,3),\ 'density', x(i,4), 'pitch', x(i,5),\ 'key', 0, 'dia', 0, 'ald', 0, 'den', 0,\ 'ten', 0,'inh', 0, 'cnt', 0, 'frq', 0); else w(i) = struct('length', x(i,1), 'bante', x(i,2), 'copper', x(i,3),\ 'density', 0, 'pitch', 0,\ 'key', 0, 'dia', 0, 'ald', 0, 'den', 0,\ 'ten', 0, 'inh', 0, 'cnt', 0, 'frq', 0); end end end # 読み込んだmwdからwireデータを作成します #-----
function SetWire(start_key, aa) global SM W is_fortepiano; for i=start_key:length(W) W(i).key = w2k(i); # key.no W(i).dia = getDia(W(i).bante); # dia W(i).ald = GetAlld(W(i).bante, W(i).copper); # all-d W(i).den = GetDensity(W(i).dia, W(i).copper, W(i).ald,\ W(i).density, W(i).pitch); # den W(i).frq = c2f(GetFreq(W(i).key, aa), W(i).cnt); # freq. [gten, W(i).ten] = GetTension(W(i).frq, W(i).length, W(i).bante,\ W(i).copper, W(i).ald, W(i).den); # ten if (is_fortepiano) sm = W(i).density; else sm = SM; end W(i).inh = GetInha(W(i).frq, W(i).length, W(i).bante, W(i).copper,\ sm, W(i).ten, W(i).ald); # inha end end # wireにtuningに必要な値いを設定します #-----
function ResetWire(wi) global SM W is_fortepiano; freq = c2f(W(wi).frq, W(wi).inh+W(wi).cnt); # [gten, W(wi).ten] = GetTension(freq, W(wi).length, W(wi).bante, W(wi).copper,\ W(wi).ald, W(wi).den); # ten if (is_fortepiano) sm = W(wi).density; else sm = SM; end W(wi).inh = GetInha(freq, W(wi).length, W(wi).bante, W(wi).copper,\ sm, W(wi).ten, W(wi).ald); # inha end # セント値の変更後に wireの値を再計算します #-----
function ad = GetAlld(bante, copper) global is_fortepiano; if (is_fortepiano) ad = bante; else ad = copper*0.94*2+GetDia(bante); end end # 巻線を加えた時の弦径を計算します #-----
function den = GetDensity(dia, copper, alld, density, wpitch) global WM KM SM is_fortepiano; mm = 20; if (copper > 0) if (is_fortepiano) den = (density*(dia/mm)^2+WM*(copper/mm)^2*\ ((dia+copper)/mm)*pi*10/wpitch)/(dia/mm)^2; else j = (alld/2)^2; g = (dia/2)^2; den = (KM*(j-g)+SM*g)/j; end else if (is_fortepiano) den = density; else den = SM; end end end # 弦密度を計算します #-----
function [dia, aa] = GetDia(bante) ba = 12:0.5:25; dm = 1.25:0.05:1.500; da = 0.725:0.025:1.225; di = [da dm]; dia = -1; aa = 440; if (bante < 12 && bante > 0.1) dia = bante; aa = 415; else x = find(ba == bante); if (x > 0) dia = di(x); end end end # 番手から弦径を得ます #-----
function inh = GetInha(freq, leng, ban, cop, sm, ten, alld) me = 1000; cm = 10; [di, aa] = GetDia(ban); if (cop > 0) inh = 3.3*cm^13*(di/cm)^2/(leng/cm)^4/\ ((ten/pi/(sm*me))^(1/2)/(leng/me)/(di/me))^2*\ (1+alld/di/cm); else inh = 3.3*cm^13*(di/cm)^2/(leng/cm)^4/freq^2; end end # インハーモニシティ値を計算します #-----
function [gten, ten] = GetTension(freq, leng, ban, cop, alld, den) global SM NG is_fortepiano; mm = 1000; [dia, pitch] = GetDia(ban); if (is_fortepiano) di = dia; else if (cop > 0) di = alld; else di = dia; end end if (cop > 0) de = den; else if (is_fortepiano) de = den; else de = SM; end end ten = pi*de*mm*freq^2*(leng/mm)^2*(di/mm)^2; gten = ten/NG; end # 弦張力を計算します #-----
function freq = GetFreq(key, pitch) if (nargin < 1) usage("GetFreq([key | key_list], [pitch (440)])"); elseif (nargin < 2) pitch = 440; end freq = pitch.*2.^((key-49)./12); end # キーから周波数を計算します #-----
function f = c2f(freq, cent) f = freq.*2.^(cent/1200); end # セント値から周波数を計算します #-----
function wi = k2w(k) global head; ob = head(1); db = head(2); sb = head(3); if (k < ob) wi = k-1; elseif (k >= sb) wi = k-sb+db; else wi = (k-ob)*2+ob-1; end wi = wi+1; end # キーからwire番号を得ます #-----
function key = w2k(w) global head; ob = head(1); db = head(2); sb = head(3); if (w < db) if (w >= ob) key = round(ob+1+(w-ob)/2); else key = w+1; end else key = w-db+sb; end key = key-1; end # wire番号からキーを得ます #-----
function x = itvl2wire(wi, inte) nk = w2k(wi); x = wi+inte; xk = w2k(x); while(nk+inte > xk) xk = w2k(++x); end while(nk+inte < xk) xk = w2k(--x); end end # 音程からwire番号を得ます #-----
function [inter, intst] = Interval(inte) intn = [1 16 15; 2 9 8; 3 6 5; 4 5 4; 5 4 3; 6 7 5;\ 7 3 2; 8 8 5; 9 5 3; 10 7 4; 11 15 8; 12 2 1;\ 16 5 2; 19 3 1; 24 4 1; 28 5 1; 31 6 1; 36 8 1]; ratio = {'mi.2nd' 'Mj.2nd' 'mi.3rd' 'Mj.3rd' 'P.4th' 'Dim.5th'\ 'P.5th' 'mi.6th' 'Mj.6th' 'mi.7th' 'Mj.7th' 'Octave'\ '10th' '12th' '2octave' 'Oct.10th' 'Oct.12th' '3octave'}; inter = -1; intst = ''; x = find(intn(:, 1) == inte); if (x > 0) inter = intn(x, 1:3); intst = ratio{x}; end end # 音程からキー間隔|倍音数を得ます