home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / src / play.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-24  |  6.8 KB  |  333 lines

  1. /* play.c - play a sound file on the speaker
  2.  **
  3.  ** Copyright (C) 1989 by Jef Poskanzer.
  4.  **
  5.  ** Modified 24-May-91 by Jamie Zawinski (for Lucid Emacs.)
  6.  ** Modified 17-Dec-92 by Jamie Zawinski (largely rewritten for SunOS 4.1.3.)
  7.  **
  8.  ** Permission to use, copy, modify, and distribute this software and its
  9.  ** documentation for any purpose and without fee is hereby granted, provided
  10.  ** that the above copyright notice appear in all copies and that both that
  11.  ** copyright notice and this permission notice appear in supporting
  12.  ** documentation.  This software is provided "as is" without express or
  13.  ** implied warranty.
  14.  */
  15.  
  16. #if __STDC__
  17. #include <stdlib.h>
  18. #include <unistd.h>
  19. #endif
  20.  
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <sys/signal.h>
  24. #include <sys/fcntl.h>
  25. #include <sys/file.h>
  26.  
  27. #include <multimedia/libaudio.h>
  28. #include <multimedia/audio_device.h>
  29.  
  30. #if __STDC__                /* warning suppression */
  31. extern int audio__setplayhdr();
  32. extern int audio__setgain();
  33. extern int audio__flush();
  34. extern int audio_decode_filehdr();
  35. extern int audio_read_filehdr();
  36. extern int audio_cmp_hdr();
  37. extern int audio_enc_to_str();
  38. extern int audio_drain();
  39. extern void usleep();
  40. #endif
  41.  
  42.  
  43. #ifdef emacs
  44. extern char *sys_errlist[];
  45. extern int errno, sys_nerr;
  46. extern void message ();
  47. # define perror(string) \
  48.     message("audio: %s, %s ", string, \
  49.         (errno < sys_nerr) ? sys_errlist[errno] : \
  50.         "unknown")
  51. # define warn(str) message ("audio: %s ", (str))
  52. #else /* !emacs */
  53. # define warn(str) fprintf (stderr, "%s\n", (str))
  54. #endif /* emacs */
  55.  
  56. static void (*sighup_handler) ();
  57. static void (*sigint_handler) ();
  58. static void sighandler ();
  59.  
  60. static int audio_fd;
  61.  
  62. #define audio_open()    open ("/dev/audio", (O_WRONLY | O_NDELAY))
  63.  
  64. static int reset_volume_p, reset_device_p;
  65. static double old_volume;
  66. static Audio_hdr dev_hdr;
  67.  
  68. static int
  69. init_device (volume, data, fd, header_length)
  70.      int volume;
  71.      unsigned char *data;
  72.      int fd;
  73.      int *header_length;
  74. {
  75. #ifdef SUNOS4_0_3
  76.   if (header_length) *header_length = 0;
  77.   return 0;
  78. #else
  79.   Audio_hdr file_hdr;
  80.   
  81.   reset_volume_p = 0;
  82.   reset_device_p = 0;
  83.  
  84.   if (data && fd) abort (); /* one or the other */
  85.  
  86.   if (AUDIO_SUCCESS != audio_get_play_config (audio_fd, &dev_hdr))
  87.     {
  88.       perror ("Not a valid audio device");
  89.       return 1;
  90.     }
  91.   
  92.   if (AUDIO_SUCCESS != (data
  93.             ? audio_decode_filehdr (data, &file_hdr, header_length)
  94.             : audio_read_filehdr (fd, &file_hdr, 0, 0)))
  95.     {
  96.       if (data)
  97.     perror ("invalid audio data");
  98.       else
  99.     perror ("invalid audio file");
  100.       return 1;
  101.     }
  102.   
  103.   audio_flush_play (audio_fd);
  104.  
  105.   if (0 != audio_cmp_hdr (&dev_hdr, &file_hdr))
  106.     {
  107.       Audio_hdr new_hdr;
  108.       new_hdr = file_hdr;
  109.       reset_device_p = 1;
  110.       if (AUDIO_SUCCESS != audio_set_play_config (audio_fd, &new_hdr))
  111.     {
  112.       char buf1 [100], buf2 [100], buf3 [250];
  113.       audio_enc_to_str (&file_hdr, buf1);
  114.       audio_enc_to_str (&new_hdr, buf2);
  115.       sprintf (buf3, "wanted %s, got %s", buf1, buf2);
  116.       warn (buf3);
  117.       return 1;
  118.     }
  119.     }
  120.  
  121.   if (volume < 0 || volume > 100)
  122.     {
  123.       char buf [255];
  124.       sprintf (buf, "volume must be between 0 and 100 (not %d)", volume);
  125.       warn (buf);
  126.       return 1;
  127.     }
  128.   {
  129.     /* set the volume; scale it to 0.0 - 1.0 */
  130.     double V = (volume / 100.0);
  131.     audio_get_play_gain (audio_fd, &old_volume);
  132.     reset_volume_p = 1;
  133.     audio_set_play_gain (audio_fd, &V);
  134.   }
  135.  
  136.   return 0;
  137. #endif
  138. }
  139.  
  140.  
  141. static void
  142. reset_device (wait_p)
  143.      int wait_p;
  144. {
  145.   if (wait_p)
  146.     audio_drain (audio_fd, 1);
  147.   else
  148.     audio_flush_play (audio_fd);
  149.   if (reset_device_p)
  150.     audio_set_play_config (audio_fd, &dev_hdr);
  151.   if (reset_volume_p)
  152.     audio_set_play_gain (audio_fd, &old_volume);
  153. }
  154.  
  155.  
  156. void
  157. play_sound_file (sound_file, volume)
  158.     char *sound_file;
  159.     int volume;
  160. {
  161.   int rrtn, wrtn;
  162.   unsigned char buf [255];
  163.   int file_fd;
  164.   
  165.   audio_fd = audio_open ();
  166.  
  167.   if (audio_fd < 0)
  168.     {
  169.       perror ("open /dev/audio");
  170.       return;
  171.     }
  172.  
  173.   sighup_handler = signal (SIGHUP, sighandler);
  174.   sigint_handler = signal (SIGINT, sighandler);
  175.   
  176.   file_fd = open (sound_file, O_RDONLY);
  177.   if (file_fd < 0)
  178.     {
  179.       perror (sound_file);
  180.       goto END_OF_PLAY;
  181.     }
  182.  
  183.   if (init_device (volume, 0, file_fd, 0))
  184.     goto END_OF_PLAY;
  185.     
  186.   while (1)
  187.     {
  188.       rrtn = read (file_fd, (char *) buf, sizeof (buf));
  189.       if (rrtn < 0)
  190.     {
  191.       perror ("read");
  192.       goto END_OF_PLAY;
  193.     }
  194.       if (rrtn == 0)
  195.     break;
  196.     
  197.       while (1)
  198.     {
  199.       wrtn = write (audio_fd, (char *) buf, rrtn);
  200.       if (wrtn < 0)
  201.         {
  202.           perror ("write");
  203.           goto END_OF_PLAY;
  204.         }
  205.       if (wrtn != 0)
  206.         break;
  207.  
  208.       if (AUDIO_ERR_INTERRUPTED == audio_drain (audio_fd, 1))
  209.         goto END_OF_PLAY;
  210.     }
  211.       if (wrtn != rrtn)
  212.     {
  213.       char buf [255];
  214.       sprintf (buf, "play: rrtn = %d, wrtn = %d", rrtn, wrtn);
  215.       warn (buf);
  216.       goto END_OF_PLAY;
  217.     }
  218.     }
  219.   
  220.  END_OF_PLAY:
  221.  
  222.   if (file_fd > 0)
  223.     close (file_fd);
  224.  
  225.   if (audio_fd > 0)
  226.     {
  227.       reset_device (1);
  228.       close (audio_fd);
  229.     }
  230.  
  231.   (void) signal (SIGHUP, sighup_handler);
  232.   (void) signal (SIGINT, sigint_handler);
  233. }
  234.  
  235.  
  236. void
  237. play_sound_data (data, length, volume)
  238.      unsigned char *data;
  239.      int length, volume;
  240. {
  241.   int wrtn, start = 0;
  242.   int ilen;
  243.  
  244.   audio_fd = -1;
  245.  
  246.   if (length == 0) return;
  247.  
  248.   /* this is just to get a better error message */
  249.   if (strncmp (".snd\0", (char *) data, 4))
  250.     {
  251.       warn ("Not valid audio data (bad magic number)");
  252.       goto END_OF_PLAY;
  253.     }
  254.   if (length <= sizeof (Audio_hdr))
  255.     {
  256.       warn ("Not valid audio data (too short)");
  257.       goto END_OF_PLAY;
  258.     }
  259.  
  260.   audio_fd = audio_open ();
  261.   if (audio_fd < 0)
  262.     {
  263.       perror ("open /dev/audio");
  264.       return;
  265.     }
  266.  
  267.   sighup_handler = signal (SIGHUP, sighandler);
  268.   sigint_handler = signal (SIGINT, sighandler);
  269.     
  270.   if (init_device (volume, data, 0, &ilen))
  271.     goto END_OF_PLAY;
  272.       
  273.   data   += (ilen<<2);
  274.   length -= (ilen<<2);
  275.   if (length <= 1)
  276.     goto END_OF_PLAY;
  277.     
  278.   while (1)
  279.     {
  280.       wrtn = write (audio_fd, (char *) (data+start), length-start);
  281.       if (wrtn < 0)
  282.     {
  283.       perror ("write");
  284.       goto END_OF_PLAY;
  285.     }
  286.       if (wrtn != 0)
  287.     {
  288.       start += wrtn;
  289.       break;
  290.     }
  291.       if (AUDIO_ERR_INTERRUPTED == audio_drain (audio_fd, 1))
  292.     goto END_OF_PLAY;
  293.     }
  294.   if (wrtn != length)
  295.     {
  296.       char buf [255];
  297.       sprintf (buf, "play: rrtn = %d, wrtn = %d", length, wrtn);
  298.       warn (buf);
  299.       goto END_OF_PLAY;
  300.     }
  301.   
  302.  END_OF_PLAY:
  303.  
  304.   if (audio_fd > 0)
  305.     {
  306.       reset_device (1);
  307.       close (audio_fd);
  308.     }
  309.  
  310.   (void) signal (SIGHUP, sighup_handler);
  311.   (void) signal (SIGINT, sigint_handler);
  312. }
  313.  
  314.  
  315. static void
  316. sighandler (sig, code, scp, addr)
  317.      int sig, code;
  318.      struct sigcontext *scp;
  319.      char *addr;
  320. {
  321.   if (audio_fd > 0)
  322.     {
  323.       reset_device (0);
  324.       close (audio_fd);
  325.     }
  326.   if (sig == SIGHUP && sighup_handler)
  327.     sighup_handler (sig, code, scp, addr);
  328.   else if (sig == SIGINT && sigint_handler)
  329.     sigint_handler (sig, code, scp, addr);
  330.   else
  331.     exit (1);
  332. }
  333.