/* DTMF.C */ /* Author: Emil LAURENTIU */ /* Last modified: Tuesday, 05 August 1997 */ #include #include #include #include #include "freq.h" extern char matrix_dtmf[4][4]; extern int f_dtmf[]; extern double f_ctcss[]; extern int sb_f_dtmf[]; extern int dtmf_delay; extern int sb_addr; static unsigned ticking = 0; static FM_Instrument instrument = { 0x3f, 0x3f, /* Level */ 0x00, 0x00, /* Multiple */ 0x00, 0x00, /* Attack */ 0x00, 0x00, /* Decay */ 0x0f, 0x0f, /* Sustain */ 0x00, 0x00, /* Release */ 0x00, 0x00, /* WaveSelect */ 0x00, 0x00, /* Amp_Vib_EnvG */ 0x01, 0x00 /* Algorithm, Feedback */ }; int notes[12] = {0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE}; /* dtmf.c 05/08/97 23.37.34 */ unsigned char op_p( int voice, int op ); void Sb_FM_Reset( void ); void Sb_FM_Key_Off( int voice ); void Sb_FM_Key_On( int voice, int freq, int octave ); void Sb_FM_Voice_Volume( int voice, int op, int vol ); void Sb_FM_Voice_At_De( int voice, int op, int atack, int decay ); void Sb_FM_Voice_Su_Re( int voice, int op, int sustain, int release ); void Sb_FM_Voice_Character( int voice, int op, int amp_vib_envg, int multiple ); void Sb_FM_Voice_WaveSelect( int voice, int op, int wave ); void Sb_FM_Voice_FeedBack( int voice, int type, int strength ); void Sb_FM_Set_Voice( int voice, FM_Instrument * ins ); void interrupt new_timer( void ); unsigned long timer_hiticks( void ); void delay_loop( int time ); void generate_DTMF( char *nr ); double generate_CTCSS( int gen_ctcss ); static void WriteFM( int addr, unsigned char data ) { int i; /* Left Channel */ outportb( sb_addr + 0, addr ); for ( i = 0; i < 6; i++ ) inportb( sb_addr + 0 ); outportb( sb_addr + 1, data ); for ( i = 0; i < 35; i++ ) inportb( sb_addr + 0 ); /* Rigth Channel */ outportb( sb_addr + 2, addr ); for ( i = 0; i < 6; i++ ) inportb( sb_addr + 2 ); outportb( sb_addr + 3, data ); for ( i = 0; i < 35; i++ ) inportb( sb_addr + 2 ); } unsigned char op_p( int voice, int op ) { unsigned char c; c = ( --voice ) % 9; c = ( c / 3 ) << 3 | c % 3; c += 3 * ( ( --op ) & 1 ); return ( c ); } void Sb_FM_Reset( void ) { int i; WriteFM( 1, 0x20 ); /* FM waveform */ WriteFM( 4, 0 ); /* disable timers */ WriteFM( 8, 0 ); /* select FM music mode */ WriteFM( 0xbd, 0xc0 ); /* no drums */ for ( i = 1; i <= 9; i++ ) { Sb_FM_Key_Off( i ); Sb_FM_Voice_WaveSelect( i, 1, 0 ); Sb_FM_Voice_WaveSelect( i, 2, 0 ); } } void Sb_FM_Key_Off( int voice ) { WriteFM( 0xB0 + ( --voice ) % 9, 0 ); /* turn voice off */ } void Sb_FM_Key_On( int voice, int freq, int octave ) { --voice; voice %= 9; WriteFM( 0xb0 + voice, 0 ); WriteFM( 0xa0 + voice, freq & 0xff ); WriteFM( 0xb0 + voice, ( freq >> 8 ) | ( octave << 2 ) | 0x20 ); } void Sb_FM_Voice_Volume( int voice, int op, int vol ) { WriteFM( 0x40 + op_p( voice, op ), ~vol & 0x3f | 0x40 ); } void Sb_FM_Voice_At_De( int voice, int op, int atack, int decay ) { WriteFM( 0x60 + op_p( voice, op ), ( ~atack & 0xf ) << 4 | decay & 0xf ); } void Sb_FM_Voice_Su_Re( int voice, int op, int sustain, int release ) { WriteFM( 0x80 + op_p( voice, op ), ( sustain & 0xf ) << 4 | ~release & 0xf ); } void Sb_FM_Voice_Character( int voice, int op, int amp_vib_envg, int multiple ) { WriteFM( 0x20 + op_p( voice, op ), ( amp_vib_envg & 7 ) << 5 | ( multiple + 1 ) & 0xf ); } void Sb_FM_Voice_WaveSelect( int voice, int op, int wave ) { WriteFM( 0xe0 + op_p( voice, op ), wave & 3 ); } void Sb_FM_Voice_FeedBack( int voice, int type, int strength ) { WriteFM( 0xc0 + ( --voice ) % 9, ( strength & 7 ) << 1 | type & 1 ); } void Sb_FM_Set_Voice( int voice, FM_Instrument * ins ) { int op; for ( op = 1; op <= 2; op++ ) { Sb_FM_Voice_Volume( voice, op, ins->Level[op - 1] ); Sb_FM_Voice_At_De( voice, op, ins->Atack[op - 1], ins->Decay[op - 1] ); Sb_FM_Voice_Su_Re( voice, op, ins->Sustain[op - 1], ins->Release[op - 1] ); Sb_FM_Voice_Character( voice, op, ins->Amp_Vib_EnvG[op - 1], ins->Multiple[op - 1] ); Sb_FM_Voice_WaveSelect( voice, op, ins->WaveSelect[op - 1] ); } Sb_FM_Voice_FeedBack( voice, ins->Algorithm, ins->Feedback ); } void interrupt new_timer( ) { ticking++; outportb( 0x20, 0x20 ); /* Send EOI */ } unsigned long timer_hiticks( ) { outportb( 0x43, 0x00 ); /* Send latch command to 8253 counter 0 */ return ( ( unsigned long ) ticking << 16 ) | ( unsigned ) -( inportb( 0x40 ) | ( inportb( 0x40 ) << 8 ) ); } void delay_loop( int time ) /* Delay is in milisecond increments */ { unsigned long val; val = timer_hiticks( ) + 1193L * time; while ( val > timer_hiticks( ) ); /* Wait */ } void generate_DTMF( char *nr ) { int i, j; int xoff = WINDOW_LEFT; char nc; int key; void interrupt( *old_int ) ( ); disable( ); old_int = getvect( 8 ); /* timer */ setvect( 8, new_timer ); enable( ); Sb_FM_Set_Voice( 1, &instrument ); Sb_FM_Set_Voice( 2, &instrument ); Sb_FM_Voice_Volume( 1, 1, 0x3f ); Sb_FM_Voice_Volume( 2, 1, 0x3f ); Sb_FM_Voice_Volume( 1, 2, 0x3f ); Sb_FM_Voice_Volume( 2, 2, 0x3f ); while ( *nr ) { key = 0; for ( i = 0; i < 4; i++ ) for ( j = 0; j < 4; j++ ) if ( matrix_dtmf[i][j] == *nr ) { key++; Sb_FM_Key_On( 1, sb_f_dtmf[i], 5 ); Sb_FM_Key_On( 2, sb_f_dtmf[j + 4], 6 ); } nc = *( nr + 1 ); *( nr + 1 ) = 0; draw_text_left( xoff, MGY, nr ); xoff += 8; *( nr + 1 ) = nc; if ( key ) delay_loop( dtmf_delay << 1 ); Sb_FM_Key_Off( 1 ); Sb_FM_Key_Off( 2 ); if ( !key ) delay_loop( dtmf_delay << 1 ); delay_loop( dtmf_delay ); nr++; } Sb_FM_Voice_Volume( 1, 1, 0 ); Sb_FM_Voice_Volume( 2, 1, 0 ); Sb_FM_Voice_Volume( 1, 2, 0 ); Sb_FM_Voice_Volume( 2, 2, 0 ); disable( ); setvect( 8, old_int ); enable( ); } double generate_CTCSS( int gen_ctcss ) { double err = 0; const double step = 1e5 / 2097152; int factor, multiply; if ( gen_ctcss == CTCSS_MAX ) Sb_FM_Key_Off( 3 ); else { Sb_FM_Set_Voice( 3, &instrument ); multiply = f_ctcss[gen_ctcss] / step / 1024; multiply++; WriteFM( 0x20 + op_p( 3, 1 ), multiply ); /* use freq * multiply */ WriteFM( 0x20 + op_p( 3, 2 ), multiply ); /* for better resolution */ factor = f_ctcss[gen_ctcss] / step / multiply + 0.5; err = step * factor * multiply - f_ctcss[gen_ctcss]; Sb_FM_Key_On( 3, factor, 0 ); /* use ocatave 0 */ WriteFM( 0x40 + op_p( 3, 1 ), 0xC0 ); /* maximum volume (0x3F) */ WriteFM( 0x40 + op_p( 3, 2 ), 0xC0 ); /* 6 db/octave decrease */ } return ( err ); }