話速変換機(速聴機)のファームウエア
話速変換機(速聴機)の全ファームウエアはかなりのステップになりますので、キーポイントとなる話速変換アルゴリズムを記載します。
機能フローの「モード選択」「話速変換再生(S再生)」に対応しています。
★メイン(モード選択)
#include <stdio.h>
#include <dsplib.h>
#include "vm.h"
#include "ui.h"
#include "fs.h"
#include "dsp.h"
#include "drv.h"
static int fs_init_p;
static int cur_sel;
extern void rec_init();
extern void rec();
extern void play_init();
extern void play_s();
extern void play_p();
extern void thru_init();
extern void thru();
extern void del_init();
extern void del();
static SETTINGS *settings;
static void init_settings()
{
if(fs_init_p)
{
settings = fs_read_settings();
dsp_set_ingain(settings->ingain);
dsp_set_outgain(settings->outgain);
dsp_set_preamp(settings->preamp);
dsp_set_speed(settings->speed);
dsp_set_pitch(settings->pitch);
dsp_set_geq(settings->geq);
}
}
static void update_settings()
{
if(fs_init_p)
{
settings->ingain = dsp_get_ingain();
settings->outgain = dsp_get_outgain();
settings->preamp = dsp_get_preamp();
settings->speed = dsp_get_speed();
settings->pitch = dsp_get_pitch();
dsp_get_geq(settings->geq);
fs_write_settings(settings);
}
}
void vm_save_settings()
{
update_settings();
}
int vm_format()
{
int yes_p;
yes_p = 0;
ui_menu_del(3,0);
ui_menu_yesno(yes_p);
while(1)
{
switch(ui_get_event())
{
case E_LEFT:
yes_p = 1;
ui_menu_yesno(yes_p);
break;
case E_RIGHT:
yes_p = 0;
ui_menu_yesno(yes_p);
break;
case E_OK:
if(yes_p)
{
lcd_begin_wait();
fs_format();
lcd_end_wait();
return 0;
}
else
return -1;
break;
}
}
}
void main()
{
int k;
int format_error;
drv_init();
ui_init();
dsp_init();
rec_init();
play_init();
thru_init();
del_init();
cur_sel = 0;
ui_menu_main(0,0);
for(k=0;k<10000;k++)
{
asm(" NOP");
asm(" NOP");
asm(" NOP");
}
dsp_disable_output();
dsp_disable_input();
fs_init_p = 0;
format_error = 0;
while(1)
{
if(!cf_exists_p())
{
fs_init_p = 0;
format_error = 0;
}
if(!cf_exists_p() || format_error)
{
ui_show_warn(WARN_NOCARD);
fs_init_p = 0;
ui_menu_main(cur_sel,0);
}
else
{
if(fs_init_p == 0)
{
if(fs_init() && vm_format())
{
format_error = 1;
}
else
{
fs_init_p = 1;
init_settings();
}
}
if(fs_full_p())
{
ui_show_warn(WARN_CARDFULL);
ui_menu_main(cur_sel,2);
}
else if(99 <= fs_max_track())
{
ui_show_warn(WARN_TRACKFULL);
ui_menu_main(cur_sel,2);
}
else
{
ui_show_warn(WARN_NONE);
ui_menu_main(cur_sel,1);
}
}
switch(ui_get_event())
{
case E_DOWN:
if(cur_sel < 4)
{
cur_sel++;
ui_menu_main(cur_sel,fs_init_p);
}
break;
case E_UP:
if(0 < cur_sel)
{
cur_sel--;
ui_menu_main(cur_sel,fs_init_p);
}
break;
case E_OK:
switch(cur_sel)
{
case 0:
if(fs_init_p && fs_max_track() < 99)
{
rec();
update_settings();
ui_menu_main(cur_sel,fs_init_p);
}
break;
case 1:
if(fs_init_p)
{
play_s();
update_settings();
ui_menu_main(cur_sel,fs_init_p);
}
break;
case 2:
if(fs_init_p)
{
play_p();
update_settings();
ui_menu_main(cur_sel,fs_init_p);
}
break;
case 3:
if(fs_init_p)
{
del();
update_settings();
ui_menu_main(cur_sel,fs_init_p);
}
break;
case 4:
thru();
update_settings();
ui_menu_main(cur_sel,fs_init_p);
break;
}
break;
}
}
}★話速変換
#include <string.h>
#include "ui.h"
#include "fs.h"
#include "dsp.h"
static int cur_sel; // 0:main 1:start/stop 2:vol 3:speed 4:filter
static int playing_p;
static int cur_vol;
static int cur_speed;
static int cur_filter;
static int exit_p;
static void update_volume()
{
dsp_set_outgain(cur_vol);
ui_menu_play(2,cur_vol,playing_p);
}
static void update_speed()
{
dsp_set_speed(cur_speed);
ui_menu_play(3,cur_speed,playing_p);
}
static void update_filter()
{
dsp_set_filter(cur_filter);
ui_menu_play(4,cur_filter,playing_p);
}
static void update_menu()
{
int p;
switch(cur_sel)
{
case 0: p = 0; break;
case 1: p = 0; break;
case 2: p = cur_vol; break;
case 3: p = cur_speed; break;
case 4: p = cur_filter; break;
}
ui_menu_play(cur_sel,p,playing_p);
}
static void play_down()
{
if(cur_sel < 4)
{
cur_sel++;
update_menu();
}
}
static void play_up()
{
if(0 < cur_sel)
{
cur_sel--;
update_menu();
}
}
static void play_left()
{
switch(cur_sel)
{
case 2:
if(-42 < cur_vol)
{
cur_vol -= 2;
update_volume();
}
break;
case 3:
if(5 < cur_speed)
{
cur_speed--;
update_speed();
}
break;
case 4:
if(0 < cur_filter)
{
cur_filter--;
update_filter();
}
break;
}
}
static void play_right()
{
switch(cur_sel)
{
case 2:
if(cur_vol < 20)
{
cur_vol += 2;
update_volume();
}
break;
case 3:
if(cur_speed < 40)
{
cur_speed++;
update_speed();
}
break;
case 4:
if(cur_filter < 8)
{
cur_filter++;
update_filter();
}
break;
}
}
static short *sig;
static void play_ok()
{
switch(cur_sel)
{
case 0:
exit_p = 1;
break;
case 1:
if(playing_p)
{
playing_p = 0;
dsp_disable_output();
}
else
{
sig = NULL;
fs_seek(0);
dsp_enable_output();
playing_p = 1;
}
update_menu();
break;
}
}
void play()
{
cur_sel = 0;
playing_p = 0;
cur_vol = dsp_get_outgain();
cur_speed = 10;
cur_filter = dsp_get_filter();
exit_p = 0;
ui_menu_play(cur_sel,0,0);
dsp_disable_output();
dsp_disable_input();
dsp_set_pitch(0);
dsp_set_speed(10);
while(!exit_p)
{
switch(ui_get_event())
{
case E_UP: play_up(); break;
case E_DOWN: play_down(); break;
case E_LEFT: play_left(); break;
case E_RIGHT: play_right(); break;
case E_OK: play_ok(); break;
}
if(playing_p)
{
if(dsp_putsig(sig) == 0)
{
sig = fs_read();
if(sig)
{
dsp(sig);
ui_show_level(dsp_get_level() >> 4);
}
else
{
playing_p = 0;
dsp_disable_output();
update_menu();
}
}
}
else
ui_show_level(0);
}
dsp_disable_output();
dsp_disable_input();
}
★DSP
#include <dsplib.h>
#include "vm.h"
#include "codec.h"
#include "dsp.h"
const int tbl_hanning[] = {
0,0,5,11,20,31,45,61,79,100,124,150,178,209,242,278,
316,357,400,445,493,543,596,651,708,768,830,895,961,1031,1102,1176,
1252,1330,1411,1494,1579,1666,1756,1848,1942,2038,2137,2237,2340,
2445,2552,2661,
2772,2885,3000,3117,3236,3358,3481,3606,3733,3862,3993,4125,4260,
4396,4535,4675,
4816,4960,5105,5252,5401,5551,5703,5857,6012,6169,6327,6487,6648,
6811,6975,7140,
7308,7476,7646,7817,7989,8163,8338,8514,8691,8869,9049,9230,9411,
9594,9778,9963,
10149,10335,10523,10712,10901,11091,11282,11474,11667,11860,12054,
12249,12444,12640,12836,13033,
13230,13428,13627,13826,14025,14224,14424,14624,14825,15025,15226,
15427,15628,15830,16031,16232,
16535,16736,16937,17139,17340,17541,17742,17942,18143,18343,18543,
18742,18941,19140,19339,19537,
19734,19931,20127,20323,20518,20713,20907,21100,21293,21485,21676,
21866,22055,22244,22432,22618,
22804,22989,23173,23356,23537,23718,23898,24076,24253,24429,24604,
24778,24950,25121,25291,25459,
25627,25792,25956,26119,26280,26440,26598,26755,26910,27064,27216,
27366,27515,27662,27807,27951,
28092,28232,28371,28507,28642,28774,28905,29034,29161,29286,29409,
29531,29650,29767,29882,29995,
30106,30215,30322,30427,30530,30630,30729,30825,30919,31011,31101,
31188,31273,31356,31437,31515,
31591,31665,31736,31806,31872,31937,31999,32059,32116,32171,32224,
32274,32322,32367,32410,32451,
32489,32525,32558,32589,32617,32643,32667,32688,32706,32722,32736,
32747,32756,32762,32767,32767
};
static int enable_p;
static int cur_preamp;
static int cur_ingain;
static int cur_outgain;
static int cur_pitch;
static int cur_filter;
static int cur_speed;
#pragma DATA_SECTION(fftwrk,"fftbuf")
static short fftwrk[BLOCKSIZE2];
static short blurdly[BLOCKSIZE];
static short blurdlyw[BLOCKSIZE];
#pragma DATA_SECTION(_delay_buf,"dbuf")
#pragma DATA_SECTION(_delay_buf2,"dbuf")
static short _delay_buf[32];
static short *delay_buf = &_delay_buf[0];
static short _delay_buf2[16];
static short *delay_buf2 = &_delay_buf2[0];
#include "coef.c"
#pragma DATA_SECTION(geq_coef, "filt_coef")
static short geq_coef[32];
static short* filter_coef[9] = {
coef_0,
coef_1,
coef_2,
coef_3,
coef_4,
coef_5,
coef_6,
coef_7,
coef_8
};
static void clr_dbuf()
{
int i;
for(i=0;i<BLOCKSIZE2;i++) fftwrk[i] = 0;
for(i=0;i<BLOCKSIZE;i++) blurdly[i] = 0;
for(i=0;i<BLOCKSIZE;i++) blurdlyw[i] = 0;
for(i=0;i<16;i++) _delay_buf[i] = 0;
delay_buf = &_delay_buf[0];
for(i=0;i<16;i++) _delay_buf2[i] = 0;
delay_buf2 = &_delay_buf2[0];
}
unsigned long magn[BLOCKSIZE];
void group(short *sig, short *g, short *p)
{
short k;
short l,d,n;
magn[0] = ((long)sig[0] * (long)sig[0]);
for(k=1;k<BLOCKSIZE-1;k++)
magn[k] = ((long)sig[2*k ] * (long)sig[2*k ]
+ (long)sig[2*k+1] * (long)sig[2*k+1]);
magn[k] = ((long)sig[1] * (long)sig[1]);
g[0] = p[0] = n = 0;
for(k=2;k<BLOCKSIZE-2;k++)
{
if(magn[k-2] < magn[k] && magn[k-1] < magn[k] &&
magn[k] > magn[k+1] && magn[k] > magn[k+2])
{
p[n] = k;
n++;
}
}
for(k=l=0;k<n-1;k++)
{
d = (p[k] + p[k+1]) / 2 - l;
memset(&g[l],k,d);
l += d;
}
for(;l<BLOCKSIZE;l++)
g[l] = k;
}
int pc;
int pswrk[BLOCKSIZE2];
void pitch_shift_s(short s, short *sig, short *g, short *p)
{
int k;
int idx;
int rp;
int ip;
memset(pswrk,0,BLOCKSIZE2);
for(k=2;k<BLOCKSIZE;k++)
{
idx = (((long)s * (long)p[g[k]] + 8192) >> 14)
+ (k - p[g[k]]);
rp = sig[2*k+0];
ip = sig[2*k+1];
if(BLOCKSIZE - 32 < idx)
continue;
if(idx < 4)
continue;
if((pc & 0x01) && ((idx - k) & 0x01))
{
rp *= -1;
ip *= -1;
}
pswrk[2*idx+0] += rp;
pswrk[2*idx+1] += ip;
}
for(k=0;k<8;k++) pswrk[k] = sig[k];
memcpy(sig,pswrk,BLOCKSIZE2);
pc++;
}
void pitch_shift(short s, short *sig, short *g, short *p)
{
int k;
int idx;
int rp;
int ip;
memset(pswrk,0,BLOCKSIZE2);
for(k=2;k<BLOCKSIZE;k++)
{
idx = (((long)s * (long)p[g[k]] + 8192) >> 14)
+ (k - p[g[k]]);
rp = sig[2*k+0];
ip = sig[2*k+1];
if(BLOCKSIZE < idx)
{
idx = 2*BLOCKSIZE - idx;
ip *= -1;
}
if(idx < 0)
{
idx *= -1;
ip *= -1;
}
if((pc & 0x01) && ((idx - k) & 0x01))
{
rp *= -1;
ip *= -1;
}
if(BLOCKSIZE == idx)
{
pswrk[1] += rp < ip ? ip : rp;
continue;
}
if(idx == 0)
{
pswrk[0] += rp < ip ? ip : rp;
continue;
}
pswrk[2*idx+0] += rp;
pswrk[2*idx+1] += ip;
}
memcpy(sig,pswrk,BLOCKSIZE2);
pc++;
}
short geq_values[32];
short geq_parm[16];
void filter(short *sig, int f)
{
int k;
for(k=0; k < BLOCKSIZE; k++)
{
sig[2*k] = ((long)geq_values[k/8]
* (long)sig[2*k]) >> 15;
sig[2*k+1] = ((long)geq_values[k/8]
* (long)sig[2*k+1]) >> 15;
}
}
short pwrk[BLOCKSIZE2];
short gwrk[BLOCKSIZE2];
short pstbl[25] = {
8192, 8679, 9195, 9741, 10321, 10934,
11585, 12273, 13003, 13776, 14596, 15463,
16383, 17357, 18389, 19483, 20641, 21869,
23169, 24547, 26006, 27553, 29191, 30927,
32766
};
short sctbl[45] = {
0,0,0,0,0,
32766,27306,23404,20480,18204,
16383,14894,13652,12602,11702,
10922,10239,9637,9102,8623,
16383,16383,14894,14894,13652,
13652,12602,12602,11702,11702,
10922,10922,10239,10239,9637,
9637,9102,9102,8623,8623,
16383,12970,10922,9557,8192
};
void dsp_0(short *sig)
{
int i;
for(i=0;i<BLOCKSIZE;i++)
sig[i] >>= 2;
if(cur_speed < 7)
fir(sig, coef_noise_filter_1, sig,
&delay_buf2, 4, BLOCKSIZE);
if(30 <= cur_speed)
fir(sig, coef_hpf,sig,&delay_buf2,4,BLOCKSIZE);
}
void dbxcomp(short* buf)
{
int k;
int neg;
for(k=0;k<BLOCKSIZE;k++)
{
neg = buf[k] < 0 ? 1 : 0;
buf[k] = neg ? -buf[k] : buf[k];
if(buf[k] < 8192)
buf[k] = 15210 * (long)buf[k] / 8192;
else if(buf[k] < 16384)
buf[k] = 1174 * (long)(buf[k] - 8192)
/ 8192 + 15210;
else
buf[k] = 1166 * (long)(buf[k] - 16384)
/ 16384 + 16384;
buf[k] = neg ? -buf[k] : buf[k];
}
}
void dbxexp(short* buf)
{
int k;
int neg;
for(k=0;k<BLOCKSIZE;k++)
{
neg = buf[k] < 0 ? 1 : 0;
buf[k] = neg ? -buf[k] : buf[k];
if(buf[k] < 15210)
buf[k] = (long)8192 * (long)buf[k]
/ (long)15210;
else if(buf[k] < 16384)
buf[k] = (long)8192 * (long)(buf[k] - 15210)
/ (long)1174 + 8192;
else
buf[k] = (long)16384 * (long)(buf[k] - 16384)
/ (long)1166 + 16384;
buf[k] = neg ? -buf[k] : buf[k];
}
}
void dsp_test(short* sig)
{
int i;
memcpy(fftwrk,blurdly,BLOCKSIZE);
memcpy(&fftwrk[BLOCKSIZE],sig,BLOCKSIZE);
memcpy(blurdly,sig,BLOCKSIZE);
cbrev(fftwrk,fftwrk,BLOCKSIZE2/2);
rfft(fftwrk,BLOCKSIZE2,1);
unpacki(fftwrk,BLOCKSIZE2);
cbrev(fftwrk,fftwrk,BLOCKSIZE2/2);
rifft(fftwrk,BLOCKSIZE2,0);
for(i=0;i<BLOCKSIZE;i++)
fftwrk[i] = ((long)fftwrk[i] * (long)tbl_hanning[i]) >> 15;
for(i=0;i<BLOCKSIZE;i++)
fftwrk[BLOCKSIZE+i] = ((long)fftwrk[BLOCKSIZE+i]
* (long)tbl_hanning[BLOCKSIZE-1-i]) >> 15;
for(i=0;i<BLOCKSIZE;i++)
sig[i] = blurdlyw[i] + fftwrk[i];
dbxexp(sig);
memcpy(blurdlyw,&fftwrk[BLOCKSIZE],BLOCKSIZE);
}
void dsp(short* sig)
{
int i;
if(cur_speed < 10 || 0 < cur_pitch)
fir(sig, coef_noise_filter_1, sig, &delay_buf2, 4, BLOCKSIZE);
if(30 <= cur_speed || 0 > cur_pitch)
fir(sig, coef_hpf,sig,&delay_buf2,4,BLOCKSIZE);
memcpy(fftwrk,blurdly,BLOCKSIZE);
memcpy(&fftwrk[BLOCKSIZE],sig,BLOCKSIZE);
memcpy(blurdly,sig,BLOCKSIZE);
cbrev(fftwrk,fftwrk,BLOCKSIZE2/2);
rfft(fftwrk,BLOCKSIZE2,1);
filter(fftwrk,cur_filter);
group(fftwrk,gwrk,pwrk);
if(cur_pitch)
pitch_shift_s(pstbl[cur_pitch+12],fftwrk,gwrk,pwrk);
if(cur_speed != 10)
pitch_shift_s(sctbl[cur_speed],fftwrk,gwrk,pwrk);
unpacki(fftwrk,BLOCKSIZE2);
cbrev(fftwrk,fftwrk,BLOCKSIZE2/2);
rifft(fftwrk,BLOCKSIZE2,0);
for(i=0;i<BLOCKSIZE;i++)
fftwrk[i] = ((long)fftwrk[i] * (long)tbl_hanning[i]) >> 15;
for(i=0;i<BLOCKSIZE;i++)
fftwrk[BLOCKSIZE+i] = ((long)fftwrk[BLOCKSIZE+i]
* (long)tbl_hanning[BLOCKSIZE-1-i]) >> 15;
for(i=0;i<BLOCKSIZE;i++)
sig[i] = blurdlyw[i] + fftwrk[i];
memcpy(blurdlyw,&fftwrk[BLOCKSIZE],BLOCKSIZE);
}
void dsp_init()
{
int k;
cur_preamp = 12;
cur_ingain = 0;
cur_outgain = -10;
cur_pitch = 0;
cur_filter = 1;
cur_speed = 10;
for(k=0;k<32;k++)
geq_values[k] = 0x7fff;
for(k=0;k<16;k++)
geq_parm[k] = 7;
for(k=0;k<32;k++)
geq_coef[k] = 0;
geq_coef[0] = 32767;
clr_dbuf();
codec_init();
enable_p = 0;
}
void dsp_on()
{
clr_dbuf();
codec_init();
dsp_set_outgain(cur_outgain);
enable_p = 1;
}
void dsp_off()
{
codec_disable_rx();
codec_disable_tx();
enable_p = 0;
}
int dsp_enable_p()
{
return enable_p;
}
void dsp_enable_input()
{
clr_dbuf();
codec_enable_rx();
}
void dsp_disable_input()
{
codec_disable_rx();
}
void dsp_enable_output()
{
clr_dbuf();
codec_enable_tx();
}
void dsp_disable_output()
{
codec_disable_tx();
}
int dsp_putsig_ready_p()
{
return codec_putsig_ready_p();
}
int dsp_getsig_ready_p()
{
return codec_getsig_ready_p();
}
int dsp_putsig(short* sig)
{
if(sig)
return codec_putsig(sig);
else
return 0;
}
short* dsp_getsig()
{
return codec_getsig();
}
void dsp_set_preamp(int g)
{
cur_preamp = g;
switch(g)
{
case 0:
codec_set_reg(5,0xb8 | 0);
break;
case 6:
codec_set_reg(5,0xb8 | 1);
break;
case 12:
codec_set_reg(5,0xb8 | 2);
break;
case 24:
codec_set_reg(5,0xb8 | 3);
break;
default:
cur_preamp = 12;
codec_set_reg(5,0xb8 | 2);
break;
}
}
int dsp_get_preamp()
{
return cur_preamp;
}
void dsp_set_ingain(int g)
{
if(g < -42) g = -42;
if(21 < g) g = 20;
cur_ingain = g;
codec_set_reg(5,0x3f & (g + 42));
}
int dsp_get_ingain()
{
return cur_ingain;
}
void dsp_set_outgain(int g)
{
if(g < -42) g = -42;
if(21 < g) g = 20;
cur_outgain = g;
codec_set_reg(5,0x40 | (0x3f & (g + 42)));
}
void dsp_mute()
{
codec_set_reg(5,0x7f);
}
void dsp_unmute()
{
codec_set_reg(5,0x40 | (0x3f & (cur_outgain + 42)));
}
int dsp_get_outgain()
{
return cur_outgain;
}
void dsp_set_filter(int f)
{
cur_filter = f;
}
int dsp_get_filter()
{
return cur_filter;
}
void dsp_set_pitch(int p)
{
cur_pitch = p;
}
int dsp_get_pitch()
{
return cur_pitch;
}
static const int speed_ctrl_mtbl[45] = {
0,0,0,0,0,
10,10,10,10,10,
10,10,10,10,10,
10,10,10,10,10,
10,10,10,10,10,
10,10,10,10,10,
10,10,10,10,10,
10,10,10,10,10,
10,19,16,14,12
};
static const int speed_ctrl_mtbl[45] = {
0,0,0,0,0,
8,8,8,8,8,
8,8,8,8,8,
8,8,8,8,8,
8,8,8,8,8,
8,8,8,8,8,
8,8,8,8,8,
8,8,8,8,8,
8,19,16,14,12
};
static const int speed_ctrl_mtbl[45] = {
13,13,13,13,13,
13,13,13,13,13,
13,13,13,13,13,
13,13,13,13,13,
13,13,13,13,13,
13,13,13,13,13,
13,13,13,13,13,
13,13,13,13,13,
13,13,13,13,13
};
static const int speed_ctrl_mtbl[45] = {
9,9,9,9,9,
9,9,9,9,9,
9,9,9,9,9,
9,9,9,9,9,
9,9,9,9,9,
9,9,9,9,9,
9,9,9,9,9,
9,9,9,9,9,
9,9,9,9,9
};
static const int speed_ctrl_mtbl[45] = {
0,0,0,0,0,
24,21,18,16,14,
12,22,21,19,18,
17,16,15,14,13,
12,24,22,22,21,
21,19,19,18,18,
17,17,16,16,15,
15,14,14,13,13,
12,19,16,14,12
};
static const int pitch_speed_mtbl[13] = {
46, 49, 52, 55, 58, 61, 65, 69, 73, 77, 82, 87, 92
};
void set_mnp(int m, int n, int p)
{
codec_set_reg(4,0x80 | m);
codec_set_reg(4,n << 3 | p);
}
void dsp_set_pitch_speed(int p)
{
codec_set_reg(4,0x80 | pitch_speed_mtbl[p + 6]);
}
void dsp_set_speed(int s)
{
if(s == 0)
{
codec_set_reg(4,0x80 | CODEC_M);
cur_speed = 10;
}
else
{
codec_set_reg(4,0x80 | CODEC_M);
cur_speed = s;
}
}
int dsp_get_speed()
{
return cur_speed;
}
int dsp_calc_level(short* sig)
{
unsigned long x;
int level;
int k;
x = 0;
for(k=0;k<BLOCKSIZE;k++)
x += ((long)sig[k] * (long)sig[k]) >> 15;
for(level = 31; 0 <= level; level--)
{
if(0x80000000 & x)
return level;
x <<= 1;
}
return 0;
}
static int conv(int nx, short* x, int ny, short* y, short* ans)
{
int k;
int s;
int n;
n = (nx-1)+(ny-1)+1;
for(k=0;k<n;k++)
{
ans[k] = 0;
for(s=0;s<=k;s++)
{
ans[k] += (long)(s < nx ? x[s] : 0)
* (long)(k-s < ny ? y[k - s] : 0) >> 15;
}
}
return n;
}
static const short cosine[16] = {
32767,
32137,
30273,
27245,
23170,
18204,
12539,
6393,
0,
-6393,
-12539,
-18204,
-23170,
-27245,
-30273,
-32137
};
static void root_to_coef(short* r, short* a)
{
short t[32];
short x[4];
short na;
short k;
a[0] = (long)r * (long)r >> 15;
a[1] = -2 * (long)cosine[0] * (long)r;
a[2] = 1;
na = 3;
for(k=1; k < 16; k++)
{
x[0] = (long)r * (long)r;
x[1] = -2 * (long)cosine[k] * (long)r;
x[2] = 1;
na = conv(3,x, na, a, t);
memcpy(a,t,na);
}
}
static const short geq_vtbl[8] = {
0x1000,
0x2000,
0x3000,
0x4000,
0x5000,
0x6000,
0x7000,
0x7fff
};
static setup_geq_filter(short* g)
{
short r[16];
int k;
for(k=0;k<16;k++)
r[k] = geq_vtbl[g[k]];
root_to_coef(r,geq_coef);
}
void dsp_set_geq(short* values)
{
int k;
int n;
switch(cur_speed)
{
case 9:
n = 15;
break;
case 8:
n = 14;
break;
case 7:
n = 13;
break;
case 6:
n = 12;
break;
case 5:
n = 11;
break;
default:
n = 16;
break;
}
for(k=0;k<n;k++)
{
if(values[k] < 0)
geq_parm[k] = 0;
else if(values[k] > 7)
geq_parm[k] = 7;
else
geq_parm[k] = values[k];
}
for(k=0;k<15;k++)
{
geq_values[2*k+2] = geq_values[2*k+1]
= ((long)geq_vtbl[values[k]]
* (long)geq_vtbl[values[k+1]]) >> 15;
}
geq_values[0] = geq_vtbl[values[0]];
geq_values[31] = geq_vtbl[values[15]];
}
void dsp_get_geq(short* values)
{
memcpy(values,geq_parm,sizeof(geq_parm));
if(cur_speed <= 9)
values[15] = 0;
if(cur_speed <= 8)
values[14] = 0;
if(cur_speed <= 7)
values[13] = 0;
if(cur_speed <= 6)
values[12] = 0;
if(cur_speed <= 5)
values[11] = 0;
}