1 /* $Id$ */
2 /*
3 * Known bugs (sorted by importance):
4 * - human delay (ca. 200 ms or more???) and buffering delay (341 ms @48 kHz/64 KByte)
5 * should be subtracted
6 * - error handling
7 * - cos slope on direction changes
8 * - calibration file of soundcard/amplifier/head phone
9 * - worse handling
10 * - +/- handling via mouse (do you have code?) in a dark room
11 * - ENTER as direction change
12 * - finer precalculated ATH for pre-emphasis
13 */
14
15 /*
16 * Suggested level ranges:
17 * 180 Hz...13.5 kHz: 50...70 dB
18 * 100 Hz...15.0 kHz: 40...70 dB
19 * 70 Hz...16.0 kHz: 30...70 dB
20 * 45 Hz...16.5 kHz: 20...70 dB
21 * 30 Hz...17.5 kHz: 10...70 dB
22 * 25 Hz...18.0 kHz: 5...75 dB
23 * 20 Hz...19.0 kHz: 0...80 dB
24 * 16 Hz...20.0 kHz: -10...80 dB
25 */
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #include <assert.h>
32 #include <errno.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <fcntl.h>
38 #include <limits.h>
39 #include <termios.h>
40 #include <math.h>
41 #include <time.h>
42 #include <signal.h>
43 #include <sys/ioctl.h>
44 #include <sys/time.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #ifdef HAVE_SYS_SOUNDCARD_H
48 # include <sys/soundcard.h>
49 #elif defined(HAVE_LINUX_SOUNDCARD_H)
50 # include <linux/soundcard.h>
51 #else
52 # error no soundcard include
53 #endif
54
55
56
57 #define AUDIO_DEVICE "/dev/dsp"
58 //#define COOLEDIT_FILE "/mnt/dosd/cooledit.wav"
59 #define DELAY_UNTIL_XCHG 2.5
60 #define TURN_STEPS 2400
61
62 /******************************************************************************************************
63 * soundcard stuff
64 ******************************************************************************************************/
65
66 const double dither_coeff [] [16] = {
67 { /* 48 kHz */ 3.35185352775391591311, 4.24914379295482032978, 1.78042251729150153086, -0.92601381419186201184, -1.37308596104182343645, -1.85951915999247704829, -3.28074437872632330526, -3.05496670185702990882, -1.22855462839450528837, -0.30291531959171267015, -0.18598486195652600770, 0.42010512205702003790, 0.92278786111368653452, 0.62102380451771775193, 0.14312897206650044828, -0.00454721508203927746 },
68 { /* 56 kHz */ 3.86404134982280628749, 6.67195592701613291071, 5.90576195467245802046, 1.57589705921487261981, -2.10618201389737372178, -2.74191788822507184395, -2.62175070636849999396, -3.78505226463032808863, -4.45698848578010438284, -2.76825966243460536110, -0.26509931375584007312, 0.67853812028968716799, 0.17633528441477021892, -0.28511417191837823770, -0.21866605100975608470, -0.04751674094456833719 },
69 { /* 64 kHz */ 4.09276938880098092172, 8.27424044674659812937, 10.11503162292146762880, 7.19159801569544317353, 1.39770070291739556523, -2.86595901981244688601, -3.76567274050094691362, -3.58051445684472378298, -4.78262917738758022539, -6.53075750894777650899, -6.31330514306857055627, -3.69971382767763534195, -0.78125094191744878298, 0.59027508113837267217, 0.53500264009607367648, 0.14860043567206217506 },
70 { /* 72 kHz */ 4.13833553801985235465, 9.02461778089340082437, 12.93090366932740510782, 12.66372285767699051948, 7.76122176702274149630, 1.30617257555732278296, -2.92859120887121285358, -4.02438598495837830627, -4.16673068132491936262, -5.55618065300129916574, -7.82657788611231653103, -8.83055904466106668035, -7.34884789347713815672, -4.33977664906048314891, -1.67711310288611975398, -0.33086687044710235420 },
71 { /* 80 kHz */ 4.22135293342667005517, 9.76639846582539722375, 15.46562682418357478290, 17.54378549927855248346, 13.29112084313158963396, 3.51512441998252657470, -7.51025671462502577300,-14.84164320864536219368,-16.10306907358826504148,-12.54775907691866414402, -7.40560667268782655149, -3.34708029482052565732, -1.19572214872925790860, -0.39582185216275086786, -0.14803160816846603424, -0.04292818488627011881 },
72 { /* 88 kHz */ 4.18521467865996935325, 9.96765821475909556942, 16.91905760389390617551, 21.74016824668913557689, 20.96457146354060682367, 13.28640453421253890542, 0.85116933842171101587,-11.66054516261007127469,-19.62750656985581800169,-20.98831962473015904508,-16.95374072505042825458,-10.68848180295390154146, -5.17169792984369678908, -1.79975409439650319129, -0.38057073791415898674, -0.02672653932844656975 },
73 { /* 96 kHz */ 4.09418877324899473189, 9.77977364010870211207, 17.10120082680385341159, 23.37356217615995036818, 25.27121942060722374276, 20.64059991613550174190, 9.99721445051475610371, -3.39833000550997938512,-15.03410054392933377278,-21.36704201000683067679,-21.40772859969388741685,-16.79355426136657673808,-10.48570200688141622163, -5.07642951516127438486, -1.75555240936989159436, -0.33817997298586054131 },
74 };
75
76 typedef struct {
77 const char* device;
78 int fd;
79 long double sample_freq;
80 const double* dither;
81 int channels;
82 int bits;
83 } soundcard_t;
84
85 typedef signed short sample_t;
86 typedef sample_t stereo_t [2];
87
open_soundcard(soundcard_t * const k,const char * device,const int channels,const int bits,const long double freq)88 int open_soundcard (
89 soundcard_t* const k,
90 const char* device,
91 const int channels,
92 const int bits,
93 const long double freq )
94 {
95 int arg;
96 int org;
97 int index;
98 int status;
99
100 k->device = device;
101 if ( -1 == (k->fd = open ( k->device, O_WRONLY )) ) {
102 perror("opening of audio device failed");
103 return -1;
104 }
105
106 if ( -1 == (status = ioctl (k->fd, SOUND_PCM_SYNC, 0))) {
107 fprintf ( stderr, "%s: SOUND_PCM_SYNC ioctl failed: %s\n", k->device, strerror (errno));
108 return -1;
109 }
110
111 org = arg = channels;
112 if ( -1 == (status = ioctl (k->fd, SOUND_PCM_WRITE_CHANNELS, &arg)) ) {
113 fprintf ( stderr, "%s: SOUND_PCM_WRITE_CHANNELS (%d) ioctl failed: %s\n" , k->device, channels, strerror (errno) );
114 return -1;
115 }
116 if (arg != org) {
117 fprintf ( stderr, "%s: unable to set number of channels: %d instead of %d\n", k->device, arg, org );
118 return -1;
119 }
120 k->channels = arg;
121
122 org = arg = bits;
123 if ( -1 == (status = ioctl (k->fd, SOUND_PCM_WRITE_BITS, &arg)) ) {
124 fprintf ( stderr, "%s: SOUND_PCM_WRITE_BITS ioctl failed\n", k->device );
125 return -1;
126 }
127 if (arg != org) {
128 fprintf ( stderr, "%s: unable to set sample size: %d instead of %d\n", k->device, arg, org );
129 return -1;
130 }
131 k->bits = arg;
132
133 org = arg = k->bits <= 8 ? AFMT_U8 : AFMT_S16_LE;
134 if ( -1 == ioctl (k->fd, SNDCTL_DSP_SETFMT, &arg) ) {
135 fprintf ( stderr, "%s: SNDCTL_DSP_SETFMT ioctl failed\n", k->device );
136 return -1;
137 }
138 if ((arg & org) == 0) {
139 fprintf ( stderr, "%s: unable to set data format\n", k->device );
140 return -1;
141 }
142
143 org = arg = (int) floor ( freq + 0.5 );
144 if ( -1 == (status = ioctl (k->fd, SOUND_PCM_WRITE_RATE, &arg)) ) {
145 fprintf ( stderr, "%s: SOUND_PCM_WRITE_WRITE ioctl failed\n", k->device );
146 return -1;
147 }
148 k->sample_freq = (long double)arg;
149 index = (arg - 44000) / 8000;
150 if ( index < 0 ) index = 0;
151 if ( index >= sizeof(dither_coeff)/sizeof(*dither_coeff) ) index = sizeof(dither_coeff)/sizeof(*dither_coeff) - 1;
152 k->dither = dither_coeff [ index ];
153 return 0;
154 }
155
play_soundcard(soundcard_t * const k,stereo_t * samples,size_t length)156 int play_soundcard ( soundcard_t* const k, stereo_t* samples, size_t length )
157 {
158 size_t bytes = length * sizeof (*samples);
159
160 #ifdef COOLEDIT_FILE
161 static int fd = -1;
162 if ( fd < 0 ) fd = open ( COOLEDIT_FILE, O_WRONLY | O_CREAT );
163 write ( fd, samples, bytes );
164 #endif
165
166 return write ( k->fd, samples, bytes ) == bytes ? 0 : -1;
167 }
168
close_soundcard(soundcard_t * const k)169 int close_soundcard ( soundcard_t* const k )
170 {
171 return close (k->fd);
172 }
173
174
175 /******************************************************************************************************
176 * frequency stuff
177 ******************************************************************************************************/
178
179 typedef enum {
180 linear = 0,
181 logarithm = 1,
182 square = 2,
183 cubic = 3,
184 erb = 4,
185 recip = 5
186 } genmode_t;
187
linear_f(long double x)188 static long double linear_f ( long double x ) { return x > 0.L ? x : 0.0L; }
logarithm_f(long double x)189 static long double logarithm_f ( long double x ) { return x > 0.L ? log10 (x) : -3.5L; }
square_f(long double x)190 static long double square_f ( long double x ) { return x > 0.L ? sqrt (x) : 0.0L; }
cubic_f(long double x)191 static long double cubic_f ( long double x ) { return x > 0.L ? pow (x,1/3.) : 0.0L; }
erb_f(long double x)192 static long double erb_f ( long double x ) { return log (1. + 0.00437*x); }
recip_f(long double x)193 static long double recip_f ( long double x ) { return x > 1.L ? 1.L/x : 1.0L; }
194
inv_linear_f(long double x)195 static long double inv_linear_f ( long double x ) { return x; }
inv_logarithm_f(long double x)196 static long double inv_logarithm_f ( long double x ) { return pow (10., x); }
inv_square_f(long double x)197 static long double inv_square_f ( long double x ) { return x*x; }
inv_cubic_f(long double x)198 static long double inv_cubic_f ( long double x ) { return x*x*x; }
inv_erb_f(long double x)199 static long double inv_erb_f ( long double x ) { return (exp(x) - 1.) * (1./0.00437); }
inv_recip_f(long double x)200 static long double inv_recip_f ( long double x ) { return x > 1.L ? 1.L/x : 1.0L; }
201
202 typedef long double (*converter_fn_t) ( long double );
203
204 const converter_fn_t func [] = { linear_f, logarithm_f, square_f, cubic_f , erb_f , recip_f };
205 const converter_fn_t inv_func [] = { inv_linear_f, inv_logarithm_f, inv_square_f, inv_cubic_f, inv_erb_f, inv_recip_f };
206
207 typedef struct {
208 genmode_t genmode;
209 long double start_freq;
210 long double stop_freq;
211 long double sample_freq;
212 unsigned long duration;
213
214 long double phase;
215 long double param1;
216 long double param2;
217 unsigned long counter;
218 } generator_t;
219
open_generator(generator_t * const g,const soundcard_t * const s,const genmode_t genmode,const long double duration,const long double start_freq,const long double stop_freq)220 int open_generator (
221 generator_t* const g,
222 const soundcard_t* const s,
223 const genmode_t genmode,
224 const long double duration,
225 const long double start_freq,
226 const long double stop_freq )
227 {
228 g->sample_freq = s->sample_freq;
229 g->genmode = genmode;
230 g->start_freq = start_freq;
231 g->stop_freq = stop_freq;
232 g->duration = (unsigned long) floor ( duration * g->sample_freq + 0.5 );
233
234 if ( g->duration < 2 )
235 return -1;
236
237 if ( g->genmode >= sizeof (func)/sizeof(*func) )
238 return -1;
239
240 g->param1 = func [g->genmode] ( g->start_freq / g->sample_freq );
241 g->param2 = ( func [ g->genmode ] ( g->stop_freq / g->sample_freq ) - g->param1 )
242 / ( g->duration - 1 );
243 g->phase = 0.L;
244 g->counter= 0;
245
246 return 0;
247 }
248
iterate_generator(generator_t * const g)249 long double iterate_generator ( generator_t* const g )
250 {
251 long double freq;
252
253 freq = inv_func [ g->genmode ] ( g->param1 + g->counter++ * g->param2 );
254
255 g->phase += freq;
256 if (g->phase > 15.)
257 g->phase -= 16.;
258 return sin ( 2.*M_PI * g->phase );
259 }
260
get_sine(generator_t * const g)261 long double get_sine ( generator_t* const g )
262 {
263 return sin ( 2.*M_PI * g->phase );
264 }
265
get_cosine(generator_t * const g)266 long double get_cosine ( generator_t* const g )
267 {
268 return cos ( 2.*M_PI * g->phase );
269 }
270
271
frequency(const generator_t * const g)272 long double frequency ( const generator_t* const g )
273 {
274 return inv_func [ g->genmode ] ( g->param1 + g->counter * g->param2 ) * g->sample_freq;
275 }
276
close_generator(generator_t * const g)277 int close_generator ( generator_t* const g )
278 {
279 return 0;
280 }
281
282 /******************************************************************************************************
283 * amplitude stuff
284 ******************************************************************************************************/
285
286 typedef enum {
287 up = 0,
288 down = 1,
289 turn_up = 2,
290 turn_down = 3,
291 still_up = 4,
292 still_down = 5,
293 change = 6
294 } direction_t;
295
296
297 typedef struct {
298 long double sample_freq;
299 direction_t direction; // down, up, still_up, still_down, turn_down, turn_up
300 int multiplier; // -TURN_STEPS: down, +TURN_STEPS up
301 long double amplitude;
302 long double delta_amplitude;
303 long direction_change;
304 } amplitude_t;
305
open_amplifier(amplitude_t * const a,const soundcard_t * const s,const long double start_ampl,const double dB_per_sec)306 int open_amplifier (
307 amplitude_t* const a,
308 const soundcard_t* const s,
309 const long double start_ampl,
310 const double dB_per_sec )
311 {
312 a->sample_freq = s->sample_freq;
313 a->direction = up;
314 a->multiplier = +TURN_STEPS;
315 a->amplitude = start_ampl * 32767.;
316 a->delta_amplitude = dB_per_sec * 0.1151292546497022842 / s->sample_freq / TURN_STEPS;
317 a->direction_change = 0;
318
319 srand ( time (NULL) );
320 return 0;
321 }
322
iterate_amplifier(amplitude_t * const a)323 long double iterate_amplifier ( amplitude_t* const a )
324 {
325 switch ( a->direction ) {
326 case still_up:
327 assert (a->multiplier == +TURN_STEPS);
328 if (a->direction_change > 0 )
329 a->direction_change--;
330 else
331 a->direction = turn_down;
332 break;
333 case still_down:
334 assert (a->multiplier == -TURN_STEPS);
335 if (a->direction_change > 0 )
336 a->direction_change--;
337 else
338 a->direction = turn_up;
339 break;
340 case turn_up:
341 assert (a->direction_change == 0);
342 if ( a->multiplier < +TURN_STEPS )
343 a->multiplier++;
344 else
345 a->direction = up;
346 break;
347 case turn_down:
348 assert (a->direction_change == 0);
349 if ( a->multiplier > -TURN_STEPS )
350 a->multiplier--;
351 else
352 a->direction = down;
353 break;
354 case up:
355 assert (a->multiplier == +TURN_STEPS);
356 assert (a->direction_change == 0);
357 break;
358 case down:
359 assert (a->multiplier == -TURN_STEPS);
360 assert (a->direction_change == 0);
361 break;
362 default:
363 fprintf ( stderr, "\n\r*** Bug! ***\n");
364 break;
365 }
366
367 a->amplitude *= 1.L + a->delta_amplitude * a->multiplier;
368 return a->amplitude;
369 }
370
amplitude(const amplitude_t * const a)371 long double amplitude ( const amplitude_t* const a )
372 {
373 return a->amplitude / 32767.;
374 }
375
change_direction(amplitude_t * const a,direction_t new_direction)376 int change_direction ( amplitude_t* const a, direction_t new_direction )
377 {
378 switch ( new_direction ) {
379 case up:
380 if (a->direction == down) {
381 a->direction = still_down;
382 } else {
383 fprintf ( stderr, "Direction not down, so ignored\n" );
384 return -1;
385 }
386 break;
387 case down:
388 if (a->direction == up) {
389 a->direction = still_up;
390 } else {
391 fprintf ( stderr, "Direction not up, so ignored\n" );
392 return -1;
393 }
394 break;
395 case change:
396 switch ( a->direction ) {
397 case up:
398 a->direction = still_up;
399 break;
400 case down:
401 a->direction = still_down;
402 break;
403 default:
404 fprintf ( stderr, "Direction still changing, so ignored\n" );
405 return -1;
406 }
407 break;
408
409 default:
410 fprintf ( stderr, "Direction unknown, so ignored\n" );
411 return -1;
412 }
413
414 a->direction_change = 1 + rand () * (a->sample_freq * DELAY_UNTIL_XCHG / RAND_MAX);
415 return 0;
416 }
417
close_amplifier(amplitude_t * const a)418 int close_amplifier ( amplitude_t* const a )
419 {
420 return 0;
421 }
422
423
ATH(double freq)424 double ATH ( double freq )
425 {
426 static float tab [] = {
427 /* 10.0 */ 96.69, 96.69, 96.26, 95.12,
428 /* 12.6 */ 93.53, 91.13, 88.82, 86.76,
429 /* 15.8 */ 84.69, 82.43, 79.97, 77.48,
430 /* 20.0 */ 74.92, 72.39, 70.00, 67.62,
431 /* 25.1 */ 65.29, 63.02, 60.84, 59.00,
432 /* 31.6 */ 57.17, 55.34, 53.51, 51.67,
433 /* 39.8 */ 50.04, 48.12, 46.38, 44.66,
434 /* 50.1 */ 43.10, 41.73, 40.50, 39.22,
435 /* 63.1 */ 37.23, 35.77, 34.51, 32.81,
436 /* 79.4 */ 31.32, 30.36, 29.02, 27.60,
437 /* 100.0 */ 26.58, 25.91, 24.41, 23.01,
438 /* 125.9 */ 22.12, 21.25, 20.18, 19.00,
439 /* 158.5 */ 17.70, 16.82, 15.94, 15.12,
440 /* 199.5 */ 14.30, 13.41, 12.60, 11.98,
441 /* 251.2 */ 11.36, 10.57, 9.98, 9.43,
442 /* 316.2 */ 8.87, 8.46, 7.44, 7.12,
443 /* 398.1 */ 6.93, 6.68, 6.37, 6.06,
444 /* 501.2 */ 5.80, 5.55, 5.29, 5.02,
445 /* 631.0 */ 4.75, 4.48, 4.22, 3.98,
446 /* 794.3 */ 3.75, 3.51, 3.27, 3.22,
447 /* 1000.0 */ 3.12, 3.01, 2.91, 2.68,
448 /* 1258.9 */ 2.46, 2.15, 1.82, 1.46,
449 /* 1584.9 */ 1.07, 0.61, 0.13, -0.35,
450 /* 1995.3 */ -0.96, -1.56, -1.79, -2.35,
451 /* 2511.9 */ -2.95, -3.50, -4.01, -4.21,
452 /* 3162.3 */ -4.46, -4.99, -5.32, -5.35,
453 /* 3981.1 */ -5.13, -4.76, -4.31, -3.13,
454 /* 5011.9 */ -1.79, 0.08, 2.03, 4.03,
455 /* 6309.6 */ 5.80, 7.36, 8.81, 10.22,
456 /* 7943.3 */ 11.54, 12.51, 13.48, 14.21,
457 /* 10000.0 */ 14.79, 13.99, 12.85, 11.93,
458 /* 12589.3 */ 12.87, 15.19, 19.14, 23.69,
459 /* 15848.9 */ 33.52, 48.65, 59.42, 61.77,
460 /* 19952.6 */ 63.85, 66.04, 68.33, 70.09,
461 /* 25118.9 */ 70.66, 71.27, 71.91, 72.60,
462 };
463 double freq_log;
464 double dB;
465 unsigned index;
466
467 if ( freq < 10. ) freq = 10.;
468 if ( freq > 25000. ) freq = 25000.;
469
470 freq_log = 40. * log10 (0.1 * freq); /* 4 steps per third, starting at 10 Hz */
471 index = (unsigned) freq_log;
472 assert ( index < sizeof(tab)/sizeof(*tab) );
473 dB = tab [index] * (1 + index - freq_log) + tab [index+1] * (freq_log - index);
474 return pow ( 10., 0.05*dB );
475 }
476
477 /******************************************************************************************************
478 * keyboard stuff
479 ******************************************************************************************************/
480
481 typedef struct {
482 int init;
483 struct termios stored_setting;
484 struct termios current_setting;
485 } keyboard_t;
486
487 static keyboard_t* __k;
488
489 /* Restore term-settings to those saved when term_init was called */
490
term_restore(void)491 static void term_restore (void)
492 {
493 tcsetattr ( 0, TCSANOW, &(__k->stored_setting) );
494 } /* term_restore */
495
496 /* Clean up terminal; called on exit */
497
term_exit(int sig)498 static void term_exit ( int sig )
499 {
500 term_restore ();
501 } /* term_exit */
502
503 /* Will be called when ctrl-Z is pressed, this correctly handles the terminal */
504
term_ctrl_z(int sig)505 static void term_ctrl_z ( int sig )
506 {
507 signal ( SIGTSTP, term_ctrl_z );
508 term_restore ();
509 kill ( getpid(), SIGSTOP );
510 } /* term_ctrl_z */
511
512 /* Will be called when application is continued after having been stopped */
513
term_cont(int sig)514 static void term_cont ( int sig )
515 {
516 signal ( SIGCONT, term_cont );
517 tcsetattr ( 0, TCSANOW, &(__k->current_setting) );
518 } /* term_cont() */
519
open_keyboard(keyboard_t * const k)520 int open_keyboard ( keyboard_t* const k )
521 {
522 __k = k;
523 tcgetattr ( 0, &(k->stored_setting) );
524 tcgetattr ( 0, &(k->current_setting) );
525
526 signal ( SIGINT, term_exit ); /* We _must_ clean up when we exit */
527 signal ( SIGQUIT, term_exit );
528 signal ( SIGTSTP, term_ctrl_z ); /* Ctrl-Z must also be handled */
529 signal ( SIGCONT, term_cont );
530 // atexit ( term_exit );
531
532 /* One or more characters are sufficient to cause a read to return */
533 cfmakeraw ( &(k->current_setting) );
534 k->current_setting.c_oflag |= ONLCR | OPOST; /* enables NL => CRLF on output */
535
536 tcsetattr ( 0, TCSANOW, &(k->current_setting) );
537 return 0;
538 }
539
getchar_keyboard(keyboard_t * const k)540 int getchar_keyboard ( keyboard_t* const k )
541 {
542 struct timeval t;
543 fd_set fd [1];
544 int ret;
545 unsigned char c;
546
547 FD_SET (0, fd);
548 t.tv_sec = 0;
549 t.tv_usec = 0;
550
551 ret = select ( 1, fd, NULL, NULL, &t );
552
553 switch ( ret ) {
554 case 0:
555 return -1;
556 case 1:
557 ret = read (0, &c, 1);
558 return ret == 1 ? c : -1;
559 default:
560 return -2;
561 }
562 }
563
close_keyboard(keyboard_t * const k)564 int close_keyboard ( keyboard_t* const k )
565 {
566 term_restore ();
567 return 0;
568 }
569
570
571 /******************************************************************************************************
572 * reporting stuff
573 ******************************************************************************************************/
574
report_open(void)575 int report_open ( void )
576 {
577 static char buff [32767];
578 fflush ( stdout );
579 setvbuf ( stdout, buff, _IOFBF, sizeof(buff) );
580 return 0;
581 }
582
report(const generator_t * const g,const amplitude_t * const a)583 int report ( const generator_t* const g, const amplitude_t* const a )
584 {
585 static double last_freq = -1.;
586 static double last_level = -1.;
587 double freq;
588 double level;
589
590 freq = frequency (g);
591 level = 20. * log10 (amplitude (a) * ATH (freq) ) + 80.;
592
593 if ( last_freq >= 0 )
594 printf ( "%11.3f %8.2f\n", sqrt (freq*last_freq), 0.5 * (level+last_level) );
595 printf ( "# %9.3f %8.2f\n", freq, level );
596
597 fflush ( stdout );
598
599 last_freq = freq;
600 last_level = level;
601 return 0;
602 }
603
report_close(void)604 int report_close ( void )
605 {
606 printf ( "%%%%\n\n" );
607 fflush ( stdout );
608 close ( dup ( fileno(stdout) ) );
609 setvbuf ( stdout, NULL, _IONBF, 0 );
610 return 0;
611 }
612
613
614 /******************************************************************************************************
615 * main stuff
616 ******************************************************************************************************/
617
618 typedef enum {
619 left = 0,
620 right = 1,
621 phase0 = 2,
622 both = 2,
623 phase90 = 3,
624 phase180 = 4,
625 phasemod = 5
626 } earmode_t;
627
scalar(const double * a,const double * b)628 static long double scalar ( const double* a, const double* b )
629 {
630 return a[ 0]*b[ 0] + a[ 1]*b[ 1] + a[ 2]*b[ 2] + a[ 3]*b[ 3]
631 +a[ 4]*b[ 4] + a[ 5]*b[ 5] + a[ 6]*b[ 6] + a[ 7]*b[ 7]
632 +a[ 8]*b[ 8] + a[ 9]*b[ 9] + a[10]*b[10] + a[11]*b[11]
633 +a[12]*b[12] + a[13]*b[13] + a[14]*b[14] + a[15]*b[15];
634 }
635
experiment(generator_t * const g,amplitude_t * const a,keyboard_t * const k,soundcard_t * const s,earmode_t earmode)636 int experiment ( generator_t* const g,
637 amplitude_t* const a,
638 keyboard_t* const k,
639 soundcard_t* const s,
640 earmode_t earmode )
641 {
642 long i;
643 int j;
644 stereo_t samples [512];
645 static double quant_errors [2] [16];
646 long double val;
647 double ampl;
648 long ival;
649
650 fprintf ( stderr, "\r+++ up +++" );
651 for ( i = 0; i < g->duration; i += sizeof(samples)/sizeof(*samples) ) {
652 fprintf ( stderr, "%3lu%%\b\b\b\b", i*100lu/g->duration );
653
654 for (j = 0; j < sizeof(samples)/sizeof(*samples); j++ ) {
655 ampl = iterate_amplifier (a) * ATH (frequency (g));
656 val = ampl * iterate_generator (g);
657 ival = (long) floor ( val + 0.5 + scalar (quant_errors[0], s->dither) );
658
659 if ( ival != (sample_t) ival ) {
660 report (g, a);
661 fprintf ( stderr, "\rOverrun \n\n" );
662 return -1;
663 }
664 memmove ( & quant_errors [0] [1], & quant_errors [0] [0],
665 sizeof(quant_errors[0]) - sizeof(quant_errors[0][0]) );
666 quant_errors [0] [0] = val - ival;
667 switch ( earmode ) {
668 case both:
669 samples [j] [0] = samples [j] [1] = ival;
670 break;
671 case left:
672 samples [j] [0] = ival;
673 samples [j] [1] = 0;
674 break;
675 case right:
676 samples [j] [0] = 0;
677 samples [j] [1] = ival;
678 break;
679 case phase180:
680 samples [j] [0] = ival == -32768 ? 32767 : -ival;
681 samples [j] [1] = +ival;
682 break;
683 case phase90:
684 samples [j] [0] = ival;
685 val = ampl * get_cosine (g);
686 ival = (long) floor ( val + 0.5 + scalar (quant_errors[1], s->dither) );
687 if ( ival != (sample_t) ival ) {
688 report (g, a);
689 fprintf ( stderr, "\rOverrun \n\n" );
690 return -1;
691 }
692 memmove ( & quant_errors [1] [1], & quant_errors [1] [0],
693 sizeof(quant_errors[1]) - sizeof(quant_errors[1][0]) );
694 quant_errors [1] [0] = val - ival;
695 samples [j] [1] = ival;
696 break;
697 default:
698 assert (0);
699 return -1;
700 }
701 }
702 play_soundcard ( s, samples, sizeof(samples)/sizeof(*samples) );
703 if ( amplitude (a) * ATH (frequency (g)) <= 3.16227766e-6 ) {
704 report (g, a);
705 fprintf ( stderr, "\rUnderrun \n\n" );
706 return -1;
707 }
708
709 switch ( getchar_keyboard (k) ) {
710 case '+':
711 fprintf ( stderr, "\r+++ up +++" );
712 report (g, a);
713 change_direction ( a, up );
714 break;
715 case '-':
716 fprintf ( stderr, "\r--- down ---" );
717 report (g, a);
718 change_direction ( a, down );
719 break;
720 case '\r':
721 case '\n':
722 fprintf ( stderr, "\r** change **" );
723 report (g, a);
724 change_direction ( a, change );
725 break;
726 case 'C'&0x1F:
727 case 'q':
728 case 'Q':
729 case 'x':
730 case 'X':
731 fprintf ( stderr, "\rBreak \n\n" );
732 fflush ( stderr );
733 return -1;
734 default:
735 fprintf ( stderr, "\a" );
736 break;
737 case -1:
738 break;
739 }
740 }
741
742 fprintf ( stderr, "\rReady \n\n" );
743 return 0;
744 }
745
usage(void)746 static void usage ( void )
747 {
748 static const char help[] =
749 "'Absolute Threshold of Hearing' -- Version 0.07 (C) Frank Klemm 2000\n"
750 "\n"
751 "usage:\n"
752 " ath type minfreq maxfreq duration ampl_speed [start_level [earmode] > reportfile\n"
753 "\n"
754 " type: linear, logarithm, square, cubic, erb, recip\n"
755 " minfreq: initial frequency [Hz]\n"
756 " maxfreq: end frequency [Hz]\n"
757 " duration: duration of the experiment [s]\n"
758 " ampl_speed: amplitude slope speed [phon/s]\n"
759 " start_level: absolute level at startup [0...1]\n"
760 " earmode: left, right, both, phase90, phase180\n"
761 "\n"
762 "example:\n"
763 " ath erb 700 22000 600 3 0.0001 > result1\n"
764 " ath erb 1400 16 360 3 0.0001 > result2\n"
765 "\n"
766 "handling:\n"
767 " press '-' once when you start hearing a tone\n"
768 " press '+' once when you stop hearing a tone\n"
769 " press 'q' to early leave the program\n"
770 " on errors the pressed key is ignored\n";
771
772 fprintf ( stderr, "%s\n", help );
773 }
774
main(int argc,char ** argv)775 int main ( int argc, char** argv )
776 {
777 generator_t g;
778 amplitude_t a;
779 soundcard_t s;
780 keyboard_t k;
781 genmode_t genmode;
782 earmode_t earmode;
783
784 if ( argc == 1 ) {
785 usage ();
786 system ( "./ath erb 700 22000 600 3 0.0001 > result1" );
787 system ( "./ath erb 1400 16 360 3 0.0001 > result2" );
788 system ( "xmgr result1 result2 &> /dev/null &" );
789 return 0;
790 }
791
792 if ( argc < 6 ) {
793 usage ();
794 return 1;
795 }
796
797 if ( 0 == strncmp ( argv[1], "li" , 2) ) genmode = linear;
798 else if ( 0 == strncmp ( argv[1], "lo" , 2) ) genmode = logarithm;
799 else if ( 0 == strncmp ( argv[1], "sq" , 2) ) genmode = square;
800 else if ( 0 == strncmp ( argv[1], "cu" , 2) ) genmode = cubic;
801 else if ( 0 == strncmp ( argv[1], "er" , 2) ) genmode = erb;
802 else if ( 0 == strncmp ( argv[1], "re" , 2) ) genmode = recip;
803 else {
804 usage ();
805 return 1;
806 }
807
808 if ( argc < 8 ) earmode = both;
809 else if ( 0 == strncmp ( argv[7], "le" , 2) ) earmode = left;
810 else if ( 0 == strncmp ( argv[7], "ri" , 2) ) earmode = right;
811 else if ( 0 == strncmp ( argv[7], "bo" , 2) ) earmode = both;
812 else if ( 0 == strncmp ( argv[7], "phase9" , 6) ) earmode = phase90;
813 else if ( 0 == strncmp ( argv[7], "phase1" , 6) ) earmode = phase180;
814 else {
815 usage ();
816 return 1;
817 }
818
819
820 open_soundcard ( &s, AUDIO_DEVICE, sizeof(stereo_t)/sizeof(sample_t), CHAR_BIT*sizeof(sample_t), 96000.0 );
821 open_generator ( &g, &s, genmode, atof (argv[4]), atof (argv[2]), atof (argv[3]) );
822 open_amplifier ( &a, &s, argc > 6 ? atof (argv[6]) : 0.0001, atof (argv[5]) );
823 open_keyboard ( &k );
824
825 report_open ( );
826 experiment ( &g, &a, &k, &s, earmode );
827 report_close ( );
828
829 close_keyboard ( &k );
830 close_amplifier( &a );
831 close_generator( &g );
832 close_soundcard( &s );
833
834 return 0;
835 }
836
837 /* end of ath.c */
838
839
840