Mercurial > SDL_sound_CoreAudio
comparison playsound/playsound.c @ 383:818f9af97a19
Cleanups, FIXME removals, and better command line handling.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 05 Jul 2002 20:05:03 +0000 |
parents | cbb15ecf423a |
children | 3bd96d2d553c |
comparison
equal
deleted
inserted
replaced
382:ce998ee6194f | 383:818f9af97a19 |
---|---|
55 #define DEFAULT_AUDIOBUF 4096 | 55 #define DEFAULT_AUDIOBUF 4096 |
56 | 56 |
57 #define PLAYSOUND_VER_MAJOR 0 | 57 #define PLAYSOUND_VER_MAJOR 0 |
58 #define PLAYSOUND_VER_MINOR 1 | 58 #define PLAYSOUND_VER_MINOR 1 |
59 #define PLAYSOUND_VER_PATCH 5 | 59 #define PLAYSOUND_VER_PATCH 5 |
60 | |
61 | |
62 static const char *option_list[] = | |
63 { | |
64 "--rate", "n Playback at sample rate of n HZ.", | |
65 "--format", "fmt Playback in fmt format (see below).", | |
66 "--channels", "n Playback on n channels (1 or 2).", | |
67 "--decodebuf", "n Buffer n decoded bytes at a time (default 16384).", | |
68 "--audiobuf", "n Buffer n samples to audio device (default 4096).", | |
69 "--volume", "n Playback volume multiplier (default 1.0).", | |
70 "--stdin", "[ext] Read from stdin (treat data as format [ext])", | |
71 "--version", " Display version information and exit.", | |
72 "--decoders", " List supported data formats and exit.", | |
73 "--predecode", " Decode entire sample before playback.", | |
74 "--loop", "n Loop playback n times.", | |
75 "--seek", "list List of seek points and playback durations.", | |
76 "--credits", " Shameless promotion.", | |
77 "--help", " Display this information and exit.", | |
78 NULL, NULL | |
79 }; | |
80 | |
60 | 81 |
61 static void output_versions(const char *argv0) | 82 static void output_versions(const char *argv0) |
62 { | 83 { |
63 Sound_Version compiled; | 84 Sound_Version compiled; |
64 Sound_Version linked; | 85 Sound_Version linked; |
118 } /* output_decoders */ | 139 } /* output_decoders */ |
119 | 140 |
120 | 141 |
121 static void output_usage(const char *argv0) | 142 static void output_usage(const char *argv0) |
122 { | 143 { |
144 const char **i = option_list; | |
145 | |
123 fprintf(stderr, | 146 fprintf(stderr, |
124 "USAGE: %s [...options...] [soundFile1] ... [soundFileN]\n" | 147 "USAGE: %s [...options...] [soundFile1] ... [soundFileN]\n" |
125 "\n" | 148 "\n" |
126 " Options:\n" | 149 " Options:\n", |
127 " --rate n Playback at sample rate of n HZ.\n" | 150 argv0); |
128 " --format fmt Playback in fmt format (see below).\n" | 151 |
129 " --channels n Playback on n channels (1 or 2).\n" | 152 while (*i != NULL) |
130 " --decodebuf n Buffer n decoded bytes at a time (default %d).\n" | 153 { |
131 " --audiobuf n Buffer n samples to audio device (default %d).\n" | 154 const char *option = *(i++); |
132 " --volume n Playback volume multiplier (default 1.0).\n" | 155 const char *optiondesc = *(i++); |
133 " --stdin [ext] Read from stdin (treat data as format [ext])\n" | 156 fprintf(stderr, " %s %s\n", option, optiondesc); |
134 " --version Display version information and exit.\n" | 157 } /* while */ |
135 " --decoders List supported data formats and exit.\n" | 158 |
136 " --predecode Decode entire sample before playback.\n" | 159 fprintf(stderr, |
137 " --loop n Loop playback n times.\n" | |
138 " --seek list List of seek points and playback durations.\n" | |
139 " --credits Shameless promotion.\n" | |
140 " --help Display this information and exit.\n" | |
141 "\n" | 160 "\n" |
142 " Valid arguments to the --format option are:\n" | 161 " Valid arguments to the --format option are:\n" |
143 " U8 Unsigned 8-bit.\n" | 162 " U8 Unsigned 8-bit.\n" |
144 " S8 Signed 8-bit.\n" | 163 " S8 Signed 8-bit.\n" |
145 " U16LSB Unsigned 16-bit (least significant byte first).\n" | 164 " U16LSB Unsigned 16-bit (least significant byte first).\n" |
155 " The third mm:SS:ss is another seek after the duration of\n" | 174 " The third mm:SS:ss is another seek after the duration of\n" |
156 " playback has completed. If the final playback duration is\n" | 175 " playback has completed. If the final playback duration is\n" |
157 " omitted, playback continues until the end of the file.\n" | 176 " omitted, playback continues until the end of the file.\n" |
158 " The \"mm\" and \"SS\" portions may be omitted. --loop\n" | 177 " The \"mm\" and \"SS\" portions may be omitted. --loop\n" |
159 " and --seek can coexist.\n" | 178 " and --seek can coexist.\n" |
160 "\n", | 179 "\n"); |
161 argv0, DEFAULT_DECODEBUF, DEFAULT_AUDIOBUF); | |
162 } /* output_usage */ | 180 } /* output_usage */ |
163 | 181 |
164 | 182 |
165 static void output_credits(void) | 183 static void output_credits(void) |
166 { | 184 { |
313 } /* sigint_catcher */ | 331 } /* sigint_catcher */ |
314 #endif | 332 #endif |
315 | 333 |
316 | 334 |
317 /* global decoding state. */ | 335 /* global decoding state. */ |
318 /* !!! FIXME: Put this in a struct and pass a pointer to it as the | 336 typedef struct |
319 * !!! FIXME: audio callback's argument. This will clean up the | 337 { |
320 * !!! FIXME: namespace and let me reinitialize this for each file in | 338 Uint8 *decoded_ptr; |
321 * !!! FIXME: a cleaner way. | 339 Uint32 decoded_bytes; |
322 */ | 340 int predecode; |
323 static volatile Uint8 *decoded_ptr = NULL; | 341 int looping; |
324 static volatile Uint32 decoded_bytes = 0; | 342 int wants_volume_change; |
325 static volatile int predecode = 0; | 343 float volume; |
326 static volatile int looping = 0; | 344 Uint32 total_seeks; |
327 static volatile int wants_volume_change = 0; | 345 Uint32 *seek_list; |
328 static volatile float volume = 1.0; | 346 Uint32 seek_index; |
329 static volatile Uint32 total_seeks = 0; | 347 Sint32 bytes_before_next_seek; |
330 static volatile Uint32 *seek_list = NULL; | 348 } playsound_global_state; |
331 static volatile Uint32 seek_index = 0; | 349 |
332 static volatile Sint32 bytes_before_next_seek = -1; | 350 static volatile playsound_global_state global_state; |
351 | |
333 | 352 |
334 static Uint32 cvtMsToBytePos(Sound_AudioInfo *info, Uint32 ms) | 353 static Uint32 cvtMsToBytePos(Sound_AudioInfo *info, Uint32 ms) |
335 { | 354 { |
336 /* "frames" == "sample frames" */ | 355 /* "frames" == "sample frames" */ |
337 float frames_per_ms = ((float) info->rate) / 1000.0; | 356 float frames_per_ms = ((float) info->rate) / 1000.0; |
341 } /* cvtMsToBytePos */ | 360 } /* cvtMsToBytePos */ |
342 | 361 |
343 | 362 |
344 static void do_seek(Sound_Sample *sample) | 363 static void do_seek(Sound_Sample *sample) |
345 { | 364 { |
365 Uint32 *seek_list = global_state.seek_list; | |
366 Uint32 seek_index = global_state.seek_index; | |
367 Uint32 total_seeks = global_state.total_seeks; | |
368 | |
346 fprintf(stdout, "Seeking to %.2d:%.2d:%.4d...\n", | 369 fprintf(stdout, "Seeking to %.2d:%.2d:%.4d...\n", |
347 (int) ((seek_list[seek_index] / 1000) / 60), | 370 (int) ((seek_list[seek_index] / 1000) / 60), |
348 (int) ((seek_list[seek_index] / 1000) % 60), | 371 (int) ((seek_list[seek_index] / 1000) % 60), |
349 (int) ((seek_list[seek_index] % 1000))); | 372 (int) ((seek_list[seek_index] % 1000))); |
350 | 373 |
351 if (predecode) | 374 if (global_state.predecode) |
352 { | 375 { |
353 Uint32 pos = cvtMsToBytePos(&sample->desired, seek_list[seek_index]); | 376 Uint32 pos = cvtMsToBytePos(&sample->desired, seek_list[seek_index]); |
354 if (pos > sample->buffer_size) | 377 if (pos > sample->buffer_size) |
355 { | 378 { |
356 fprintf(stderr, "Seek past end of predecoded buffer.\n"); | 379 fprintf(stderr, "Seek past end of predecoded buffer.\n"); |
357 done_flag = 1; | 380 done_flag = 1; |
358 } /* if */ | 381 } /* if */ |
359 else | 382 else |
360 { | 383 { |
361 decoded_ptr = (((Uint8 *) sample->buffer) + pos); | 384 global_state.decoded_ptr = (((Uint8 *) sample->buffer) + pos); |
362 decoded_bytes = sample->buffer_size - pos; | 385 global_state.decoded_bytes = sample->buffer_size - pos; |
363 } /* else */ | 386 } /* else */ |
364 } /* if */ | 387 } /* if */ |
365 else | 388 else |
366 { | 389 { |
367 if (!Sound_Seek(sample, seek_list[seek_index])) | 390 if (!Sound_Seek(sample, seek_list[seek_index])) |
371 } /* if */ | 394 } /* if */ |
372 } /* else */ | 395 } /* else */ |
373 | 396 |
374 seek_index++; | 397 seek_index++; |
375 if (seek_index >= total_seeks) | 398 if (seek_index >= total_seeks) |
376 bytes_before_next_seek = -1; /* no more seeks. */ | 399 global_state.bytes_before_next_seek = -1; /* no more seeks. */ |
377 else | 400 else |
378 { | 401 { |
379 bytes_before_next_seek = cvtMsToBytePos(&sample->desired, | 402 global_state.bytes_before_next_seek = cvtMsToBytePos(&sample->desired, |
380 seek_list[seek_index]); | 403 seek_list[seek_index]); |
381 seek_index++; | 404 seek_index++; |
382 } /* else */ | 405 } /* else */ |
406 | |
407 global_state.seek_index = seek_index; | |
383 } /* do_seek */ | 408 } /* do_seek */ |
384 | 409 |
385 | 410 |
386 /* | 411 /* |
387 * This updates (decoded_bytes) and (decoded_ptr) with more audio data, | 412 * This updates (decoded_bytes) and (decoded_ptr) with more audio data, |
389 */ | 414 */ |
390 static int read_more_data(Sound_Sample *sample) | 415 static int read_more_data(Sound_Sample *sample) |
391 { | 416 { |
392 if (done_flag) /* probably a sigint; stop trying to read. */ | 417 if (done_flag) /* probably a sigint; stop trying to read. */ |
393 { | 418 { |
394 decoded_bytes = 0; | 419 global_state.decoded_bytes = 0; |
395 return(0); | 420 return(0); |
396 } /* if */ | 421 } /* if */ |
397 | 422 |
398 if ((bytes_before_next_seek >= 0) && | 423 if ((global_state.bytes_before_next_seek >= 0) && |
399 (decoded_bytes > bytes_before_next_seek)) | 424 (global_state.decoded_bytes > global_state.bytes_before_next_seek)) |
400 { | 425 { |
401 decoded_bytes = bytes_before_next_seek; | 426 global_state.decoded_bytes = global_state.bytes_before_next_seek; |
402 } /* if */ | 427 } /* if */ |
403 | 428 |
404 if (decoded_bytes > 0) /* don't need more data; just return. */ | 429 if (global_state.decoded_bytes > 0) /* don't need more data; just return. */ |
405 return(decoded_bytes); | 430 return(global_state.decoded_bytes); |
406 | 431 |
407 /* Need more audio data. See if we're supposed to seek... */ | 432 /* Need more audio data. See if we're supposed to seek... */ |
408 if ((bytes_before_next_seek == 0) && (seek_index < total_seeks)) | 433 if ((global_state.bytes_before_next_seek == 0) && |
434 (global_state.seek_index < global_state.total_seeks)) | |
409 { | 435 { |
410 do_seek(sample); /* do it, baby! */ | 436 do_seek(sample); /* do it, baby! */ |
411 return(read_more_data(sample)); /* handle loops conditions. */ | 437 return(read_more_data(sample)); /* handle loops conditions. */ |
412 } /* if */ | 438 } /* if */ |
413 | 439 |
414 /* See if there's more to be read... */ | 440 /* See if there's more to be read... */ |
415 if ( (bytes_before_next_seek != 0) && | 441 if ( (global_state.bytes_before_next_seek != 0) && |
416 (!(sample->flags & (SOUND_SAMPLEFLAG_ERROR | SOUND_SAMPLEFLAG_EOF))) ) | 442 (!(sample->flags & (SOUND_SAMPLEFLAG_ERROR | SOUND_SAMPLEFLAG_EOF))) ) |
417 { | 443 { |
418 decoded_bytes = Sound_Decode(sample); | 444 global_state.decoded_bytes = Sound_Decode(sample); |
419 if (sample->flags & SOUND_SAMPLEFLAG_ERROR) | 445 if (sample->flags & SOUND_SAMPLEFLAG_ERROR) |
420 { | 446 { |
421 fprintf(stderr, "Error in decoding sound file!\n" | 447 fprintf(stderr, "Error in decoding sound file!\n" |
422 " reason: [%s].\n", Sound_GetError()); | 448 " reason: [%s].\n", Sound_GetError()); |
423 } /* if */ | 449 } /* if */ |
424 | 450 |
425 decoded_ptr = sample->buffer; | 451 global_state.decoded_ptr = sample->buffer; |
426 return(read_more_data(sample)); /* handle loops conditions. */ | 452 return(read_more_data(sample)); /* handle loops conditions. */ |
427 } /* if */ | 453 } /* if */ |
428 | 454 |
429 /* No more to be read from stream, but we may want to loop the sample. */ | 455 /* No more to be read from stream, but we may want to loop the sample. */ |
430 | 456 |
431 if (!looping) | 457 if (!global_state.looping) |
432 return(0); | 458 return(0); |
433 | 459 |
434 looping--; | 460 global_state.looping--; |
435 | 461 |
436 seek_index = 0; | 462 global_state.seek_index = 0; |
437 bytes_before_next_seek = (total_seeks > 0) ? 0 : -1; | 463 global_state.bytes_before_next_seek = |
464 (global_state.total_seeks > 0) ? 0 : -1; | |
438 | 465 |
439 /* we just need to point predecoded samples to the start of the buffer. */ | 466 /* we just need to point predecoded samples to the start of the buffer. */ |
440 if (predecode) | 467 if (global_state.predecode) |
441 { | 468 { |
442 decoded_bytes = sample->buffer_size; | 469 global_state.decoded_bytes = sample->buffer_size; |
443 decoded_ptr = sample->buffer; | 470 global_state.decoded_ptr = sample->buffer; |
444 } /* if */ | 471 } /* if */ |
445 else | 472 else |
446 { | 473 { |
447 Sound_Rewind(sample); /* error is checked in recursion. */ | 474 Sound_Rewind(sample); /* error is checked in recursion. */ |
448 } /* else */ | 475 } /* else */ |
457 int i; | 484 int i; |
458 Uint16 *u16src = NULL; | 485 Uint16 *u16src = NULL; |
459 Uint16 *u16dst = NULL; | 486 Uint16 *u16dst = NULL; |
460 Sint16 *s16src = NULL; | 487 Sint16 *s16src = NULL; |
461 Sint16 *s16dst = NULL; | 488 Sint16 *s16dst = NULL; |
462 | 489 float volume = global_state.volume; |
463 if (!wants_volume_change) | 490 |
491 if (!global_state.wants_volume_change) | |
464 { | 492 { |
465 memcpy(dst, src, len); | 493 memcpy(dst, src, len); |
466 return; | 494 return; |
467 } | 495 } /* if */ |
468 | 496 |
469 /* !!! FIXME: This would be more efficient with a lookup table. */ | 497 /* !!! FIXME: This would be more efficient with a lookup table. */ |
470 switch (sample->desired.format) | 498 switch (sample->desired.format) |
471 { | 499 { |
472 case AUDIO_U8: | 500 case AUDIO_U8: |
484 u16dst = (Uint16 *) dst; | 512 u16dst = (Uint16 *) dst; |
485 for (i = 0; i < len; i += sizeof (Uint16), u16src++, u16dst++) | 513 for (i = 0; i < len; i += sizeof (Uint16), u16src++, u16dst++) |
486 { | 514 { |
487 *u16dst = (Uint16) (((float) (SDL_SwapLE16(*u16src))) * volume); | 515 *u16dst = (Uint16) (((float) (SDL_SwapLE16(*u16src))) * volume); |
488 *u16dst = SDL_SwapLE16(*u16dst); | 516 *u16dst = SDL_SwapLE16(*u16dst); |
489 } | 517 } /* for */ |
490 break; | 518 break; |
491 | 519 |
492 case AUDIO_S16LSB: | 520 case AUDIO_S16LSB: |
493 s16src = (Sint16 *) src; | 521 s16src = (Sint16 *) src; |
494 s16dst = (Sint16 *) dst; | 522 s16dst = (Sint16 *) dst; |
495 for (i = 0; i < len; i += sizeof (Sint16), s16src++, s16dst++) | 523 for (i = 0; i < len; i += sizeof (Sint16), s16src++, s16dst++) |
496 { | 524 { |
497 *s16dst = (Sint16) (((float) (SDL_SwapLE16(*s16src))) * volume); | 525 *s16dst = (Sint16) (((float) (SDL_SwapLE16(*s16src))) * volume); |
498 *s16dst = SDL_SwapLE16(*s16dst); | 526 *s16dst = SDL_SwapLE16(*s16dst); |
499 } | 527 } /* for */ |
500 break; | 528 break; |
501 | 529 |
502 case AUDIO_U16MSB: | 530 case AUDIO_U16MSB: |
503 u16src = (Uint16 *) src; | 531 u16src = (Uint16 *) src; |
504 u16dst = (Uint16 *) dst; | 532 u16dst = (Uint16 *) dst; |
505 for (i = 0; i < len; i += sizeof (Uint16), u16src++, u16dst++) | 533 for (i = 0; i < len; i += sizeof (Uint16), u16src++, u16dst++) |
506 { | 534 { |
507 *u16dst = (Uint16) (((float) (SDL_SwapBE16(*u16src))) * volume); | 535 *u16dst = (Uint16) (((float) (SDL_SwapBE16(*u16src))) * volume); |
508 *u16dst = SDL_SwapBE16(*u16dst); | 536 *u16dst = SDL_SwapBE16(*u16dst); |
509 } | 537 } /* for */ |
510 break; | 538 break; |
511 | 539 |
512 case AUDIO_S16MSB: | 540 case AUDIO_S16MSB: |
513 s16src = (Sint16 *) src; | 541 s16src = (Sint16 *) src; |
514 s16dst = (Sint16 *) dst; | 542 s16dst = (Sint16 *) dst; |
515 for (i = 0; i < len; i += sizeof (Sint16), s16src++, s16dst++) | 543 for (i = 0; i < len; i += sizeof (Sint16), s16src++, s16dst++) |
516 { | 544 { |
517 *s16dst = (Sint16) (((float) (SDL_SwapBE16(*s16src))) * volume); | 545 *s16dst = (Sint16) (((float) (SDL_SwapBE16(*s16src))) * volume); |
518 *s16dst = SDL_SwapBE16(*s16dst); | 546 *s16dst = SDL_SwapBE16(*s16dst); |
519 } | 547 } /* for */ |
520 break; | 548 break; |
521 } | 549 } /* switch */ |
522 } | 550 } /* memcpy_with_volume */ |
523 | 551 |
524 | 552 |
525 static void audio_callback(void *userdata, Uint8 *stream, int len) | 553 static void audio_callback(void *userdata, Uint8 *stream, int len) |
526 { | 554 { |
527 Sound_Sample *sample = (Sound_Sample *) userdata; | 555 Sound_Sample *sample = (Sound_Sample *) userdata; |
540 } /* if */ | 568 } /* if */ |
541 | 569 |
542 /* decoded_bytes and decoder_ptr are updated as necessary... */ | 570 /* decoded_bytes and decoder_ptr are updated as necessary... */ |
543 | 571 |
544 cpysize = len - bw; | 572 cpysize = len - bw; |
545 if (cpysize > decoded_bytes) | 573 if (cpysize > global_state.decoded_bytes) |
546 cpysize = decoded_bytes; | 574 cpysize = global_state.decoded_bytes; |
547 | 575 |
548 if (cpysize > 0) | 576 if (cpysize > 0) |
549 { | 577 { |
550 memcpy_with_volume(sample, stream + bw, | 578 memcpy_with_volume(sample, stream + bw, |
551 (Uint8 *) decoded_ptr, cpysize); | 579 (Uint8 *) global_state.decoded_ptr, |
580 cpysize); | |
581 | |
552 bw += cpysize; | 582 bw += cpysize; |
553 decoded_ptr += cpysize; | 583 global_state.decoded_ptr += cpysize; |
554 decoded_bytes -= cpysize; | 584 global_state.decoded_bytes -= cpysize; |
555 if (bytes_before_next_seek >= 0) | 585 if (global_state.bytes_before_next_seek >= 0) |
556 bytes_before_next_seek -= cpysize; | 586 global_state.bytes_before_next_seek -= cpysize; |
557 } /* if */ | 587 } /* if */ |
558 } /* while */ | 588 } /* while */ |
559 } /* audio_callback */ | 589 } /* audio_callback */ |
560 | 590 |
561 | 591 |
613 return; | 643 return; |
614 } /* if */ | 644 } /* if */ |
615 | 645 |
616 strcpy(list, _list); | 646 strcpy(list, _list); |
617 | 647 |
618 if (seek_list != NULL) | 648 if (global_state.seek_list != NULL) |
619 free((void *) seek_list); | 649 free((void *) global_state.seek_list); |
620 | 650 |
621 total_seeks = count_seek_list(list); | 651 global_state.total_seeks = count_seek_list(list); |
622 seek_list = (Uint32 *) malloc(total_seeks * sizeof (Uint32)); | 652 |
623 if (seek_list == NULL) | 653 global_state.seek_list = |
654 (Uint32 *) malloc(global_state.total_seeks * sizeof (Uint32)); | |
655 | |
656 if (global_state.seek_list == NULL) | |
624 { | 657 { |
625 fprintf(stderr, "malloc() failed. Skipping seek list.\n"); | 658 fprintf(stderr, "malloc() failed. Skipping seek list.\n"); |
626 total_seeks = 0; | 659 global_state.total_seeks = 0; |
627 return; | 660 return; |
628 } /* if */ | 661 } /* if */ |
629 | 662 |
630 for (i = 0; i < total_seeks; i++) | 663 for (i = 0; i < global_state.total_seeks; i++) |
631 { | 664 { |
632 char *ptr = strchr(list, ';'); | 665 char *ptr = strchr(list, ';'); |
633 if (ptr != NULL) | 666 if (ptr != NULL) |
634 *ptr = '\0'; | 667 *ptr = '\0'; |
635 seek_list[i] = parse_time_str(list); | 668 global_state.seek_list[i] = parse_time_str(list); |
636 list = ptr + 1; | 669 list = ptr + 1; |
637 } /* for */ | 670 } /* for */ |
671 | |
672 global_state.bytes_before_next_seek = 0; | |
638 | 673 |
639 free(save_list); | 674 free(save_list); |
640 } /* parse_seek_list */ | 675 } /* parse_seek_list */ |
641 | 676 |
642 | 677 |
656 return AUDIO_S16MSB; | 691 return AUDIO_S16MSB; |
657 return 0; | 692 return 0; |
658 } /* str_to_fmt */ | 693 } /* str_to_fmt */ |
659 | 694 |
660 | 695 |
696 static int valid_cmdline(int argc, char **argv) | |
697 { | |
698 int i; | |
699 | |
700 if (argc < 2) /* no command line? Show help text and quit. */ | |
701 { | |
702 output_usage(argv[0]); | |
703 return(0); | |
704 } /* if */ | |
705 | |
706 /* Make sure all command line options are valid. */ | |
707 for (i = 1; i < argc; i++) | |
708 { | |
709 const char **opts = option_list; | |
710 | |
711 if (strncmp(argv[i], "--", 2) != 0) /* not an option; skip it. */ | |
712 continue; | |
713 | |
714 while (*opts != NULL) | |
715 { | |
716 if (strcmp(argv[i], *(opts++)) == 0) | |
717 break; | |
718 | |
719 opts++; /* skip option description. */ | |
720 } /* else */ | |
721 | |
722 if (*opts == NULL) /* didn't find it in option_list... */ | |
723 { | |
724 fprintf(stderr, "unknown option: \"%s\"\n", argv[i]); | |
725 return(0); | |
726 } /* if */ | |
727 } /* for */ | |
728 | |
729 return(1); /* everything appears to be in order. */ | |
730 } /* valid_cmdline */ | |
731 | |
732 | |
661 int main(int argc, char **argv) | 733 int main(int argc, char **argv) |
662 { | 734 { |
663 Sound_AudioInfo sound_desired; | 735 Sound_AudioInfo sound_desired; |
664 Uint32 audio_buffersize = DEFAULT_AUDIOBUF; | |
665 Uint32 decode_buffersize = DEFAULT_DECODEBUF; | |
666 SDL_AudioSpec sdl_desired; | 736 SDL_AudioSpec sdl_desired; |
667 SDL_AudioSpec sdl_actual; | 737 SDL_AudioSpec sdl_actual; |
738 Uint32 audio_buffersize; | |
739 Uint32 decode_buffersize; | |
668 Sound_Sample *sample; | 740 Sound_Sample *sample; |
669 int use_specific_audiofmt = 0; | 741 int use_specific_audiofmt = 0; |
670 int i; | 742 int i; |
671 int delay; | 743 int delay; |
672 int new_sample = 1; | 744 int new_sample = 1; |
745 Uint32 sdl_init_flags = SDL_INIT_AUDIO; | |
746 | |
747 #if ENABLE_EVENTS | |
748 SDL_Surface *screen = NULL; | |
749 SDL_Event event; | |
750 | |
751 sdl_init_flags |= SDL_INIT_VIDEO; | |
752 #endif | |
673 | 753 |
674 #ifdef HAVE_SETBUF | 754 #ifdef HAVE_SETBUF |
675 setbuf(stdout, NULL); | 755 setbuf(stdout, NULL); |
676 setbuf(stderr, NULL); | 756 setbuf(stderr, NULL); |
677 #endif | 757 #endif |
678 | 758 |
679 if (argc < 2) | 759 if (!valid_cmdline(argc, argv)) |
680 { | |
681 output_usage(argv[0]); | |
682 return(42); | 760 return(42); |
683 } /* if */ | 761 |
684 | 762 /* Handle some command lines upfront. */ |
685 /* Check some command lines upfront. */ | |
686 for (i = 0; i < argc; i++) | 763 for (i = 0; i < argc; i++) |
687 { | 764 { |
688 if (strncmp(argv[i], "--", 2) != 0) | 765 if (strncmp(argv[i], "--", 2) != 0) |
689 continue; | 766 continue; |
690 | 767 |
718 | 795 |
719 output_decoders(); | 796 output_decoders(); |
720 Sound_Quit(); | 797 Sound_Quit(); |
721 return(0); | 798 return(0); |
722 } /* else if */ | 799 } /* else if */ |
723 | |
724 /* !!! FIXME: Verify other --arguments are valid. */ | |
725 #if 0 | |
726 else | |
727 { | |
728 fprintf(stderr, "unknown option: \"%s\"\n", argv[i]); | |
729 return(42); | |
730 } /* else */ | |
731 #endif | |
732 } /* for */ | 800 } /* for */ |
733 | 801 |
734 if (!init_archive(argv[0])) | 802 if (!init_archive(argv[0])) |
735 return(42); | 803 return(42); |
736 | 804 |
737 if (SDL_Init(SDL_INIT_AUDIO) == -1) | 805 if (SDL_Init(sdl_init_flags) == -1) |
738 { | 806 { |
739 fprintf(stderr, "SDL_Init(SDL_INIT_AUDIO) failed!\n" | 807 fprintf(stderr, "SDL_Init() failed!\n" |
740 " reason: [%s].\n", SDL_GetError()); | 808 " reason: [%s].\n", SDL_GetError()); |
741 return(42); | 809 return(42); |
742 } /* if */ | 810 } /* if */ |
743 | 811 |
744 if (!Sound_Init()) | 812 if (!Sound_Init()) |
751 | 819 |
752 #if HAVE_SIGNAL_H | 820 #if HAVE_SIGNAL_H |
753 signal(SIGINT, sigint_catcher); | 821 signal(SIGINT, sigint_catcher); |
754 #endif | 822 #endif |
755 | 823 |
824 #if ENABLE_EVENTS | |
825 screen = SDL_SetVideoMode(320, 240, 8, 0); | |
826 assert(screen != NULL); | |
827 #endif | |
828 | |
756 for (i = 1; i < argc; i++) | 829 for (i = 1; i < argc; i++) |
757 { | 830 { |
758 char *filename = NULL; | 831 char *filename = NULL; |
759 | 832 |
760 /* !!! FIXME: Go read gripe about all the global variables. */ | |
761 /* set variables back to defaults for next file... */ | 833 /* set variables back to defaults for next file... */ |
762 if (new_sample) | 834 if (new_sample) |
763 { | 835 { |
764 new_sample = 0; | 836 if (global_state.seek_list != NULL) |
765 memset(&sound_desired, '\0', sizeof (sound_desired)); | 837 free((void *) global_state.seek_list); |
766 done_flag = 0; | 838 |
767 decoded_ptr = NULL; | 839 memset((void *) &global_state, '\0', sizeof (global_state)); |
768 decoded_bytes = 0; | 840 global_state.volume = 1.0; |
769 predecode = 0; | 841 global_state.bytes_before_next_seek = -1; |
770 looping = 0; | |
771 audio_buffersize = DEFAULT_AUDIOBUF; | 842 audio_buffersize = DEFAULT_AUDIOBUF; |
772 decode_buffersize = DEFAULT_DECODEBUF; | 843 decode_buffersize = DEFAULT_DECODEBUF; |
773 sample = NULL; | |
774 use_specific_audiofmt = 0; | |
775 wants_volume_change = 0; | |
776 volume = 1.0; | |
777 if (seek_list != NULL) | |
778 { | |
779 free((void *) seek_list); | |
780 seek_list = NULL; | |
781 } /* if */ | |
782 total_seeks = 0; | |
783 seek_index = 0; | |
784 bytes_before_next_seek = -1; | |
785 } /* if */ | 844 } /* if */ |
786 | 845 |
787 if (strcmp(argv[i], "--rate") == 0 && argc > i + 1) | 846 if (strcmp(argv[i], "--rate") == 0 && argc > i + 1) |
788 { | 847 { |
789 use_specific_audiofmt = 1; | 848 use_specific_audiofmt = 1; |
830 decode_buffersize = atoi(argv[++i]); | 889 decode_buffersize = atoi(argv[++i]); |
831 } /* else if */ | 890 } /* else if */ |
832 | 891 |
833 else if (strcmp(argv[i], "--volume") == 0 && argc > i + 1) | 892 else if (strcmp(argv[i], "--volume") == 0 && argc > i + 1) |
834 { | 893 { |
835 volume = atof(argv[++i]); | 894 global_state.volume = atof(argv[++i]); |
836 if (volume != 1.0) | 895 if (global_state.volume != 1.0) |
837 wants_volume_change = 1; | 896 global_state.wants_volume_change = 1; |
838 } /* else if */ | 897 } /* else if */ |
839 | 898 |
840 else if (strcmp(argv[i], "--predecode") == 0) | 899 else if (strcmp(argv[i], "--predecode") == 0) |
841 { | 900 { |
842 predecode = 1; | 901 global_state.predecode = 1; |
843 } /* else if */ | 902 } /* else if */ |
844 | 903 |
845 else if (strcmp(argv[i], "--loop") == 0) | 904 else if (strcmp(argv[i], "--loop") == 0) |
846 { | 905 { |
847 looping = atoi(argv[++i]); | 906 global_state.looping = atoi(argv[++i]); |
848 } /* else if */ | 907 } /* else if */ |
849 | 908 |
850 else if (strcmp(argv[i], "--seek") == 0) | 909 else if (strcmp(argv[i], "--seek") == 0) |
851 { | 910 { |
852 parse_seek_list(argv[++i]); | 911 parse_seek_list(argv[++i]); |
866 decode_buffersize); | 925 decode_buffersize); |
867 } /* if */ | 926 } /* if */ |
868 | 927 |
869 else if (strncmp(argv[i], "--", 2) == 0) | 928 else if (strncmp(argv[i], "--", 2) == 0) |
870 { | 929 { |
871 /* ignore it. */ | 930 /* ignore it, since it was handled at startup. */ |
872 } /* else if */ | 931 } /* else if */ |
873 | 932 |
874 else | 933 else |
875 { | 934 { |
876 filename = argv[i]; | 935 filename = argv[i]; |
897 " reason: [%s].\n", | 956 " reason: [%s].\n", |
898 filename, Sound_GetError()); | 957 filename, Sound_GetError()); |
899 continue; | 958 continue; |
900 } /* if */ | 959 } /* if */ |
901 | 960 |
902 if (total_seeks > 0) | 961 if (global_state.total_seeks > 0) |
903 { | 962 { |
904 if ((!predecode) && (!(sample->flags & SOUND_SAMPLEFLAG_CANSEEK))) | 963 if ((!global_state.predecode) && |
964 (!(sample->flags & SOUND_SAMPLEFLAG_CANSEEK))) | |
905 { | 965 { |
906 fprintf(stderr, "Want seeks, but sample cannot handle it!\n"); | 966 fprintf(stderr, "Want seeks, but sample cannot handle it!\n"); |
907 Sound_FreeSample(sample); | 967 Sound_FreeSample(sample); |
908 close_archive(filename); | 968 close_archive(filename); |
909 continue; | 969 continue; |
910 } /* if */ | 970 } /* if */ |
911 | |
912 bytes_before_next_seek = 0; | |
913 } /* if */ | 971 } /* if */ |
914 | 972 |
915 /* | 973 /* |
916 * Unless explicitly specified, pick the format from the sound | 974 * Unless explicitly specified, pick the format from the sound |
917 * to be played. | 975 * to be played. |
942 return(42); | 1000 return(42); |
943 } /* if */ | 1001 } /* if */ |
944 | 1002 |
945 fprintf(stdout, "Now playing [%s]...\n", filename); | 1003 fprintf(stdout, "Now playing [%s]...\n", filename); |
946 | 1004 |
947 if (predecode) | 1005 if (global_state.predecode) |
948 { | 1006 { |
949 fprintf(stdout, " predecoding..."); | 1007 fprintf(stdout, " predecoding..."); |
950 decoded_bytes = Sound_DecodeAll(sample); | 1008 global_state.decoded_bytes = Sound_DecodeAll(sample); |
951 decoded_ptr = sample->buffer; | 1009 global_state.decoded_ptr = sample->buffer; |
952 if (sample->flags & SOUND_SAMPLEFLAG_ERROR) | 1010 if (sample->flags & SOUND_SAMPLEFLAG_ERROR) |
953 { | 1011 { |
954 fprintf(stderr, | 1012 fprintf(stderr, |
955 "Couldn't fully decode \"%s\"!\n" | 1013 "Couldn't fully decode \"%s\"!\n" |
956 " reason: [%s].\n" | 1014 " reason: [%s].\n" |
957 " (playing first %lu bytes of decoded data...)\n", | 1015 " (playing first %lu bytes of decoded data...)\n", |
958 filename, Sound_GetError(), decoded_bytes); | 1016 filename, Sound_GetError(), global_state.decoded_bytes); |
959 } /* if */ | 1017 } /* if */ |
960 else | 1018 else |
961 { | 1019 { |
962 fprintf(stdout, "done.\n"); | 1020 fprintf(stdout, "done.\n"); |
963 } /* else */ | 1021 } /* else */ |
964 } /* if */ | 1022 } /* if */ |
965 | 1023 |
966 SDL_PauseAudio(0); | 1024 SDL_PauseAudio(0); |
967 #if ENABLE_EVENTS | 1025 |
968 { | |
969 SDL_Surface *screen; | |
970 SDL_Event event; | |
971 | |
972 screen = SDL_SetVideoMode (320, 240, 8, 0); | |
973 | |
974 while (!done_flag) { | |
975 | |
976 SDL_Delay(1); | |
977 SDL_PollEvent (&event); | |
978 | |
979 if (event.type == SDL_KEYDOWN) { | |
980 | |
981 done_flag = 1; | |
982 break; | |
983 } | |
984 | |
985 } | |
986 } | |
987 #endif /* ENABLE_EVENTS */ | |
988 while (!done_flag) | 1026 while (!done_flag) |
989 { | 1027 { |
1028 #if ENABLE_EVENTS | |
1029 SDL_PollEvent(&event); | |
1030 if ((event.type == SDL_KEYDOWN) || (event.type == SDL_QUIT)) | |
1031 done_flag = 1; | |
1032 #endif | |
1033 | |
990 SDL_Delay(10); | 1034 SDL_Delay(10); |
991 } /* while */ | 1035 } /* while */ |
1036 | |
992 SDL_PauseAudio(1); | 1037 SDL_PauseAudio(1); |
993 | 1038 |
994 /* | 1039 /* |
995 * Sleep two buffers' worth of audio before closing, in order | 1040 * Sleep two buffers' worth of audio before closing, in order |
996 * to allow the playback to finish. This isn't always enough; | 1041 * to allow the playback to finish. This isn't always enough; |