pal_generate_tones.hcc


//  pal_generate_tones.hcc

/*  Use Pal Audio to generate tones.
 *
 *    Switch (button) 0: 440 Hz sine wave
 *    Switch (button) 1: 880 Hz sine wave
 *    Both switches:     Sum of 440 and 880.
 *
 *  Uses waveform intensities generated by 
 *  Generate_PAL_Samples.java.
 *
 *  For visualization with Waveform Analyzer,
 *  set the trace parameters to 50,000 points
 *  with a 1,000 nsec period.
 *
 *  Author:   C. Vickery
 *  Fall, 2003
 *
 */

#ifdef USE_SIM
#define PAL_ACTUAL_CLOCK_RATE 1000000
set clock = external "P1"
  with
  {
    extlib  = "DKSync.dll",
    extinst = "1000", // Period of 1MHz simulated clock
    extfunc = "DKSyncGetSet"
  };

//  Use switches instead of buttons when simulating so that
//  both can be on at the same time.
#define SW0 8
#define SW1 9
#define NUM_SWITCHES 10
#endif

#if (defined USE_RC200 || USE_RC200E)
#define PAL_TARGET_CLOCK_RATE 50000000
#define SW0 0
#define SW1 1
#define NUM_SWITCHES 2
#endif

#include <pal_master.hch>
#include <stdlib.hch>
#define true  TRUE
#define false FALSE

//  Bits per sample.
/*  Notes:
 *    1.  The macro expr bps must be defined before #including header
 *        files produceded by Generate_PAL_Samples.java.
 *    2.  The value of bps will vary depending on the target platform.
 *        For example, when USE_SIM is defined, it is 16, but when
 *        USE_RC200 is defined it is 20.
 */
macro expr bps = ( PalAudioOutGetMaxDataWidthCT() );

//  Lookup tables for the two waveforms.  The header files were
//  produced by Generate_PAL_Samples.java, which also defines values
//  for sampleRate_xxx and numSamples_xxx.
rom signed bps a_440[] =
#include "a-440.hch"

rom signed bps a_880[] =
#include "a-880.hch"

signed bps left;        //  Value output to both channels, actually.

#ifdef USE_SIM

//  A "feature" of the DKConnect DLL is that it can handle unsigned
//  values of any width, but signed values only of 32 bits.  So we
//  sign extend the values being output to 32 bits and output the 32
//  bit values after scaling them up to make the amplitude of the
//  waveform big enough to see.
//  (Celoxica service call 00011469; November 18, 2003.)

interface bus_out() left_channel( signed 32 out =
                                      (adjs(left, 32) << (32 - bps)) )
  with
  {
    extlib  = "DKConnect.dll",
    extinst = "t(32)",
    extfunc = "DKConnectGetSet"
  };

#endif


//  micro_delay()
//  ------------------------------------------------------------------
/*
 */
macro proc micro_delay( microsec )
{
  macro expr clocks = PAL_ACTUAL_CLOCK_RATE / 1000000 * microsec;
  unsigned (log2ceil( clocks )) counter;
  counter = clocks;
  while ( counter )
    counter--;
}


//  main()
//  ------------------------------------------------------------------
/*
 *    Generates sine waves from rom lookup tables.
 */
  void main( void )
  {
    unsigned 1 b0, b1;                            //  Switches
    unsigned (log2ceil( numSamples_440 )) i_440;  //  Samples index
    unsigned (log2ceil( numSamples_880 )) i_880;  //  Samples index


    PalVersionRequire( 1, 2 );
    PalSwitchRequire( NUM_SWITCHES );
    PalAudioOutRequire( 1 );

    i_440 = 0;
    i_880 = 0;

    par
    {
      PalAudioOutEnable(PalAudioOutCT( 0 ) );
      seq
      {
        PalAudioOutRun(PalAudioOutCT( 0 ), PAL_ACTUAL_CLOCK_RATE );
        PalAudioOutSetSampleRate( PalAudioOutCT( 0 ), 
          assert( sampleRate_440 == sampleRate_880, sampleRate_440,
          "440 and 880 Hz sampling rates are not the same (%d - %d)",
           sampleRate_440, sampleRate_880 ) );
      }


      //  Generate a tone intensity, depending on states of switches
      while ( true )
      {
        switch ( b1@b0 )
        {
          //  No tone
          case 0b00:
            left  = 0;
            break;

          //  440 Hz
          case 0b01:
            left  = a_440[i_440];
            break;

          //  880 Hz
          case 0b10:
            left  = a_880[i_880];
            break;

          //  440 mixed with 880
          /*
           *  Halve each intenstity before summing to avoid overflow.
           */
          case 0b11:
            left = (a_440[i_440] >> 1) + (a_880[i_880] >> 1);
            break;
        }
        par
        {
          PalAudioOutWrite( PalAudioOutCT( 0 ), left, left );
          i_440++;
          i_880++;
        }
        //  Wrap indices if necessary
        par
        {
          if ( i_440 == numSamples_440 )
          {
            i_440 = 0;
          }
          if ( i_880 == numSamples_880 )
          {
            i_880 = 0;
          }
        }
      }

      //  Switch handler
      while ( true )
      {
        PalSwitchRead( PalSwitchCT( SW0 ), &b0 );
        PalSwitchRead( PalSwitchCT( SW1 ), &b1 );
      }
    }
  }