RC200AudioSamples.java


/* RC200AudioSamples.java
 * 
 *  Created on: Nov 8, 2003
 *  Author:     C. Vickery
 *
 *  $Log$
 * 
 */

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;

//  Class RC200AudioSamples
//  ------------------------------------------------------------------
/**
 * 
 *  Generate Samples, like class GenerateSamples, except with
 *  generated file name and parameters for use with RC200 PSL.
 *
 *  @author vickery
 *
 *
 */
  public class RC200AudioSamples
  {
    static int sampling_rate  = 8000;
    static int sound_frequency     = 440;
    static int bitsPerSample  = 20;
    static int numSamples     = 0;

    static final double twoPi = Math.PI + Math.PI;
    static final double log2  = Math.log( 2 );


  //  decize()
  //  --------------------------------------------------------------
  /**
   *    Generate the n-digit decimal representation of an int.
   *    Assumes the int is positive.
   */
    static String decize( int val, int numDigits )
    {
      StringBuffer sb =
                        new StringBuffer( Integer.toString( val ) );
      while ( sb.length() < numDigits )
      {
        sb.insert(0, ' ' );
      }
      return new String( sb );
    }

  //  hexadize()
  //  --------------------------------------------------------------
  /**
   *    Generate the n-digit hexadecimal representation of an int.
   */
    static String hexadize( int val, int numDigits )
    {
      StringBuffer sb = 
                     new StringBuffer( Integer.toHexString( val ) );
      while (sb.length() < numDigits )
      {
        sb.insert(0, '0' );
      }
      if ( sb.length() > numDigits )
      {
        sb.delete( 0,  (sb.length() - numDigits) );
      }
      for (int i = 0; i < numDigits; i++ )
      {
        char c = Character.toUpperCase( sb.charAt( i ) );
        sb.setCharAt( i, c );
      }
      sb.insert(0, "0x" );
      return new String( sb );
    }


  //  main()
  //  ----------------------------------------------------------------
  /**
   *    
   */
    public static void main(String[] args)
    {
      for (int i = 0; i < args.length; i++ )
      {
        try
        {
          if ( "-r".equals( args[i] ) )
          {
            sampling_rate = Integer.decode( args[ ++i] ).intValue();
            if (  (sampling_rate !=  8000) &&
                  (sampling_rate != 16000) &&
                  (sampling_rate != 32000) &&
                  (sampling_rate != 48000) &&
                  (sampling_rate != 11025) &&
                  (sampling_rate != 22050) &&
                  (sampling_rate != 44100) )
            {
              System.err.println( args[i] + " is not a valid audio" +
              " sampling rate for the RC200" );
              System.exit( 1 );
            }
            continue;
          }

          if ( "-f".equals( args[i] ) )
          {
            sound_frequency = Integer.decode( args[++i] ).intValue();
            continue;
          }
        }
        catch (NumberFormatException e)
        {
          System.err.println( e + " is not a valid number." );
          System.exit( 1 );
        }
        catch (ArrayIndexOutOfBoundsException e)
        {
          System.err.println( "Missing option value. ");
          System.exit( 1 );
        }
        System.err.println( args[i] + " is not a valid option." );
        System.exit( 1 );
      }

      //  Output file is named "samples_xxx_yyy.hch" where
      //    xxx is sound frequency
      //    yyy is sampling rate
      PrintWriter pout = null;
      try
      {
        pout = new PrintWriter( 
          new FileWriter( "samples_" + sound_frequency + "_" +
                                           sampling_rate + ".hch" ) );
      }
      catch (IOException e)
      {
        System.err.println( e );
        System.exit( 1 );
      }

      //  Calculate actual number of samples.
      numSamples = 1 + (sampling_rate / sound_frequency);

      //  Generate double values of the samples but print integer
      //  approximations.
      DecimalFormat df5 = new DecimalFormat( " 0.00000;-0.00000" );

      int scaleFactor         = 1 << (bitsPerSample - 1);
      int mask                = scaleFactor - 1; // Mersenne
      int numHexDigits        = (bitsPerSample + 3) /4;

      double secondsPerSample = 1.0 / sampling_rate;
      double secondsPerCycle  = 1.0 / sound_frequency;
      double timeNow          = 0.0;  //  sampling time
      double radiansNow       = 0.0;  //  cycle time

      pout.println( "  {" );
      pout.println(
            "//   Value\tSample#       Time   radians     Value" );

      for ( int i=0; i< numSamples; i++ )
      {
        //  Get value between -1.0 and +1.0
        double realSampleValue = Math.sin( radiansNow );
        //  Convert to signed int between -2^n and +2^n-1
        int intSampleValue =
                        (int)(realSampleValue * scaleFactor);
        //  Display values in format suitable for generating
        //  Handel-C code.
        pout.println( "    " 
          + hexadize( intSampleValue, numHexDigits ) + ", /* "
          + decize( i, 4 ) + ":  "
          + df5.format( timeNow )  + "  "
          + df5.format( radiansNow ) + "  "
          + df5.format( realSampleValue ) + "  */" );

        timeNow += secondsPerSample;

        if ( timeNow > secondsPerCycle )
          timeNow -= secondsPerCycle;

        radiansNow = twoPi * timeNow/secondsPerCycle;
      }
      //  End of initialization list
      pout.println( "  };" );
        
    //  Need to tell compiler integer values for parameters
    double khz_rate = sampling_rate / 1000.0;
    pout.println( "// Number of samples for a " + sound_frequency  +
                   "Hz tone sampled at a " + khz_rate + "KHz rate " );
    pout.println( "// with " +  bitsPerSample + " bits per sample." );
    int sampleInterval = (int)(1E9 * 1.0 / sampling_rate );
    pout.println( "macro expr numSamples_" + sound_frequency + "_" +
                           sampling_rate + " = " + numSamples + ";" );
    pout.close();
    }
  }