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なので下位の計算は全くしてません。