📄 ath.c
字号:
}double ATH ( double freq ){ static float tab [] = { /* 10.0 */ 96.69, 96.69, 96.26, 95.12, /* 12.6 */ 93.53, 91.13, 88.82, 86.76, /* 15.8 */ 84.69, 82.43, 79.97, 77.48, /* 20.0 */ 74.92, 72.39, 70.00, 67.62, /* 25.1 */ 65.29, 63.02, 60.84, 59.00, /* 31.6 */ 57.17, 55.34, 53.51, 51.67, /* 39.8 */ 50.04, 48.12, 46.38, 44.66, /* 50.1 */ 43.10, 41.73, 40.50, 39.22, /* 63.1 */ 37.23, 35.77, 34.51, 32.81, /* 79.4 */ 31.32, 30.36, 29.02, 27.60, /* 100.0 */ 26.58, 25.91, 24.41, 23.01, /* 125.9 */ 22.12, 21.25, 20.18, 19.00, /* 158.5 */ 17.70, 16.82, 15.94, 15.12, /* 199.5 */ 14.30, 13.41, 12.60, 11.98, /* 251.2 */ 11.36, 10.57, 9.98, 9.43, /* 316.2 */ 8.87, 8.46, 7.44, 7.12, /* 398.1 */ 6.93, 6.68, 6.37, 6.06, /* 501.2 */ 5.80, 5.55, 5.29, 5.02, /* 631.0 */ 4.75, 4.48, 4.22, 3.98, /* 794.3 */ 3.75, 3.51, 3.27, 3.22, /* 1000.0 */ 3.12, 3.01, 2.91, 2.68, /* 1258.9 */ 2.46, 2.15, 1.82, 1.46, /* 1584.9 */ 1.07, 0.61, 0.13, -0.35, /* 1995.3 */ -0.96, -1.56, -1.79, -2.35, /* 2511.9 */ -2.95, -3.50, -4.01, -4.21, /* 3162.3 */ -4.46, -4.99, -5.32, -5.35, /* 3981.1 */ -5.13, -4.76, -4.31, -3.13, /* 5011.9 */ -1.79, 0.08, 2.03, 4.03, /* 6309.6 */ 5.80, 7.36, 8.81, 10.22, /* 7943.3 */ 11.54, 12.51, 13.48, 14.21, /* 10000.0 */ 14.79, 13.99, 12.85, 11.93, /* 12589.3 */ 12.87, 15.19, 19.14, 23.69, /* 15848.9 */ 33.52, 48.65, 59.42, 61.77, /* 19952.6 */ 63.85, 66.04, 68.33, 70.09, /* 25118.9 */ 70.66, 71.27, 71.91, 72.60, }; double freq_log; double dB; unsigned index; if ( freq < 10. ) freq = 10.; if ( freq > 25000. ) freq = 25000.; freq_log = 40. * log10 (0.1 * freq); /* 4 steps per third, starting at 10 Hz */ index = (unsigned) freq_log; assert ( index < sizeof(tab)/sizeof(*tab) ); dB = tab [index] * (1 + index - freq_log) + tab [index+1] * (freq_log - index); return pow ( 10., 0.05*dB );}/****************************************************************************************************** * keyboard stuff ******************************************************************************************************/typedef struct { int init; struct termios stored_setting; struct termios current_setting;} keyboard_t;static keyboard_t* __k;/* Restore term-settings to those saved when term_init was called */static void term_restore (void){ tcsetattr ( 0, TCSANOW, &(__k->stored_setting) );} /* term_restore *//* Clean up terminal; called on exit */static void term_exit ( int sig ){ term_restore ();} /* term_exit *//* Will be called when ctrl-Z is pressed, this correctly handles the terminal */static void term_ctrl_z ( int sig ){ signal ( SIGTSTP, term_ctrl_z ); term_restore (); kill ( getpid(), SIGSTOP );} /* term_ctrl_z *//* Will be called when application is continued after having been stopped */static void term_cont ( int sig ){ signal ( SIGCONT, term_cont ); tcsetattr ( 0, TCSANOW, &(__k->current_setting) );} /* term_cont() */int open_keyboard ( keyboard_t* const k ){ __k = k; tcgetattr ( 0, &(k->stored_setting) ); tcgetattr ( 0, &(k->current_setting) ); signal ( SIGINT, term_exit ); /* We _must_ clean up when we exit */ signal ( SIGQUIT, term_exit ); signal ( SIGTSTP, term_ctrl_z ); /* Ctrl-Z must also be handled */ signal ( SIGCONT, term_cont );// atexit ( term_exit ); /* One or more characters are sufficient to cause a read to return */ cfmakeraw ( &(k->current_setting) ); k->current_setting.c_oflag |= ONLCR | OPOST; /* enables NL => CRLF on output */ tcsetattr ( 0, TCSANOW, &(k->current_setting) ); return 0;}int getchar_keyboard ( keyboard_t* const k ){ struct timeval t; fd_set fd [1]; int ret; unsigned char c; FD_SET (0, fd); t.tv_sec = 0; t.tv_usec = 0; ret = select ( 1, fd, NULL, NULL, &t ); switch ( ret ) { case 0: return -1; case 1: ret = read (0, &c, 1); return ret == 1 ? c : -1; default: return -2; }}int close_keyboard ( keyboard_t* const k ){ term_restore (); return 0;}/****************************************************************************************************** * reporting stuff ******************************************************************************************************/int report_open ( void ){ static char buff [32767]; fflush ( stdout ); setvbuf ( stdout, buff, _IOFBF, sizeof(buff) ); return 0;}int report ( const generator_t* const g, const amplitude_t* const a ){ static double last_freq = -1.; static double last_level = -1.; double freq; double level; freq = frequency (g); level = 20. * log10 (amplitude (a) * ATH (freq) ) + 80.; if ( last_freq >= 0 ) printf ( "%11.3f %8.2f\n", sqrt (freq*last_freq), 0.5 * (level+last_level) ); printf ( "# %9.3f %8.2f\n", freq, level ); fflush ( stdout ); last_freq = freq; last_level = level; return 0;}int report_close ( void ){ printf ( "%%%%\n\n" ); fflush ( stdout ); close ( dup ( fileno(stdout) ) ); setvbuf ( stdout, NULL, _IONBF, 0 ); return 0;}/****************************************************************************************************** * main stuff ******************************************************************************************************/typedef enum { left = 0, right = 1, phase0 = 2, both = 2, phase90 = 3, phase180 = 4, phasemod = 5 } earmode_t;static long double scalar ( const double* a, const double* b ){ return a[ 0]*b[ 0] + a[ 1]*b[ 1] + a[ 2]*b[ 2] + a[ 3]*b[ 3] +a[ 4]*b[ 4] + a[ 5]*b[ 5] + a[ 6]*b[ 6] + a[ 7]*b[ 7] +a[ 8]*b[ 8] + a[ 9]*b[ 9] + a[10]*b[10] + a[11]*b[11] +a[12]*b[12] + a[13]*b[13] + a[14]*b[14] + a[15]*b[15];}int experiment ( generator_t* const g, amplitude_t* const a, keyboard_t* const k, soundcard_t* const s, earmode_t earmode ){ long i; int j; stereo_t samples [512]; static double quant_errors [2] [16]; long double val; double ampl; long ival; fprintf ( stderr, "\r+++ up +++" ); for ( i = 0; i < g->duration; i += sizeof(samples)/sizeof(*samples) ) { fprintf ( stderr, "%3lu%%\b\b\b\b", i*100lu/g->duration ); for (j = 0; j < sizeof(samples)/sizeof(*samples); j++ ) { ampl = iterate_amplifier (a) * ATH (frequency (g)); val = ampl * iterate_generator (g); ival = (long) floor ( val + 0.5 + scalar (quant_errors[0], s->dither) ); if ( ival != (sample_t) ival ) { report (g, a); fprintf ( stderr, "\rOverrun \n\n" ); return -1; } memmove ( & quant_errors [0] [1], & quant_errors [0] [0], sizeof(quant_errors[0]) - sizeof(quant_errors[0][0]) ); quant_errors [0] [0] = val - ival; switch ( earmode ) { case both: samples [j] [0] = samples [j] [1] = ival; break; case left: samples [j] [0] = ival; samples [j] [1] = 0; break; case right: samples [j] [0] = 0; samples [j] [1] = ival; break; case phase180: samples [j] [0] = ival == -32768 ? 32767 : -ival; samples [j] [1] = +ival; break; case phase90: samples [j] [0] = ival; val = ampl * get_cosine (g); ival = (long) floor ( val + 0.5 + scalar (quant_errors[1], s->dither) ); if ( ival != (sample_t) ival ) { report (g, a); fprintf ( stderr, "\rOverrun \n\n" ); return -1; } memmove ( & quant_errors [1] [1], & quant_errors [1] [0], sizeof(quant_errors[1]) - sizeof(quant_errors[1][0]) ); quant_errors [1] [0] = val - ival; samples [j] [1] = ival; break; default: assert (0); return -1; } } play_soundcard ( s, samples, sizeof(samples)/sizeof(*samples) ); if ( amplitude (a) * ATH (frequency (g)) <= 3.16227766e-6 ) { report (g, a); fprintf ( stderr, "\rUnderrun \n\n" ); return -1; } switch ( getchar_keyboard (k) ) { case '+': fprintf ( stderr, "\r+++ up +++" ); report (g, a); change_direction ( a, up ); break; case '-': fprintf ( stderr, "\r--- down ---" ); report (g, a); change_direction ( a, down ); break; case '\r': case '\n': fprintf ( stderr, "\r** change **" ); report (g, a); change_direction ( a, change ); break; case 'C'&0x1F: case 'q': case 'Q': case 'x': case 'X': fprintf ( stderr, "\rBreak \n\n" ); fflush ( stderr ); return -1; default: fprintf ( stderr, "\a" ); break; case -1: break; } } fprintf ( stderr, "\rReady \n\n" ); return 0;}static void usage ( void ){ static const char help[] = "'Absolute Threshold of Hearing' -- Version 0.07 (C) Frank Klemm 2000\n" "\n" "usage:\n" " ath type minfreq maxfreq duration ampl_speed [start_level [earmode] > reportfile\n" "\n" " type: linear, logarithm, square, cubic, erb, recip\n" " minfreq: initial frequency [Hz]\n" " maxfreq: end frequency [Hz]\n" " duration: duration of the experiment [s]\n" " ampl_speed: amplitude slope speed [phon/s]\n" " start_level: absolute level at startup [0...1]\n" " earmode: left, right, both, phase90, phase180\n" "\n" "example:\n" " ath erb 700 22000 600 3 0.0001 > result1\n" " ath erb 1400 16 360 3 0.0001 > result2\n" "\n" "handling:\n" " press '-' once when you start hearing a tone\n" " press '+' once when you stop hearing a tone\n" " press 'q' to early leave the program\n" " on errors the pressed key is ignored\n"; fprintf ( stderr, "%s\n", help );}int main ( int argc, char** argv ){ generator_t g; amplitude_t a; soundcard_t s; keyboard_t k; genmode_t genmode; earmode_t earmode; if ( argc == 1 ) { usage (); system ( "./ath erb 700 22000 600 3 0.0001 > result1" ); system ( "./ath erb 1400 16 360 3 0.0001 > result2" ); system ( "xmgr result1 result2 &> /dev/null &" ); return 0; } if ( argc < 6 ) { usage (); return 1; } if ( 0 == strncmp ( argv[1], "li" , 2) ) genmode = linear; else if ( 0 == strncmp ( argv[1], "lo" , 2) ) genmode = logarithm; else if ( 0 == strncmp ( argv[1], "sq" , 2) ) genmode = square; else if ( 0 == strncmp ( argv[1], "cu" , 2) ) genmode = cubic; else if ( 0 == strncmp ( argv[1], "er" , 2) ) genmode = erb; else if ( 0 == strncmp ( argv[1], "re" , 2) ) genmode = recip; else { usage (); return 1; } if ( argc < 8 ) earmode = both; else if ( 0 == strncmp ( argv[7], "le" , 2) ) earmode = left; else if ( 0 == strncmp ( argv[7], "ri" , 2) ) earmode = right; else if ( 0 == strncmp ( argv[7], "bo" , 2) ) earmode = both; else if ( 0 == strncmp ( argv[7], "phase9" , 6) ) earmode = phase90; else if ( 0 == strncmp ( argv[7], "phase1" , 6) ) earmode = phase180; else { usage (); return 1; } open_soundcard ( &s, AUDIO_DEVICE, sizeof(stereo_t)/sizeof(sample_t), CHAR_BIT*sizeof(sample_t), 96000.0 ); open_generator ( &g, &s, genmode, atof (argv[4]), atof (argv[2]), atof (argv[3]) ); open_amplifier ( &a, &s, argc > 6 ? atof (argv[6]) : 0.0001, atof (argv[5]) ); open_keyboard ( &k ); report_open ( ); experiment ( &g, &a, &k, &s, earmode ); report_close ( ); close_keyboard ( &k ); close_amplifier( &a ); close_generator( &g ); close_soundcard( &s ); return 0;}/* end of ath.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -