Lynx-EyEDの電音鍵盤 新館

制御とか数学とか駄文とか

16bit分計算させるだけ時間の無駄なんじゃないかな

ADPCMのデコードが余りにも音割れするのと、計算量の多さでPSoCにかなり負担が掛かっているようなので、デコード処理を独自に作り直してみました。

まあまあの音質でしょう。

なお、音声の出力は8bit-PWMで行うので、8bit分の計算ですむように工夫しました。
ほかの8bitマイコンでも8*8の乗算器がある(PIC18Fなど)ならちょっとの改造でこのコードで使いまわせます。このコードをima_adpcm.cなどのファイル名で保存して、#includeしてやれば、

hoge = ADPCMDecoder(char fuga);

で、fuga(下位4bit-ADPCMデータ)を8bit-PCMデータhogeに変換します。

volatile const unsigned char StepTbl[89] = {

0 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,1 ,
1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,
1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,
1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,
2 ,2 ,2 ,2 ,2 ,3 ,3 ,3 ,3 ,3 ,
3 ,3 ,3 ,3 ,4 ,4 ,5 ,5 ,6 ,6 ,
7 ,7 ,8 ,9 ,10,11,12,13,15,15,
15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15	
};

const signed char scale_change_tbl[8] = {
   -1, -1, -1, -1, 2, 4, 6, 8};

signed char	scale;
signed long	adpcmdata;

unsigned char ADPCMDecoder(unsigned char code)
{
	int dlevel;
	MUL0_X = (code & 0x07);
	MUL0_Y = StepTbl[scale];// scale:index

	dlevel = (((MUL0_DH << 8)& 0xff00) | MUL0_DL);

	if(code & 0x08){
  		adpcmdata -= dlevel;
  		if(adpcmdata < -128)adpcmdata = -128;
	}else{  
	adpcmdata += dlevel;
  	if(adpcmdata >= 127)adpcmdata =  127;
	}

	scale += scale_change_tbl[code & 0x07];
	if(scale < 0)scale = 0;
	else if(scale >= 89)scale = 88;

	return ((unsigned char)adpcmdata + 128);
}

という感じです。LPF2をお忘れなく。

                  • -

※追記(10月29日)なお、音割れを防ぐためソースコードの9,10行目を書き換えています。
これはWindowsのサウンドレコーダでのADPCMエンコードを前提としています。
元の音声データが十分小さい音量であればデコード時にPCMデータが飽和する可能性は低くなりますのでオリジナルのコーディングで構いません。

※追記(12月5日)ソースのscaleは89個必要なので(エンコードするときは89個という前提でエンコードされている)修正しました。使用するのはデコード後の上位8bitなので下位の計算は全くしてません。