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

  1. /*
  2.  *  @(#) maplay.cc 1.20, last edit: 6/22/94 12:32:55
  3.  *  @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
  4.  *  @(#) Berlin University of Technology
  5.  *
  6.  *  Many thanks for ideas and implementations to:
  7.  *  -> Jim Boucher (jboucher@flash.bu.edu)
  8.  *     for his idea and first implementation of 8 kHz u-law output
  9.  *  -> Louis P. Kruger (lpkruger@phoenix.princeton.edu)
  10.  *     for his implementation of the LinuxObuffer class
  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.  *    - minor changes to create a LinuxObuffer object
  30.  *    - minor changes for a u-law version, which creates 8 kHz u-law output
  31.  *      on an amd device or in stdout mode, if compiled with ULAW defined
  32.  *    - option -amd forces maplay to treat /dev/audio as an amd device
  33.  *      in the u-law version. This is helpful on some SPARC clones.
  34.  *    - iostreams manipulator calls like "cerr << setw (2) << ..." replaced by
  35.  *      "cerr.width (2); ..." due to problems with older GNU C++ releases.
  36.  */
  37.  
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <math.h>
  42. #include <iostream.h>
  43. #include <iomanip.h>
  44. #include "all.h"
  45. #include "crc.h"
  46. #include "header.h"
  47. #include "ibitstream.h"
  48. #include "obuffer.h"
  49. #include "subband.h"
  50. #include "subband_layer_1.h"
  51. #include "subband_layer_2.h"
  52. #include "synthesis_filter.h"
  53.  
  54.  
  55. // data extracted from commandline arguments:
  56. static char *filename;
  57. static bool verbose_mode = False, filter_check = False;
  58. static bool stdout_mode = False;
  59. static enum e_channels which_channels = both;
  60. static bool use_speaker = False, use_headphone = False, use_line_out = False;
  61. #ifdef ULAW
  62. static bool force_amd = False;
  63. #endif
  64. static bool use_own_scalefactor = False;
  65. static real scalefactor;
  66.  
  67. // data extracted from header of first frame:
  68. static uint32 layer;
  69. static e_mode mode;
  70. static e_sample_frequency sample_frequency;
  71.  
  72. // objects needed for playing a file:
  73. static Ibitstream *stream;
  74. static Header *header;
  75. static Crc16 *crc;
  76. static Subband *subbands[32];
  77. static SynthesisFilter *filter1 = NULL, *filter2 = NULL;
  78. static Obuffer *buffer = NULL;
  79.  
  80.  
  81. static void Exit (int returncode)
  82.   // delete some objects and exit
  83. {
  84.   delete buffer;    // delete on NULL-pointers are harmless
  85.   delete filter1;
  86.   delete filter2;
  87.   delete header;
  88.   delete stream;
  89.   exit (returncode);
  90. }
  91.  
  92.  
  93. main (int argc, char *argv[])
  94. {
  95.   int i;
  96.   bool read_ready = False, write_ready = False;
  97.  
  98.   if (argc < 2 || !strncmp (argv[1], "-h", 2))
  99.   {
  100. usage:
  101.     cerr << "\nusage: " << argv[0]
  102.      << " [-v] [-s] [-l] [-r] "
  103. #ifdef SPARC
  104.         "[-us] [-uh] "
  105. #ifndef SunOS4_1_1
  106.         "[-ul] "
  107. #endif
  108. #endif
  109.         "[-c] [-f ushort] filename\n"
  110.         "  filename   filename of a MPEG audio stream or - for stdin\n"
  111.         "  -v         verbose mode\n"
  112. #ifdef ULAW
  113.         "  -s         write u-law samples at 8 kHz rate to stdout\n"
  114. #else
  115.         "  -s         write pcm samples to stdout\n"
  116. #endif
  117.         "  -l         decode only the left channel\n"
  118.         "  -r         decode only the right channel\n"
  119. #ifdef SPARC
  120.         "  -us        send audio signal to speaker (default)\n"
  121.         "  -uh        send audio signal to headphone\n"
  122. #ifndef SunOS4_1_1
  123.         "  -ul        send audio signal to line out\n"
  124. #endif
  125. #endif
  126. #ifdef ULAW
  127.         "  -amd       force maplay to treat /dev/audio as an amd device\n"
  128. #endif
  129.         "  -c         check for filter range violations\n"
  130.         "  -f ushort  use this scalefactor instead of the default value 32768\n\n"
  131.         "@(#) MPEG Audio Player maplay 1.2 "
  132. #ifdef ULAW
  133.         "(8 kHz u-law "
  134. #else
  135.         "("
  136. #endif
  137. #ifdef Indigo
  138.         "Indigo IRIX"
  139. #else
  140. #ifdef SunOS4_1_1
  141.         "SPARC SunOS 4.1.1"
  142. #else
  143. #ifdef SunOS4_1_3
  144.         "SPARC SunOS 4.1.3"
  145. #else
  146. #ifdef Solaris
  147.         "SPARC Solaris 2.x"
  148. #else
  149. #ifdef LINUX
  150.         "Linux"
  151. #else
  152. #ifdef ULTRIX
  153.         "RISC ULTRIX 4.x"
  154. #else
  155.         "unknown"
  156. #endif
  157. #endif
  158. #endif
  159. #endif
  160. #endif
  161. #endif
  162.         " version)\n"
  163.         "@(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)\n"
  164.         "@(#) Berlin University of Technology\n"
  165.         "@(#) Created: 6/23/94 14:12:46\n"
  166.         "@(#) This program is free software. See the GNU General Public License\n"
  167.         "@(#) in the file COPYING for more details.\n\n";
  168.     exit (0);
  169.   }
  170.  
  171.   // parse arguments:
  172.   for (i = 1; i < argc; ++i)
  173.     if (argv[i][0] == '-' && argv[i][1])
  174.       switch ((int)argv[i][1])
  175.       {
  176.     case 'v':
  177.       verbose_mode = True;
  178.       break;
  179.     case 's':
  180.       stdout_mode = True;
  181.       break;
  182.     case 'l':
  183.       which_channels = left;
  184.       break;
  185.     case 'r':
  186.       which_channels = right;
  187.       break;
  188. #ifdef SPARC
  189.     case 'u':
  190.       switch (argv[i][2])
  191.       {
  192.         case 's':
  193.           use_speaker = True;
  194.           break;
  195.         case 'h':
  196.           use_headphone = True;
  197.           break;
  198. #ifndef SunOS4_1_1
  199.         case 'l':
  200.           use_line_out = True;
  201.           break;
  202. #endif
  203.         default:
  204.           goto usage;
  205.       }
  206.       break;
  207. #endif
  208. #ifdef ULAW
  209.     case 'a':
  210.       force_amd = True;
  211.       break;
  212. #endif
  213.     case 'c':
  214.       filter_check = True;
  215.       break;
  216.     case 'f':
  217.       if (++i == argc)
  218.       {
  219.         cerr << "please specify a new scalefactor after the -f option!\n";
  220.         exit (1);
  221.       }
  222.       use_own_scalefactor = True;
  223.       sscanf (argv[i], "%f", &scalefactor);
  224.       break;
  225.     default:
  226.       goto usage;
  227.       }
  228.     else if (!filename)
  229.       filename = argv[i];
  230.     else
  231.       goto usage;
  232.  
  233.   if (!filename)
  234.     goto usage;
  235.   if (!(use_speaker || use_headphone || use_line_out))
  236.     use_speaker = True;
  237.  
  238.   if (!strcmp (filename, "-"))
  239.     stream = new Ibitstream (0);        // read from stdin
  240.   else
  241.     stream = new Ibitstream (filename);        // read from file
  242.  
  243.   header = new Header;
  244.   if (!header->read_header (stream, &crc))
  245.   {
  246.     cerr << "no header found!\n";
  247.     Exit (1);
  248.   }
  249.  
  250.   // get info from header of first frame:
  251.   layer = header->layer ();
  252.   if ((mode = header->mode ()) == single_channel)
  253.     which_channels = left;
  254.   sample_frequency = header->sample_frequency ();
  255.  
  256.   // create filter(s):
  257. #ifdef ULAW
  258.   if (use_own_scalefactor)
  259.     filter1 = new SynthesisFilter (0, sample_frequency, scalefactor);
  260.   else
  261.     filter1 = new SynthesisFilter (0, sample_frequency);
  262.   if (mode != single_channel && which_channels == both)
  263.     if (use_own_scalefactor)
  264.       filter2 = new SynthesisFilter (1, sample_frequency, scalefactor);
  265.     else
  266.       filter2 = new SynthesisFilter (1, sample_frequency);
  267. #else
  268.   if (use_own_scalefactor)
  269.     filter1 = new SynthesisFilter (0, scalefactor);
  270.   else
  271.     filter1 = new SynthesisFilter (0);
  272.   if (mode != single_channel && which_channels == both)
  273.     if (use_own_scalefactor)
  274.       filter2 = new SynthesisFilter (1, scalefactor);
  275.     else
  276.       filter2 = new SynthesisFilter (1);
  277. #endif    // !ULAW
  278.  
  279.   // create buffer:
  280.   if (stdout_mode)
  281.     if (mode == single_channel || which_channels != both)
  282.       buffer = new FileObuffer (1);
  283.     else
  284.       buffer = new FileObuffer (2);
  285.   else
  286. #ifdef Indigo
  287.   {
  288.     if (mode == single_channel || which_channels != both)
  289.       buffer = new IndigoObuffer (1, header);
  290.     else
  291.       buffer = new IndigoObuffer (2, header);
  292.   }
  293. #else
  294. #ifdef SPARC
  295.   {
  296. #ifdef ULAW
  297.     if (SparcObuffer::class_suitable ((mode == single_channel || which_channels != both) ? 1 : 2,
  298.                       force_amd))    // amd device available?
  299.       buffer = new SparcObuffer (header, use_speaker, use_headphone, use_line_out);
  300. #else
  301.     if (SparcObuffer::class_suitable ())        // dbri device available?
  302.       if (mode == single_channel || which_channels != both)
  303.     buffer = new SparcObuffer (1, header, use_speaker, use_headphone, use_line_out);
  304.       else
  305.     buffer = new SparcObuffer (2, header, use_speaker, use_headphone, use_line_out);
  306. #endif
  307.     else
  308.       Exit (0);
  309.   }
  310. #else
  311. #ifdef LINUX
  312.   {
  313.     if (LinuxObuffer::class_suitable (mode == single_channel || which_channels != both) ? 1 : 2)
  314.       if (mode == single_channel || which_channels != both)
  315.     buffer = new LinuxObuffer (1, header);
  316.       else
  317.     buffer = new LinuxObuffer (2, header);
  318.     else
  319.       Exit (0);
  320.   }
  321. #else
  322. //#ifdef your_machine
  323. //  {
  324. //    if (mode == single_channel || which_channels != both)
  325. //      buffer = new your_Obuffer (your_parameters);    // mono
  326. //    else
  327. //      buffer = new your_Obuffer (your_parameters);    // stereo
  328. //  }
  329. //#else
  330.   {
  331.     cerr << "Sorry, I don't know your audio device.\n"
  332.         "Please use the stdout mode.\n";
  333.     Exit (0);
  334.   }
  335. //#endif    // !your_machine
  336. #endif    // !LINUX
  337. #endif    // !SPARC
  338. #endif    // !Indigo
  339.  
  340.   if (verbose_mode)
  341.   {
  342.     // print informations about the stream
  343.     char *name = strrchr (filename, '/');
  344.     if (name)
  345.       ++name;
  346.     else
  347.       name = filename;
  348.     cerr << name << " is a layer " << header->layer_string () << ' '
  349.      << header->mode_string () << " MPEG audio stream with";
  350.     if (!header->checksums ())
  351.       cerr << "out";
  352.     cerr << " checksums.\nThe sample frequency is "
  353.      << header->sample_frequency_string () << " at a bitrate of "
  354.      << header->bitrate_string () << ".\n"
  355.         "This stream is ";
  356.     if (header->original ())
  357.       cerr << "an original";
  358.     else
  359.       cerr << "a copy";
  360.     cerr << " and is ";
  361.     if (!header->copyright ())
  362.       cerr << "not ";
  363.     cerr << "copyright protected.\n";
  364.   }
  365.  
  366.   do
  367.   {
  368.     // is there a change in important parameters?
  369.     // (bitrate switching is allowed)
  370.     if (header->layer () != layer)
  371.     {
  372.       // layer switching is allowed
  373.       if (verbose_mode)
  374.     cerr << "switching to layer " << header->layer_string () << ".\n";
  375.       layer = header->layer ();
  376.     }
  377.     if ((mode == single_channel && header->mode () != single_channel) ||
  378.     (mode != single_channel && header->mode () == single_channel))
  379.     {
  380.       // switching from single channel to stereo or vice versa is not allowed
  381.       cerr << "illegal switch from single channel to stereo or vice versa!\n";
  382.       Exit (1);
  383.     }
  384.     if (header->sample_frequency () != sample_frequency)
  385.     {
  386.       // switching the sample frequency is not allowed
  387.       cerr << "sorry, can't switch the sample frequency in the middle of the stream!\n";
  388.       Exit (1);
  389.     }
  390.  
  391.     // create subband objects:
  392.     if (header->layer () == 1)
  393.     {
  394.       if (header->mode () == single_channel)
  395.     for (i = 0; i < header->number_of_subbands (); ++i)
  396.       subbands[i] = new SubbandLayer1 (i);
  397.       else if (header->mode () == joint_stereo)
  398.       {
  399.     for (i = 0; i < header->intensity_stereo_bound (); ++i)
  400.       subbands[i] = new SubbandLayer1Stereo (i);
  401.     for (; i < header->number_of_subbands (); ++i)
  402.       subbands[i] = new SubbandLayer1IntensityStereo (i);
  403.       }
  404.       else
  405.     for (i = 0; i < header->number_of_subbands (); ++i)
  406.       subbands[i] = new SubbandLayer1Stereo (i);
  407.     }
  408.     else if (header->layer () == 2)
  409.     {
  410.       if (header->mode () == single_channel)
  411.     for (i = 0; i < header->number_of_subbands (); ++i)
  412.       subbands[i] = new SubbandLayer2 (i);
  413.       else if (header->mode () == joint_stereo)
  414.       {
  415.     for (i = 0; i < header->intensity_stereo_bound (); ++i)
  416.       subbands[i] = new SubbandLayer2Stereo (i);
  417.     for (; i < header->number_of_subbands (); ++i)
  418.       subbands[i] = new SubbandLayer2IntensityStereo (i);
  419.       }
  420.       else
  421.     for (i = 0; i < header->number_of_subbands (); ++i)
  422.       subbands[i] = new SubbandLayer2Stereo (i);
  423.     }
  424.     else
  425.     {
  426.       cerr << "sorry, layer 3 not implemented!\n";
  427.       Exit (0);
  428.     }
  429.  
  430.     // start to read audio data:
  431.     for (i = 0; i < header->number_of_subbands (); ++i)
  432.       subbands[i]->read_allocation (stream, header, crc);
  433.  
  434.     if (header->layer () == 2)
  435.       for (i = 0; i < header->number_of_subbands (); ++i)
  436.     ((SubbandLayer2 *)subbands[i])->read_scalefactor_selection (stream, crc);
  437.  
  438.     if (!crc || header->checksum_ok ())
  439.     {
  440.       // no checksums or checksum ok, continue reading from stream:
  441.       for (i = 0; i < header->number_of_subbands (); ++i)
  442.     subbands[i]->read_scalefactor (stream, header);
  443.  
  444.       do
  445.       {
  446.     for (i = 0; i < header->number_of_subbands (); ++i)
  447.       read_ready = subbands[i]->read_sampledata (stream);
  448.  
  449.     do
  450.     {
  451.       for (i = 0; i < header->number_of_subbands (); ++i)
  452.         write_ready = subbands[i]->put_next_sample (which_channels, filter1, filter2);
  453.  
  454.       filter1->calculate_pcm_samples (buffer);
  455.       if (which_channels == both && header->mode () != single_channel)
  456.         filter2->calculate_pcm_samples (buffer);
  457.     }
  458.     while (!write_ready);
  459.       }
  460.       while (!read_ready);
  461.  
  462.       buffer->write_buffer (1);        // write to stdout
  463.     }
  464.     else
  465.       // Sh*t! Wrong crc checksum in frame!
  466.       cerr << "WARNING: frame contains wrong crc checksum! (throwing frame away)\n";
  467.  
  468.     for (i = 0; i < header->number_of_subbands (); ++i)
  469.       delete subbands[i];
  470.   }
  471.   while (header->read_header (stream, &crc));
  472.  
  473.   delete buffer;
  474.  
  475.   uint32 range_violations = filter1->violations ();
  476.   if (mode != single_channel && which_channels == both)
  477.    range_violations += filter2->violations ();
  478.  
  479.   if (filter_check)
  480.   {
  481.     // check whether (one of) the filter(s) produced values not in [-1.0, 1.0]:
  482.     if (range_violations)
  483.     {
  484.       cerr << range_violations << " range violations have occured!\n";
  485.       if (stdout_mode)
  486.     cerr << "If you notice these violations,\n";
  487.       else
  488.     cerr << "If you have noticed these violations,\n";
  489.       cerr << "please use the -f option with the value ";
  490.       if (mode != single_channel && which_channels == both &&
  491.       filter2->hardest_violation () > filter1->hardest_violation ())
  492.     cerr << filter2->recommended_scalefactor ();
  493.       else
  494.     cerr << filter1->recommended_scalefactor ();
  495.       cerr << "\nor a greater value up to 32768 and try again.\n";
  496.     }
  497.   }
  498.   if (verbose_mode)
  499.   {
  500.     // print playtime of stream:
  501.     real playtime = filter1->seconds_played (Header::frequency (sample_frequency));
  502.     uint32 minutes = (uint32)(playtime / 60.0);
  503.     uint32 seconds = (uint32)playtime - minutes * 60;
  504.     uint32 centiseconds = (uint32)((playtime - (real)(minutes * 60) - (real)seconds) * 100.0);
  505.     cerr << "end of stream, playtime: " << minutes << ':';
  506.     cerr.width (2);
  507.     cerr.fill ('0');
  508.     cerr << seconds << '.';
  509.     cerr.width (2);
  510.     cerr.fill ('0');
  511.     cerr << centiseconds << '\n';
  512.   }
  513.  
  514.   return 0;
  515. }
  516.