Mercurial > oggdemo
changeset 2:3617357a1b90
Added keyboard commands:
p play/pause
q quit
n next file
v previous file
f fast forward
b fast backward
author | Eris Caffee <discordia@eldalin.com> |
---|---|
date | Tue, 05 Aug 2014 12:15:46 -0500 |
parents | 03892700ff0d |
children | 4d73408a0b71 |
files | playogg.c playogg.h |
diffstat | 2 files changed, 171 insertions(+), 54 deletions(-) [+] |
line diff
1.1 --- a/playogg.c Tue Jul 22 16:27:42 2014 -0500 1.2 +++ b/playogg.c Tue Aug 05 12:15:46 2014 -0500 1.3 @@ -4,6 +4,8 @@ 1.4 1.5 #include <getopt.h> 1.6 #include <signal.h> 1.7 +#include <termios.h> 1.8 +#include <unistd.h> 1.9 1.10 #include <ao/ao.h> 1.11 #include <vorbis/vorbisfile.h> 1.12 @@ -17,7 +19,6 @@ 1.13 int list_devices; 1.14 char* device; 1.15 char **files; 1.16 - int skip_next; 1.17 char *outfile; 1.18 int ao_endian; 1.19 int ao_device_id; 1.20 @@ -26,12 +27,19 @@ 1.21 ao_sample_format ao_format; 1.22 } options; 1.23 1.24 + 1.25 + 1.26 +struct termios termios_orig; 1.27 + 1.28 +/******************************************************************************/ 1.29 int 1.30 main (int argc, char **argv ) { 1.31 1.32 init(); 1.33 parse_command_line( argc, argv ); 1.34 1.35 + term_init(); 1.36 + 1.37 if ( ! sound_init() ) { 1.38 exit( EXIT_FAILURE ); 1.39 } 1.40 @@ -41,15 +49,22 @@ 1.41 } 1.42 1.43 char **file = options.files; 1.44 - int ok = 1; 1.45 - while (ok && file && *file) { 1.46 + int next = 1; /* -1 play previous file, 0 stop playing, 1 play next file */ 1.47 + while (next && file && *file) { 1.48 if ( options.verbose ) { 1.49 printf( "Next file: %s\n", *file ); 1.50 } 1.51 - ok = sound_play_file( *file ); 1.52 - file++; 1.53 + next = sound_play_file( *file ); 1.54 + if ( next < 0 ) { 1.55 + if ( file > options.files ) { 1.56 + file--; 1.57 + } 1.58 + } 1.59 + else { 1.60 + file++; 1.61 + } 1.62 if ( options.outfile ) { 1.63 - ok = 0; // Only convert one file 1.64 + next = 0; // Only convert one file 1.65 } 1.66 } 1.67 1.68 @@ -58,14 +73,6 @@ 1.69 1.70 /******************************************************************************/ 1.71 void 1.72 -sig_handler ( int sig ) { 1.73 - if ( SIGINT == sig ) { 1.74 - options.skip_next = 1; 1.75 - } 1.76 - } 1.77 - 1.78 -/******************************************************************************/ 1.79 -void 1.80 err_exit ( char * msg ) { 1.81 fprintf(stderr, "FATAL ERROR: %s\n", msg ? msg : "Unknown error" ); 1.82 exit( EXIT_FAILURE ); 1.83 @@ -81,7 +88,6 @@ 1.84 options.device = NULL; 1.85 options.list_devices = 0; 1.86 options.files = NULL; 1.87 - options.skip_next = 0; 1.88 options.outfile = NULL; 1.89 options.ao_endian = 1; 1.90 options.ao_device_id = -1; 1.91 @@ -89,11 +95,6 @@ 1.92 options.ao_driver_info = NULL; 1.93 memset( &options.ao_format, 0, sizeof(ao_sample_format) ); 1.94 1.95 - struct sigaction sigact; 1.96 - memset( &sigact, 0, sizeof(sigact) ); 1.97 - sigact.sa_handler = sig_handler; 1.98 - sigaction( SIGINT, &sigact, NULL ); 1.99 - 1.100 } 1.101 1.102 /******************************************************************************/ 1.103 @@ -318,13 +319,20 @@ 1.104 int 1.105 sound_play_file ( char *file ) { 1.106 OggVorbis_File vf; 1.107 - int ok = 1; 1.108 + int next_file = 1; 1.109 1.110 int err = ov_fopen( file, &vf ); 1.111 if ( err ) { 1.112 - fprintf( stderr, "Unable to open file: %d\n", err ); 1.113 - ok = 0; 1.114 - return ok; 1.115 + if ( OV_ENOTVORBIS == err ) { 1.116 + fprintf( stderr, "Not a Vorbis file\n" ); 1.117 + } 1.118 + else if ( OV_EVERSION == err ) { 1.119 + fprintf( stderr, "Incompatible Vorbis version\n" ); 1.120 + } 1.121 + else { 1.122 + fprintf( stderr, "Unable to open file: %d\n", err ); 1.123 + } 1.124 + return next_file; 1.125 } 1.126 1.127 sound_print_comments( &vf ); 1.128 @@ -336,44 +344,101 @@ 1.129 printf( "Decoded length: %ld samples\n", (long) ov_pcm_total( &vf, -1 ) ); 1.130 } 1.131 1.132 - char pcm[PCM_BUFFER_SIZE]; 1.133 - int current_section; 1.134 int done = 0; 1.135 + int paused = 0; 1.136 1.137 - while ( ! done && ! options.skip_next ) { 1.138 - long bytes_read = ov_read( &vf, pcm, sizeof(pcm), options.ao_endian, 2, 1, ¤t_section ); 1.139 + while ( ! done ) { 1.140 1.141 - if ( 0 == bytes_read ) { 1.142 - done = 1; 1.143 - } 1.144 - else if ( OV_HOLE == bytes_read ) { 1.145 - if (options.verbose ) { 1.146 - fprintf( stderr, "error: hole in data\n" ); 1.147 + if ( ! paused ) { 1.148 + if ( ! sound_play_section( &vf ) ) { 1.149 + done = 1; 1.150 } 1.151 } 1.152 - else if ( OV_EBADLINK == bytes_read ) { 1.153 - if (options.verbose ) { 1.154 - fprintf( stderr, "error: invalid stream section in data\n" ); 1.155 + 1.156 + char c; 1.157 + int num_read = read( fileno( stdin ), &c, sizeof( char ) ); 1.158 + if ( 1 == num_read ) { 1.159 + switch (c) { 1.160 + 1.161 + case 'p' : 1.162 + case 'P' : 1.163 + paused = ~paused; 1.164 + break; 1.165 + 1.166 + case 'q' : 1.167 + case 'Q' : 1.168 + done = 1; 1.169 + next_file = 0; 1.170 + break; 1.171 + 1.172 + case 'n' : 1.173 + case 'N' : 1.174 + done = 1; 1.175 + next_file = 1; 1.176 + break; 1.177 + 1.178 + case 'v' : 1.179 + case 'V' : 1.180 + done = 1; 1.181 + next_file = -1; 1.182 + break; 1.183 + 1.184 + case 'f' : 1.185 + case 'F' : 1.186 + done = sound_skip_ahead( &vf ); 1.187 + break; 1.188 + 1.189 + case 'b' : 1.190 + case 'B' : 1.191 + done = sound_skip_back( &vf ); 1.192 + break; 1.193 + 1.194 + default: 1.195 + break; 1.196 } 1.197 + 1.198 + 1.199 } 1.200 - else if ( OV_EINVAL == bytes_read ) { 1.201 - fprintf( stderr, "error: Unable to read file headers.\n" ); 1.202 - done = 1; 1.203 - } 1.204 - else { 1.205 - // Play it! 1.206 - if ( ! ao_play( options.ao_device, pcm, bytes_read ) ) { 1.207 - done = 1; 1.208 - ok = 0; 1.209 - } 1.210 - } 1.211 - 1.212 + 1.213 } 1.214 1.215 ov_clear( &vf ); 1.216 1.217 - if ( options.skip_next ) { 1.218 - options.skip_next = 0; 1.219 + return next_file; 1.220 + } 1.221 + 1.222 +/******************************************************************************/ 1.223 +int 1.224 +sound_play_section ( OggVorbis_File *vf ) { 1.225 + static char pcm[PCM_BUFFER_SIZE]; 1.226 + static int current_section; 1.227 + 1.228 + int ok = 1; 1.229 + 1.230 + long bytes_read = ov_read( vf, pcm, sizeof(pcm), options.ao_endian, 2, 1, ¤t_section ); 1.231 + 1.232 + if ( 0 == bytes_read ) { 1.233 + ok = 0; 1.234 + } 1.235 + else if ( OV_HOLE == bytes_read ) { 1.236 + if (options.verbose ) { 1.237 + fprintf( stderr, "error: hole in data\n" ); 1.238 + } 1.239 + } 1.240 + else if ( OV_EBADLINK == bytes_read ) { 1.241 + if (options.verbose ) { 1.242 + fprintf( stderr, "error: invalid stream section in data\n" ); 1.243 + } 1.244 + } 1.245 + else if ( OV_EINVAL == bytes_read ) { 1.246 + fprintf( stderr, "error: Unable to read file headers.\n" ); 1.247 + ok = 0; 1.248 + } 1.249 + else { 1.250 + // Play it! 1.251 + if ( ! ao_play( options.ao_device, pcm, bytes_read ) ) { 1.252 + ok = 0; 1.253 + } 1.254 } 1.255 1.256 return ok; 1.257 @@ -381,7 +446,7 @@ 1.258 1.259 /******************************************************************************/ 1.260 void 1.261 -sound_print_comments ( OggVorbis_File *vf) { 1.262 +sound_print_comments ( OggVorbis_File *vf ) { 1.263 1.264 char **comments = ov_comment( vf, -1 )->user_comments; 1.265 1.266 @@ -422,3 +487,51 @@ 1.267 ao_shutdown(); 1.268 } 1.269 1.270 +/******************************************************************************/ 1.271 +#define SKIP_TIME 1.0 1.272 +int 1.273 +sound_skip_ahead ( OggVorbis_File *vf ) { 1.274 + double total_time = ov_time_total( vf, -1 ); 1.275 + double current_time = ov_time_tell( vf ); 1.276 + double new_position = current_time + SKIP_TIME; 1.277 + if ( total_time < new_position ) { 1.278 + return 1; 1.279 + } 1.280 + return ov_time_seek( vf, new_position ); 1.281 + } 1.282 + 1.283 +/******************************************************************************/ 1.284 +int 1.285 +sound_skip_back ( OggVorbis_File *vf ) { 1.286 + double current_time = ov_time_tell( vf ); 1.287 + double new_position = current_time - SKIP_TIME; 1.288 + if ( new_position > 0.0 ) { 1.289 + return ov_time_seek( vf, new_position ); 1.290 + } 1.291 + return ov_time_seek( vf, 0.0 ); 1.292 + } 1.293 + 1.294 +/******************************************************************************/ 1.295 +void 1.296 +term_init ( void ) { 1.297 + tcgetattr( fileno( stdin ), &termios_orig ); 1.298 + 1.299 + struct termios termios_new; 1.300 + tcgetattr( fileno( stdin ), &termios_new ); 1.301 + termios_new.c_lflag |= ICANON; 1.302 + termios_new.c_lflag ^= ICANON; 1.303 + termios_new.c_lflag |= ECHO; 1.304 + termios_new.c_lflag ^= ECHO; 1.305 + termios_new.c_cc[VMIN] = 0; 1.306 + termios_new.c_cc[VTIME] = 0; 1.307 + tcsetattr( fileno( stdin ), TCSANOW, &termios_new ); 1.308 + 1.309 + atexit( term_reset ); 1.310 + 1.311 + } 1.312 + 1.313 +/******************************************************************************/ 1.314 +void 1.315 +term_reset ( void ) { 1.316 + tcsetattr( fileno( stdin ), TCSANOW, &termios_orig ); 1.317 + }
2.1 --- a/playogg.h Tue Jul 22 16:27:42 2014 -0500 2.2 +++ b/playogg.h Tue Aug 05 12:15:46 2014 -0500 2.3 @@ -13,8 +13,12 @@ 2.4 int sound_list_devices ( void ); 2.5 int sound_init ( void ); 2.6 int sound_play_file ( char *file ); 2.7 -void sound_print_comments ( OggVorbis_File *vf); 2.8 +int sound_play_section ( OggVorbis_File *vf ); 2.9 +void sound_print_comments ( OggVorbis_File *vf ); 2.10 +int sound_skip_ahead ( OggVorbis_File *vf ); 2.11 +int sound_skip_back ( OggVorbis_File *vf ); 2.12 void sound_shutdown ( void ); 2.13 - 2.14 +void term_init ( void ); 2.15 +void term_reset ( void ); 2.16 2.17 #endif