1159b3361Sopenharmony_ci/* $Id$ */ 2159b3361Sopenharmony_ci/* 3159b3361Sopenharmony_ci * Known bugs (sorted by importance): 4159b3361Sopenharmony_ci * - human delay (ca. 200 ms or more???) and buffering delay (341 ms @48 kHz/64 KByte) 5159b3361Sopenharmony_ci * should be subtracted 6159b3361Sopenharmony_ci * - error handling 7159b3361Sopenharmony_ci * - cos slope on direction changes 8159b3361Sopenharmony_ci * - calibration file of soundcard/amplifier/head phone 9159b3361Sopenharmony_ci * - worse handling 10159b3361Sopenharmony_ci * - +/- handling via mouse (do you have code?) in a dark room 11159b3361Sopenharmony_ci * - ENTER as direction change 12159b3361Sopenharmony_ci * - finer precalculated ATH for pre-emphasis 13159b3361Sopenharmony_ci */ 14159b3361Sopenharmony_ci 15159b3361Sopenharmony_ci/* 16159b3361Sopenharmony_ci * Suggested level ranges: 17159b3361Sopenharmony_ci * 180 Hz...13.5 kHz: 50...70 dB 18159b3361Sopenharmony_ci * 100 Hz...15.0 kHz: 40...70 dB 19159b3361Sopenharmony_ci * 70 Hz...16.0 kHz: 30...70 dB 20159b3361Sopenharmony_ci * 45 Hz...16.5 kHz: 20...70 dB 21159b3361Sopenharmony_ci * 30 Hz...17.5 kHz: 10...70 dB 22159b3361Sopenharmony_ci * 25 Hz...18.0 kHz: 5...75 dB 23159b3361Sopenharmony_ci * 20 Hz...19.0 kHz: 0...80 dB 24159b3361Sopenharmony_ci * 16 Hz...20.0 kHz: -10...80 dB 25159b3361Sopenharmony_ci */ 26159b3361Sopenharmony_ci 27159b3361Sopenharmony_ci#ifdef HAVE_CONFIG_H 28159b3361Sopenharmony_ci# include <config.h> 29159b3361Sopenharmony_ci#endif 30159b3361Sopenharmony_ci 31159b3361Sopenharmony_ci#include <assert.h> 32159b3361Sopenharmony_ci#include <errno.h> 33159b3361Sopenharmony_ci#include <stdio.h> 34159b3361Sopenharmony_ci#include <stdlib.h> 35159b3361Sopenharmony_ci#include <unistd.h> 36159b3361Sopenharmony_ci#include <string.h> 37159b3361Sopenharmony_ci#include <fcntl.h> 38159b3361Sopenharmony_ci#include <limits.h> 39159b3361Sopenharmony_ci#include <termios.h> 40159b3361Sopenharmony_ci#include <math.h> 41159b3361Sopenharmony_ci#include <time.h> 42159b3361Sopenharmony_ci#include <signal.h> 43159b3361Sopenharmony_ci#include <sys/ioctl.h> 44159b3361Sopenharmony_ci#include <sys/time.h> 45159b3361Sopenharmony_ci#include <sys/types.h> 46159b3361Sopenharmony_ci#include <sys/stat.h> 47159b3361Sopenharmony_ci#ifdef HAVE_SYS_SOUNDCARD_H 48159b3361Sopenharmony_ci# include <sys/soundcard.h> 49159b3361Sopenharmony_ci#elif defined(HAVE_LINUX_SOUNDCARD_H) 50159b3361Sopenharmony_ci# include <linux/soundcard.h> 51159b3361Sopenharmony_ci#else 52159b3361Sopenharmony_ci# error no soundcard include 53159b3361Sopenharmony_ci#endif 54159b3361Sopenharmony_ci 55159b3361Sopenharmony_ci 56159b3361Sopenharmony_ci 57159b3361Sopenharmony_ci#define AUDIO_DEVICE "/dev/dsp" 58159b3361Sopenharmony_ci//#define COOLEDIT_FILE "/mnt/dosd/cooledit.wav" 59159b3361Sopenharmony_ci#define DELAY_UNTIL_XCHG 2.5 60159b3361Sopenharmony_ci#define TURN_STEPS 2400 61159b3361Sopenharmony_ci 62159b3361Sopenharmony_ci/****************************************************************************************************** 63159b3361Sopenharmony_ci * soundcard stuff 64159b3361Sopenharmony_ci ******************************************************************************************************/ 65159b3361Sopenharmony_ci 66159b3361Sopenharmony_ciconst double dither_coeff [] [16] = { 67159b3361Sopenharmony_ci { /* 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 }, 68159b3361Sopenharmony_ci { /* 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 }, 69159b3361Sopenharmony_ci { /* 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 }, 70159b3361Sopenharmony_ci { /* 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 }, 71159b3361Sopenharmony_ci { /* 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 }, 72159b3361Sopenharmony_ci { /* 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 }, 73159b3361Sopenharmony_ci { /* 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 }, 74159b3361Sopenharmony_ci}; 75159b3361Sopenharmony_ci 76159b3361Sopenharmony_citypedef struct { 77159b3361Sopenharmony_ci const char* device; 78159b3361Sopenharmony_ci int fd; 79159b3361Sopenharmony_ci long double sample_freq; 80159b3361Sopenharmony_ci const double* dither; 81159b3361Sopenharmony_ci int channels; 82159b3361Sopenharmony_ci int bits; 83159b3361Sopenharmony_ci} soundcard_t; 84159b3361Sopenharmony_ci 85159b3361Sopenharmony_citypedef signed short sample_t; 86159b3361Sopenharmony_citypedef sample_t stereo_t [2]; 87159b3361Sopenharmony_ci 88159b3361Sopenharmony_ciint open_soundcard ( 89159b3361Sopenharmony_ci soundcard_t* const k, 90159b3361Sopenharmony_ci const char* device, 91159b3361Sopenharmony_ci const int channels, 92159b3361Sopenharmony_ci const int bits, 93159b3361Sopenharmony_ci const long double freq ) 94159b3361Sopenharmony_ci{ 95159b3361Sopenharmony_ci int arg; 96159b3361Sopenharmony_ci int org; 97159b3361Sopenharmony_ci int index; 98159b3361Sopenharmony_ci int status; 99159b3361Sopenharmony_ci 100159b3361Sopenharmony_ci k->device = device; 101159b3361Sopenharmony_ci if ( -1 == (k->fd = open ( k->device, O_WRONLY )) ) { 102159b3361Sopenharmony_ci perror("opening of audio device failed"); 103159b3361Sopenharmony_ci return -1; 104159b3361Sopenharmony_ci } 105159b3361Sopenharmony_ci 106159b3361Sopenharmony_ci if ( -1 == (status = ioctl (k->fd, SOUND_PCM_SYNC, 0))) { 107159b3361Sopenharmony_ci fprintf ( stderr, "%s: SOUND_PCM_SYNC ioctl failed: %s\n", k->device, strerror (errno)); 108159b3361Sopenharmony_ci return -1; 109159b3361Sopenharmony_ci } 110159b3361Sopenharmony_ci 111159b3361Sopenharmony_ci org = arg = channels; 112159b3361Sopenharmony_ci if ( -1 == (status = ioctl (k->fd, SOUND_PCM_WRITE_CHANNELS, &arg)) ) { 113159b3361Sopenharmony_ci fprintf ( stderr, "%s: SOUND_PCM_WRITE_CHANNELS (%d) ioctl failed: %s\n" , k->device, channels, strerror (errno) ); 114159b3361Sopenharmony_ci return -1; 115159b3361Sopenharmony_ci } 116159b3361Sopenharmony_ci if (arg != org) { 117159b3361Sopenharmony_ci fprintf ( stderr, "%s: unable to set number of channels: %d instead of %d\n", k->device, arg, org ); 118159b3361Sopenharmony_ci return -1; 119159b3361Sopenharmony_ci } 120159b3361Sopenharmony_ci k->channels = arg; 121159b3361Sopenharmony_ci 122159b3361Sopenharmony_ci org = arg = bits; 123159b3361Sopenharmony_ci if ( -1 == (status = ioctl (k->fd, SOUND_PCM_WRITE_BITS, &arg)) ) { 124159b3361Sopenharmony_ci fprintf ( stderr, "%s: SOUND_PCM_WRITE_BITS ioctl failed\n", k->device ); 125159b3361Sopenharmony_ci return -1; 126159b3361Sopenharmony_ci } 127159b3361Sopenharmony_ci if (arg != org) { 128159b3361Sopenharmony_ci fprintf ( stderr, "%s: unable to set sample size: %d instead of %d\n", k->device, arg, org ); 129159b3361Sopenharmony_ci return -1; 130159b3361Sopenharmony_ci } 131159b3361Sopenharmony_ci k->bits = arg; 132159b3361Sopenharmony_ci 133159b3361Sopenharmony_ci org = arg = k->bits <= 8 ? AFMT_U8 : AFMT_S16_LE; 134159b3361Sopenharmony_ci if ( -1 == ioctl (k->fd, SNDCTL_DSP_SETFMT, &arg) ) { 135159b3361Sopenharmony_ci fprintf ( stderr, "%s: SNDCTL_DSP_SETFMT ioctl failed\n", k->device ); 136159b3361Sopenharmony_ci return -1; 137159b3361Sopenharmony_ci } 138159b3361Sopenharmony_ci if ((arg & org) == 0) { 139159b3361Sopenharmony_ci fprintf ( stderr, "%s: unable to set data format\n", k->device ); 140159b3361Sopenharmony_ci return -1; 141159b3361Sopenharmony_ci } 142159b3361Sopenharmony_ci 143159b3361Sopenharmony_ci org = arg = (int) floor ( freq + 0.5 ); 144159b3361Sopenharmony_ci if ( -1 == (status = ioctl (k->fd, SOUND_PCM_WRITE_RATE, &arg)) ) { 145159b3361Sopenharmony_ci fprintf ( stderr, "%s: SOUND_PCM_WRITE_WRITE ioctl failed\n", k->device ); 146159b3361Sopenharmony_ci return -1; 147159b3361Sopenharmony_ci } 148159b3361Sopenharmony_ci k->sample_freq = (long double)arg; 149159b3361Sopenharmony_ci index = (arg - 44000) / 8000; 150159b3361Sopenharmony_ci if ( index < 0 ) index = 0; 151159b3361Sopenharmony_ci if ( index >= sizeof(dither_coeff)/sizeof(*dither_coeff) ) index = sizeof(dither_coeff)/sizeof(*dither_coeff) - 1; 152159b3361Sopenharmony_ci k->dither = dither_coeff [ index ]; 153159b3361Sopenharmony_ci return 0; 154159b3361Sopenharmony_ci} 155159b3361Sopenharmony_ci 156159b3361Sopenharmony_ciint play_soundcard ( soundcard_t* const k, stereo_t* samples, size_t length ) 157159b3361Sopenharmony_ci{ 158159b3361Sopenharmony_ci size_t bytes = length * sizeof (*samples); 159159b3361Sopenharmony_ci 160159b3361Sopenharmony_ci#ifdef COOLEDIT_FILE 161159b3361Sopenharmony_ci static int fd = -1; 162159b3361Sopenharmony_ci if ( fd < 0 ) fd = open ( COOLEDIT_FILE, O_WRONLY | O_CREAT ); 163159b3361Sopenharmony_ci write ( fd, samples, bytes ); 164159b3361Sopenharmony_ci#endif 165159b3361Sopenharmony_ci 166159b3361Sopenharmony_ci return write ( k->fd, samples, bytes ) == bytes ? 0 : -1; 167159b3361Sopenharmony_ci} 168159b3361Sopenharmony_ci 169159b3361Sopenharmony_ciint close_soundcard ( soundcard_t* const k ) 170159b3361Sopenharmony_ci{ 171159b3361Sopenharmony_ci return close (k->fd); 172159b3361Sopenharmony_ci} 173159b3361Sopenharmony_ci 174159b3361Sopenharmony_ci 175159b3361Sopenharmony_ci/****************************************************************************************************** 176159b3361Sopenharmony_ci * frequency stuff 177159b3361Sopenharmony_ci ******************************************************************************************************/ 178159b3361Sopenharmony_ci 179159b3361Sopenharmony_citypedef enum { 180159b3361Sopenharmony_ci linear = 0, 181159b3361Sopenharmony_ci logarithm = 1, 182159b3361Sopenharmony_ci square = 2, 183159b3361Sopenharmony_ci cubic = 3, 184159b3361Sopenharmony_ci erb = 4, 185159b3361Sopenharmony_ci recip = 5 186159b3361Sopenharmony_ci} genmode_t; 187159b3361Sopenharmony_ci 188159b3361Sopenharmony_cistatic long double linear_f ( long double x ) { return x > 0.L ? x : 0.0L; } 189159b3361Sopenharmony_cistatic long double logarithm_f ( long double x ) { return x > 0.L ? log10 (x) : -3.5L; } 190159b3361Sopenharmony_cistatic long double square_f ( long double x ) { return x > 0.L ? sqrt (x) : 0.0L; } 191159b3361Sopenharmony_cistatic long double cubic_f ( long double x ) { return x > 0.L ? pow (x,1/3.) : 0.0L; } 192159b3361Sopenharmony_cistatic long double erb_f ( long double x ) { return log (1. + 0.00437*x); } 193159b3361Sopenharmony_cistatic long double recip_f ( long double x ) { return x > 1.L ? 1.L/x : 1.0L; } 194159b3361Sopenharmony_ci 195159b3361Sopenharmony_cistatic long double inv_linear_f ( long double x ) { return x; } 196159b3361Sopenharmony_cistatic long double inv_logarithm_f ( long double x ) { return pow (10., x); } 197159b3361Sopenharmony_cistatic long double inv_square_f ( long double x ) { return x*x; } 198159b3361Sopenharmony_cistatic long double inv_cubic_f ( long double x ) { return x*x*x; } 199159b3361Sopenharmony_cistatic long double inv_erb_f ( long double x ) { return (exp(x) - 1.) * (1./0.00437); } 200159b3361Sopenharmony_cistatic long double inv_recip_f ( long double x ) { return x > 1.L ? 1.L/x : 1.0L; } 201159b3361Sopenharmony_ci 202159b3361Sopenharmony_citypedef long double (*converter_fn_t) ( long double ); 203159b3361Sopenharmony_ci 204159b3361Sopenharmony_ciconst converter_fn_t func [] = { linear_f, logarithm_f, square_f, cubic_f , erb_f , recip_f }; 205159b3361Sopenharmony_ciconst converter_fn_t inv_func [] = { inv_linear_f, inv_logarithm_f, inv_square_f, inv_cubic_f, inv_erb_f, inv_recip_f }; 206159b3361Sopenharmony_ci 207159b3361Sopenharmony_citypedef struct { 208159b3361Sopenharmony_ci genmode_t genmode; 209159b3361Sopenharmony_ci long double start_freq; 210159b3361Sopenharmony_ci long double stop_freq; 211159b3361Sopenharmony_ci long double sample_freq; 212159b3361Sopenharmony_ci unsigned long duration; 213159b3361Sopenharmony_ci 214159b3361Sopenharmony_ci long double phase; 215159b3361Sopenharmony_ci long double param1; 216159b3361Sopenharmony_ci long double param2; 217159b3361Sopenharmony_ci unsigned long counter; 218159b3361Sopenharmony_ci} generator_t; 219159b3361Sopenharmony_ci 220159b3361Sopenharmony_ciint open_generator ( 221159b3361Sopenharmony_ci generator_t* const g, 222159b3361Sopenharmony_ci const soundcard_t* const s, 223159b3361Sopenharmony_ci const genmode_t genmode, 224159b3361Sopenharmony_ci const long double duration, 225159b3361Sopenharmony_ci const long double start_freq, 226159b3361Sopenharmony_ci const long double stop_freq ) 227159b3361Sopenharmony_ci{ 228159b3361Sopenharmony_ci g->sample_freq = s->sample_freq; 229159b3361Sopenharmony_ci g->genmode = genmode; 230159b3361Sopenharmony_ci g->start_freq = start_freq; 231159b3361Sopenharmony_ci g->stop_freq = stop_freq; 232159b3361Sopenharmony_ci g->duration = (unsigned long) floor ( duration * g->sample_freq + 0.5 ); 233159b3361Sopenharmony_ci 234159b3361Sopenharmony_ci if ( g->duration < 2 ) 235159b3361Sopenharmony_ci return -1; 236159b3361Sopenharmony_ci 237159b3361Sopenharmony_ci if ( g->genmode >= sizeof (func)/sizeof(*func) ) 238159b3361Sopenharmony_ci return -1; 239159b3361Sopenharmony_ci 240159b3361Sopenharmony_ci g->param1 = func [g->genmode] ( g->start_freq / g->sample_freq ); 241159b3361Sopenharmony_ci g->param2 = ( func [ g->genmode ] ( g->stop_freq / g->sample_freq ) - g->param1 ) 242159b3361Sopenharmony_ci / ( g->duration - 1 ); 243159b3361Sopenharmony_ci g->phase = 0.L; 244159b3361Sopenharmony_ci g->counter= 0; 245159b3361Sopenharmony_ci 246159b3361Sopenharmony_ci return 0; 247159b3361Sopenharmony_ci} 248159b3361Sopenharmony_ci 249159b3361Sopenharmony_cilong double iterate_generator ( generator_t* const g ) 250159b3361Sopenharmony_ci{ 251159b3361Sopenharmony_ci long double freq; 252159b3361Sopenharmony_ci 253159b3361Sopenharmony_ci freq = inv_func [ g->genmode ] ( g->param1 + g->counter++ * g->param2 ); 254159b3361Sopenharmony_ci 255159b3361Sopenharmony_ci g->phase += freq; 256159b3361Sopenharmony_ci if (g->phase > 15.) 257159b3361Sopenharmony_ci g->phase -= 16.; 258159b3361Sopenharmony_ci return sin ( 2.*M_PI * g->phase ); 259159b3361Sopenharmony_ci} 260159b3361Sopenharmony_ci 261159b3361Sopenharmony_cilong double get_sine ( generator_t* const g ) 262159b3361Sopenharmony_ci{ 263159b3361Sopenharmony_ci return sin ( 2.*M_PI * g->phase ); 264159b3361Sopenharmony_ci} 265159b3361Sopenharmony_ci 266159b3361Sopenharmony_cilong double get_cosine ( generator_t* const g ) 267159b3361Sopenharmony_ci{ 268159b3361Sopenharmony_ci return cos ( 2.*M_PI * g->phase ); 269159b3361Sopenharmony_ci} 270159b3361Sopenharmony_ci 271159b3361Sopenharmony_ci 272159b3361Sopenharmony_cilong double frequency ( const generator_t* const g ) 273159b3361Sopenharmony_ci{ 274159b3361Sopenharmony_ci return inv_func [ g->genmode ] ( g->param1 + g->counter * g->param2 ) * g->sample_freq; 275159b3361Sopenharmony_ci} 276159b3361Sopenharmony_ci 277159b3361Sopenharmony_ciint close_generator ( generator_t* const g ) 278159b3361Sopenharmony_ci{ 279159b3361Sopenharmony_ci return 0; 280159b3361Sopenharmony_ci} 281159b3361Sopenharmony_ci 282159b3361Sopenharmony_ci/****************************************************************************************************** 283159b3361Sopenharmony_ci * amplitude stuff 284159b3361Sopenharmony_ci ******************************************************************************************************/ 285159b3361Sopenharmony_ci 286159b3361Sopenharmony_citypedef enum { 287159b3361Sopenharmony_ci up = 0, 288159b3361Sopenharmony_ci down = 1, 289159b3361Sopenharmony_ci turn_up = 2, 290159b3361Sopenharmony_ci turn_down = 3, 291159b3361Sopenharmony_ci still_up = 4, 292159b3361Sopenharmony_ci still_down = 5, 293159b3361Sopenharmony_ci change = 6 294159b3361Sopenharmony_ci} direction_t; 295159b3361Sopenharmony_ci 296159b3361Sopenharmony_ci 297159b3361Sopenharmony_citypedef struct { 298159b3361Sopenharmony_ci long double sample_freq; 299159b3361Sopenharmony_ci direction_t direction; // down, up, still_up, still_down, turn_down, turn_up 300159b3361Sopenharmony_ci int multiplier; // -TURN_STEPS: down, +TURN_STEPS up 301159b3361Sopenharmony_ci long double amplitude; 302159b3361Sopenharmony_ci long double delta_amplitude; 303159b3361Sopenharmony_ci long direction_change; 304159b3361Sopenharmony_ci} amplitude_t; 305159b3361Sopenharmony_ci 306159b3361Sopenharmony_ciint open_amplifier ( 307159b3361Sopenharmony_ci amplitude_t* const a, 308159b3361Sopenharmony_ci const soundcard_t* const s, 309159b3361Sopenharmony_ci const long double start_ampl, 310159b3361Sopenharmony_ci const double dB_per_sec ) 311159b3361Sopenharmony_ci{ 312159b3361Sopenharmony_ci a->sample_freq = s->sample_freq; 313159b3361Sopenharmony_ci a->direction = up; 314159b3361Sopenharmony_ci a->multiplier = +TURN_STEPS; 315159b3361Sopenharmony_ci a->amplitude = start_ampl * 32767.; 316159b3361Sopenharmony_ci a->delta_amplitude = dB_per_sec * 0.1151292546497022842 / s->sample_freq / TURN_STEPS; 317159b3361Sopenharmony_ci a->direction_change = 0; 318159b3361Sopenharmony_ci 319159b3361Sopenharmony_ci srand ( time (NULL) ); 320159b3361Sopenharmony_ci return 0; 321159b3361Sopenharmony_ci} 322159b3361Sopenharmony_ci 323159b3361Sopenharmony_cilong double iterate_amplifier ( amplitude_t* const a ) 324159b3361Sopenharmony_ci{ 325159b3361Sopenharmony_ci switch ( a->direction ) { 326159b3361Sopenharmony_ci case still_up: 327159b3361Sopenharmony_ci assert (a->multiplier == +TURN_STEPS); 328159b3361Sopenharmony_ci if (a->direction_change > 0 ) 329159b3361Sopenharmony_ci a->direction_change--; 330159b3361Sopenharmony_ci else 331159b3361Sopenharmony_ci a->direction = turn_down; 332159b3361Sopenharmony_ci break; 333159b3361Sopenharmony_ci case still_down: 334159b3361Sopenharmony_ci assert (a->multiplier == -TURN_STEPS); 335159b3361Sopenharmony_ci if (a->direction_change > 0 ) 336159b3361Sopenharmony_ci a->direction_change--; 337159b3361Sopenharmony_ci else 338159b3361Sopenharmony_ci a->direction = turn_up; 339159b3361Sopenharmony_ci break; 340159b3361Sopenharmony_ci case turn_up: 341159b3361Sopenharmony_ci assert (a->direction_change == 0); 342159b3361Sopenharmony_ci if ( a->multiplier < +TURN_STEPS ) 343159b3361Sopenharmony_ci a->multiplier++; 344159b3361Sopenharmony_ci else 345159b3361Sopenharmony_ci a->direction = up; 346159b3361Sopenharmony_ci break; 347159b3361Sopenharmony_ci case turn_down: 348159b3361Sopenharmony_ci assert (a->direction_change == 0); 349159b3361Sopenharmony_ci if ( a->multiplier > -TURN_STEPS ) 350159b3361Sopenharmony_ci a->multiplier--; 351159b3361Sopenharmony_ci else 352159b3361Sopenharmony_ci a->direction = down; 353159b3361Sopenharmony_ci break; 354159b3361Sopenharmony_ci case up: 355159b3361Sopenharmony_ci assert (a->multiplier == +TURN_STEPS); 356159b3361Sopenharmony_ci assert (a->direction_change == 0); 357159b3361Sopenharmony_ci break; 358159b3361Sopenharmony_ci case down: 359159b3361Sopenharmony_ci assert (a->multiplier == -TURN_STEPS); 360159b3361Sopenharmony_ci assert (a->direction_change == 0); 361159b3361Sopenharmony_ci break; 362159b3361Sopenharmony_ci default: 363159b3361Sopenharmony_ci fprintf ( stderr, "\n\r*** Bug! ***\n"); 364159b3361Sopenharmony_ci break; 365159b3361Sopenharmony_ci } 366159b3361Sopenharmony_ci 367159b3361Sopenharmony_ci a->amplitude *= 1.L + a->delta_amplitude * a->multiplier; 368159b3361Sopenharmony_ci return a->amplitude; 369159b3361Sopenharmony_ci} 370159b3361Sopenharmony_ci 371159b3361Sopenharmony_cilong double amplitude ( const amplitude_t* const a ) 372159b3361Sopenharmony_ci{ 373159b3361Sopenharmony_ci return a->amplitude / 32767.; 374159b3361Sopenharmony_ci} 375159b3361Sopenharmony_ci 376159b3361Sopenharmony_ciint change_direction ( amplitude_t* const a, direction_t new_direction ) 377159b3361Sopenharmony_ci{ 378159b3361Sopenharmony_ci switch ( new_direction ) { 379159b3361Sopenharmony_ci case up: 380159b3361Sopenharmony_ci if (a->direction == down) { 381159b3361Sopenharmony_ci a->direction = still_down; 382159b3361Sopenharmony_ci } else { 383159b3361Sopenharmony_ci fprintf ( stderr, "Direction not down, so ignored\n" ); 384159b3361Sopenharmony_ci return -1; 385159b3361Sopenharmony_ci } 386159b3361Sopenharmony_ci break; 387159b3361Sopenharmony_ci case down: 388159b3361Sopenharmony_ci if (a->direction == up) { 389159b3361Sopenharmony_ci a->direction = still_up; 390159b3361Sopenharmony_ci } else { 391159b3361Sopenharmony_ci fprintf ( stderr, "Direction not up, so ignored\n" ); 392159b3361Sopenharmony_ci return -1; 393159b3361Sopenharmony_ci } 394159b3361Sopenharmony_ci break; 395159b3361Sopenharmony_ci case change: 396159b3361Sopenharmony_ci switch ( a->direction ) { 397159b3361Sopenharmony_ci case up: 398159b3361Sopenharmony_ci a->direction = still_up; 399159b3361Sopenharmony_ci break; 400159b3361Sopenharmony_ci case down: 401159b3361Sopenharmony_ci a->direction = still_down; 402159b3361Sopenharmony_ci break; 403159b3361Sopenharmony_ci default: 404159b3361Sopenharmony_ci fprintf ( stderr, "Direction still changing, so ignored\n" ); 405159b3361Sopenharmony_ci return -1; 406159b3361Sopenharmony_ci } 407159b3361Sopenharmony_ci break; 408159b3361Sopenharmony_ci 409159b3361Sopenharmony_ci default: 410159b3361Sopenharmony_ci fprintf ( stderr, "Direction unknown, so ignored\n" ); 411159b3361Sopenharmony_ci return -1; 412159b3361Sopenharmony_ci } 413159b3361Sopenharmony_ci 414159b3361Sopenharmony_ci a->direction_change = 1 + rand () * (a->sample_freq * DELAY_UNTIL_XCHG / RAND_MAX); 415159b3361Sopenharmony_ci return 0; 416159b3361Sopenharmony_ci} 417159b3361Sopenharmony_ci 418159b3361Sopenharmony_ciint close_amplifier ( amplitude_t* const a ) 419159b3361Sopenharmony_ci{ 420159b3361Sopenharmony_ci return 0; 421159b3361Sopenharmony_ci} 422159b3361Sopenharmony_ci 423159b3361Sopenharmony_ci 424159b3361Sopenharmony_cidouble ATH ( double freq ) 425159b3361Sopenharmony_ci{ 426159b3361Sopenharmony_ci static float tab [] = { 427159b3361Sopenharmony_ci /* 10.0 */ 96.69, 96.69, 96.26, 95.12, 428159b3361Sopenharmony_ci /* 12.6 */ 93.53, 91.13, 88.82, 86.76, 429159b3361Sopenharmony_ci /* 15.8 */ 84.69, 82.43, 79.97, 77.48, 430159b3361Sopenharmony_ci /* 20.0 */ 74.92, 72.39, 70.00, 67.62, 431159b3361Sopenharmony_ci /* 25.1 */ 65.29, 63.02, 60.84, 59.00, 432159b3361Sopenharmony_ci /* 31.6 */ 57.17, 55.34, 53.51, 51.67, 433159b3361Sopenharmony_ci /* 39.8 */ 50.04, 48.12, 46.38, 44.66, 434159b3361Sopenharmony_ci /* 50.1 */ 43.10, 41.73, 40.50, 39.22, 435159b3361Sopenharmony_ci /* 63.1 */ 37.23, 35.77, 34.51, 32.81, 436159b3361Sopenharmony_ci /* 79.4 */ 31.32, 30.36, 29.02, 27.60, 437159b3361Sopenharmony_ci /* 100.0 */ 26.58, 25.91, 24.41, 23.01, 438159b3361Sopenharmony_ci /* 125.9 */ 22.12, 21.25, 20.18, 19.00, 439159b3361Sopenharmony_ci /* 158.5 */ 17.70, 16.82, 15.94, 15.12, 440159b3361Sopenharmony_ci /* 199.5 */ 14.30, 13.41, 12.60, 11.98, 441159b3361Sopenharmony_ci /* 251.2 */ 11.36, 10.57, 9.98, 9.43, 442159b3361Sopenharmony_ci /* 316.2 */ 8.87, 8.46, 7.44, 7.12, 443159b3361Sopenharmony_ci /* 398.1 */ 6.93, 6.68, 6.37, 6.06, 444159b3361Sopenharmony_ci /* 501.2 */ 5.80, 5.55, 5.29, 5.02, 445159b3361Sopenharmony_ci /* 631.0 */ 4.75, 4.48, 4.22, 3.98, 446159b3361Sopenharmony_ci /* 794.3 */ 3.75, 3.51, 3.27, 3.22, 447159b3361Sopenharmony_ci /* 1000.0 */ 3.12, 3.01, 2.91, 2.68, 448159b3361Sopenharmony_ci /* 1258.9 */ 2.46, 2.15, 1.82, 1.46, 449159b3361Sopenharmony_ci /* 1584.9 */ 1.07, 0.61, 0.13, -0.35, 450159b3361Sopenharmony_ci /* 1995.3 */ -0.96, -1.56, -1.79, -2.35, 451159b3361Sopenharmony_ci /* 2511.9 */ -2.95, -3.50, -4.01, -4.21, 452159b3361Sopenharmony_ci /* 3162.3 */ -4.46, -4.99, -5.32, -5.35, 453159b3361Sopenharmony_ci /* 3981.1 */ -5.13, -4.76, -4.31, -3.13, 454159b3361Sopenharmony_ci /* 5011.9 */ -1.79, 0.08, 2.03, 4.03, 455159b3361Sopenharmony_ci /* 6309.6 */ 5.80, 7.36, 8.81, 10.22, 456159b3361Sopenharmony_ci /* 7943.3 */ 11.54, 12.51, 13.48, 14.21, 457159b3361Sopenharmony_ci /* 10000.0 */ 14.79, 13.99, 12.85, 11.93, 458159b3361Sopenharmony_ci /* 12589.3 */ 12.87, 15.19, 19.14, 23.69, 459159b3361Sopenharmony_ci /* 15848.9 */ 33.52, 48.65, 59.42, 61.77, 460159b3361Sopenharmony_ci /* 19952.6 */ 63.85, 66.04, 68.33, 70.09, 461159b3361Sopenharmony_ci /* 25118.9 */ 70.66, 71.27, 71.91, 72.60, 462159b3361Sopenharmony_ci }; 463159b3361Sopenharmony_ci double freq_log; 464159b3361Sopenharmony_ci double dB; 465159b3361Sopenharmony_ci unsigned index; 466159b3361Sopenharmony_ci 467159b3361Sopenharmony_ci if ( freq < 10. ) freq = 10.; 468159b3361Sopenharmony_ci if ( freq > 25000. ) freq = 25000.; 469159b3361Sopenharmony_ci 470159b3361Sopenharmony_ci freq_log = 40. * log10 (0.1 * freq); /* 4 steps per third, starting at 10 Hz */ 471159b3361Sopenharmony_ci index = (unsigned) freq_log; 472159b3361Sopenharmony_ci assert ( index < sizeof(tab)/sizeof(*tab) ); 473159b3361Sopenharmony_ci dB = tab [index] * (1 + index - freq_log) + tab [index+1] * (freq_log - index); 474159b3361Sopenharmony_ci return pow ( 10., 0.05*dB ); 475159b3361Sopenharmony_ci} 476159b3361Sopenharmony_ci 477159b3361Sopenharmony_ci/****************************************************************************************************** 478159b3361Sopenharmony_ci * keyboard stuff 479159b3361Sopenharmony_ci ******************************************************************************************************/ 480159b3361Sopenharmony_ci 481159b3361Sopenharmony_citypedef struct { 482159b3361Sopenharmony_ci int init; 483159b3361Sopenharmony_ci struct termios stored_setting; 484159b3361Sopenharmony_ci struct termios current_setting; 485159b3361Sopenharmony_ci} keyboard_t; 486159b3361Sopenharmony_ci 487159b3361Sopenharmony_cistatic keyboard_t* __k; 488159b3361Sopenharmony_ci 489159b3361Sopenharmony_ci/* Restore term-settings to those saved when term_init was called */ 490159b3361Sopenharmony_ci 491159b3361Sopenharmony_cistatic void term_restore (void) 492159b3361Sopenharmony_ci{ 493159b3361Sopenharmony_ci tcsetattr ( 0, TCSANOW, &(__k->stored_setting) ); 494159b3361Sopenharmony_ci} /* term_restore */ 495159b3361Sopenharmony_ci 496159b3361Sopenharmony_ci/* Clean up terminal; called on exit */ 497159b3361Sopenharmony_ci 498159b3361Sopenharmony_cistatic void term_exit ( int sig ) 499159b3361Sopenharmony_ci{ 500159b3361Sopenharmony_ci term_restore (); 501159b3361Sopenharmony_ci} /* term_exit */ 502159b3361Sopenharmony_ci 503159b3361Sopenharmony_ci/* Will be called when ctrl-Z is pressed, this correctly handles the terminal */ 504159b3361Sopenharmony_ci 505159b3361Sopenharmony_cistatic void term_ctrl_z ( int sig ) 506159b3361Sopenharmony_ci{ 507159b3361Sopenharmony_ci signal ( SIGTSTP, term_ctrl_z ); 508159b3361Sopenharmony_ci term_restore (); 509159b3361Sopenharmony_ci kill ( getpid(), SIGSTOP ); 510159b3361Sopenharmony_ci} /* term_ctrl_z */ 511159b3361Sopenharmony_ci 512159b3361Sopenharmony_ci/* Will be called when application is continued after having been stopped */ 513159b3361Sopenharmony_ci 514159b3361Sopenharmony_cistatic void term_cont ( int sig ) 515159b3361Sopenharmony_ci{ 516159b3361Sopenharmony_ci signal ( SIGCONT, term_cont ); 517159b3361Sopenharmony_ci tcsetattr ( 0, TCSANOW, &(__k->current_setting) ); 518159b3361Sopenharmony_ci} /* term_cont() */ 519159b3361Sopenharmony_ci 520159b3361Sopenharmony_ciint open_keyboard ( keyboard_t* const k ) 521159b3361Sopenharmony_ci{ 522159b3361Sopenharmony_ci __k = k; 523159b3361Sopenharmony_ci tcgetattr ( 0, &(k->stored_setting) ); 524159b3361Sopenharmony_ci tcgetattr ( 0, &(k->current_setting) ); 525159b3361Sopenharmony_ci 526159b3361Sopenharmony_ci signal ( SIGINT, term_exit ); /* We _must_ clean up when we exit */ 527159b3361Sopenharmony_ci signal ( SIGQUIT, term_exit ); 528159b3361Sopenharmony_ci signal ( SIGTSTP, term_ctrl_z ); /* Ctrl-Z must also be handled */ 529159b3361Sopenharmony_ci signal ( SIGCONT, term_cont ); 530159b3361Sopenharmony_ci// atexit ( term_exit ); 531159b3361Sopenharmony_ci 532159b3361Sopenharmony_ci /* One or more characters are sufficient to cause a read to return */ 533159b3361Sopenharmony_ci cfmakeraw ( &(k->current_setting) ); 534159b3361Sopenharmony_ci k->current_setting.c_oflag |= ONLCR | OPOST; /* enables NL => CRLF on output */ 535159b3361Sopenharmony_ci 536159b3361Sopenharmony_ci tcsetattr ( 0, TCSANOW, &(k->current_setting) ); 537159b3361Sopenharmony_ci return 0; 538159b3361Sopenharmony_ci} 539159b3361Sopenharmony_ci 540159b3361Sopenharmony_ciint getchar_keyboard ( keyboard_t* const k ) 541159b3361Sopenharmony_ci{ 542159b3361Sopenharmony_ci struct timeval t; 543159b3361Sopenharmony_ci fd_set fd [1]; 544159b3361Sopenharmony_ci int ret; 545159b3361Sopenharmony_ci unsigned char c; 546159b3361Sopenharmony_ci 547159b3361Sopenharmony_ci FD_SET (0, fd); 548159b3361Sopenharmony_ci t.tv_sec = 0; 549159b3361Sopenharmony_ci t.tv_usec = 0; 550159b3361Sopenharmony_ci 551159b3361Sopenharmony_ci ret = select ( 1, fd, NULL, NULL, &t ); 552159b3361Sopenharmony_ci 553159b3361Sopenharmony_ci switch ( ret ) { 554159b3361Sopenharmony_ci case 0: 555159b3361Sopenharmony_ci return -1; 556159b3361Sopenharmony_ci case 1: 557159b3361Sopenharmony_ci ret = read (0, &c, 1); 558159b3361Sopenharmony_ci return ret == 1 ? c : -1; 559159b3361Sopenharmony_ci default: 560159b3361Sopenharmony_ci return -2; 561159b3361Sopenharmony_ci } 562159b3361Sopenharmony_ci} 563159b3361Sopenharmony_ci 564159b3361Sopenharmony_ciint close_keyboard ( keyboard_t* const k ) 565159b3361Sopenharmony_ci{ 566159b3361Sopenharmony_ci term_restore (); 567159b3361Sopenharmony_ci return 0; 568159b3361Sopenharmony_ci} 569159b3361Sopenharmony_ci 570159b3361Sopenharmony_ci 571159b3361Sopenharmony_ci/****************************************************************************************************** 572159b3361Sopenharmony_ci * reporting stuff 573159b3361Sopenharmony_ci ******************************************************************************************************/ 574159b3361Sopenharmony_ci 575159b3361Sopenharmony_ciint report_open ( void ) 576159b3361Sopenharmony_ci{ 577159b3361Sopenharmony_ci static char buff [32767]; 578159b3361Sopenharmony_ci fflush ( stdout ); 579159b3361Sopenharmony_ci setvbuf ( stdout, buff, _IOFBF, sizeof(buff) ); 580159b3361Sopenharmony_ci return 0; 581159b3361Sopenharmony_ci} 582159b3361Sopenharmony_ci 583159b3361Sopenharmony_ciint report ( const generator_t* const g, const amplitude_t* const a ) 584159b3361Sopenharmony_ci{ 585159b3361Sopenharmony_ci static double last_freq = -1.; 586159b3361Sopenharmony_ci static double last_level = -1.; 587159b3361Sopenharmony_ci double freq; 588159b3361Sopenharmony_ci double level; 589159b3361Sopenharmony_ci 590159b3361Sopenharmony_ci freq = frequency (g); 591159b3361Sopenharmony_ci level = 20. * log10 (amplitude (a) * ATH (freq) ) + 80.; 592159b3361Sopenharmony_ci 593159b3361Sopenharmony_ci if ( last_freq >= 0 ) 594159b3361Sopenharmony_ci printf ( "%11.3f %8.2f\n", sqrt (freq*last_freq), 0.5 * (level+last_level) ); 595159b3361Sopenharmony_ci printf ( "# %9.3f %8.2f\n", freq, level ); 596159b3361Sopenharmony_ci 597159b3361Sopenharmony_ci fflush ( stdout ); 598159b3361Sopenharmony_ci 599159b3361Sopenharmony_ci last_freq = freq; 600159b3361Sopenharmony_ci last_level = level; 601159b3361Sopenharmony_ci return 0; 602159b3361Sopenharmony_ci} 603159b3361Sopenharmony_ci 604159b3361Sopenharmony_ciint report_close ( void ) 605159b3361Sopenharmony_ci{ 606159b3361Sopenharmony_ci printf ( "%%%%\n\n" ); 607159b3361Sopenharmony_ci fflush ( stdout ); 608159b3361Sopenharmony_ci close ( dup ( fileno(stdout) ) ); 609159b3361Sopenharmony_ci setvbuf ( stdout, NULL, _IONBF, 0 ); 610159b3361Sopenharmony_ci return 0; 611159b3361Sopenharmony_ci} 612159b3361Sopenharmony_ci 613159b3361Sopenharmony_ci 614159b3361Sopenharmony_ci/****************************************************************************************************** 615159b3361Sopenharmony_ci * main stuff 616159b3361Sopenharmony_ci ******************************************************************************************************/ 617159b3361Sopenharmony_ci 618159b3361Sopenharmony_citypedef enum { 619159b3361Sopenharmony_ci left = 0, 620159b3361Sopenharmony_ci right = 1, 621159b3361Sopenharmony_ci phase0 = 2, 622159b3361Sopenharmony_ci both = 2, 623159b3361Sopenharmony_ci phase90 = 3, 624159b3361Sopenharmony_ci phase180 = 4, 625159b3361Sopenharmony_ci phasemod = 5 626159b3361Sopenharmony_ci} earmode_t; 627159b3361Sopenharmony_ci 628159b3361Sopenharmony_cistatic long double scalar ( const double* a, const double* b ) 629159b3361Sopenharmony_ci{ 630159b3361Sopenharmony_ci return a[ 0]*b[ 0] + a[ 1]*b[ 1] + a[ 2]*b[ 2] + a[ 3]*b[ 3] 631159b3361Sopenharmony_ci +a[ 4]*b[ 4] + a[ 5]*b[ 5] + a[ 6]*b[ 6] + a[ 7]*b[ 7] 632159b3361Sopenharmony_ci +a[ 8]*b[ 8] + a[ 9]*b[ 9] + a[10]*b[10] + a[11]*b[11] 633159b3361Sopenharmony_ci +a[12]*b[12] + a[13]*b[13] + a[14]*b[14] + a[15]*b[15]; 634159b3361Sopenharmony_ci} 635159b3361Sopenharmony_ci 636159b3361Sopenharmony_ciint experiment ( generator_t* const g, 637159b3361Sopenharmony_ci amplitude_t* const a, 638159b3361Sopenharmony_ci keyboard_t* const k, 639159b3361Sopenharmony_ci soundcard_t* const s, 640159b3361Sopenharmony_ci earmode_t earmode ) 641159b3361Sopenharmony_ci{ 642159b3361Sopenharmony_ci long i; 643159b3361Sopenharmony_ci int j; 644159b3361Sopenharmony_ci stereo_t samples [512]; 645159b3361Sopenharmony_ci static double quant_errors [2] [16]; 646159b3361Sopenharmony_ci long double val; 647159b3361Sopenharmony_ci double ampl; 648159b3361Sopenharmony_ci long ival; 649159b3361Sopenharmony_ci 650159b3361Sopenharmony_ci fprintf ( stderr, "\r+++ up +++" ); 651159b3361Sopenharmony_ci for ( i = 0; i < g->duration; i += sizeof(samples)/sizeof(*samples) ) { 652159b3361Sopenharmony_ci fprintf ( stderr, "%3lu%%\b\b\b\b", i*100lu/g->duration ); 653159b3361Sopenharmony_ci 654159b3361Sopenharmony_ci for (j = 0; j < sizeof(samples)/sizeof(*samples); j++ ) { 655159b3361Sopenharmony_ci ampl = iterate_amplifier (a) * ATH (frequency (g)); 656159b3361Sopenharmony_ci val = ampl * iterate_generator (g); 657159b3361Sopenharmony_ci ival = (long) floor ( val + 0.5 + scalar (quant_errors[0], s->dither) ); 658159b3361Sopenharmony_ci 659159b3361Sopenharmony_ci if ( ival != (sample_t) ival ) { 660159b3361Sopenharmony_ci report (g, a); 661159b3361Sopenharmony_ci fprintf ( stderr, "\rOverrun \n\n" ); 662159b3361Sopenharmony_ci return -1; 663159b3361Sopenharmony_ci } 664159b3361Sopenharmony_ci memmove ( & quant_errors [0] [1], & quant_errors [0] [0], 665159b3361Sopenharmony_ci sizeof(quant_errors[0]) - sizeof(quant_errors[0][0]) ); 666159b3361Sopenharmony_ci quant_errors [0] [0] = val - ival; 667159b3361Sopenharmony_ci switch ( earmode ) { 668159b3361Sopenharmony_ci case both: 669159b3361Sopenharmony_ci samples [j] [0] = samples [j] [1] = ival; 670159b3361Sopenharmony_ci break; 671159b3361Sopenharmony_ci case left: 672159b3361Sopenharmony_ci samples [j] [0] = ival; 673159b3361Sopenharmony_ci samples [j] [1] = 0; 674159b3361Sopenharmony_ci break; 675159b3361Sopenharmony_ci case right: 676159b3361Sopenharmony_ci samples [j] [0] = 0; 677159b3361Sopenharmony_ci samples [j] [1] = ival; 678159b3361Sopenharmony_ci break; 679159b3361Sopenharmony_ci case phase180: 680159b3361Sopenharmony_ci samples [j] [0] = ival == -32768 ? 32767 : -ival; 681159b3361Sopenharmony_ci samples [j] [1] = +ival; 682159b3361Sopenharmony_ci break; 683159b3361Sopenharmony_ci case phase90: 684159b3361Sopenharmony_ci samples [j] [0] = ival; 685159b3361Sopenharmony_ci val = ampl * get_cosine (g); 686159b3361Sopenharmony_ci ival = (long) floor ( val + 0.5 + scalar (quant_errors[1], s->dither) ); 687159b3361Sopenharmony_ci if ( ival != (sample_t) ival ) { 688159b3361Sopenharmony_ci report (g, a); 689159b3361Sopenharmony_ci fprintf ( stderr, "\rOverrun \n\n" ); 690159b3361Sopenharmony_ci return -1; 691159b3361Sopenharmony_ci } 692159b3361Sopenharmony_ci memmove ( & quant_errors [1] [1], & quant_errors [1] [0], 693159b3361Sopenharmony_ci sizeof(quant_errors[1]) - sizeof(quant_errors[1][0]) ); 694159b3361Sopenharmony_ci quant_errors [1] [0] = val - ival; 695159b3361Sopenharmony_ci samples [j] [1] = ival; 696159b3361Sopenharmony_ci break; 697159b3361Sopenharmony_ci default: 698159b3361Sopenharmony_ci assert (0); 699159b3361Sopenharmony_ci return -1; 700159b3361Sopenharmony_ci } 701159b3361Sopenharmony_ci } 702159b3361Sopenharmony_ci play_soundcard ( s, samples, sizeof(samples)/sizeof(*samples) ); 703159b3361Sopenharmony_ci if ( amplitude (a) * ATH (frequency (g)) <= 3.16227766e-6 ) { 704159b3361Sopenharmony_ci report (g, a); 705159b3361Sopenharmony_ci fprintf ( stderr, "\rUnderrun \n\n" ); 706159b3361Sopenharmony_ci return -1; 707159b3361Sopenharmony_ci } 708159b3361Sopenharmony_ci 709159b3361Sopenharmony_ci switch ( getchar_keyboard (k) ) { 710159b3361Sopenharmony_ci case '+': 711159b3361Sopenharmony_ci fprintf ( stderr, "\r+++ up +++" ); 712159b3361Sopenharmony_ci report (g, a); 713159b3361Sopenharmony_ci change_direction ( a, up ); 714159b3361Sopenharmony_ci break; 715159b3361Sopenharmony_ci case '-': 716159b3361Sopenharmony_ci fprintf ( stderr, "\r--- down ---" ); 717159b3361Sopenharmony_ci report (g, a); 718159b3361Sopenharmony_ci change_direction ( a, down ); 719159b3361Sopenharmony_ci break; 720159b3361Sopenharmony_ci case '\r': 721159b3361Sopenharmony_ci case '\n': 722159b3361Sopenharmony_ci fprintf ( stderr, "\r** change **" ); 723159b3361Sopenharmony_ci report (g, a); 724159b3361Sopenharmony_ci change_direction ( a, change ); 725159b3361Sopenharmony_ci break; 726159b3361Sopenharmony_ci case 'C'&0x1F: 727159b3361Sopenharmony_ci case 'q': 728159b3361Sopenharmony_ci case 'Q': 729159b3361Sopenharmony_ci case 'x': 730159b3361Sopenharmony_ci case 'X': 731159b3361Sopenharmony_ci fprintf ( stderr, "\rBreak \n\n" ); 732159b3361Sopenharmony_ci fflush ( stderr ); 733159b3361Sopenharmony_ci return -1; 734159b3361Sopenharmony_ci default: 735159b3361Sopenharmony_ci fprintf ( stderr, "\a" ); 736159b3361Sopenharmony_ci break; 737159b3361Sopenharmony_ci case -1: 738159b3361Sopenharmony_ci break; 739159b3361Sopenharmony_ci } 740159b3361Sopenharmony_ci } 741159b3361Sopenharmony_ci 742159b3361Sopenharmony_ci fprintf ( stderr, "\rReady \n\n" ); 743159b3361Sopenharmony_ci return 0; 744159b3361Sopenharmony_ci} 745159b3361Sopenharmony_ci 746159b3361Sopenharmony_cistatic void usage ( void ) 747159b3361Sopenharmony_ci{ 748159b3361Sopenharmony_ci static const char help[] = 749159b3361Sopenharmony_ci "'Absolute Threshold of Hearing' -- Version 0.07 (C) Frank Klemm 2000\n" 750159b3361Sopenharmony_ci "\n" 751159b3361Sopenharmony_ci "usage:\n" 752159b3361Sopenharmony_ci " ath type minfreq maxfreq duration ampl_speed [start_level [earmode] > reportfile\n" 753159b3361Sopenharmony_ci "\n" 754159b3361Sopenharmony_ci " type: linear, logarithm, square, cubic, erb, recip\n" 755159b3361Sopenharmony_ci " minfreq: initial frequency [Hz]\n" 756159b3361Sopenharmony_ci " maxfreq: end frequency [Hz]\n" 757159b3361Sopenharmony_ci " duration: duration of the experiment [s]\n" 758159b3361Sopenharmony_ci " ampl_speed: amplitude slope speed [phon/s]\n" 759159b3361Sopenharmony_ci " start_level: absolute level at startup [0...1]\n" 760159b3361Sopenharmony_ci " earmode: left, right, both, phase90, phase180\n" 761159b3361Sopenharmony_ci "\n" 762159b3361Sopenharmony_ci "example:\n" 763159b3361Sopenharmony_ci " ath erb 700 22000 600 3 0.0001 > result1\n" 764159b3361Sopenharmony_ci " ath erb 1400 16 360 3 0.0001 > result2\n" 765159b3361Sopenharmony_ci "\n" 766159b3361Sopenharmony_ci "handling:\n" 767159b3361Sopenharmony_ci " press '-' once when you start hearing a tone\n" 768159b3361Sopenharmony_ci " press '+' once when you stop hearing a tone\n" 769159b3361Sopenharmony_ci " press 'q' to early leave the program\n" 770159b3361Sopenharmony_ci " on errors the pressed key is ignored\n"; 771159b3361Sopenharmony_ci 772159b3361Sopenharmony_ci fprintf ( stderr, "%s\n", help ); 773159b3361Sopenharmony_ci} 774159b3361Sopenharmony_ci 775159b3361Sopenharmony_ciint main ( int argc, char** argv ) 776159b3361Sopenharmony_ci{ 777159b3361Sopenharmony_ci generator_t g; 778159b3361Sopenharmony_ci amplitude_t a; 779159b3361Sopenharmony_ci soundcard_t s; 780159b3361Sopenharmony_ci keyboard_t k; 781159b3361Sopenharmony_ci genmode_t genmode; 782159b3361Sopenharmony_ci earmode_t earmode; 783159b3361Sopenharmony_ci 784159b3361Sopenharmony_ci if ( argc == 1 ) { 785159b3361Sopenharmony_ci usage (); 786159b3361Sopenharmony_ci system ( "./ath erb 700 22000 600 3 0.0001 > result1" ); 787159b3361Sopenharmony_ci system ( "./ath erb 1400 16 360 3 0.0001 > result2" ); 788159b3361Sopenharmony_ci system ( "xmgr result1 result2 &> /dev/null &" ); 789159b3361Sopenharmony_ci return 0; 790159b3361Sopenharmony_ci } 791159b3361Sopenharmony_ci 792159b3361Sopenharmony_ci if ( argc < 6 ) { 793159b3361Sopenharmony_ci usage (); 794159b3361Sopenharmony_ci return 1; 795159b3361Sopenharmony_ci } 796159b3361Sopenharmony_ci 797159b3361Sopenharmony_ci if ( 0 == strncmp ( argv[1], "li" , 2) ) genmode = linear; 798159b3361Sopenharmony_ci else if ( 0 == strncmp ( argv[1], "lo" , 2) ) genmode = logarithm; 799159b3361Sopenharmony_ci else if ( 0 == strncmp ( argv[1], "sq" , 2) ) genmode = square; 800159b3361Sopenharmony_ci else if ( 0 == strncmp ( argv[1], "cu" , 2) ) genmode = cubic; 801159b3361Sopenharmony_ci else if ( 0 == strncmp ( argv[1], "er" , 2) ) genmode = erb; 802159b3361Sopenharmony_ci else if ( 0 == strncmp ( argv[1], "re" , 2) ) genmode = recip; 803159b3361Sopenharmony_ci else { 804159b3361Sopenharmony_ci usage (); 805159b3361Sopenharmony_ci return 1; 806159b3361Sopenharmony_ci } 807159b3361Sopenharmony_ci 808159b3361Sopenharmony_ci if ( argc < 8 ) earmode = both; 809159b3361Sopenharmony_ci else if ( 0 == strncmp ( argv[7], "le" , 2) ) earmode = left; 810159b3361Sopenharmony_ci else if ( 0 == strncmp ( argv[7], "ri" , 2) ) earmode = right; 811159b3361Sopenharmony_ci else if ( 0 == strncmp ( argv[7], "bo" , 2) ) earmode = both; 812159b3361Sopenharmony_ci else if ( 0 == strncmp ( argv[7], "phase9" , 6) ) earmode = phase90; 813159b3361Sopenharmony_ci else if ( 0 == strncmp ( argv[7], "phase1" , 6) ) earmode = phase180; 814159b3361Sopenharmony_ci else { 815159b3361Sopenharmony_ci usage (); 816159b3361Sopenharmony_ci return 1; 817159b3361Sopenharmony_ci } 818159b3361Sopenharmony_ci 819159b3361Sopenharmony_ci 820159b3361Sopenharmony_ci open_soundcard ( &s, AUDIO_DEVICE, sizeof(stereo_t)/sizeof(sample_t), CHAR_BIT*sizeof(sample_t), 96000.0 ); 821159b3361Sopenharmony_ci open_generator ( &g, &s, genmode, atof (argv[4]), atof (argv[2]), atof (argv[3]) ); 822159b3361Sopenharmony_ci open_amplifier ( &a, &s, argc > 6 ? atof (argv[6]) : 0.0001, atof (argv[5]) ); 823159b3361Sopenharmony_ci open_keyboard ( &k ); 824159b3361Sopenharmony_ci 825159b3361Sopenharmony_ci report_open ( ); 826159b3361Sopenharmony_ci experiment ( &g, &a, &k, &s, earmode ); 827159b3361Sopenharmony_ci report_close ( ); 828159b3361Sopenharmony_ci 829159b3361Sopenharmony_ci close_keyboard ( &k ); 830159b3361Sopenharmony_ci close_amplifier( &a ); 831159b3361Sopenharmony_ci close_generator( &g ); 832159b3361Sopenharmony_ci close_soundcard( &s ); 833159b3361Sopenharmony_ci 834159b3361Sopenharmony_ci return 0; 835159b3361Sopenharmony_ci} 836159b3361Sopenharmony_ci 837159b3361Sopenharmony_ci/* end of ath.c */ 838159b3361Sopenharmony_ci 839159b3361Sopenharmony_ci 840