home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / maplay-1.2 / obuffer.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-04  |  14.9 KB  |  640 lines

  1. /*
  2.  *  @(#) obuffer.cc 1.15, last edit: 6/23/94 13:04:36
  3.  *  @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
  4.  *  @(#) Berlin University of Technology
  5.  *
  6.  *  Idea and first implementation for u-law output with fast downsampling by
  7.  *  Jim Boucher (jboucher@flash.bu.edu)
  8.  *
  9.  *  LinuxObuffer class written by
  10.  *  Louis P. Kruger (lpkruger@phoenix.princeton.edu)
  11.  *
  12.  *  This program is free software; you can redistribute it and/or modify
  13.  *  it under the terms of the GNU General Public License as published by
  14.  *  the Free Software Foundation; either version 2 of the License, or
  15.  *  (at your option) any later version.
  16.  *
  17.  *  This program is distributed in the hope that it will be useful,
  18.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  *  GNU General Public License for more details.
  21.  *
  22.  *  You should have received a copy of the GNU General Public License
  23.  *  along with this program; if not, write to the Free Software
  24.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  */
  26.  
  27. /*
  28.  *  Changes from version 1.1 to 1.2:
  29.  *    - new LinuxObuffer class, which works with 16 bit soundcards
  30.  *      like Gravis Ultrasound, SoundBlaster 16 or Pro Audio Spectrum 16,
  31.  *      if attached to /dev/dsp
  32.  *    - ShortObuffer renamed to FileObuffer
  33.  *    - If ULAW is defined:
  34.  *      - SparcObuffer feeds mono u-law output to an amd device (u-law format).
  35.  *        The required downsampling to 8 kHz in done in the synthesis filter.
  36.  *      - FileObuffer creates u-law output at 8 kHz instead of 16 bit PCM samples.
  37.  *    - O_NDELAY flag is cleared now after a successful open syscall
  38.  *      on /dev/audio (caused problems under Solaris)
  39.  *    - options -us, -uh and -ul should work now
  40.  *    - FileObuffer can handle incomplete write syscalls now
  41.  */
  42.  
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <errno.h>
  47. #include <unistd.h>
  48. #include <fcntl.h>
  49. #include <sys/ioctl.h>
  50. #include <iostream.h>
  51. #include "obuffer.h"
  52. #include "header.h"
  53. #ifdef ULAW
  54. #include "ulaw.h"
  55. #endif
  56.  
  57.  
  58. #ifdef SunOS
  59. extern "C" int ioctl (int, int ...);        // Why...???
  60. #endif
  61.  
  62.  
  63. FileObuffer::FileObuffer (uint32 number_of_channels)
  64. {
  65. #ifdef DEBUG
  66.   if (!number_of_channels || number_of_channels > MAXCHANNELS)
  67.   {
  68.     cerr << "FileObuffer: number of channels has to be in [1, " <<  MAXCHANNELS << "] !\n";
  69.     exit (1);
  70.   }
  71. #endif
  72.  
  73. #ifdef ULAW
  74.   if (number_of_channels > 1)
  75.     cerr << "Are you sure you need stereo u-law output?\n";
  76. #endif
  77.   channels = number_of_channels;
  78.   for (int i = 0; i < number_of_channels; ++i)
  79.     bufferp[i] = buffer + i;
  80. }
  81.  
  82.  
  83. void FileObuffer::append (uint32 channel, int16 value)
  84. {
  85. #ifdef DEBUG
  86.   if (channel >= channels)
  87.   {
  88.     cerr << "illegal channelnumber in FileObuffer::append()!\n";
  89.     exit (1);
  90.   }
  91.   if (bufferp[channel] - buffer >= OBUFFERSIZE)
  92.   {
  93.     cerr << "FileObuffer: buffer overflow!\n";
  94.     exit (1);
  95.   }
  96. #endif
  97.  
  98. #ifdef ULAW
  99.   // convert 16-bit PCM sample to 8-bit ulaw:
  100.   *bufferp[channel] = linear2ulaw[value >> 3];
  101. #else
  102.   *bufferp[channel] = value;
  103. #endif
  104.   bufferp[channel] += channels;
  105. }
  106.  
  107.  
  108. void FileObuffer::write_buffer (int fd)
  109. {
  110.   int length = (int)((char *)bufferp[0] - (char *)buffer), writelength;
  111.  
  112.   if ((writelength = write (fd, (char *)buffer, length)) != length)
  113.   {
  114.     // buffer has not been written completely
  115.     if (writelength < 0)
  116.     {
  117.       perror ("write");
  118.       exit (1);
  119.     }
  120.     length -= writelength;
  121.     char *buffer_pos = (char *)buffer;
  122.     do
  123.     {
  124.       buffer_pos += writelength;
  125.       if ((writelength = write (fd, buffer_pos, length)) < 0)
  126.       {
  127.     perror ("write");
  128.     exit (1);
  129.       }
  130.     }
  131.     while (length -= writelength);
  132.   }
  133.  
  134.   for (int i = 0; i < channels; ++i)
  135.     bufferp[i] = buffer + i;
  136. }
  137.  
  138.  
  139.  
  140. #ifdef Indigo
  141. IndigoObuffer::IndigoObuffer (uint32 number_of_channels, Header *header)
  142. {
  143. #ifdef DEBUG
  144.   if (!number_of_channels || number_of_channels > MAXCHANNELS)
  145.   {
  146.     cerr << "IndigoObuffer: number of channels has to be in [1, " <<  MAXCHANNELS << "] !\n";
  147.     exit (1);
  148.   }
  149. #endif
  150.   channels = number_of_channels;
  151.   for (int i = 0; i < number_of_channels; ++i)
  152.     bufferp[i] = buffer + i;
  153.  
  154.   // open an audio port and configure it:
  155.   ALconfig config;
  156.   if (!(config = ALnewconfig ()))
  157.   {
  158.     cerr << "ALnewconfig failed!\n";
  159.     exit (1);
  160.   }
  161.   ALsetwidth (config, AL_SAMPLE_16);
  162.   if (channels == 1)
  163.     ALsetchannels (config, AL_MONO);
  164.   else
  165.     ALsetchannels (config, AL_STEREO);
  166.   if (!(port = ALopenport ("MPEG audio player", "w", config)))
  167.   {
  168.     cerr << "can't allocate an audio port!\n";
  169.     exit (1);
  170.   }
  171.  
  172.   // set sample rate:
  173.   long pvbuffer[2] = { AL_OUTPUT_RATE, 0 };
  174.   pvbuffer[1] = header->frequency ();
  175.   ALsetparams (AL_DEFAULT_DEVICE, pvbuffer, 2);
  176.   ALfreeconfig (config);
  177. }
  178.  
  179.  
  180. IndigoObuffer::~IndigoObuffer (void)
  181. {
  182.   while (ALgetfilled (port) > 0)
  183.     sleep (1);
  184.   ALcloseport (port);
  185. }
  186.  
  187.  
  188. void IndigoObuffer::append (uint32 channel, int16 value)
  189. {
  190. #ifdef DEBUG
  191.   if (channel >= channels)
  192.   {
  193.     cerr << "illegal channelnumber in IndigoObuffer::append()!\n";
  194.     exit (1);
  195.   }
  196.   if (bufferp[channel] - buffer >= OBUFFERSIZE)
  197.   {
  198.     cerr << "IndigoObuffer: buffer overflow!\n";
  199.     exit (1);
  200.   }
  201. #endif
  202.   *bufferp[channel] = value;
  203.   bufferp[channel] += channels;
  204. }
  205.  
  206.  
  207. void IndigoObuffer::write_buffer (int)
  208. {
  209.   ALwritesamps (port, buffer, (long)(bufferp[0] - buffer));
  210.   for (int i = 0; i < channels; ++i)
  211.     bufferp[i] = buffer + i;
  212. }
  213. #endif // Indigo
  214.  
  215.  
  216. #ifdef SPARC
  217. int SparcObuffer::audio_fd = -1;
  218.  
  219. #ifdef ULAW
  220. SparcObuffer::SparcObuffer (Header *header, bool use_speaker, bool use_headphone, bool use_line_out)
  221. #else
  222. SparcObuffer::SparcObuffer (uint32 number_of_channels, Header *header,
  223.                 bool use_speaker, bool use_headphone, bool use_line_out)
  224. #endif
  225. {
  226. #ifndef ULAW
  227. #ifdef DEBUG
  228.   if (!number_of_channels || number_of_channels > MAXCHANNELS)
  229.   {
  230.     cerr << "SparcObuffer: 0 < number of channels < " << MAXCHANNELS << "!\n";
  231.     exit (1);
  232.   }
  233. #endif
  234. #endif    // !ULAW
  235.  
  236.   if (audio_fd < 0)
  237.   {
  238.     cerr << "Internal error: SparcObuffer::audio_fd has to be initialized\n"
  239.         "by SparcObuffer::class_suitable()!\n";
  240.     exit (1);
  241.   }
  242.  
  243.   audio_info info;
  244.   AUDIO_INITINFO (&info);
  245. #ifdef SunOS4_1_3
  246.   info.output_muted = False;
  247. #endif
  248.   info.play.port = 0;
  249.   if (use_speaker)
  250.     info.play.port |= AUDIO_SPEAKER;
  251.   if (use_headphone)
  252.     info.play.port |= AUDIO_HEADPHONE;
  253. #ifdef SunOS4_1_3
  254.   if (use_line_out)
  255.     info.play.port |= AUDIO_LINE_OUT;
  256. #endif
  257.  
  258. #ifdef ULAW
  259.   bufferp = buffer;
  260.  
  261.   // configure the amd device:
  262.   info.play.encoding = AUDIO_ENCODING_ULAW;
  263.   info.play.precision = 8;
  264.   info.play.channels = 1;
  265.   info.play.sample_rate = 8000;
  266. #else
  267.   channels = number_of_channels;
  268.   for (int i = 0; i < number_of_channels; ++i)
  269.     bufferp[i] = buffer + i;
  270.  
  271.   // configure the dbri device:
  272.   info.play.encoding = AUDIO_ENCODING_LINEAR;
  273.   info.play.precision = 16;
  274.   info.play.channels = channels;
  275.   info.play.sample_rate = header->frequency ();
  276. #endif    // !ULAW
  277.  
  278.   if (ioctl (audio_fd, AUDIO_SETINFO, &info))
  279.   {
  280.     perror ("configuration of /dev/audio failed");
  281.     exit (1);
  282.   }
  283. }
  284.  
  285.  
  286. SparcObuffer::~SparcObuffer (void)
  287. {
  288.   ioctl (audio_fd, AUDIO_DRAIN, NULL);
  289.   close (audio_fd);
  290. }
  291.  
  292.  
  293. void SparcObuffer::append (uint32 channel, int16 value)
  294. {
  295. #ifdef ULAW
  296. #ifdef DEBUG
  297.   if (bufferp - buffer >= OBUFFERSIZE >> 1)
  298.   {
  299.     cerr << "SparcObuffer: buffer overflow!\n";
  300.     exit (1);
  301.   }
  302. #endif
  303.  
  304.   // convert 16-bit PCM sample to 8-bit ulaw:
  305.   *bufferp++ = linear2ulaw[value >> 3];
  306. #else
  307. #ifdef DEBUG
  308.   if (channel >= channels)
  309.   {
  310.     cerr << "illegal channelnumber in SparcObuffer::append()!\n";
  311.     exit (1);
  312.   }
  313.   if (bufferp[channel] - buffer >= OBUFFERSIZE)
  314.   {
  315.     cerr << "SparcObuffer: buffer overflow!\n";
  316.     exit (1);
  317.   }
  318. #endif
  319.  
  320.   *bufferp[channel] = value;
  321.   bufferp[channel] += channels;
  322. #endif    // !ULAW
  323. }
  324.  
  325.  
  326. void SparcObuffer::write_buffer (int)
  327. {
  328. #ifdef ULAW
  329.   int length = (int)((char *)bufferp - (char *)buffer);
  330. #else
  331.   int length = (int)((char *)*bufferp - (char *)buffer);
  332. #endif
  333.   if (write (audio_fd, (char *)buffer, length) != length)
  334.   {
  335.     perror ("write to /dev/audio failed");
  336.     exit (1);
  337.   }
  338. #ifdef ULAW
  339.   bufferp = buffer;
  340. #else
  341.   for (int i = 0; i < channels; ++i)
  342.     bufferp[i] = buffer + i;
  343. #endif
  344. }
  345.  
  346.  
  347. int SparcObuffer::open_audio_device (void)
  348. {
  349.   int fd;
  350.  
  351.   if ((fd = open ("/dev/audio", O_WRONLY | O_NDELAY, 0)) < 0)
  352.     if (errno == EBUSY)
  353.     {
  354.       cerr << "Sorry, the audio device is busy!\n";
  355.       exit (1);
  356.     }
  357.     else
  358.     {
  359.       perror ("can't open /dev/audio for writing");
  360.       exit (1);
  361.     }
  362.  
  363.   // turn NDELAY mode off:
  364.   int flags;
  365.   if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
  366.   {
  367.     perror ("fcntl F_GETFL on /dev/audio failed");
  368.     exit (1);
  369.   }
  370.   flags &= ~O_NDELAY;
  371.   if (fcntl (fd, F_SETFL, flags) < 0)
  372.   {
  373.     perror ("fcntl F_SETFL on /dev/audio failed");
  374.     exit (1);
  375.   }
  376.   return fd;
  377. }
  378.  
  379.  
  380. #ifdef Solaris
  381. void SparcObuffer::get_device_type (int fd, audio_device *devtype)
  382. {
  383.   if (ioctl (fd, AUDIO_GETDEV, devtype))
  384.   {
  385.     perror ("ioctl AUDIO_GETDEV on /dev/audio");
  386.     exit (1);
  387.   }
  388. }
  389. #else
  390. int SparcObuffer::get_device_type (int fd)
  391. {
  392. #ifdef AUDIO_GETDEV
  393.   int devtype;
  394.   if (ioctl (fd, AUDIO_GETDEV, &devtype))
  395.   {
  396.     perror ("ioctl AUDIO_GETDEV on /dev/audio");
  397.     exit (1);
  398.   }
  399.   return devtype;
  400. #else
  401.   cerr << "SparcObuffer::get_device_type(): AUDIO_GETDEV ioctl not available!\n";
  402.   return -1;
  403. #endif
  404. }
  405. #endif    // !Solaris
  406.  
  407.  
  408. #ifdef ULAW
  409. bool SparcObuffer::class_suitable (uint32 number_of_channels, bool force_amd)
  410. #else
  411. bool SparcObuffer::class_suitable (void)
  412. #endif
  413. {
  414. #ifdef ULAW
  415.   if (number_of_channels > 1)
  416.   {
  417.     cerr << "Your audio hardware cannot handle more than one audio channel.\n"
  418.         "Please use the option -l or -r for stereo streams.\n";
  419.     return False;
  420.   }
  421. #endif
  422.  
  423.   // check for the dbri audio device:
  424.   audio_fd = open_audio_device ();
  425.  
  426. #ifdef ULAW
  427.   if (force_amd)
  428.     return True;
  429. #endif
  430.  
  431. #ifdef Solaris
  432.   audio_device devtype;
  433.   get_device_type (audio_fd, &devtype);
  434. # ifdef ULAW
  435.     if (!strcmp (devtype.name, "SUNW,am79c30"))
  436.       return True;
  437.     else if (!strcmp (devtype.name, "SUNW,dbri"))
  438.     {
  439.       cerr << "Your machine can produce CD-quality audio output,\n"
  440.           "but this binary was compiled for 8 kHz u-law ouput. (telephone quality)\n"
  441.           "Please recompile it without the ULAW define in COMPILERFLAGS.\n"
  442.           "(or use the -amd option to use this binary with low-quality output)\n";
  443.       close (audio_fd);
  444.       return False;
  445.     }
  446. # else
  447.     if (!strcmp (devtype.name, "SUNW,dbri"))
  448.       return True;
  449.     else if (!strcmp (devtype.name, "SUNW,am79c30"))
  450.     {
  451.       cerr << "Your machine can produce 8 kHz u-law audio output only,\n"
  452.           "but this binary was compiled for CD-quality output.\n"
  453.           "Please recompile it with ULAW defined in COMPILERFLAGS\n"
  454.           "or use it in stdout mode as an decoder only.\n";
  455.       close (audio_fd);
  456.       return False;
  457.     }
  458. # endif
  459. #else
  460.   // !Solaris
  461. # ifdef SunOS4_1_1
  462.     // no AUDIO_GETDEV under SunOS 4.1.1, so we have to assume that there is
  463.     // an amd device attached to /dev/audio
  464. #   ifdef ULAW
  465.       return True;
  466. #   else
  467.       cerr << "Your machine can produce 8 kHz u-law audio output only,\n"
  468.           "but this binary was compiled for CD-quality output.\n"
  469.           "Please recompile it with ULAW defined in COMPILERFLAGS\n"
  470.           "or use it in stdout mode as an decoder only.\n";
  471.       close (audio_fd);
  472.       return False;
  473. #   endif    // !ULAW
  474. # else
  475.     // SunOS 4.1.3
  476.     int device_type = get_device_type (audio_fd);
  477. #   ifdef ULAW
  478.       if (device_type == AUDIO_DEV_AMD)
  479.     return True;
  480.       else if (device_type == AUDIO_DEV_SPEAKERBOX)
  481.       {
  482.     cerr << "Your machine can produce CD-quality audio output,\n"
  483.         "but this binary was compiled for 8 kHz u-law ouput. (telephone quality)\n"
  484.         "Please recompile it without the ULAW define in COMPILERFLAGS.\n"
  485.         "(or use the -amd option to use this binary with low-quality output)\n";
  486.     close (audio_fd);
  487.     return False;
  488.       }
  489. #   else
  490.       if (device_type == AUDIO_DEV_SPEAKERBOX)
  491.     return True;
  492.       else if (device_type == AUDIO_DEV_AMD)
  493.       {
  494.     cerr << "Your machine can produce 8 kHz u-law audio output only,\n"
  495.         "but this binary was compiled for CD-quality output.\n"
  496.         "Please recompile it with ULAW defined in COMPILERFLAGS\n"
  497.         "or use it in stdout mode as an decoder only.\n";
  498.     close (audio_fd);
  499.     return False;
  500.       }
  501. #   endif    // !ULAW
  502. # endif    // !SunOS4_1_1
  503. #endif    // !Solaris
  504.  
  505. #ifndef SunOS4_1_1
  506.   close (audio_fd);
  507.   cerr << "Sorry, I don't recognize your audio device.\n"
  508. # ifdef ULAW
  509.       "Please try the -amd option or use the stdout mode.\n";
  510. # else
  511.       "Please use the stdout mode.\n";
  512. # endif
  513.   return False;
  514. #endif
  515. }
  516.  
  517. #endif    // SPARC
  518.  
  519.  
  520. #ifdef LINUX
  521. int LinuxObuffer::audio_fd = -1;
  522.  
  523. int LinuxObuffer::open_audio_device (void)
  524. {
  525.   int fd;
  526.  
  527.   if ((fd = open ("/dev/dsp", O_WRONLY | O_NDELAY, 0)) < 0)
  528.     if (errno == EBUSY)
  529.     {
  530.       cerr << "Sorry, the audio device is busy!\n";
  531.       exit (1);
  532.     }
  533.     else
  534.     {
  535.       perror ("can't open /dev/dsp for writing");
  536.       exit (1);
  537.     }
  538.  
  539.   // turn NDELAY mode off:
  540.   int flags;
  541.   if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
  542.   {
  543.     perror ("fcntl F_GETFL on /dev/audio failed");
  544.     exit (1);
  545.   }
  546.   flags &= ~O_NDELAY;
  547.   if (fcntl (fd, F_SETFL, flags) < 0)
  548.   {
  549.     perror ("fcntl F_SETFL on /dev/audio failed");
  550.     exit (1);
  551.   }
  552.   return fd;
  553. }
  554.  
  555.  
  556. LinuxObuffer::LinuxObuffer (uint32 number_of_channels, Header *header)
  557. {
  558. #ifdef DEBUG
  559.   if (!number_of_channels || number_of_channels > MAXCHANNELS)
  560.   {
  561.     cerr << "LinuxObuffer: 0 < number of channels < " << MAXCHANNELS << "!\n";
  562.     exit (1);
  563.   }
  564. #endif
  565.   channels = number_of_channels;
  566.   for (int i = 0; i < number_of_channels; ++i)
  567.     bufferp[i] = buffer + i;
  568.  
  569.   if (audio_fd < 0)
  570.   {
  571.     cerr << "Internal error, LinuxObuffer::audio_fd has to be initialized\n"
  572.         "by LinuxObuffer::class_suitable()!\n";
  573.     exit (1);
  574.   }
  575.  
  576.   // configure the device:
  577.   int play_precision = 16;
  578.   int play_stereo = channels-1;
  579.   int play_sample_rate = header->frequency ();
  580.  
  581.   if(
  582.       ioctl(audio_fd, SNDCTL_DSP_SAMPLESIZE, &play_precision) == -1 ||
  583.       ioctl(audio_fd, SNDCTL_DSP_STEREO, &play_stereo) == -1 ||
  584.       ioctl(audio_fd, SNDCTL_DSP_SPEED, &play_sample_rate) == -1
  585.     )
  586.   {
  587.     perror ("configuration of /dev/dsp failed");
  588.     exit (1);
  589.   }
  590. }
  591.  
  592.  
  593. LinuxObuffer::~LinuxObuffer (void)
  594. {
  595.   sleep (1);
  596.   close (audio_fd);
  597. }
  598.  
  599.  
  600. void LinuxObuffer::append (uint32 channel, int16 value)
  601. {
  602. #ifdef DEBUG
  603.   if (channel >= channels)
  604.   {
  605.     cerr << "illegal channelnumber in LinuxObuffer::append()!\n";
  606.     exit (1);
  607.   }
  608.   if (bufferp[channel] - buffer >= OBUFFERSIZE)
  609.   {
  610.     cerr << "buffer overflow!\n";
  611.     exit (1);
  612.   }
  613. #endif
  614.   *bufferp[channel] = value;
  615.   bufferp[channel] += channels;
  616. }
  617.  
  618.  
  619. void LinuxObuffer::write_buffer (int)
  620. {
  621.   int length = (int)((char *)bufferp[0] - (char *)buffer);
  622.   if (write (audio_fd, buffer, length) != length)
  623.   {
  624.     perror ("write to /dev/dsp failed");
  625.     exit (1);
  626.   }
  627.   for (int i = 0; i < channels; ++i)
  628.     bufferp[i] = buffer + i;
  629. }
  630.  
  631.  
  632. bool LinuxObuffer::class_suitable (uint32 number_of_channels)
  633. {
  634.   // open the dsp audio device:
  635.   audio_fd = open_audio_device ();
  636.   return True;
  637. }
  638.  
  639. #endif    /* LINUX */
  640.