home *** CD-ROM | disk | FTP | other *** search
/ Action Ware 12: Heretic & Hexen / actionware12.iso / acware12 / sounds / mus_play / dump_mus.c < prev    next >
C/C++ Source or Header  |  1994-10-29  |  10KB  |  465 lines

  1. /*
  2.  *    Name:        MUS File Dumper
  3.  *    Version:    1.40
  4.  *    Author:        Vladimir Arnost (QA-Software)
  5.  *    Last revision:    Sep-29-1994
  6.  *    Compiler:    Borland C++ 3.1
  7.  *
  8.  */
  9.  
  10. /*
  11.  * Revision History:
  12.  *
  13.  *    Aug-1-1994    V1.00    V.Arnost
  14.  *        Written from scratch
  15.  *    Aug-9-1994    V1.20    V.Arnost
  16.  *        Fixed some minor bugs
  17.  *    Sep-16-1994    V1.30    V.Arnost
  18.  *        Added command line parser
  19.  *        Added single channel and single event type dump
  20.  *    Sep-29-1994    V1.40    V.Arnost
  21.  *        Fixed improper instrument number handling
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27.  
  28. #define VERSION       "1.40"
  29. #define COPYRIGHT  "MUS File Dump  Version "VERSION"  (c) 1994 QA-Software"
  30.  
  31. #ifndef __386__
  32. typedef unsigned char BYTE;
  33. typedef unsigned int  WORD;
  34. #endif
  35. typedef unsigned long DWORD;
  36.  
  37. struct MUSheader {
  38.     char    ID[4];        // identifier "MUS" 0x1A
  39.     WORD    scoreLen;
  40.     WORD    scoreStart;
  41.     WORD    channels;
  42.     WORD    dummy1;
  43.     WORD    instrCnt;
  44.     WORD    dummy2;
  45. //    WORD    instruments[];
  46. } header;
  47.  
  48. WORD instruments[64];
  49.  
  50. static char *instrname[] =
  51.        {"Acoustic Grand Piano",
  52.     "Bright Acoustic Piano",
  53.     "Electric Grand Piano",
  54.     "Honky-tonk Piano",
  55.     "Rhodes Paino",
  56.     "Chorused Piano",
  57.     "Harpsichord",
  58.     "Clavinet",
  59.     "Celesta",
  60.     "Glockenspiel",
  61.     "Music Box",
  62.     "Vibraphone",
  63.     "Marimba",
  64.     "Xylophone",
  65.     "Tubular-bell",
  66.     "Dulcimer",
  67.     "Hammond Organ",
  68.     "Percussive Organ",
  69.     "Rock Organ",
  70.     "Church Organ",
  71.     "Reed Organ",
  72.     "Accordion",
  73.     "Harmonica",
  74.     "Tango Accordion",
  75.     "Acoustic Guitar (nylon)",
  76.     "Acoustic Guitar (steel)",
  77.     "Electric Guitar (jazz)",
  78.     "Electric Guitar (clean)",
  79.     "Electric Guitar (muted)",
  80.     "Overdriven Guitar",
  81.     "Distortion Guitar",
  82.     "Guitar Harmonics",
  83.     "Acoustic Bass",
  84.     "Electric Bass (finger)",
  85.     "Electric Bass (pick)",
  86.     "Fretless Bass",
  87.     "Slap Bass 1",
  88.     "Slap Bass 2",
  89.     "Synth Bass 1",
  90.     "Synth Bass 2",
  91.     "Violin",
  92.     "Viola",
  93.     "Cello",
  94.     "Contrabass",
  95.     "Tremolo Strings",
  96.     "Pizzicato Strings",
  97.     "Orchestral Harp",
  98.     "Timpani",
  99.     "String Ensemble 1",
  100.     "String Ensemble 2",
  101.     "Synth Strings 1",
  102.     "Synth Strings 2",
  103.     "Choir Aahs",
  104.     "Voice Oohs",
  105.     "Synth Voice",
  106.     "Orchestra Hit",
  107.     "Trumpet",
  108.     "Trombone",
  109.     "Tuba",
  110.     "Muted Trumpet",
  111.     "French Horn",
  112.     "Brass Section",
  113.     "Synth Brass 1",
  114.     "Synth Bass 2",
  115.     "Soprano Sax",
  116.     "Alto Sax",
  117.     "Tenor Sax",
  118.     "Baritone Sax",
  119.     "Oboe",
  120.     "English Horn",
  121.     "Bassoon",
  122.     "Clarinet",
  123.     "Piccolo",
  124.     "Flute",
  125.     "Recorder",
  126.     "Pan Flute",
  127.     "Bottle Blow",
  128.     "Shakuhachi",
  129.     "Whistle",
  130.     "Ocarina",
  131.     "Lead 1 (square)",
  132.     "Lead 2 (sawtooth)",
  133.     "Lead 3 (calliope)",
  134.     "Lead 4 (chiffer)",
  135.     "Lead 5 (charang)",
  136.     "Lead 6 (voice)",
  137.     "Lead 7 (5th sawtooth)",
  138.     "Lead 8 (bass & lead)",
  139.     "Pad 1 (new age)",
  140.     "Pad 2 (warm)",
  141.     "Pad 3 (polysynth)",
  142.     "Pad 4 (choir)",
  143.     "Pad 5 (bowed glass)",
  144.     "Pad 6 (metal)",
  145.     "Pad 7 (halo)",
  146.     "Pad 8 (sweep)",
  147.     "FX 1 (rain)",
  148.     "FX 2 (soundtrack)",
  149.     "FX 3 (crystal)",
  150.     "FX 4 (atmosphere)",
  151.     "FX 5 (brightness)",
  152.     "FX 6 (goblin)",
  153.     "FX 7 (echo drops)",
  154.     "FX 8 (star-theme)",
  155.     "Sitar",
  156.     "Banjo",
  157.     "Shamisen",
  158.     "Koto",
  159.     "Kalimba",
  160.     "Bag Pipe",
  161.     "Fiddle",
  162.     "Shanai",
  163.     "Tinkle Bell",
  164.     "Agogo",
  165.     "Steel Drums",
  166.     "Woodblock",
  167.     "Taiko Drum",
  168.     "Melodic Tom",
  169.     "Synth Drum",
  170.     "Reverse Cymbal",
  171.     "Guitar Fret Noise",
  172.     "Breath Noise",
  173.     "Seashore",
  174.     "Bird Tweet",
  175.     "Telephone Ring",
  176.     "Helicopter",
  177.     "Applause",
  178.     "Gun Shot"};
  179.  
  180. static char *percussion[] =
  181.        {"Acoustic Bass Drum",
  182.     "Acoustic Bass Drum",
  183.     "Slide Stick",
  184.     "Acoustic Snare",
  185.     "Hand Clap",
  186.     "Electric Snare",
  187.     "Low Floor Tom",
  188.     "Closed High-Hat",
  189.     "High Floor Tom",
  190.     "Pedal High Hat",
  191.     "Low Tom",
  192.     "Open High Hat",
  193.     "Low-Mid Tom",
  194.     "High-Mid Tom",
  195.     "Crash Cymbal 1",
  196.     "High Tom",
  197.     "Ride Cymbal 1",
  198.     "Chinses Cymbal",
  199.     "Ride Bell",
  200.     "Tambourine",
  201.     "Splash Cymbal",
  202.     "Cowbell",
  203.     "Crash Cymbal 2",
  204.     "Vibraslap",
  205.     "Ride Cymbal 2",
  206.     "High Bongo",
  207.     "Low Bango",
  208.     "Mute High Conga",
  209.     "Open High Conga",
  210.     "Low Conga",
  211.     "High Timbale",
  212.     "Low Timbale",
  213.     "High Agogo",
  214.     "Low Agogo",
  215.     "Cabasa",
  216.     "Maracas",
  217.     "Short Whistle",
  218.     "Long Whistle",
  219.     "Short Guiro",
  220.     "Long Guiro",
  221.     "Claves",
  222.     "High Wood Block",
  223.     "Low Wood Block",
  224.     "Mute Cuica",
  225.     "Open Cuica",
  226.     "Mute Triangle",
  227.     "Open Triangle"};
  228.  
  229. /* Command-line parameters */
  230. char   *musname = NULL;
  231. int    help = 0;
  232. int    onlychannel = -1;
  233. int    onlyevent = -1;
  234.  
  235. char *note2name(BYTE note)
  236. {
  237.     static char name[8] = "";
  238.     static char *notes[] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
  239.     static char *octaves[] = {"-0", "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10"};
  240.     strcpy(name, notes[note % 12]);
  241.     strcat(name, octaves[note / 12]);
  242.     return name;
  243. }
  244.  
  245. char *instr2name(WORD instr)
  246. {
  247.     if (instr < 128)
  248.     return instrname[instr];
  249.     else if (instr >= 135 && instr < (135+47))    // there are 47 percussive instruments
  250.     return percussion[instr-135];
  251.     else
  252.     return "*Unknown*";
  253. }
  254.  
  255. int dispatchOption(char *option)
  256. {
  257.     int n;
  258.     switch (*option) {
  259.     case '?':
  260.     case 'H':        // help
  261.         help = 1;
  262.         break;
  263.     case 'C':        // channel
  264.         n = atoi(option+1);
  265.         if (onlychannel == -1) onlychannel = 0;
  266.         onlychannel |= 1 << n;
  267.         break;
  268.     case 'E':        // event
  269.         n = atoi(option+1);
  270.         if (onlyevent == -1) onlyevent = 0;
  271.         onlyevent |= 1 << n;
  272.         break;
  273.     default:
  274.         return -1;
  275.     }
  276.     return 0;
  277. }
  278.  
  279. main(int argc, char *argv[])
  280. {
  281.     FILE *f;
  282.     WORD i;
  283.     DWORD delay = 0;
  284.  
  285.     puts(COPYRIGHT);
  286.     while (argv++, --argc)
  287.     {
  288.     strupr(*argv);
  289.     if (**argv == '/' || **argv == '-')
  290.     {
  291.         if (dispatchOption(*argv+1))
  292.         {
  293.         printf("Invalid option %s\n", *argv);
  294.         return 2;
  295.         }
  296.     } else {
  297.         if (!musname)
  298.         musname = *argv;
  299.         else {
  300.         printf("Too many filenames.\n");
  301.         return 3;
  302.         }
  303.     }
  304.     }
  305.  
  306.     if (!musname || help)
  307.     {
  308.     puts("Syntax:\n"
  309.          "  DUMP_MUS filename.MUS  [options]\n"
  310.          "Options:\n"
  311.          "    /Cn   Dump events in channel number n only.\n"
  312.          "    /En   Dump events of type n only. n is 0-7."
  313.          );
  314.     return 1;
  315.     }
  316.  
  317.     if ( (f = fopen(musname, "rb")) == NULL)
  318.     {
  319.     printf("Can't open file %s\n", musname);
  320.     return 2;
  321.     }
  322.  
  323.     fread(&header, sizeof header, 1, f);
  324.     if (header.ID[0] != 'M' ||
  325.     header.ID[1] != 'U' ||
  326.     header.ID[2] != 'S' ||
  327.     header.ID[3] != 0x1A)
  328.     {
  329.     puts("Bad file.");
  330.     fclose(f);
  331.     return 3;
  332.     }
  333.  
  334.     fread(&instruments, sizeof(WORD), header.instrCnt, f);
  335.  
  336.     printf("Score Length\t\t%04Xh  (%u bytes)\n", header.scoreLen, header.scoreLen);
  337.     printf("Score Start\t\t%04Xh\n", header.scoreStart);
  338.     printf("Channels\t\t%d\n", header.channels);
  339.     printf("Instruments Used\t%d\n", header.instrCnt);
  340.     for (i = 0; i < header.instrCnt; i++)
  341.     {
  342.     register WORD ins = instruments[i];
  343.     printf("  %3d  %s\n", ins, instr2name(ins));
  344. /*    printf("  %3d  %s\n", ins, ins < 128 ? instrname[ins] :
  345.         (ins < (135+47) ? percussion[ins-135] : "*Unknown*") );  */
  346.     }
  347.     printf("\n");
  348.  
  349.     while (!feof(f))
  350.     {
  351.     int    cmd, channel, timemark, note, volume, value, show, fulldump;
  352.     DWORD    offs = ftell(f);
  353.  
  354.     if ( (value = fgetc(f)) == -1)
  355.         break;
  356.  
  357.     timemark = value & 0x80;
  358.     channel = value & 0x0F;
  359.     cmd = (value >> 4) & 0x07;
  360.     fulldump = onlychannel == -1 && onlyevent == -1;
  361.     show = fulldump || cmd == 6 || ((onlychannel & (1 << channel)) &&
  362.            (onlyevent & (1 << cmd)));
  363.     if (show)
  364.     {
  365.         if (delay)
  366.         {
  367.         printf("\t\t\tdelay: %ld\n", delay);
  368.         delay = 0;
  369.         }
  370.         printf("%06lX:  %02X ", offs, value);
  371.     }
  372.  
  373.     switch (cmd) {
  374.         case 0:    // release note
  375.         note = fgetc(f);
  376.         if (show)
  377.             printf("%02X\t\t#%d: release note %d (%s)\n",
  378.             note, channel, note, channel == 15 ? percussion[note-35] :
  379.             note2name(note));
  380.         break;
  381.         case 1:    // play note
  382.         note = fgetc(f);
  383.         if (note & 0x80)
  384.         {
  385.             volume = fgetc(f);
  386.             if (show)
  387.             printf("%02X %02X\t#%d: play note %d (%s), volume %d\n",
  388.                 note, volume, channel, note & 0x7F,
  389.                 channel == 15 ? instr2name((note & 0x7F)+100) :
  390.                 note2name(note & 0x7F), volume);
  391.         } else
  392.             if (show)
  393.             printf("%02X\t\t#%d: play note %d (%s)\n",
  394.                 note, channel, note, channel == 15 ?
  395.                 instr2name(note+100) : note2name(note));
  396.         break;
  397.         case 2:    // pitch wheel
  398.         value = fgetc(f);
  399.         if (show)
  400.             printf("%02X\t\t#%d: pitch wheel %+d\n", value, channel, value - 0x80);
  401.         break;
  402.         case 5:    // ???
  403.         case 7:    // ???
  404.         value = fgetc(f);
  405.         if (show)
  406.             printf("%02X\t\t#%d: unknown command, parameter %d\n", value, channel, value);
  407.         break;
  408.         case 3:    // set ???
  409.         value = fgetc(f);
  410.         if (show)
  411.             printf("%02X\t\t#%d: set ??? to %d\n", value, channel, value);
  412.         break;
  413.         case 4:    // change control
  414.         volume = fgetc(f);
  415.         value = fgetc(f);
  416.         if (show)
  417.         {
  418.             printf("%02X %02X\t#%d: ", volume, value, channel);
  419.             switch (volume) {
  420.             case 0: // change instrument
  421.                 printf("set instrument %d (%s)\n", value,
  422.                 value < 128 ? instrname[value] : "*Invalid*");
  423.                 break;
  424.             case 3: // change volume
  425.                 printf("set volume %d\n", value);
  426.                 break;
  427.             case 4: // change pan
  428.                 printf("set pan %+d\n", value - 0x40);
  429.                 break;
  430.             default: // ???
  431.                 printf("set control %d, %d\n", volume, value);
  432.             }
  433.         }
  434.         break;
  435.         case 6:    // end
  436.         printf("\t\t#%d: end of score\n", channel);
  437.         break;
  438.     }
  439.     if (timemark)
  440.     {
  441.         DWORD   time = 0;
  442.         BYTE    b;
  443.  
  444.         if (fulldump)
  445.         printf("%06lX:  ", ftell(f));
  446.         do {
  447.         b = fgetc(f);
  448.         if (fulldump)
  449.             printf("%02X ", b);
  450.         time <<= 7;
  451.         time += b & 0x7F;
  452.         } while (b & 0x80);
  453.  
  454.         if (fulldump)
  455.         printf("\t\tdelay: %ld\n", time);
  456.         else
  457.         delay += time;
  458.     }
  459.     }
  460.  
  461.     fclose(f);
  462.  
  463.     return 0;
  464. }
  465.