//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Mon Feb 11 20:48:51 PST 2002
// Last Modified: Mon Feb 11 20:48:54 PST 2002
// Filename:      ...sig/examples/all/mus2pmx.cpp
// Web Address:   http://sig.sapp.org/examples/museinfo/score/mus2pmx.cpp
// Syntax:        C++; museinfo
//
// Description:   Convert SCORE binary files into ASCII.
//

#include "ScoreRecord.h"
#include "Options.h"

#include <stdlib.h>

#ifndef OLDCPP
   #include <fstream>
#else
   #include <fstream.h>
#endif


// function declarations
int    readLittleShort(istream& input);
float  readLittleFloat(istream& instream);
void   convertFile(const char* filename);

// interface variables:
Options options;
int     verboseQ = 0;    // used with the -v option

//////////////////////////////////////////////////////////////////////////

int main(int argc, char** argv) {
   options.define("v|verbose=b",   "display debugging information in output");
   options.process(argc, argv);
   verboseQ = options.getBoolean("verbose");

   if (options.getArgCount() == 1) {
      convertFile(options.getArg(1));
   } else if (options.getArgCount() > 1) {
      for (int i=1; i<=options.getArgCount(); i++) {
         cout << "; FILE = " << options.getArg(i) << "\n";
         convertFile(options.getArg(i));
      }
   } else {
      cout << "Usage: " << argv[0] << " input.mus " << endl;
      exit(1);
   }

   return 0;
}


/////////////////////////////////////////////////////////////////////////


//////////////////////////////
//
// convertFile -- convert from binary to ASCII form.
//

void convertFile(const char* filename) {
   #ifndef OLDCPP
      #ifdef VISUAL
         fstream infile(filename, ios::in | ios::binary);
      #else
         fstream infile(filename, ios::in);
      #endif
   #else
      #ifdef VISUAL
         fstream infile(filename, ios::in | ios::nocreate | ios::binary);
      #else
         fstream infile(filename, ios::in | ios::nocreate);
      #endif
   #endif

   if (!infile.is_open()) {
      cerr << "Error: cannot open file: " << filename << endl;
      exit(1);
   }


   // first read the number of numbers in the data file.
   int numbercount = readLittleShort(infile);
   int readcount = 0;   // number of numbers which have been read
   if (verboseQ) {
      cout << "; NumberCount = " << numbercount << endl;
   }

   float number = 0;
   ScoreRecord record;
   // now read each data number, ignoring the trailer data
   while (!infile.eof()) {
      number = readLittleFloat(infile);
      readcount++;
      if (verboseQ) {
         if (number - (int)number > 0.0) {
            cout << "; Error in number parameter count: " << number << endl;
         }
      }

      if (number == 0.0) { 
         break;
      } else {
         readcount += (int)number;
         record.readBinary(infile, (int)number);
         record.printAscii(cout);
         cout << "\n";
      }
   }

   if (number == 0.0 && verboseQ) {
      cout << "; Trailer: " << "\n";
   }

   float oldnumber;
   union {float f; unsigned int i; } num;
   if (verboseQ) {
      num.f = readLittleFloat(infile);
      cout << "; SerialNumber:  " << num.i << "\n";
      readcount++;

      num.f = readLittleFloat(infile);
      cout << "; Score Version: " << num.f << "\n";
      readcount++;

      num.f = readLittleFloat(infile);
      cout << "; Units:         " << num.f << "\n";
      readcount++;

      number = num.f;
      oldnumber = number;
      while (number != -9999.0 && !infile.eof()) {
         number = readLittleFloat(infile);
         readcount++;
         cout << "; TrailerNumber: " << number << "\n";
         oldnumber = number;
      }
   }

   if (verboseQ) {
      cout << "; read " << readcount << " numbers in file" << "\n";
   }

   infile.close();
}



//////////////////////////////
//
// readLittleShort -- read a short int in little endian form.
//     Number is read as an unsigned short int.
//

int readLittleShort(istream& input) {
   unsigned char byteinfo[2];
   input.read((char*)byteinfo, 2);
   int output = 0;
   output = byteinfo[1];
   output = (output << 8) | byteinfo[0];
   return output;
}



///////////////////////////////
//
// readLittleFloat --
//

float readLittleFloat(istream& instream) {
   unsigned char byteinfo[4];
   instream.read((char*)byteinfo, 4);
   union { float f; unsigned int i; } num;
   num.i = 0;
   num.i = byteinfo[3];
   num.i = (num.i << 8) | byteinfo[2];
   num.i = (num.i << 8) | byteinfo[1];
   num.i = (num.i << 8) | byteinfo[0];

   return num.f;
}


// md5sum: a6ad2c6729220e33fc5b787d217c5c5b mus2pmx.cpp [20050403]