Logo Search packages:      
Sourcecode: xdemorse version File versions  Download package

display.c

/*  display.c
 *
 *  Display functions for xdemorse application
 */

/*
 *  xdemorse: An application to decode Morse code signals to text
 *
 *  Copyright (C) 2002  Neoklis Kyriazis
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License as
 *  published by the Free Software Foundation; either version 2 of
 *  the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details:
 *
 *  http://www.gnu.org/copyleft/gpl.txt
 */


#include "xdemorse.h"

/* Signal scope */
extern GtkWidget
  *gbl_waterfall,
  *gbl_scope;

/* Unit element as fragments/element */
extern int unit_elem;

/* fft in/out buffers */
extern int
  *fft_in_r,
  *fft_out_r,
  *fft_out_i;

/* Average bin values */
int gbl_bin_ave[FFT_SIZE/2];

/* Waterfall window pixbuf */
extern GdkPixbuf *gbl_wfall_pixbuf;
extern guchar *gbl_wfall_pixels;
extern gint
  gbl_wfall_rowstride,
  gbl_wfall_n_channels,
  gbl_wfall_width,
  gbl_wfall_height;

/* Runtime config data */
extern rc_data_t rc_data;

/*------------------------------------------------------------------------*/

/*  Display_Detector()
 *
 *  Updates the Detector scope display
 */

  void
Display_Detector( int plot )
{
  /* Points to plot */
  static GdkPoint points[256];
  static int points_idx = 0;
  int temp;

  /* Save values to be plotted  */
  points[points_idx].y = 87 - plot;
  if( points[points_idx].y < 3 )
      points[points_idx].y = 3;
  if( points[points_idx].y > 87 )
      points[points_idx].y = 87;
  points[points_idx].x = points_idx+3;

  /* Recycle buffer idx when full and plot */
  if( ++points_idx == 256 )
  {
      /* Draw scope background */
      gdk_draw_rectangle( gbl_scope->window,
            gbl_scope->style->white_gc,
            TRUE, 4, 3, 255, 85 );

      /* Draw scope frame */
      gdk_draw_rectangle( gbl_scope->window,
            gbl_scope->style->black_gc,
            FALSE, 3, 2, 256, 86 );

      /* Plot signal graph */
      gdk_draw_lines( gbl_scope->window,
            gbl_scope->style->black_gc,
            points, 256 );

      points_idx = 0;

      /* Draw Mark/Space threshold references */
      temp = 87 - (84*rc_data.det_thr)/100;
      gdk_draw_line( gbl_scope->window,
            gbl_scope->style->black_gc,
            3, temp, 258, temp );

  } /* if( ++points_idx == 256 ) */

} /* Display_Detector() */

/*------------------------------------------------------------------------*/

/*  Display_Signal()
 *
 *  Updates the Signal scope display
 */

  void
Display_Signal( int plot )
{
  /* Points to plot */
  static GdkPoint points[256];
  static int points_idx = 0;


  /* Save values to be plotted (SCALED) */
  points[points_idx].y = 86 - plot/64;
  if( points[points_idx].y < 3 )
      points[points_idx].y = 3;
  points[points_idx].x = points_idx+3;

  /* Recycle buffer idx when full and plot */
  if( ++points_idx == 256 )
  {
      /* Draw scope background */
      gdk_draw_rectangle( gbl_scope->window,
            gbl_scope->style->white_gc,
            TRUE, 4, 3, 255, 85 );

      /* Draw scope frame */
      gdk_draw_rectangle( gbl_scope->window,
            gbl_scope->style->black_gc,
            FALSE, 3, 2, 256, 86 );

      /* Plot signal graph */
      gdk_draw_lines( gbl_scope->window,
            gbl_scope->style->black_gc,
            points, 256 );

      points_idx = 0;

  } /* if( ++points_idx == DRAWABLE_LEN ) */

} /* Display_Signal */

/*------------------------------------------------------------------------*/

/* Display_Waterfall()
 *
 * Displays audio spectrum as "waterfall"
 */

  void
Display_Waterfall(void)
{
  int
      idh, idv,  /* Index to hor. and vert. position in warterfall */
      pixel_val, /* Greyscale value of pixel derived from fft o/p  */
      fft_idx;   /* Index to fft output array */

  /* Constant needed to draw red line in waterfall */
  static int red_line = WFALL_WIDTH/2;

  int
      bin_val, /* Value of fft output "bin" */
      bin_max; /* Maximum value of fft bins */

  /* Sliding window average of bin max values */
  static int ave_max = 1000;

  /* Pointer to current pixel */
  static guchar *pix;

  /* Draw a vertical red line in waterfall at detector's freq. */
  pix = gbl_wfall_pixels + gbl_wfall_rowstride + gbl_wfall_n_channels;
  pix += gbl_wfall_n_channels * red_line;
  pix[0] = 0xff;
  pix[1] = pix[2] = 0;

  /* Copy each line of waterfall to next one */
  for( idv = gbl_wfall_height-2; idv > 0; idv-- )
  {
      pix = gbl_wfall_pixels + gbl_wfall_rowstride * idv + gbl_wfall_n_channels;

      for( idh = 0; idh < WFALL_WIDTH; idh++ )
      {
        pix[0] = pix[ -gbl_wfall_rowstride];
        pix[1] = pix[1-gbl_wfall_rowstride];
        pix[2] = pix[2-gbl_wfall_rowstride];
        pix += gbl_wfall_n_channels;
      }
  }

  /* Got to top left +1 hor. +1 vert. of pixbuf */
  pix = gbl_wfall_pixels + gbl_wfall_rowstride + gbl_wfall_n_channels;

  /* First column of display (DC) not used */
  gbl_bin_ave[0] = 0;

  /* Do the FFT on input array */
  Ifft( FFT_SIZE );
  bin_max = 0;
  for( fft_idx = 0; fft_idx < FFT_SIZE/2; fft_idx++ )
  {
      /* Calculate signal power at each frequency (bin) */
      fft_out_r[fft_idx] /=8;
      fft_out_i[fft_idx] /=8;
      bin_val =
        fft_out_r[fft_idx]*fft_out_r[fft_idx] +
        fft_out_i[fft_idx]*fft_out_i[fft_idx];

      /* Calculate average bin values */
      gbl_bin_ave[fft_idx] = ( (gbl_bin_ave[fft_idx] *
              (BINMAX_AVE_WIN-1) + bin_val) / BINMAX_AVE_WIN );

      /* Record max bin value */
      if( bin_max < bin_val )
        bin_max = bin_val;

      /* Scale pixel values to 255 depending on ave max value */
      pixel_val = (255 * bin_val) / ave_max;
      if( pixel_val > 255 ) pixel_val = 255;

      int lim = (2*WFALL_WIDTH)/FFT_SIZE;
      /* Duplicate pixels if fft size < waterfall width */
      for( idh = 0; idh < lim; idh++ )
      {
        /* Reverse video is toggled by right click on waterfall */
        if( isFlagSet(REVERSE_VIDEO) )
            pix[0] = pix[1] = pix[2] = pixel_val;
        else
            pix[0] = pix[1] = pix[2] = 255 - pixel_val;

        pix += gbl_wfall_n_channels;
      }

  } /* for( fft_idx = 0; fft_idx < fft_end; fft_idx++ ) */

  /* Calculate sliding window average of max bin value */
  ave_max = (ave_max*(BINMAX_AVE_WIN-1) + bin_max)/BINMAX_AVE_WIN;
  if( !ave_max ) ave_max = 1;

  /* At last draw waterfall */
  gtk_widget_queue_draw( gbl_waterfall );

} /* Display_Waterfall() */

/*------------------------------------------------------------------------*/

/*  Clear_Pixbuf()
 *
 *  Initializes pixbuf of Waterfall window
 */

  void
Clear_Pixbuf( void )
{
  int i;
  guchar *p1, *p2;

  gdk_pixbuf_fill( gbl_wfall_pixbuf, 0xffffffff );

  /* Draw a box around pixbuf */
  p1 = gbl_wfall_pixels;
  p2 = gbl_wfall_pixels + (gbl_wfall_height-1)*gbl_wfall_rowstride;
  for( i = 0; i < gbl_wfall_width; i++ )
  {
      p1[0] = p1[1] = p1[2] = 0;
      p1 += gbl_wfall_n_channels;
      p2[0] = p2[1] = p2[2] = 0;
      p2 += gbl_wfall_n_channels;
  }

  p1 = gbl_wfall_pixels+gbl_wfall_rowstride;
  p2 = gbl_wfall_pixels+gbl_wfall_rowstride + (gbl_wfall_width-1)*gbl_wfall_n_channels;
  for( i = 0; i < gbl_wfall_height-1; i++ )
  {
      p1[0] = p1[1] = p1[2] = 0;
      p1 += gbl_wfall_rowstride;
      p2[0] = p2[1] = p2[2] = 0;
      p2 += gbl_wfall_rowstride;
  }

  gtk_widget_queue_draw( gbl_waterfall );

} /* Clear_Pixbuf() */

/*------------------------------------------------------------------------*/


Generated by  Doxygen 1.6.0   Back to index