psl_generate_tones.hcc


//  psl_generate_tones.hcc

/*  Use PSL Audio to generate tones.
 *
 *    Left Channel gets 440 Hz sine wave.
 *    Right Channel gets 880 Hz sine wave.
 *
 *    Buttons:    
 *      0:  Cyle through intensities
 *      1:  Cycle through sampling rates
 *
 *    Uses waveform intensities generated by RC200AudioSamples.java.
 *
 *    Author  C. Vickery
 *    Fall 2003
 */

//  Cannot use PAL Virtual Console, so no simulation is provided.
#define RC200_TARGET_CLOCK_RATE 50000000

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

#include "delays.hch"

//  Bits per sample specified in RC-200 PSL Reference Manual.
macro expr bps = 20;

//  Lookup tables for the waveforms.  The header files were
//  produced by RC200AudioSamples.java, which also defines the value
//  of numSamples_xxx_yyy, where xxx is the frequency and yyy is the
//  sampling rate (8000. 11025, 16000, 22050, 32000, 44100, or 48000).


//  Samples for the left channel (440 Hz)
rom signed bps samples_440[7][110] =
{
  #include "samples_440_8000.hch"
  #include "samples_440_11025.hch"
  #include "samples_440_16000.hch"
  #include "samples_440_22050.hch"
  #include "samples_440_32000.hch"
  #include "samples_440_44100.hch"
  #include "samples_440_48000.hch"
};

//  Parameters copied from the samples_440_nnnn header files.
macro expr numSamples_440_8000  = 19;
macro expr numSamples_440_11025 = 26;
macro expr numSamples_440_16000 = 37;
macro expr numSamples_440_22050 = 51;
macro expr numSamples_440_32000 = 73;
macro expr numSamples_440_44100 = 101;
macro expr numSamples_440_48000 = 110;  // Need 7 bits for this value

//  Row Length lookup table for samples_440
rom unsigned 7 numSamples_440[7] =
{
  numSamples_440_8000,
  numSamples_440_11025,
  numSamples_440_16000,
  numSamples_440_22050,
  numSamples_440_32000,
  numSamples_440_44100,
  numSamples_440_48000,
};


//  Samples for right channel (880 Hz)
rom signed bps samples_880[7][55] =
{
  #include "samples_880_8000.hch"
  #include "samples_880_11025.hch"
  #include "samples_880_16000.hch"
  #include "samples_880_22050.hch"
  #include "samples_880_32000.hch"
  #include "samples_880_44100.hch"
  #include "samples_880_48000.hch"
};

//  Parameters copied from the samples_880_nnnn header files.
macro expr numSamples_880_8000  = 10;
macro expr numSamples_880_11025 = 13;
macro expr numSamples_880_16000 = 19;
macro expr numSamples_880_22050 = 26;
macro expr numSamples_880_32000 = 37;
macro expr numSamples_880_44100 = 51;
macro expr numSamples_880_48000 = 55; // Need 6 bits for this value

//  Row Length lookup table for samples_880
rom unsigned 6 numSamples_880[8] =
{
  numSamples_880_8000,
  numSamples_880_11025,
  numSamples_880_16000,
  numSamples_880_22050,
  numSamples_880_32000,
  numSamples_880_44100,
  numSamples_880_48000,
};


//  Indices and limits into rows of samples
unsigned 7 i_440   = 0; //  Index in row
unsigned 6 i_880   = 0;
unsigned 7 max_440 = 0; //  End of row ...
unsigned 6 max_880 = 0; //  ... depends on sample rate.

//  Which sampling rate to use
unsigned 3 which_rate = 6; // Default is 48K
sema       rateGuard;     //  For protecting above


//  Volume and mute controls for RC200 AudioOut
static unsigned 5 volume  = 0b00000;
static unsigned 1 mute    = 1;


//  main() - FSM
//  ------------------------------------------------------------------
/*
 *    This module manages a state machine for the device.  The state
 *    consists of two values, a volume setting and the sampling rate.
 *
 *    Volume values range from 0 to 31, corresponding to each of
 *    the non-muted values for RC200AudioOutSetVolume().  The value
 *    increases by one for each press of the right (lower) button.
 *
 *    Sampling rates range from 0 to 6, which serve as an index into
 *    the seven sampling rates possible.  The value increases by 1 for
 *    each press of the left button.
 *
 *    The hex displays show the current state at all times:  The right
 *    display shows the volume, with the left decimal point on for
 *    values > 15.  The left display shows the index of the sampling
 *    rate.
 *
 *    The output is muted/unmuted every 5 sec.
 *    The right decimal point is off when the output is muted
 *
 *    b0 is the left button and b1 is the right button.
 *
 *    This FSM module also manages volume control settings for the
 *    audio out device.
 *
 */
  void main( void )
  {
    unsigned 1 b0_prev, b1_prev, b0, b1;

    b0_prev = 0;
    b1_prev = 0;

    par
    {
      RC200AudioRun( RC200_ACTUAL_CLOCK_RATE );
      seq
      {
      }
      while ( true )
      {
        milli_delay( 5000 );
        mute = 0; //  TEMP: disable cycling value of mute every 5 sec
        RC200AudioOutSetVolume( mute,  ~volume, ~volume );
      }

      while ( true )
      {

        //  Read buttons
        par
        {
            b0 = RC200Button1Read();
            b1 = RC200Button0Read();
        }

        //  Check for a new button presses
        par
        {
          //  Check if Sampling Rate button was just pressed.
          if ( b0 && ( b0 != b0_prev ) )
          {
            //  Change sampling rate.  Use a semaphore (with visual
            //  feedback) to prevent this and the generator function
            //  from accessing the sampling parameters at the same time.
            while ( trysema(rateGuard) == 0 ) delay;
            RC200LEDWrite( 0, 1 );
            which_rate = ( which_rate == 6 ) ? 0 : which_rate + 1;
            par
            {
              max_440 = numSamples_440[ which_rate ];
              max_880 = numSamples_880[ which_rate ];

              switch ( which_rate )
              {
                case 0:
                  RC200AudioOutSetSampleRate( RC200AudioSampleRate8000  );
                  break;
                case 1:
                  RC200AudioOutSetSampleRate( RC200AudioSampleRate11025 );
                  break;
                case 2:
                  RC200AudioOutSetSampleRate( RC200AudioSampleRate16000 );
                  break;
                case 3:
                  RC200AudioOutSetSampleRate( RC200AudioSampleRate22050 );
                  break;
                case 4:
                  RC200AudioOutSetSampleRate( RC200AudioSampleRate32000 );
                  break;
                case 5:
                  RC200AudioOutSetSampleRate( RC200AudioSampleRate44100 );
                  break;
                case 6:
                  RC200AudioOutSetSampleRate( RC200AudioSampleRate48000 );
                  break;
                default:
                  RC200AudioOutSetSampleRate( RC200AudioSampleRate48000 );
                  break;
              }
            }
            milli_delay( 100 ); //  So the LED can be seen.
            RC200LEDWrite( 0, 0 );
            releasesema( rateGuard );
          }

          //  Check if Volume Button was just pressed.
          if ( b1 && ( b1 != b1_prev ) )
          {
            //  Change volume
            volume++;
            RC200AudioOutSetVolume( mute,  ~volume, ~volume );
          }
        }

        //  Update button states and 7-seg displays
        par
        {
          b0_prev = b0;
          b1_prev = b1;
          RC200SevenSeg0WriteDigit( 0@which_rate, volume \\ 4 );
          RC200SevenSeg1WriteDigit( volume <- 4, ~mute );
        }
        milli_delay( 50 );  //  Debounce time for buttons
      }
    }
  }


//  main() - Generate Tones
//  ------------------------------------------------------------------
/*
 *    This is the tone generator module.
 */
  void main( void )
  {

    max_440 = numSamples_440[ which_rate ];
    max_880 = numSamples_880[ which_rate ];
    i_440   = 0; //  Index in row
    i_880   = 0;

    //  Wait for device to initialize, and set initial volume.
    milli_delay( 300 );  //  Ad hoc value used because it works.
    RC200AudioOutSetVolume( mute,  ~volume, ~volume );

    //  Generate a tone intensity, depending on FSM control.
    while ( true )
    {
      //  Critical section protected by semaphore so paramters won't
      //  be used while in an inconsistent state.
      RC200LEDWrite( 1, 1 );  //  Usually too fast to see.
      while ( trysema( rateGuard ) == 0 ) delay;
      RC200LEDWrite( 1, 0 );
      //  Write next sample to both audio channels
      RC200AudioOutWrite( samples_440[ which_rate ][ i_440 ],
                          samples_880[ which_rate ][ i_880 ] );

      //  Update indices
      par
      {
        i_440++;
        i_880++;
      }
      par
      {
        //  Increment indices modulo current row lengths.
        if ( i_440 == max_440 )
        {
          i_440 = 0;
        }
        if ( i_880 == max_880 )
        {
          i_880 = 0;
        }
      }
      releasesema( rateGuard );
    }
  }