# HG changeset patch # User Eris Caffee # Date 1407258946 18000 # Node ID 3617357a1b90010c00f59f64a3ab1f54ce1fc9bd # Parent 03892700ff0dde8320b2b967876ddfbbb62d3c76 Added keyboard commands: p play/pause q quit n next file v previous file f fast forward b fast backward diff -r 03892700ff0d -r 3617357a1b90 playogg.c --- a/playogg.c Tue Jul 22 16:27:42 2014 -0500 +++ b/playogg.c Tue Aug 05 12:15:46 2014 -0500 @@ -4,6 +4,8 @@ #include #include +#include +#include #include #include @@ -17,7 +19,6 @@ int list_devices; char* device; char **files; - int skip_next; char *outfile; int ao_endian; int ao_device_id; @@ -26,12 +27,19 @@ ao_sample_format ao_format; } options; + + +struct termios termios_orig; + +/******************************************************************************/ int main (int argc, char **argv ) { init(); parse_command_line( argc, argv ); + term_init(); + if ( ! sound_init() ) { exit( EXIT_FAILURE ); } @@ -41,15 +49,22 @@ } char **file = options.files; - int ok = 1; - while (ok && file && *file) { + int next = 1; /* -1 play previous file, 0 stop playing, 1 play next file */ + while (next && file && *file) { if ( options.verbose ) { printf( "Next file: %s\n", *file ); } - ok = sound_play_file( *file ); - file++; + next = sound_play_file( *file ); + if ( next < 0 ) { + if ( file > options.files ) { + file--; + } + } + else { + file++; + } if ( options.outfile ) { - ok = 0; // Only convert one file + next = 0; // Only convert one file } } @@ -58,14 +73,6 @@ /******************************************************************************/ void -sig_handler ( int sig ) { - if ( SIGINT == sig ) { - options.skip_next = 1; - } - } - -/******************************************************************************/ -void err_exit ( char * msg ) { fprintf(stderr, "FATAL ERROR: %s\n", msg ? msg : "Unknown error" ); exit( EXIT_FAILURE ); @@ -81,7 +88,6 @@ options.device = NULL; options.list_devices = 0; options.files = NULL; - options.skip_next = 0; options.outfile = NULL; options.ao_endian = 1; options.ao_device_id = -1; @@ -89,11 +95,6 @@ options.ao_driver_info = NULL; memset( &options.ao_format, 0, sizeof(ao_sample_format) ); - struct sigaction sigact; - memset( &sigact, 0, sizeof(sigact) ); - sigact.sa_handler = sig_handler; - sigaction( SIGINT, &sigact, NULL ); - } /******************************************************************************/ @@ -318,13 +319,20 @@ int sound_play_file ( char *file ) { OggVorbis_File vf; - int ok = 1; + int next_file = 1; int err = ov_fopen( file, &vf ); if ( err ) { - fprintf( stderr, "Unable to open file: %d\n", err ); - ok = 0; - return ok; + if ( OV_ENOTVORBIS == err ) { + fprintf( stderr, "Not a Vorbis file\n" ); + } + else if ( OV_EVERSION == err ) { + fprintf( stderr, "Incompatible Vorbis version\n" ); + } + else { + fprintf( stderr, "Unable to open file: %d\n", err ); + } + return next_file; } sound_print_comments( &vf ); @@ -336,44 +344,101 @@ printf( "Decoded length: %ld samples\n", (long) ov_pcm_total( &vf, -1 ) ); } - char pcm[PCM_BUFFER_SIZE]; - int current_section; int done = 0; + int paused = 0; - while ( ! done && ! options.skip_next ) { - long bytes_read = ov_read( &vf, pcm, sizeof(pcm), options.ao_endian, 2, 1, ¤t_section ); + while ( ! done ) { - if ( 0 == bytes_read ) { - done = 1; - } - else if ( OV_HOLE == bytes_read ) { - if (options.verbose ) { - fprintf( stderr, "error: hole in data\n" ); + if ( ! paused ) { + if ( ! sound_play_section( &vf ) ) { + done = 1; } } - else if ( OV_EBADLINK == bytes_read ) { - if (options.verbose ) { - fprintf( stderr, "error: invalid stream section in data\n" ); + + char c; + int num_read = read( fileno( stdin ), &c, sizeof( char ) ); + if ( 1 == num_read ) { + switch (c) { + + case 'p' : + case 'P' : + paused = ~paused; + break; + + case 'q' : + case 'Q' : + done = 1; + next_file = 0; + break; + + case 'n' : + case 'N' : + done = 1; + next_file = 1; + break; + + case 'v' : + case 'V' : + done = 1; + next_file = -1; + break; + + case 'f' : + case 'F' : + done = sound_skip_ahead( &vf ); + break; + + case 'b' : + case 'B' : + done = sound_skip_back( &vf ); + break; + + default: + break; } + + } - else if ( OV_EINVAL == bytes_read ) { - fprintf( stderr, "error: Unable to read file headers.\n" ); - done = 1; - } - else { - // Play it! - if ( ! ao_play( options.ao_device, pcm, bytes_read ) ) { - done = 1; - ok = 0; - } - } - + } ov_clear( &vf ); - if ( options.skip_next ) { - options.skip_next = 0; + return next_file; + } + +/******************************************************************************/ +int +sound_play_section ( OggVorbis_File *vf ) { + static char pcm[PCM_BUFFER_SIZE]; + static int current_section; + + int ok = 1; + + long bytes_read = ov_read( vf, pcm, sizeof(pcm), options.ao_endian, 2, 1, ¤t_section ); + + if ( 0 == bytes_read ) { + ok = 0; + } + else if ( OV_HOLE == bytes_read ) { + if (options.verbose ) { + fprintf( stderr, "error: hole in data\n" ); + } + } + else if ( OV_EBADLINK == bytes_read ) { + if (options.verbose ) { + fprintf( stderr, "error: invalid stream section in data\n" ); + } + } + else if ( OV_EINVAL == bytes_read ) { + fprintf( stderr, "error: Unable to read file headers.\n" ); + ok = 0; + } + else { + // Play it! + if ( ! ao_play( options.ao_device, pcm, bytes_read ) ) { + ok = 0; + } } return ok; @@ -381,7 +446,7 @@ /******************************************************************************/ void -sound_print_comments ( OggVorbis_File *vf) { +sound_print_comments ( OggVorbis_File *vf ) { char **comments = ov_comment( vf, -1 )->user_comments; @@ -422,3 +487,51 @@ ao_shutdown(); } +/******************************************************************************/ +#define SKIP_TIME 1.0 +int +sound_skip_ahead ( OggVorbis_File *vf ) { + double total_time = ov_time_total( vf, -1 ); + double current_time = ov_time_tell( vf ); + double new_position = current_time + SKIP_TIME; + if ( total_time < new_position ) { + return 1; + } + return ov_time_seek( vf, new_position ); + } + +/******************************************************************************/ +int +sound_skip_back ( OggVorbis_File *vf ) { + double current_time = ov_time_tell( vf ); + double new_position = current_time - SKIP_TIME; + if ( new_position > 0.0 ) { + return ov_time_seek( vf, new_position ); + } + return ov_time_seek( vf, 0.0 ); + } + +/******************************************************************************/ +void +term_init ( void ) { + tcgetattr( fileno( stdin ), &termios_orig ); + + struct termios termios_new; + tcgetattr( fileno( stdin ), &termios_new ); + termios_new.c_lflag |= ICANON; + termios_new.c_lflag ^= ICANON; + termios_new.c_lflag |= ECHO; + termios_new.c_lflag ^= ECHO; + termios_new.c_cc[VMIN] = 0; + termios_new.c_cc[VTIME] = 0; + tcsetattr( fileno( stdin ), TCSANOW, &termios_new ); + + atexit( term_reset ); + + } + +/******************************************************************************/ +void +term_reset ( void ) { + tcsetattr( fileno( stdin ), TCSANOW, &termios_orig ); + } diff -r 03892700ff0d -r 3617357a1b90 playogg.h --- a/playogg.h Tue Jul 22 16:27:42 2014 -0500 +++ b/playogg.h Tue Aug 05 12:15:46 2014 -0500 @@ -13,8 +13,12 @@ int sound_list_devices ( void ); int sound_init ( void ); int sound_play_file ( char *file ); -void sound_print_comments ( OggVorbis_File *vf); +int sound_play_section ( OggVorbis_File *vf ); +void sound_print_comments ( OggVorbis_File *vf ); +int sound_skip_ahead ( OggVorbis_File *vf ); +int sound_skip_back ( OggVorbis_File *vf ); void sound_shutdown ( void ); - +void term_init ( void ); +void term_reset ( void ); #endif