/* * Routine for processing the keyboard input. * * Copyright (C) 1995 Philip VanBaren */ #include #include #include #include #include #include #include #include "freq.h" #include "fft.h" #include "extern.h" #include "display.h" int display_peak = 0; /* Flag for displaying the peak information */ int help_mode = 0; /* Flag indicating help mode 0 (off), 1, or 2 */ int dtmf_mode = 0; /* Flag indicating DTMF mode */ int ctcss_mode = 0; /* Flag indicating CTCSS mode */ int log_mode = 0; /* Flag indicating LogFile mode */ int gen_ctcss = CTCSS_MAX; /* generated CTCSS frequency number * (init to none) */ double err_ctcss; int bw_mode = 0; /* Flag indicating a Black/White palette */ int freeze = 0; /* Flag indicating a paused display */ float freq_scalefactor = 1.0; /* Scalefactor for increasing the * horizonal scale */ float freq_base = 0.0; /* Base frequency for the display */ int bin = 0; /* Bin number for cursor display */ int mic_level = 0; /* Storage for mic input mixer level (0-100) */ int ext_level = 0; /* Storage for ext input mixer level (0-100) */ int int_level = 0; /* Storage for int input mixer level (0-100) */ int i; /* general miscelaneous */ FILE *log_file; /* file pointer of the log_file */ void cleanup_vga( void ) { /* * Clean up VGA registers so Borland libraries work again. */ outportb( 0x3c4, 2 ); outportb( 0x3c5, 0x0f ); /* Use all bit planes */ } void setup_vga( void ) { /* * Set up VGA registers for fast graphics display */ outportb( 0x3ce, 1 ); outportb( 0x3cf, 0 ); /* Disable set/reset for all planes */ outportb( 0x3ce, 3 ); outportb( 0x3cf, 0 ); /* No rotate, just write data */ outportb( 0x3ce, 4 ); outportb( 0x3cf, 3 ); /* Read from bit plane 3 */ outportb( 0x3ce, 5 ); outportb( 0x3cf, inportb( 0x3cf ) & 0x70 ); /* Read and write direct to * memory */ outportb( 0x3ce, 8 ); outportb( 0x3cf, 0xff ); /* Allow modification of all bits */ outportb( 0x3c4, 2 ); outportb( 0x3c5, 12 ); /* Use bit planes 2 and 3 */ } void draw_threshold_level( int color ) { int y; if ( threshold_level < 0 ) threshold_level = 0; if ( threshold_level > ys ) threshold_level = ys; y = ( WINDOW_BOTTOM - WINDOW_TOP ) * threshold_level / ys; y = ( WINDOW_BOTTOM ) - y; draw_line( WINDOW_LEFT - 1, y, WINDOW_RIGHT + 1, y, color ); } void input_text( char *text, int maxlen, int x, int y ) { /* * Input a line of text using graphical display at (x,y) Maximum length * allowed for input is given by maxlen The input begins with the current * contents of text, so this must be initialized before calling the * routine. */ int c = 0; int count; char ach[3]; ach[1] = '_'; ach[2] = 0; draw_text_left( x, y, text ); count = strlen( text ); x += count * _font_width; draw_text_left( x, y, "_" ); while ( ( c != 0x0d ) && ( c != 0x0a ) ) { c = draw_getch( ); if ( ( ( c == 0x08 ) || ( c == 0x7f ) ) && count ) { count--; x -= _font_width; draw_bar( x, y - 1, x + 2 * _font_width, y + _font_height, 0 ); draw_text_left( x, y, "_" ); } else if ( count < ( maxlen - 1 ) ) { if ( ( c >= '0' && c <= '9' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) || c == '.' || c == '\\' || c == '/' || c == ':' || c == '*' || c == '#' || c == '-' ) { draw_bar( x, y - 1, x + _font_width, y + _font_height, 0 ); ach[0] = c; text[count] = c; draw_text_left( x, y, ach ); count++; x += _font_width; } } if ( c == 0x1b ) { count = 0; break; } } text[count] = 0; } void update_display( void ) { /* Update the frequency and amplitude information displayed while */ /* the input is frozen. */ char ach[100]; double re, im; double amp, db; int bri = BitReversed[bin]; re = fftdata[bri]; im = fftdata[bri + 1]; amp = sqrt( re * re + im * im ) / 32768.0; if ( amp != 0 ) db = 20 * log10( amp ); else db = -100; draw_bar( 0, 21, 160, 71, 0 ); sprintf( ach, " Freq: %7.5g Hz ", ( double ) bin * SampleRate / fftlen ); draw_text_left( 0, 22, ach ); sprintf( ach, " Amp: %7.5g ", amp ); draw_text_left( 0, 34, ach ); sprintf( ach, " %7.5g db ", db ); draw_text_left( 0, 46, ach ); } void highlight( int on ) { /* Turn highlighting of a specified bin on the display on (1) or off (0) */ int pos; double freq = ( double ) bin * ( double ) SampleRate / fftlen; if ( logfreq ) pos = floor( log( freq / freq_base ) / log( fftlen / 2 ) * freq_scalefactor * ( double ) ( WINDOW_RIGHT - WINDOW_LEFT ) + 0.5 ); else pos = floor( ( freq - freq_base ) * ( double ) ( WINDOW_RIGHT - WINDOW_LEFT ) / ( double ) SampleRate * freq_scalefactor * 2.0 + 0.5 ); if ( on ) { draw_line( WINDOW_LEFT + pos, WINDOW_TOP, WINDOW_LEFT + pos, lasty[pos], DARK_HIGHLIGHT ); draw_line( WINDOW_LEFT + pos, lasty[pos], WINDOW_LEFT + pos, WINDOW_BOTTOM, LIGHT_HIGHLIGHT ); } else { draw_line( WINDOW_LEFT + pos, WINDOW_TOP, WINDOW_LEFT + pos, lasty[pos], 0 ); draw_line( WINDOW_LEFT + pos, lasty[pos], WINDOW_LEFT + pos, WINDOW_BOTTOM, GRAPH_COLOR ); } } void help_freze( void ) { draw_bar( WINDOW_LEFT - 5, MGY - 40, WINDOW_RIGHT + 5, MGY + _font_height, 0 ); draw_text_centered( MGX, MGY - 12, "Use arrows to move, Shift_arrows, Home & End to move quickly" ); draw_text_centered( MGX, MGY, "Enter to save to disk, Space to continue" ); } int process_input( int c, int repetitions ) { /* Process any keyboard input received by the program */ char ach[50]; int i; if ( c == 0 ) return ( 0 ); if ( freeze ) highlight( 0 ); if ( c == ' ' ) /* Toggle freeze mode on/off */ { freeze = !freeze; if ( freeze ) { if ( help_mode ) { help_mode = 0; update_header( ); } if ( ( double ) bin < freq_base * fftlen / SampleRate ) bin = ceil( freq_base * fftlen / SampleRate ); if ( ( double ) bin > maxfreq * fftlen / SampleRate ) bin = floor( maxfreq * fftlen / SampleRate ); help_freze( ); update_display( ); } else { draw_bar( 0, 21, 160, 71, 0 ); update_header( ); } } if ( dtmf_mode || ctcss_mode ) { if ( c == PG_UP ) { draw_threshold_level( 0 ); threshold_level += ys / 50; draw_threshold_level( TEXT_COLOR ); } if ( c == PG_DN ) { draw_threshold_level( 0 ); threshold_level -= ys / 50; draw_threshold_level( TEXT_COLOR ); } if ( c == 'G' || c == 'g' ) { log_mode = !log_mode; if ( log_mode ) { log_file = fopen( "dtmf_fft.log", "a" ); if ( log_file == NULL ) log_mode = 0; } else { fclose( log_file ); } update_header( ); } } if ( ( c == 'D' || c == 'd' ) && !ctcss_mode ) /* Toggle DTMF mode */ { dtmf_mode = !dtmf_mode; if ( dtmf_mode ) { halt_soundcard( ); EndFFT( ); SampleRate = 5000L; fftlen = 128; logfreq = 0; freq_scalefactor = 1.0; InitializeFFT( fftlen ); compute_window_function( ); /* Flush the buffers */ for ( i = 0; i < fftlen / 2; i++ ) displayval[i] = 0; for ( i = 0; i < fftlen; i++ ) fftdata[i] = 0; /* Re-initialize the display */ p_dtmf = 0; dtmf_nr[0] = 0; setup_xscale( ); update_header( ); reset_soundcard( ); } else { update_header( ); draw_threshold_level( 0 ); } } else if ( ( c == 'T' || c == 't' ) && !dtmf_mode ) /* Toggle CTCSS mode */ { ctcss_mode = !ctcss_mode; if ( ctcss_mode ) { halt_soundcard( ); EndFFT( ); SampleRate = 5000L; fftlen = 2048; logfreq = 1; freq_scalefactor = 1.0; InitializeFFT( fftlen ); compute_window_function( ); /* Flush the buffers */ for ( i = 0; i < fftlen / 2; i++ ) displayval[i] = 0; for ( i = 0; i < fftlen; i++ ) fftdata[i] = 0; p_dtmf = 0; dtmf_nr[0] = 0; /* Re-initialize the display */ setup_xscale( ); update_header( ); reset_soundcard( ); } else { update_header( ); draw_threshold_level( 0 ); } } else if ( freeze ) { /* Keys only valid in freeze-display */ if ( ( c == 0x0d ) || ( c == 0x0a ) ) /* saves the spectrum * data to a file */ { char filename[30]; draw_bar( WINDOW_LEFT - 5, MGY - 1, WINDOW_RIGHT + 5, MGY + _font_height, 0 ); draw_text_left( MGX - 156, MGY, "File in which to save this spectrum:" ); filename[0] = 0; input_text( filename, sizeof( filename ), MGX + 140, MGY ); if ( filename[0] != 0 ) { clock_t clk; FILE *fp = fopen( filename, "w" ); if ( fp ) { for ( i = 0; i < fftlen / 2; i++ ) { double re, im; re = fftdata[BitReversed[i]] / 32768.0; fprintf( fp, "%g\t%g\n", ( double ) i / ( double ) fftlen * ( double ) SampleRate, re ); } fclose( fp ); sprintf( ach, "Spectrum data saved in %s", filename ); } else sprintf( ach, "Unable to open (%s)", filename ); draw_bar( WINDOW_LEFT - 5, MGY - 1, WINDOW_RIGHT + 5, MGY + _font_height, 0 ); draw_text_centered( MGX, MGY, ach ); clk = clock( ); while ( !draw_getkey( ) && ( ( clock( ) - clk ) < CLOCKS_PER_SEC * 3 ) ); } draw_bar( WINDOW_LEFT - 5, MGY - 13, WINDOW_RIGHT + 5, MGY + _font_height, 0 ); help_freze( ); } if ( c == LEFT_ARROW ) /* Move the cursor one bin left */ if ( !( bioskey( 2 ) & 3 ) ) /* if no shift key is pressed */ { double current; bin -= repetitions; if ( bin <= 0 ) { if ( logfreq ) bin = 1; else bin = 0; } current = ( double ) bin *( double ) SampleRate / ( double ) fftlen; if ( current < freq_base ) { freq_base = current; /* Re-initialize the display */ setup_xscale( ); } update_display( ); } else { /* Move the cursor 10 bins left */ double current; bin -= 10 * repetitions; if ( bin <= 0 ) { if ( logfreq ) bin = 1; else bin = 0; } current = ( double ) bin *( double ) SampleRate / ( double ) fftlen; if ( current < freq_base ) { freq_base = current; /* Re-initialize the display */ setup_xscale( ); } update_display( ); } else if ( c == RIGHT_ARROW )/* Move the cursor one bin right */ if ( !( bioskey( 2 ) & 3 ) ) /* if no shift key is pressed */ { double current; bin += repetitions; if ( bin >= fftlen / 2 ) bin = fftlen / 2 - 1; current = ( double ) bin *( double ) SampleRate / ( double ) fftlen; if ( current > maxfreq ) { if ( logfreq ) freq_base = current / exp( log( fftlen / 2 ) / freq_scalefactor ); else freq_base = current - ( double ) SampleRate / ( freq_scalefactor * 2.0 ); /* Re-initialize the display */ setup_xscale( ); } update_display( ); } else { double current; bin += 10 * repetitions; if ( bin >= fftlen / 2 ) bin = fftlen / 2 - 1; current = ( double ) bin *( double ) SampleRate / ( double ) fftlen; if ( current > maxfreq ) { if ( logfreq ) freq_base = current / exp( log( fftlen / 2 ) / freq_scalefactor ); else freq_base = current - ( double ) SampleRate / ( freq_scalefactor * 2.0 ); /* Re-initialize the display */ setup_xscale( ); } update_display( ); } else if ( c == HOME ) /* Move the cursor to the lowest frequency */ { if ( logfreq ) bin = 1; else bin = 0; update_display( ); if ( ( logfreq && ( freq_base > ( ( double ) SampleRate / ( double ) fftlen ) ) ) || ( !logfreq && ( freq_base > 0 ) ) ) { freq_base = 0; /* Re-initialize the display */ setup_xscale( ); } } else if ( c == END ) /* Move the cursor to the highest frequency */ { bin = fftlen / 2 - 1; update_display( ); if ( maxfreq < ( double ) SampleRate / 2 ) { freq_base = SampleRate / 2; /* Re-initialize the display */ setup_xscale( ); } } } else if ( !dtmf_mode && !ctcss_mode ) { /* Keys only valid in non-freeze display */ if ( c == HOME ) /* Move the cursor to the lowest frequency */ { if ( logfreq && ( freq_base > ( ( double ) SampleRate / ( double ) fftlen ) ) ) { /* Re-initialize the display */ freq_base = 0; setup_xscale( ); } else if ( !logfreq && ( freq_base > 0 ) ) { /* Re-initialize the display */ freq_base = 0; setup_xscale( ); } } else if ( c == END ) /* Move the cursor to the highest frequency */ { if ( maxfreq < ( double ) SampleRate / 2 ) { freq_base = SampleRate / 2; /* Re-initialize the display */ setup_xscale( ); } } else if ( c == 'H' || c == 'h' || c == '?' || c == '/' ) /* Toggle help mode */ { help_mode++; if ( help_mode > 2 ) help_mode = 0; if ( help_mode ) show_help( ); else update_header( ); } else if ( c == 'F' || c == 'f' ) /* Change the FFT length */ { halt_soundcard( ); EndFFT( ); if ( c == 'f' ) { for ( i = 0; i < repetitions; i++ ) { fftlen *= 2; if ( fftlen > MAX_LEN ) fftlen = 8; } } else { for ( i = 0; i < repetitions; i++ ) { fftlen /= 2; if ( fftlen < 8 ) fftlen = MAX_LEN; } } InitializeFFT( fftlen ); compute_window_function( ); /* Flush the buffers */ for ( i = 0; i < fftlen / 2; i++ ) displayval[i] = 0; for ( i = 0; i < fftlen; i++ ) fftdata[i] = 0; /* Re-initialize the display */ setup_xscale( ); if ( help_mode ) show_help( ); else update_header( ); reset_soundcard( ); } else if ( c == 'R' || c == 'r' ) /* Change the sampling rate */ { char in[6]; draw_bar( WINDOW_LEFT - 5, MGY - 1, WINDOW_RIGHT + 5, MGY + _font_height, 0 ); draw_text_left( MGX - 80, MGY, "Sampling rate: " ); in[0] = 0; input_text( in, sizeof( in ), MGX + 40, MGY ); if ( in[0] != 0 ) { halt_soundcard( ); SampleRate = atol( in ); if ( SampleRate < 5000L ) SampleRate = 5000L; if ( SampleRate > 88200L ) SampleRate = 88200L; reset_soundcard( ); /* Re-initialize the display */ setup_xscale( ); } if ( help_mode ) show_help( ); else update_header( ); } } /* Keys valid in both freeze and non-freeze mode */ if ( c == 'I' || c == 'i' ) { char *p, *s; int valid; draw_bar( WINDOW_LEFT - 5, MGY - 40, WINDOW_RIGHT + 5, MGY + 8, 0 ); draw_fontcolor( BORDER_COLOR ); draw_text_left( WINDOW_LEFT, MGY - 12, "DTMF number to compose: " ); dtmf_nr[0] = 0; input_text( dtmf_nr, 64, WINDOW_LEFT, MGY ); /* maximum 64 DTMF * numbers */ draw_bar( WINDOW_LEFT - 5, MGY - 16, WINDOW_RIGHT + 5, MGY + 8, 0 ); p = s = dtmf_nr; valid = 0; while ( *p != 0 ) { if ( *p >= 'a' && *p <= 'd' ) *p &= ~0x20; /* upper case */ if ( !( *p >= '0' && *p <= '9' ) && !( *p >= 'A' && *p <= 'D' ) && *p != '*' && *p != '#' ) *p = '-'; else valid = 1; if ( valid ) *s++ = *p; p++; } while ( *--s == '-' ) ; *++s = 0; update_header( ); } else if ( c == 'A' || c == 'a' ) { char str[10]; int m = 0; int err; int old_ctcss; draw_bar( 0, 0, 639, 92, 0 ); draw_fontcolor( TEXT_COLOR ); draw_text_centered( ( WINDOW_LEFT + WINDOW_RIGHT ) / 2, 2, "Arrows to move (\033 \032 \030 \031) / Esc to exit / Enter when done" ); draw_fontcolor( LABEL_COLOR ); draw_text_left( WINDOW_LEFT, 15, "Choose a tone frequency:" ); draw_fontcolor( TEXT_COLOR ); draw_text_left( WINDOW_LEFT + 248, 15, "SPACE toggles" ); draw_fontcolor( GRAPH_COLOR ); draw_text_left( WINDOW_LEFT + 366, 15, "active" ); draw_fontcolor( TEXT_COLOR ); draw_text_left( WINDOW_LEFT + 426, 15, "/" ); draw_fontcolor( BORDER_COLOR ); draw_text_left( WINDOW_LEFT + 440, 15, "inactive" ); old_ctcss = gen_ctcss; do { switch ( m ) { case ' ': if ( gen_ctcss < CTCSS_MAX ) if ( gen_ctcss < 32 ) ctcss_act1 ^= 1L << gen_ctcss; else ctcss_act2 ^= 1L << ( gen_ctcss - 32 ); break; case LEFT_ARROW: if ( gen_ctcss >= 1 ) gen_ctcss--; break; case RIGHT_ARROW: if ( gen_ctcss < CTCSS_MAX ) gen_ctcss++; break; case UP_ARROW: if ( gen_ctcss >= 10 ) gen_ctcss -= 10; break; case DOWN_ARROW: if ( gen_ctcss <= CTCSS_MAX - 10 ) gen_ctcss += 10; break; } for ( i = 0; i <= CTCSS_MAX; i++ ) { if ( i == CTCSS_MAX ) sprintf( str, "%s", "none" ); else sprintf( str, "%5.1f", f_ctcss[i] ); if ( i == gen_ctcss ) if ( i < CTCSS_MAX && ( i < 32 ? ctcss_act1 >> i : ctcss_act2 >> ( i - 32 ) ) & 1 ) draw_fontcolor( TEXT_COLOR ); else draw_fontcolor( LABEL_COLOR ); else if ( i < CTCSS_MAX && ( i < 32 ? ctcss_act1 >> i : ctcss_act2 >> ( i - 32 ) ) & 1 ) draw_fontcolor( GRAPH_COLOR ); else draw_fontcolor( BORDER_COLOR ); draw_text_left( WINDOW_LEFT + ( i % 10 ) * 52, 29 + 11 * ( i / 10 ), str ); } } while ( ( m = draw_getkey( ) ) != 0x0d && ( m != 0x1b ) ); if ( m == 0x1b ) gen_ctcss = old_ctcss; else { halt_soundcard( ); err_ctcss = generate_CTCSS( gen_ctcss ); reset_soundcard( ); } draw_bar( 0, 0, 639, 92, 0 ); update_header( ); } else if ( c == TAB ) { dtmf_mode = ctcss_mode = 0; draw_threshold_level( 0 ); update_header( ); if ( dtmf_nr[0] != 0 ) { draw_fontcolor( TEXT_COLOR ); draw_bar( WINDOW_LEFT - 5, MGY - 16, WINDOW_RIGHT + 5, MGY + _font_height, 0 ); draw_text_left( WINDOW_LEFT, MGY - 12, "Composing: " ); halt_soundcard( ); generate_DTMF( dtmf_nr ); reset_soundcard( ); update_header( ); } } else if ( c == UP_ARROW ) { /* Increase the vertical scale factor */ if ( dtmf_mode || ctcss_mode ) draw_threshold_level( 0 ); { double last_ys = ys; for ( i = 0; i < repetitions; i++ ) { if ( ys > 0.15 ) { ys -= 0.1; } else if ( ys > 0.01 ) { ys -= 0.01; if ( ys < 0.01 ) ys = 0.01; } } if ( ys != last_ys ) setup_linscales( ); } if ( dtmf_mode || ctcss_mode ) draw_threshold_level( TEXT_COLOR ); amplitude_scale( ); } else if ( c == DOWN_ARROW ) { /* Decrease the vertical scale factor */ if ( dtmf_mode || ctcss_mode ) draw_threshold_level( 0 ); { double last_ys = ys; for ( i = 0; i < repetitions; i++ ) { if ( ys < 0.095 ) { ys += 0.01; } else if ( ys < 2.00 ) { ys += 0.1; if ( ys > 2.0 ) ys = 2.0; } } if ( ys != last_ys ) setup_linscales( ); } if ( dtmf_mode || ctcss_mode ) draw_threshold_level( TEXT_COLOR ); amplitude_scale( ); } else if ( ( c == '<' ) || ( c == CTRL_LEFT ) || ( c == ALT_LEFT ) ) { /* Decrease the horizontal scale factor */ if ( freq_scalefactor > 1.0 ) { for ( i = 0; ( freq_scalefactor > 1.0 ) && ( i < repetitions ); i++ ) { freq_scalefactor *= 0.84089641525371; /* 1/(2^0.25) */ if ( logfreq ) freq_base *= exp( log( fftlen / 2 ) * 0.07955179237314 / freq_scalefactor ); else freq_base -= ( double ) SampleRate *0.03977589618657 / freq_scalefactor; } /* Re-initialize the display */ if ( freeze ) { double current = ( double ) bin * ( double ) SampleRate / ( double ) fftlen; xrange_check( ); if ( current < freq_base ) { freq_base = current; } if ( current > maxfreq ) { if ( logfreq ) freq_base = current / exp( log( fftlen / 2 ) / freq_scalefactor ); else freq_base = current - ( double ) SampleRate / 2.0 / freq_scalefactor; } } setup_xscale( ); } } else if ( ( c == '>' ) || ( c == CTRL_RIGHT ) || ( c == ALT_RIGHT ) ) { /* Increase the horizontal scale factor */ if ( freq_scalefactor < 16.0 ) { for ( i = 0; ( freq_scalefactor < 16.0 ) && ( i < repetitions ); i++ ) { if ( logfreq ) freq_base *= exp( log( fftlen / 2 ) * 0.07955179237314 / freq_scalefactor ); else freq_base += ( double ) SampleRate *0.03977589618657 / freq_scalefactor; freq_scalefactor *= 1.18920711500272; /* 2^0.25 */ } /* Re-initialize the display */ if ( freeze ) { double current = ( double ) bin * ( double ) SampleRate / ( double ) fftlen; xrange_check( ); if ( current < freq_base ) { freq_base = current; } if ( current > maxfreq ) { if ( logfreq ) freq_base = current / exp( log( fftlen / 2 ) / freq_scalefactor ); else freq_base = current - ( double ) SampleRate / 2.0 / freq_scalefactor; } } setup_xscale( ); } } else if ( ( c == ',' ) || ( c == LEFT_ARROW ) ) { /* Shift the horizontal display to the right */ if ( maxfreq < ( double ) SampleRate / 2 ) { for ( i = 0; ( i < repetitions ) && ( maxfreq < ( double ) SampleRate / 2 ); i++ ) { if ( logfreq ) freq_base *= exp( log( fftlen / 2 ) / ( 8.0 * freq_scalefactor ) ); else freq_base += ( double ) SampleRate / ( 16.0 * freq_scalefactor ); xrange_check( ); } /* Re-initialize the display */ if ( freeze ) { double current = ( double ) bin * ( double ) SampleRate / ( double ) fftlen; if ( current < freq_base ) { bin = ceil( freq_base / ( double ) SampleRate * ( double ) fftlen ); update_display( ); } } setup_xscale( ); } } else if ( ( c == '.' ) || ( c == RIGHT_ARROW ) ) { /* Shift the horizontal display to the left */ if ( ( logfreq && ( freq_base > ( ( double ) SampleRate / ( double ) fftlen ) ) ) || ( !logfreq && ( freq_base > 0 ) ) ) { for ( i = 0; i < repetitions; i++ ) { if ( ( logfreq && ( freq_base > ( ( double ) SampleRate / ( double ) fftlen ) ) ) || ( !logfreq && ( freq_base > 0 ) ) ) { if ( logfreq ) freq_base /= exp( log( fftlen / 2 ) / ( 8.0 * freq_scalefactor ) ); else freq_base -= ( double ) SampleRate / ( 16.0 * freq_scalefactor ); } xrange_check( ); } /* Re-initialize the display */ if ( freeze ) { double current = ( double ) bin * ( double ) SampleRate / ( double ) fftlen; if ( current > maxfreq ) { bin = floor( maxfreq / ( double ) SampleRate * ( double ) fftlen ); if ( bin >= fftlen / 2 ) bin = fftlen / 2 - 1; update_display( ); } } setup_xscale( ); } } else if ( c == 'P' || c == 'p' ) /* Toggle peak display mode on/off */ { display_peak = !display_peak; if ( display_peak ) { draw_text_left( PKX - 64, PKY, "Peak at Hz" ); } else { draw_bar( PKX - 64, PKY - 1, PKX + 79, PKY + _font_height, 0 ); } } else if ( c == 'V' || c == 'v' ) /* Redraw the video display */ { draw_bar( 0, 0, 639, 479, 0 ); /* Refresh the video display */ draw_rectangle( WINDOW_LEFT - 2, WINDOW_TOP - 2, WINDOW_RIGHT + 2, WINDOW_BOTTOM + 2, BORDER_COLOR ); setup_xscale( ); amplitude_scale( ); if ( help_mode ) show_help( ); else update_header( ); if ( display_peak ) { draw_text_left( PKX - 64, PKY, "Peak at Hz" ); } if ( freeze ) { help_freze( ); update_display( ); } /* Reset the last-value contents */ for ( i = 0; i < WINDOW_RIGHT - WINDOW_LEFT; i++ ) lasty[i] = WINDOW_BOTTOM; } else if ( c == 'S' || c == 's' ) /* Save the current state to an INI * file */ { draw_bar( WINDOW_LEFT, MGY - 1, WINDOW_RIGHT + 5, MGY + _font_height, 0 ); draw_text_left( MGX - 130, MGY, "Save the current state to: " ); strncpy( ach, ini_file, 20 ); input_text( ach, 20, MGX + 86, MGY ); if ( ach[0] != 0 ) { FILE *fp; strcpy( ini_file, ach ); fp = fopen( ini_file, "w" ); if ( fp ) { fprintf( fp, "Soundcard: %d\n", Soundcard ); fprintf( fp, "Sample rate: %ld\n", SampleRate ); fprintf( fp, "FFT length: %d\n", fftlen ); fprintf( fp, "Log freq scale: %d\n", logfreq ); fprintf( fp, "Max amp: %g\n", ys ); fprintf( fp, "Base frequency: %g\n", freq_base ); fprintf( fp, "Frequency factor: %g\n", freq_scalefactor ); fprintf( fp, "DTMF & CTCSS threshold level: %g\n", threshold_level ); fprintf( fp, "DTMF delay (100 - 1000 ms): %d\n", 3 * dtmf_delay ); fprintf( fp, "CTCSS active: 0x%08lX, 0x%08lX\n", ctcss_act1, ctcss_act2 ); fprintf( fp, "Background color: %d,%d,%d\n", background.red, background.green, background.blue ); fprintf( fp, "Clipping warning color: %d,%d,%d\n", warn.red, warn.green, warn.blue ); fprintf( fp, "Graph color: %d,%d,%d\n", graph.red, graph.green, graph.blue ); fprintf( fp, "Tick mark color: %d,%d,%d\n", tick.red, tick.green, tick.blue ); fprintf( fp, "Axis label color: %d,%d,%d\n", label.red, label.green, label.blue ); fprintf( fp, "Border color: %d,%d,%d\n", border.red, border.green, border.blue ); fprintf( fp, "Text color: %d,%d,%d\n", text.red, text.green, text.blue ); fprintf( fp, "Cursor upper color: %d,%d,%d\n", darkhl.red, darkhl.green, darkhl.blue ); fprintf( fp, "Cursor lower color: %d,%d,%d\n", lighthl.red, lighthl.green, lighthl.blue ); fclose( fp ); } else { clock_t clk = clock( ); sprintf( ach, "Unable to open %s", ini_file ); draw_bar( WINDOW_LEFT - 5, MGY - 1, WINDOW_RIGHT + 5, MGY + _font_height, 0 ); draw_text_centered( MGX, MGY, ach ); while ( !draw_getkey( ) && ( ( clock( ) - clk ) < 3 * CLOCKS_PER_SEC ) ); } } if ( help_mode ) show_help( ); else update_header( ); if ( freeze ) { help_freze( ); update_display( ); } } else if ( c == 'C' || c == 'c' ) /* Toggle Black/White palette on/off */ { bw_mode = !bw_mode; if ( bw_mode ) setbwpalette( ); else setnormalpalette( ); } else if ( c == 'L' || c == 'l' ) /* Toggle linear/logarithmic * frequency axis */ { /* * Toggle between linear and logarithmic and equalizer frequency scale */ logfreq = !logfreq; if ( freeze ) { double current; if ( logfreq && ( bin == 0 ) ) bin = 1; current = ( double ) bin *( double ) SampleRate / ( double ) fftlen; xrange_check( ); if ( current < freq_base ) { freq_base = current; } if ( current > maxfreq ) { if ( !logfreq ) freq_base = current - ( double ) SampleRate / 2.0 / freq_scalefactor; else freq_base = current / exp( log( fftlen / 2 ) / freq_scalefactor ); } } setup_xscale( ); } else if ( mixers ) { if ( c == '[' ) /* External jack down */ { ext_level -= 2 * repetitions; if ( ext_level < 0 ) ext_level = 0; if ( !help_mode ) { sprintf( ach, "%3d", ext_level ); draw_bar( LVX + 104, LVY - 1, LVX + 127, LVY + _font_height, 0 ); draw_text_left( LVX + 104, LVY, ach ); } set_mixer( MIXER_EXT, ext_level ); } else if ( c == ']' ) /* External jack up */ { ext_level += 2 * repetitions; if ( ext_level > 100 ) ext_level = 100; if ( !help_mode ) { sprintf( ach, "%3d", ext_level ); draw_bar( LVX + 104, LVY - 1, LVX + 127, LVY + _font_height, 0 ); draw_text_left( LVX + 104, LVY, ach ); } set_mixer( MIXER_EXT, ext_level ); } else if ( c == '{' ) /* CD input down */ { int_level -= 2 * repetitions; if ( int_level < 0 ) int_level = 0; if ( !help_mode ) { sprintf( ach, "%3d", int_level ); draw_bar( LVX + 168, LVY - 1, LVX + 191, LVY + _font_height, 0 ); draw_text_left( LVX + 168, LVY, ach ); } set_mixer( MIXER_INT, int_level ); } else if ( c == '}' ) /* CD input up */ { int_level += 2 * repetitions; if ( int_level > 100 ) int_level = 100; if ( !help_mode ) { sprintf( ach, "%3d", int_level ); draw_bar( LVX + 168, LVY - 1, LVX + 191, LVY + _font_height, 0 ); draw_text_left( LVX + 168, LVY, ach ); } set_mixer( MIXER_INT, int_level ); } else if ( c == '(' ) /* Mic input down */ { mic_level -= 2 * repetitions; if ( mic_level < 0 ) mic_level = 0; if ( !help_mode ) { sprintf( ach, "%3d", mic_level ); draw_bar( LVX + 32, LVY - 1, LVX + 55, LVY + _font_height, 0 ); draw_text_left( LVX + 32, LVY, ach ); } set_mixer( MIXER_MIC, mic_level ); } else if ( c == ')' ) /* Mic input up */ { mic_level += 2 * repetitions; if ( mic_level > 100 ) mic_level = 100; if ( !help_mode ) { sprintf( ach, "%3d", mic_level ); draw_bar( LVX + 32, LVY - 1, LVX + 55, LVY + _font_height, 0 ); draw_text_left( LVX + 32, LVY, ach ); } set_mixer( MIXER_MIC, mic_level ); } } if ( freeze ) highlight( 1 ); return ( c == 'E' || c == 'e' || c == 'Q' || c == 'q' || c == 0x1b ); }