今日のStudy:オーディオ/フォルマント

注意:音出ます。
http://labs.zkdesign.jp/av512/512_15.html

musicdsp.orgというサイトを漁っていたら処理速度的に使えそうなフォルマントフィルタのアルゴリズムがあったので移植してみた。ノイズにかけたら音がゴルゴっぽくてウケた。

っていうか未だにBPFの計算式みたいのとかいった基本が全然何もわかってないので、これの特性をコントロール、とかが全然できないのが悩みどころ…。いい加減ちゃんと離散フーリエ変換とか学ぼうか…。

で、多分誰の役にも立たなそうだけど一応今回移植したソース。元のソースこちら

package {
	import de.popforge.audio.output.Sample;

	public class FormantFilter {
		
		// A,E,I,O,U
		
		private const coeff:Array=[
			[	3.11044e-06,
				8.943665402,-36.83889529,92.01697887,-154.337906,181.6233289,
				-151.8651235,89.09614114,-35.10298511,8.388101016,-0.923313471
			],
			[	4.36215e-06,
				8.90438318,-36.55179099,91.05750846,-152.422234,179.1170248,
				-149.6496211,87.78352223,-34.60687431,8.282228154,-0.914150747
			],
			[	3.33819e-06,
				8.893102966,-36.49532826,90.96543286,-152.4545478,179.4835618,
				-150.315433,88.43409371,-34.98612086,8.407803364,-0.932568035
			],
			[	1.13572e-06,
				8.994734087,-37.2084849,93.22900521,-156.6929844,184.596544,
				-154.3755513,90.49663749,-35.58964535,8.478996281,-0.929252233
			],
			[	4.09431e-07,
				8.997322763,-37.20218544,93.11385476,-156.2530937,183.7080141,
				-153.2631681,89.59539726,-35.12454591,8.338655623,-0.910251753
			]
		]

		private var memoryL:Array=[0,0,0,0,0,0,0,0,0,0];
		private var memoryR:Array=[0,0,0,0,0,0,0,0,0,0];

		
		public function FormantFilter() {
		}
		
		/**
		 * 
		 * @param	samples
		 * @param	vowelNum 0-4 = [A,E,I,O,U]
		 */
		public function processAudio(samples:Array,vowelNum:int=0):Array{
			
			var smpl:Sample;
			var valL:Number;
			var valR:Number;
			var len:uint=samples.length;

			for(var i:int;i<len;++i){
				smpl=samples[i];
				valL=smpl.left;
				valR=smpl.right;

				//process Lch
				valL=coeff[vowelNum][0] * valL +
						coeff[vowelNum][1]  *memoryL[0] +  
						coeff[vowelNum][2]  *memoryL[1] +
						coeff[vowelNum][3]  *memoryL[2] +
						coeff[vowelNum][4]  *memoryL[3] +
						coeff[vowelNum][5]  *memoryL[4] +
						coeff[vowelNum][6]  *memoryL[5] +
						coeff[vowelNum][7]  *memoryL[6] +
						coeff[vowelNum][8]  *memoryL[7] +
						coeff[vowelNum][9]  *memoryL[8] +
						coeff[vowelNum][10] *memoryL[9];
				//update Lch memory
				memoryL.unshift(valL);
				memoryL.pop();
				
				
				
				//process Rch
				valR=coeff[vowelNum][0] * valR +
						coeff[vowelNum][1]  *memoryR[0] +  
						coeff[vowelNum][2]  *memoryR[1] +
						coeff[vowelNum][3]  *memoryR[2] +
						coeff[vowelNum][4]  *memoryR[3] +
						coeff[vowelNum][5]  *memoryR[4] +
						coeff[vowelNum][6]  *memoryR[5] +
						coeff[vowelNum][7]  *memoryR[6] +
						coeff[vowelNum][8]  *memoryR[7] +
						coeff[vowelNum][9]  *memoryR[8] +
						coeff[vowelNum][10] *memoryR[9];
				
				//update Rch memory
				memoryR.unshift(valR);
				memoryR.pop();
				
				
				//update sample
				smpl.left=valL;
				smpl.right=valR;
			}
			return(samples);
		}
	}
	
}