annotate model/image.c @ 0:5242703e91d3 tip

Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author tomwalters
date Fri, 20 May 2011 15:19:45 +0100
parents
children
rev   line source
tomwalters@0 1 /*
tomwalters@0 2 SCCS VERSION 1.29 WITH 1.28 STRIPPED OUT.
tomwalters@0 3
tomwalters@0 4
tomwalters@0 5
tomwalters@0 6 Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989
tomwalters@0 7 ===========================================================================
tomwalters@0 8
tomwalters@0 9 Permission to use, copy, modify, and distribute this software without fee
tomwalters@0 10 is hereby granted for research purposes, provided that this copyright
tomwalters@0 11 notice appears in all copies and in all supporting documentation, and that
tomwalters@0 12 the software is not redistributed for any fee (except for a nominal shipping
tomwalters@0 13 charge). Anyone wanting to incorporate all or part of this software in a
tomwalters@0 14 commercial product must obtain a license from the Medical Research Council.
tomwalters@0 15
tomwalters@0 16 The MRC makes no representations about the suitability of this
tomwalters@0 17 software for any purpose. It is provided "as is" without express or implied
tomwalters@0 18 warranty.
tomwalters@0 19 */
tomwalters@0 20
tomwalters@0 21 /***************************************************************************
tomwalters@0 22 * image.c Version with trigger at right end of sai.
tomwalters@0 23 * =======
tomwalters@0 24 * Input data derived from a cochleagram is used to construct a stabilised
tomwalters@0 25 * auditory image (sai) of size `chans' * `framewidth' points.
tomwalters@0 26 *
tomwalters@0 27 * Organisation of data.
tomwalters@0 28 * Data is 2-dimensional: in time (rows) and frequency (columns).
tomwalters@0 29 *
tomwalters@0 30 * Input data is ordered by columns. The input array consists of blocks (columns)
tomwalters@0 31 * of `chans' points, each column being one time sample of `chans' channels.
tomwalters@0 32 * The zero'th point in each column is the lowest frequency channel.
tomwalters@0 33 *
tomwalters@0 34 * Output (sai) data is ordered by rows. The output array consists of blocks
tomwalters@0 35 * (rows) of `framewidth' points.
tomwalters@0 36 * The zero'th point in each row is the "oldest" time, as the time origin is
tomwalters@0 37 * on the right edge of the sai.
tomwalters@0 38 *
tomwalters@0 39 * Each sai is called a `frame', and its dimensions are `chans' rows by
tomwalters@0 40 * `framewidth' columns. In the code, the `framewidth' is often represented
tomwalters@0 41 * as imagewidth/chans, where imagewidth is the total amount of data in an
tomwalters@0 42 * sai frame, (ie. imagewidth=chans*framewidth).
tomwalters@0 43
tomwalters@0 44 * This module has been modified to have 5 levels of strobing.
tomwalters@0 45 A Jay Datta 6/03/95
tomwalters@0 46 ***************************************************************************/
tomwalters@0 47
tomwalters@0 48 #include <math.h>
tomwalters@0 49 #include <string.h>
tomwalters@0 50
tomwalters@0 51 #include "options.h"
tomwalters@0 52 #include "stitch.h"
tomwalters@0 53 #include "source.h"
tomwalters@0 54 #include "model.h"
tomwalters@0 55 #include "units.h"
tomwalters@0 56 #include "image.h"
tomwalters@0 57 #include "calc.h"
tomwalters@0 58
tomwalters@0 59 #define MAX_BUFFER (1l<<15)
tomwalters@0 60
tomwalters@0 61 #ifdef FLOAT
tomwalters@0 62 #define INPUT_SCALE 0.25
tomwalters@0 63 #define DECAY_SCALE 0.875
tomwalters@0 64 #else
tomwalters@0 65 #define INPUT_SHIFT 2
tomwalters@0 66 #define DECAY_ROUND 7
tomwalters@0 67 #endif
tomwalters@0 68 #define DECAY_SHIFT 3
tomwalters@0 69
tomwalters@0 70 #define MAXCHAN 1000
tomwalters@0 71
tomwalters@0 72 #ifndef lint
tomwalters@0 73 static char *sccs_id = "@(#)image.c 1.27 J. Holdsworth, M. Allerhand (MRC-APU) 6/6/91" ;
tomwalters@0 74 #endif
tomwalters@0 75
tomwalters@0 76 #ifdef DSP32
tomwalters@0 77 static int segsize = 16 ;
tomwalters@0 78 #else
tomwalters@0 79 static int segsize = 50 ;
tomwalters@0 80 #endif
tomwalters@0 81
tomwalters@0 82 typedef enum { False, True } Bool ;
tomwalters@0 83 typedef struct Node{int index; short val; struct Node *next;} node;
tomwalters@0 84
tomwalters@0 85 static void doColumn();
tomwalters@0 86 static Pointer sai_callback();
tomwalters@0 87 static Pointer summary_callback();
tomwalters@0 88 static void save_callback();
tomwalters@0 89 static void addIn();
tomwalters@0 90 static void decayImage();
tomwalters@0 91
tomwalters@0 92 void output_simple_strobe_info();
tomwalters@0 93 void doList_strobe_info();
tomwalters@0 94 void output_thresh_info();
tomwalters@0 95 void decay_strobe_threshold();
tomwalters@0 96 void print_trigger_debugging_info();
tomwalters@0 97
tomwalters@0 98 void initlist();
tomwalters@0 99 node *getnode();
tomwalters@0 100 node *insertl();
tomwalters@0 101 void inss();
tomwalters@0 102
tomwalters@0 103 FILE *trigger_file;
tomwalters@0 104 FILE *infotxt_file;
tomwalters@0 105 FILE *thresho_file;
tomwalters@0 106
tomwalters@0 107 int locmax_searchtime[MAXCHAN];
tomwalters@0 108 int locmax_searchstart[MAXCHAN];
tomwalters@0 109 int val[MAXCHAN];
tomwalters@0 110 int ltime[MAXCHAN];
tomwalters@0 111 int initial_strobe_candidate_time[MAXCHAN];
tomwalters@0 112 int ttime[MAXCHAN];
tomwalters@0 113
tomwalters@0 114 static node *start, *endl, *pp, *qq;
tomwalters@0 115 static char *exposwitch;
tomwalters@0 116
tomwalters@0 117 #ifdef FLOAT
tomwalters@0 118 float *S;
tomwalters@0 119 #else
tomwalters@0 120 short *S;
tomwalters@0 121 #endif
tomwalters@0 122
tomwalters@0 123
tomwalters@0 124 /***************************************************************************
tomwalters@0 125 * struct _sai_state:
tomwalters@0 126 * The source->info->state structure which is initialised by the
tomwalters@0 127 * routine Sai, and is then the state argument for the callback
tomwalters@0 128 * function: sai_callback.
tomwalters@0 129 ***************************************************************************/
tomwalters@0 130 struct _sai_state {
tomwalters@0 131 struct _pullable_source parent ;
tomwalters@0 132 Source source;
tomwalters@0 133 void (*trigger)(); /* trigger algorithm (originally doColumn) */
tomwalters@0 134 unsigned chans; /* number of filter channels */
tomwalters@0 135 unsigned framestep; /* sai display update period */
tomwalters@0 136 DataType *image; /* sai array (DataType = short) */
tomwalters@0 137 unsigned imagewidth; /* length of sai array (framewidth*chans) */
tomwalters@0 138 unsigned imagenwidth; /* portion of sai array for transient info */
tomwalters@0 139 unsigned decay_time; /* a factor of sai decay time constant */
tomwalters@0 140 unsigned decay_count;
tomwalters@0 141 ScalarType *framedecay; /* array of factors for cochleagram frame */
tomwalters@0 142 int *cps; /* array of 1/centre-freq (in samples) */
tomwalters@0 143 int *isPulse; /* array of bools, to see if data > thres */
tomwalters@0 144
tomwalters@0 145 int Stcrit; /* int restriction */
tomwalters@0 146 int SusThresh; /* Level 2 user settable thresh */
tomwalters@0 147 ScalarType triggerdecay; /* prop/point decay for strobe threshold */
tomwalters@0 148 int *trigtime; /* time of last trigger pulse */
tomwalters@0 149 int *trigheight; /* height of last trigger pulse */
tomwalters@0 150 int *isStrobe; /* array of booleans, set when pulse peak found */
tomwalters@0 151 float *thresh; /* array of thresholds, one per channel */
tomwalters@0 152 float *tlim; /* linear decay value */
tomwalters@0 153 int time; /* keep track of sai */
tomwalters@0 154 int *previnput; /* lock till new pulse found */
tomwalters@0 155 int *def_strobe_candidate_time;
tomwalters@0 156 int *def_strobe_height;
tomwalters@0 157 char *switch_info;
tomwalters@0 158 int tlim1;
tomwalters@0 159 int stlag; /* strobe nwid first attempt to decouple nwids */
tomwalters@0 160 };
tomwalters@0 161
tomwalters@0 162 /***************************************************************************
tomwalters@0 163 * Sai:
tomwalters@0 164 * Sai is called from SaiEntry (in module model.c).
tomwalters@0 165 * Routines in this module it uses are:
tomwalters@0 166 * doColumn, (which uses: addIn)
tomwalters@0 167 * sai_callback, (which uses: decayImage)
tomwalters@0 168 *
tomwalters@0 169 * SaiEntry (in model.c) is the entry-point function to the stabilised image
tomwalters@0 170 * processing module. Its purpose is to prepare the arguments for Sai by
tomwalters@0 171 * converting parameter-option strings to integers, and then to call Sai.
tomwalters@0 172 *
tomwalters@0 173 * Sai is called with the following arguments (in model.c):
tomwalters@0 174 * Sai( source, Frameheight(), segment, width,
tomwalters@0 175 * (int) Samples( decaystr )/Framestep(), (int) Freq( samplestr ),
tomwalters@0 176 * frequencies, Samples(ttstr)/Framestep(), Samples(cgmstr)/Framestep(),
tomwalters@0 177 * (int) Freq("250Hz"), (int) Freq("20Hz") ) ;
tomwalters@0 178 *
tomwalters@0 179 * The arguments are as follows:
tomwalters@0 180 * (The option name refers to the description given by "help". The values etc
tomwalters@0 181 * can be found in table.c as described in model.docs).
tomwalters@0 182 *
tomwalters@0 183 * Argument Option name Default Comment
tomwalters@0 184 * -------- ----------- ------- -------
tomwalters@0 185 * chans (see below) Number of filter channels
tomwalters@0 186 * framestep segment_sai 16ms SAI display update period
tomwalters@0 187 * framewidth duration_sai 32ms SAI duration (ms)
tomwalters@0 188 * decay decayrate_sai 32ms SAI decay time constant (SU/ms) 15ms NOW Default
tomwalters@0 189 * samplerate samplerate 20000. Input wave sample rate (Hz)
tomwalters@0 190 * cfs (see below) An array of filter centre frequencies
tomwalters@0 191 * cgmdecay napdecay_sai 16ms NAP (ie cochleagram) decay time constant
tomwalters@0 192 *
tomwalters@0 193 * Both "chans" and "cfs" are setup from the routine "updateFrequencies" in
tomwalters@0 194 * model.c, because both arguments are derived from three basic parameters:
tomwalters@0 195 *
tomwalters@0 196 * minstr mincf_afb 220Hz Minimum center frequency (Hz)
tomwalters@0 197 * maxstr maxcf_afb 4400Hz Maximum center frequency (Hz)
tomwalters@0 198 * denstr dencf_afb 4. Filter density (filters/critical band)
tomwalters@0 199 *
tomwalters@0 200 * The "chans" argument is calculated in the routine "NumberCenterFrequencies",
tomwalters@0 201 * and the result is copied into the "frameheightstr" by a call to the routine
tomwalters@0 202 * "setFrameheight".
tomwalters@0 203 * The "cfs" argument is calculated in the routine "GenerateCenterFrequencies".
tomwalters@0 204 * (Both CenterFrequency routines are in gamma_tone.c).
tomwalters@0 205 *
tomwalters@0 206 ***************************************************************************/
tomwalters@0 207
tomwalters@0 208 Source Sai(source, chans, framestep, pwidth, nwidth, decay, samplerate, cfs, ttdecay, cgmdecay, tlim1, tlim2, suslevel, susthresh, switchinfo, expoSwitch,stlag)
tomwalters@0 209 Source source ;
tomwalters@0 210 int chans, framestep, pwidth, nwidth, decay ;
tomwalters@0 211 int samplerate;
tomwalters@0 212 double *cfs ;
tomwalters@0 213 double ttdecay, cgmdecay ;
tomwalters@0 214 int tlim1, tlim2;
tomwalters@0 215 int suslevel;
tomwalters@0 216 char *susthresh;
tomwalters@0 217 char *switchinfo;
tomwalters@0 218 char *expoSwitch;
tomwalters@0 219 int stlag;
tomwalters@0 220 {
tomwalters@0 221
tomwalters@0 222 DeclareNew( struct _sai_state *, state ) ;
tomwalters@0 223 int i, chan, startup, segment, framewidth ;
tomwalters@0 224 double pts_per_ms, lin_napdec, lin_napfac ; /* roy 11-8-92 roy */
tomwalters@0 225 char *ThreshoFile, *InfotxtFile, *TriggerFile;
tomwalters@0 226
tomwalters@0 227 exposwitch=(char *)calloc(5, sizeof(char));
tomwalters@0 228 exposwitch=expoSwitch;
tomwalters@0 229
tomwalters@0 230 ThreshoFile = (char *)calloc(256, sizeof(char));
tomwalters@0 231 InfotxtFile = (char *)calloc(256, sizeof(char));
tomwalters@0 232 TriggerFile = (char *)calloc(256, sizeof(char));
tomwalters@0 233
tomwalters@0 234 state->switch_info = (char *)calloc(256,sizeof(char));
tomwalters@0 235 state->switch_info = switchinfo;
tomwalters@0 236
tomwalters@0 237 if (!strcmp(susthresh, "on"))
tomwalters@0 238 state->SusThresh=0;
tomwalters@0 239 else if (!strcmp(susthresh, "off"))
tomwalters@0 240 state->SusThresh=1;
tomwalters@0 241 else
tomwalters@0 242 state->SusThresh=atoi(susthresh);
tomwalters@0 243
tomwalters@0 244 if (!strcmp(state->switch_info, "off"))
tomwalters@0 245 ;
tomwalters@0 246 else if (!strcmp(state->switch_info, "on"))
tomwalters@0 247 infotxt_file=stdout;
tomwalters@0 248 else{
tomwalters@0 249 strcpy(InfotxtFile, switchinfo);
tomwalters@0 250 strcat(InfotxtFile, ".info");
tomwalters@0 251 infotxt_file=fopen(InfotxtFile, "w");
tomwalters@0 252
tomwalters@0 253 strcpy(TriggerFile, switchinfo);
tomwalters@0 254 strcat(TriggerFile, ".trigger");
tomwalters@0 255 trigger_file=fopen(TriggerFile, "w");
tomwalters@0 256
tomwalters@0 257 strcpy(ThreshoFile, switchinfo);
tomwalters@0 258 strcat(ThreshoFile, ".thresh");
tomwalters@0 259 thresho_file=fopen(ThreshoFile, "w");
tomwalters@0 260 }
tomwalters@0 261
tomwalters@0 262 initlist();
tomwalters@0 263 state->tlim1=0;
tomwalters@0 264
tomwalters@0 265 framewidth = pwidth+nwidth;
tomwalters@0 266
tomwalters@0 267 pts_per_ms = (double)samplerate/1000 ;
tomwalters@0 268
tomwalters@0 269 state->stlag=stlag; /* NEW line 95April */
tomwalters@0 270 /* Initialise members of the sai state structure */
tomwalters@0 271 state->source = NewRetainingSource( source, sizeof ( DataType ) * framewidth * chans ) ;
tomwalters@0 272 state->chans = chans ;
tomwalters@0 273 state->trigger = doColumn ;
tomwalters@0 274 state->framestep = framestep * chans ;
tomwalters@0 275 state->imagewidth = framewidth * chans ; /* size of sai buffer */
tomwalters@0 276 state->imagenwidth = nwidth * chans ; /* size of buffer for transient info */
tomwalters@0 277 state->decay_time = decay * -log( 1. - 1. / ( 1 << DECAY_SHIFT ) ) ;
tomwalters@0 278 state->decay_count = state->decay_time ;
tomwalters@0 279
tomwalters@0 280 state->Stcrit = suslevel;
tomwalters@0 281 if (stlag==0 && state->Stcrit==5) /* was nwid NEW */
tomwalters@0 282 state->Stcrit = suslevel-1;
tomwalters@0 283
tomwalters@0 284 /* state->SusThresh = susthresh; */
tomwalters@0 285
tomwalters@0 286 if (!strcmp(exposwitch, "on")) fprintf(stderr, "Exponential trigger decay SWITCH is ON\n");
tomwalters@0 287 /* if (!strcmp(exposwitch, "off")) printf("SWITCH is OFF\n"); */
tomwalters@0 288
tomwalters@0 289 if (!strcmp(exposwitch, "on"))
tomwalters@0 290 state->triggerdecay = (double) 1-((ttdecay / pts_per_ms ) /100.0) ;
tomwalters@0 291 else
tomwalters@0 292 state->triggerdecay = (double) (ttdecay /pts_per_ms) / 100.0 ;
tomwalters@0 293
tomwalters@0 294 if (!strcmp(switchinfo, "off"))
tomwalters@0 295 ;
tomwalters@0 296 else
tomwalters@0 297 fprintf(infotxt_file, "\ntriggerdecay = %15e\n", state->triggerdecay);
tomwalters@0 298
tomwalters@0 299 state->isStrobe = NewZeroedArray( int, state->chans, "image.c for Strobe" ) ;
tomwalters@0 300 state->isPulse = NewZeroedArray( int, state->chans, "image.c for trigger pulse" ) ;
tomwalters@0 301 state->trigtime = NewZeroedArray( int, state->chans, "image.c for trigger time" ) ;
tomwalters@0 302 state->trigheight = NewZeroedArray( int, state->chans, "image.c for trigger height" ) ;
tomwalters@0 303 state->thresh = NewZeroedArray( float, state->chans, "image.c for thresh" ) ;
tomwalters@0 304 state->tlim = NewZeroedArray( float, state->chans, "image.c for decay" ) ;
tomwalters@0 305 state->time = 0; /* Time initialized to Zero */
tomwalters@0 306 state->previnput = NewZeroedArray( int, state->chans, "image.c for pulse lock" ) ;
tomwalters@0 307
tomwalters@0 308 state->def_strobe_candidate_time = NewZeroedArray( int, state->chans, "image.c for prevtrig time" );
tomwalters@0 309 state->def_strobe_height = NewZeroedArray( int, state->chans, "image.c for prev trig" );
tomwalters@0 310
tomwalters@0 311 for (chan=0; chan < MAXCHAN; chan++)
tomwalters@0 312 locmax_searchtime[chan]=0;
tomwalters@0 313 for (chan=0; chan < MAXCHAN; chan++)
tomwalters@0 314 locmax_searchstart[chan]=0;
tomwalters@0 315 for (chan=0; chan < MAXCHAN; chan++)
tomwalters@0 316 val[chan]=0;
tomwalters@0 317 for (chan=0; chan < MAXCHAN; chan++)
tomwalters@0 318 initial_strobe_candidate_time[chan]=0;
tomwalters@0 319 for (chan=0; chan < MAXCHAN; chan++)
tomwalters@0 320 ltime[chan]=0;
tomwalters@0 321 for (chan=0; chan < MAXCHAN; chan++)
tomwalters@0 322 ttime[chan]=0;
tomwalters@0 323
tomwalters@0 324 #ifdef FLOAT
tomwalters@0 325 S=(float *)calloc(state->chans, sizeof(float));
tomwalters@0 326 #else
tomwalters@0 327 S=(short *)calloc(state->chans, sizeof(short));
tomwalters@0 328 #endif
tomwalters@0 329
tomwalters@0 330 /* Declare new arrays for members of state structure */
tomwalters@0 331
tomwalters@0 332 state->framedecay = NewArray( ScalarType, framewidth, "image.c for decay" ) ;
tomwalters@0 333 state->image = NewZeroedArray( DataType, state->imagewidth, "image.c for image" ) ;
tomwalters@0 334 state->cps = NewZeroedArray( int, state->chans, "image.c for channel centre periods" ) ;
tomwalters@0 335
tomwalters@0 336 /* Initialise cochleagram frame decay factors */
tomwalters@0 337 if (cgmdecay > 0)
tomwalters@0 338 {
tomwalters@0 339 /* 11111 roy 11-8-92 These mods change to a linear nap decay. 1111111 roy */
tomwalters@0 340 /* It requires pts_per_ms, lin_napdec and lin_napfac declared just after DeclareNew above */
tomwalters@0 341
tomwalters@0 342 lin_napdec = ((cgmdecay/100)/pts_per_ms)/pts_per_ms ; /* roy 19-8 roy */
tomwalters@0 343
tomwalters@0 344 /* cgmdecay is div by pts_per_ms to get back to napdecay in the original units */
tomwalters@0 345 /* When napdecay is interpreted as the % to decay per ms, and since we are */
tomwalters@0 346 /* operating in points, we need napdec/pts_per_ms, as the dec for each pt within the ms */
tomwalters@0 347 /* The decay vector is set to scale the NAP by 1.0 at strobe point. So, in the sai, */
tomwalters@0 348 /* it falls to the left AND RISES to the right of 0 ms. **** roy **** */
tomwalters@0 349
tomwalters@0 350 lin_napfac = 1.0 + nwidth*lin_napdec ;
tomwalters@0 351
tomwalters@0 352 for (i=0 ; i < framewidth ; i++)
tomwalters@0 353 {
tomwalters@0 354 if ( lin_napfac > 0 )
tomwalters@0 355 state->framedecay[i] = SCALAR( lin_napfac );
tomwalters@0 356 else
tomwalters@0 357 state->framedecay[i] = SCALAR( 0 );
tomwalters@0 358 lin_napfac -= lin_napdec ;
tomwalters@0 359 }
tomwalters@0 360 }
tomwalters@0 361 else /* disable decay factor on zero argument */
tomwalters@0 362 for (i=0 ; i < framewidth ; i++)
tomwalters@0 363 state->framedecay[i] = SCALAR( 1.0 ) ;
tomwalters@0 364
tomwalters@0 365 /* Initialise centre-period for each channel */
tomwalters@0 366 for (i=0 ; i < state->chans ; i++)
tomwalters@0 367 state->cps[i] = samplerate / cfs[i];
tomwalters@0 368
tomwalters@0 369 #if defined( PC ) || defined( THINK_C )
tomwalters@0 370 if( (long) ( MAX_BUFFER - (long) state->imagewidth * sizeof ( DataType ) ) < (long) ( state->chans * sizeof ( DataType ) ) )
tomwalters@0 371 stitch_error( "Sorry, image larger than maximum buffer size\n" ) ;
tomwalters@0 372 #endif
tomwalters@0 373
tomwalters@0 374 /* for (i=0; i<state->imagewidth;i++)
tomwalters@0 375 fprintf(stderr, "Image Buffer is %f, count = %d\n", *(state->image+i), (i+1)); */
tomwalters@0 376
tomwalters@0 377
tomwalters@0 378
tomwalters@0 379 return ( SetPullableSource( state, sai_callback, "image.c stabilised image" ) ) ;
tomwalters@0 380 }
tomwalters@0 381
tomwalters@0 382 /****************************************************************************
tomwalters@0 383 * sai_callback
tomwalters@0 384 * The callback function at source->info->callback in the source
tomwalters@0 385 * returned by Sai.
tomwalters@0 386 * A "frame" is a window over the cochleagram, of size chans * points.
tomwalters@0 387 * A "segment" is a stretch of the cochleagram which is segsize (ie 50) time
tomwalters@0 388 * samples long, ie segsize columns of the cochleagram.
tomwalters@0 389 *
tomwalters@0 390 * This callback routine is executed once for each sai frame which is plotted.
tomwalters@0 391 * "*bytes" is the number of bytes in the sai, ie:
tomwalters@0 392 * *bytes = state->imagewidth * sizeof(DataType)
tomwalters@0 393 ****************************************************************************/
tomwalters@0 394 static Pointer sai_callback( state, bytes )
tomwalters@0 395 struct _sai_state *state ;
tomwalters@0 396 ByteCount *bytes ;
tomwalters@0 397 {
tomwalters@0 398 register long col, point ;
tomwalters@0 399 register long points = state->framestep; /* total num points under frame */
tomwalters@0 400 #if defined( PC )
tomwalters@0 401 int segment = ( MAX_BUFFER - state->imagewidth * sizeof ( DataType ) ) / state->chans / sizeof ( DataType ) * state->chans ;
tomwalters@0 402 #else
tomwalters@0 403 int segment = segsize * state->chans ;
tomwalters@0 404 #endif
tomwalters@0 405 register DataType *input ; /* cochleagram (input) data array */
tomwalters@0 406 static int first=1;
tomwalters@0 407 static int test=0;
tomwalters@0 408 int chan;
tomwalters@0 409 int i;
tomwalters@0 410 /* #if defined( PC )
tomwalters@0 411 test=1;
tomwalters@0 412 #else
tomwalters@0 413 if (state->SusThresh == 0)
tomwalters@0 414 segment= 30 * state->chans ;
tomwalters@0 415 #endif */
tomwalters@0 416
tomwalters@0 417 /* test++; */
tomwalters@0 418
tomwalters@0 419
tomwalters@0 420 /* If size argument is zero, then by convention free space and return null */
tomwalters@0 421 if( *bytes == 0 ) {
tomwalters@0 422 Pull( state->source, 0 ) ;
tomwalters@0 423 Delete( state->image ) ;
tomwalters@0 424 return ( DeletePullableSource( state ) ) ;
tomwalters@0 425 }
tomwalters@0 426
tomwalters@0 427 /* Initially pull enough data to buffer transient info ahead of the trigger */
tomwalters@0 428 /* Note, the pull operation is not valid when the size arg is zero. */
tomwalters@0 429 /* The result would be a segmentation fault on the next pull, below. */
tomwalters@0 430
tomwalters@0 431 if (state->Stcrit==0 || state->Stcrit==1 || state->Stcrit==2 || state->Stcrit==3)
tomwalters@0 432 if (first) {
tomwalters@0 433 if (state->imagenwidth > 0)
tomwalters@0 434 input = PullItems(state->source, state->imagenwidth, DataType);
tomwalters@0 435 first = 0;
tomwalters@0 436 }
tomwalters@0 437
tomwalters@0 438
tomwalters@0 439 /* Search frame in segment blocks for trigger-points */
tomwalters@0 440 for( point=0 ; point < points ; point += segment ) {
tomwalters@0 441 if( segment > points - point ) /* Finish at end of frame */
tomwalters@0 442 segment = points - point ;
tomwalters@0 443 /* Get one segment of the input data */
tomwalters@0 444 /* Pull 50 columns of data from the source, in buffer *input. */
tomwalters@0 445 /* Keep one sai of data, from last pull, in buffer behind *input */
tomwalters@0 446 input = PullItems(state->source, segment, DataType);
tomwalters@0 447
tomwalters@0 448 for( col=0 ; col < segment ; col += state->chans ) {
tomwalters@0 449 /* Retard the "current" data point by transient buffer width */
tomwalters@0 450 /* (This retards the trigger by the transient time, about 5ms) */
tomwalters@0 451 if (state->Stcrit==0 || state->Stcrit==1 || state->Stcrit==2 || state->Stcrit==3)
tomwalters@0 452 state->trigger(input-state->imagenwidth, state) ;
tomwalters@0 453 else{
tomwalters@0 454 state->trigger( input, state) ; /* -state->imagenwidth, state ) ; */
tomwalters@0 455 /*fprintf(stderr, " %d ", points) ; */ }
tomwalters@0 456 input += state->chans ; /* next column */
tomwalters@0 457 /* decay image periodically, once every `decay_time' columns */
tomwalters@0 458 /* Lines moved down */
tomwalters@0 459 if( --state->decay_count <= 0 ) {
tomwalters@0 460 decayImage( state ) ;
tomwalters@0 461 state->decay_count = state->decay_time ;
tomwalters@0 462 }
tomwalters@0 463 } /* for each col */
tomwalters@0 464 } /* for each seg */
tomwalters@0 465
tomwalters@0 466 /* whatever the number of bytes requested, the image is always this size */
tomwalters@0 467 *bytes = state->imagewidth * sizeof ( *state->image ) ;
tomwalters@0 468
tomwalters@0 469 /* if (state->Stcrit==1 && state->SusThresh==0){
tomwalters@0 470 if (test%5==0)
tomwalters@0 471 decayImage( state );
tomwalters@0 472 test++;}
tomwalters@0 473 else if (state->Stcrit==1 && state->SusThresh>0){ changed 2 to 3
tomwalters@0 474 if (test%10==0)
tomwalters@0 475 decayImage( state );
tomwalters@0 476 test++;}
tomwalters@0 477 else{ */
tomwalters@0 478
tomwalters@0 479 return ( (Pointer) state->image ) ;
tomwalters@0 480 }
tomwalters@0 481
tomwalters@0 482 /****************************************************************************
tomwalters@0 483 * decayImage
tomwalters@0 484 * Periodically attenuate image to give computationally efficient image decay.
tomwalters@0 485 * Attenuate all points in the sai by a constant factor.
tomwalters@0 486 ****************************************************************************/
tomwalters@0 487 static void decayImage( state )
tomwalters@0 488 struct _sai_state *state ;
tomwalters@0 489 {
tomwalters@0 490 register DataType *image_ptr, *image_end ;
tomwalters@0 491 #ifdef FLOAT
tomwalters@0 492 register FLOAT image_decay = DECAY_SCALE ;
tomwalters@0 493 #endif
tomwalters@0 494
tomwalters@0 495 image_end = state->image + state->imagewidth ; /* end of sai array */
tomwalters@0 496 #ifdef FLOAT
tomwalters@0 497 for( image_ptr=state->image ; image_ptr < image_end ; )
tomwalters@0 498 *image_ptr++ *= image_decay ;
tomwalters@0 499 #else
tomwalters@0 500 for( image_ptr=state->image ; image_ptr < image_end ; image_ptr++ )
tomwalters@0 501 *image_ptr -= *image_ptr + DECAY_ROUND >> DECAY_SHIFT ;
tomwalters@0 502 #endif
tomwalters@0 503 return ;
tomwalters@0 504 }
tomwalters@0 505
tomwalters@0 506 /****************************************************************************
tomwalters@0 507 * doColumn
tomwalters@0 508 * Trigger algorithm for Sai.
tomwalters@0 509 * Installed as source->info->state->trigger.
tomwalters@0 510 *
tomwalters@0 511 ****************************************************************************/
tomwalters@0 512 static void doColumn( input, state )
tomwalters@0 513 DataType *input ;
tomwalters@0 514 struct _sai_state *state ;
tomwalters@0 515 {
tomwalters@0 516
tomwalters@0 517 register int chan ;
tomwalters@0 518 float strobelag;
tomwalters@0 519 int s_lag;
tomwalters@0 520
tomwalters@0 521
tomwalters@0 522 short *STI;
tomwalters@0 523 static int check=0;
tomwalters@0 524 int storev;
tomwalters@0 525 char buf[2];
tomwalters@0 526 short stipts=-2000;
tomwalters@0 527 short zeroval=0;
tomwalters@0 528
tomwalters@0 529 STI=(short *)calloc(state->chans, sizeof(short));
tomwalters@0 530
tomwalters@0 531 strobelag = (double) (state->time)-(state->stlag);
tomwalters@0 532
tomwalters@0 533 s_lag=(state->time)-(state->stlag);
tomwalters@0 534
tomwalters@0 535 /* For each channel up column, add a row of data to sai if the */
tomwalters@0 536 /* current point is non-zero. Add the row from the current point */
tomwalters@0 537 /* plus state->imagenwidth, to display the transient (nwidth) info. */
tomwalters@0 538
tomwalters@0 539
tomwalters@0 540 /* 000000000000000000000000 stcrit 0000000000000000000000000000000000 */
tomwalters@0 541 /* Add on every point : Low Pass Filter */
tomwalters@0 542
tomwalters@0 543 if (state->Stcrit==0)
tomwalters@0 544 {
tomwalters@0 545 for( chan=0 ; chan < state->chans ; chan++ )
tomwalters@0 546 {
tomwalters@0 547 addIn(input+(state->imagenwidth), chan, state);
tomwalters@0 548 output_simple_strobe_info(state, stipts);
tomwalters@0 549 }
tomwalters@0 550 } /* if (state->Stcrit==0) */
tomwalters@0 551
tomwalters@0 552
tomwalters@0 553 /* 111111111111111111111111 stcrit 1111111111111111111111111111111111 */
tomwalters@0 554 /* Add on every point greater than "stthresh_ai" (default 0) */
tomwalters@0 555
tomwalters@0 556 if (state->Stcrit==1)
tomwalters@0 557 {
tomwalters@0 558 for( chan=0 ; chan < state->chans ; chan++ )
tomwalters@0 559 {
tomwalters@0 560 if (input[chan] > state->SusThresh )
tomwalters@0 561 {
tomwalters@0 562 addIn(input+(state->imagenwidth), chan, state);
tomwalters@0 563 output_simple_strobe_info(state, stipts);
tomwalters@0 564 }
tomwalters@0 565 else if (input[chan] <=state->SusThresh)
tomwalters@0 566 output_simple_strobe_info(state, zeroval);
tomwalters@0 567 }
tomwalters@0 568 } /* if (state->Stcrit==1) */
tomwalters@0 569
tomwalters@0 570
tomwalters@0 571 /* 222222222222222222222222 stcrit 2222222222222222222222222222222222 */
tomwalters@0 572 /* Add on every Nap pulse peak */
tomwalters@0 573
tomwalters@0 574 if (state->Stcrit==2)
tomwalters@0 575 {
tomwalters@0 576 for( chan=0 ; chan < state->chans ; chan++ )
tomwalters@0 577 {
tomwalters@0 578 if (state->isStrobe[chan]) /* Check to see if it is time to addIn */
tomwalters@0 579 {
tomwalters@0 580 addIn(input+((state->imagenwidth)-2*(state->chans)), chan, state);
tomwalters@0 581 state->isStrobe[chan]=0; /* Reset strobe flag */
tomwalters@0 582 doList_strobe_info(state, chan);
tomwalters@0 583 }
tomwalters@0 584
tomwalters@0 585 /* Find a pulse peak routine */
tomwalters@0 586
tomwalters@0 587 if (!state->isPulse[chan]) /* Not in pulse, looking for pulse */
tomwalters@0 588 {
tomwalters@0 589 state->thresh[chan]=input[chan];
tomwalters@0 590 if (input[chan] > 0 /*state->thresh[chan] */ ) /* Start of a Nap pulse */
tomwalters@0 591 state->isPulse[chan] =1; /* set in pulse flag */
tomwalters@0 592 }
tomwalters@0 593 else /* In pulse, looking for peak */
tomwalters@0 594 {
tomwalters@0 595 if (input[chan] < state->thresh[chan]) /* peak found */
tomwalters@0 596 {
tomwalters@0 597 state->isPulse[chan]=0;
tomwalters@0 598 state->isStrobe[chan]=1; /* set strobe pending flag */
tomwalters@0 599 }
tomwalters@0 600 else
tomwalters@0 601 state->thresh[chan]=input[chan];
tomwalters@0 602 }
tomwalters@0 603 output_thresh_info(state, chan);
tomwalters@0 604 }
tomwalters@0 605 } /* if (state->stcrit==2) */
tomwalters@0 606
tomwalters@0 607
tomwalters@0 608
tomwalters@0 609 /* 333333333333333333333333 stcrit 3333333333333333333333333333333333 */
tomwalters@0 610 /* Add on pulse peaks that exceed strobe threshold (temporal shadow ) */
tomwalters@0 611 /* Primitive Local Max algorithm */
tomwalters@0 612
tomwalters@0 613 if (state->Stcrit==3)
tomwalters@0 614 {
tomwalters@0 615 for( chan=0 ; chan < state->chans ; chan++ )
tomwalters@0 616 {
tomwalters@0 617 if (state->isStrobe[chan]) /* Check to see if it is time to addIn */
tomwalters@0 618 {
tomwalters@0 619 addIn(input+((state->imagenwidth)-2*(state->chans)), chan, state);
tomwalters@0 620 state->isStrobe[chan] = 0; /* Reset strobe flag */
tomwalters@0 621 doList_strobe_info(state, chan);
tomwalters@0 622 }
tomwalters@0 623
tomwalters@0 624 /* Find a pulse peak routine */
tomwalters@0 625
tomwalters@0 626 if (!state->isPulse[chan]) /* Not in Pulse, looking for Pulse */
tomwalters@0 627 {
tomwalters@0 628 if (input[chan] > state->thresh[chan] && input[chan] > state->previnput[chan])
tomwalters@0 629 { /* Previnput check ensures threshold decay
tomwalters@0 630 does not cut into pulse */
tomwalters@0 631
tomwalters@0 632 state->isPulse[chan] = 1; /* set flag: in pulse */
tomwalters@0 633 state->thresh[chan] = input[chan]; /* start search for peak */
tomwalters@0 634 }
tomwalters@0 635 else {
tomwalters@0 636 decay_strobe_threshold(state, chan);
tomwalters@0 637 if (input[chan]==0) /* in the zeroes between nap pulses */
tomwalters@0 638 state->previnput[chan] = 0; /* Set it to Zero previnput */
tomwalters@0 639 }
tomwalters@0 640 }
tomwalters@0 641
tomwalters@0 642 if (state->isPulse[chan]) /* Else in ongoing pulse looking for peak */
tomwalters@0 643 {
tomwalters@0 644 if (input[chan] <= state->thresh[chan] && input[chan] <= state->previnput[chan])
tomwalters@0 645 /* pulse peak found */
tomwalters@0 646 {
tomwalters@0 647 state->isPulse[chan] = 0; /* clear flag: not in pulse */
tomwalters@0 648 state->isStrobe[chan] = 1; /* set Strobe pending flag */
tomwalters@0 649 if (!strcmp(exposwitch, "off"))
tomwalters@0 650 state->tlim[chan]=state->triggerdecay * state->thresh[chan];
tomwalters@0 651 state->trigtime[chan]=(state->time)-1;
tomwalters@0 652 /* state->previnput[chan]=input[cha */
tomwalters@0 653 }
tomwalters@0 654 else /* still in pulse, so continue search for peak */
tomwalters@0 655 state->thresh[chan] = input[chan];
tomwalters@0 656
tomwalters@0 657 } /* if in Pulse */
tomwalters@0 658 state->previnput[chan]=input[chan];
tomwalters@0 659 output_thresh_info(state, chan);
tomwalters@0 660 } /* for all chans... */
tomwalters@0 661 } /* if (state->Stcrit==3) */
tomwalters@0 662
tomwalters@0 663
tomwalters@0 664
tomwalters@0 665 /* 444444444444444444444444 stcrit 4444444444444444444444444444444444 */
tomwalters@0 666 /* Add on pulse peaks that exceed strobe threshold and which are not succeeded by
tomwalters@0 667 a larger pulse in nwid ms. (Better Local Max mechanism) */
tomwalters@0 668
tomwalters@0 669 if (state->Stcrit==4)
tomwalters@0 670 {
tomwalters@0 671 for( chan=0 ; chan < state->chans ; chan++ )
tomwalters@0 672 {
tomwalters@0 673 if (state->isStrobe[chan]) /* Check to see if it is time to addIn */
tomwalters@0 674 {
tomwalters@0 675 if ( strobelag-1 >= state->trigtime[chan])
tomwalters@0 676 /* initiates strobe after nwid ms */
tomwalters@0 677 {
tomwalters@0 678 addIn(input-(state->chans), chan, state);
tomwalters@0 679 doList_strobe_info(state, chan);
tomwalters@0 680 state->isStrobe[chan] = 0; /* Reset strobe flag */
tomwalters@0 681 state->trigheight[chan] = 0; /* Reset local max value */
tomwalters@0 682
tomwalters@0 683 }
tomwalters@0 684 }
tomwalters@0 685
tomwalters@0 686 /* Find a pulse peak routine */
tomwalters@0 687
tomwalters@0 688 if (!state->isPulse[chan]) /* Not in Pulse, looking for pulse */
tomwalters@0 689 {
tomwalters@0 690 if (input[chan] > state->thresh[chan] && input[chan] > state->previnput[chan])
tomwalters@0 691 { /* Previnput check ensures threshold
tomwalters@0 692 decay does not cut into pulse */
tomwalters@0 693
tomwalters@0 694 state->isPulse[chan] = 1; /* set flag: in pulse */
tomwalters@0 695 state->thresh[chan] = input[chan]; /* start search for peak */
tomwalters@0 696 /* state->previnput[chan]= 1; in pulse till the next zero value */
tomwalters@0 697 }
tomwalters@0 698 else
tomwalters@0 699 {
tomwalters@0 700 decay_strobe_threshold(state, chan);
tomwalters@0 701 if (input[chan]==0) /* in the zeroes between nap pulses */
tomwalters@0 702 state->previnput[chan] = 0; /* Free previnput */
tomwalters@0 703 }
tomwalters@0 704 }
tomwalters@0 705
tomwalters@0 706 if (state->isPulse[chan]) /* Else in ongoing pulse, looking for peak */
tomwalters@0 707 {
tomwalters@0 708 if (input[chan] <= state->thresh[chan] && input[chan] <= state->previnput[chan])
tomwalters@0 709 /* pulse peak found */
tomwalters@0 710 {
tomwalters@0 711 state->isPulse[chan] = 0; /* clear flag: not in pulse */
tomwalters@0 712 state->isStrobe[chan] = 1; /* set Strobe pending flag */
tomwalters@0 713
tomwalters@0 714 if ( state->thresh[chan] > state->trigheight[chan] )
tomwalters@0 715 /* Check for LOCAL MAX */
tomwalters@0 716 {
tomwalters@0 717 state->trigheight[chan] = state->thresh[chan];
tomwalters@0 718 state->trigtime[chan] = (state->time)-1; /* Set strobe time */
tomwalters@0 719 if (!strcmp(exposwitch, "off"))
tomwalters@0 720 state->tlim[chan]=state->triggerdecay * state->trigheight[chan];
tomwalters@0 721 }
tomwalters@0 722 }
tomwalters@0 723 else /* still in pulse, so continue search for peak */
tomwalters@0 724 state->thresh[chan] = input[chan];
tomwalters@0 725 } /* if in Pulse */
tomwalters@0 726 state->previnput[chan]=input[chan];
tomwalters@0 727 output_thresh_info(state, chan);
tomwalters@0 728 } /* for all chans... */
tomwalters@0 729 } /* if (state->Stcrit==4) */
tomwalters@0 730
tomwalters@0 731
tomwalters@0 732
tomwalters@0 733 /* 555555555555555555555555 stcrit 5555555555555555555555555555555555 */
tomwalters@0 734 /* Add on pulse peaks that exceed storbe threshold and which are not succeeded by
tomwalters@0 735 a larger pulse in nwid ms, provided total lag is < 2*nwid ms
tomwalters@0 736 Local Max mechanism with a timeout */
tomwalters@0 737
tomwalters@0 738 if (state->Stcrit==5)
tomwalters@0 739 {
tomwalters@0 740 for (chan = 0; chan < state->chans; chan++)
tomwalters@0 741 {
tomwalters@0 742 if(state->isStrobe[chan]) /* Check to see if it is time to addIn */
tomwalters@0 743 { /* check for waiting till the first local max found */
tomwalters@0 744 if (strobelag-1 >= state->def_strobe_candidate_time[chan])
tomwalters@0 745 /* initiate strobe after nwid ms */
tomwalters@0 746 {
tomwalters@0 747 /* print_trigger_debugging_info(state, chan, s_lag, 1); */
tomwalters@0 748 addIn(input-state->chans, chan, state);
tomwalters@0 749 doList_strobe_info(state, chan);
tomwalters@0 750
tomwalters@0 751 state->def_strobe_candidate_time[chan] = 0; /* Reset strobe time */
tomwalters@0 752 state->def_strobe_height[chan] = 0; /* Reset local max value */
tomwalters@0 753 state->trigheight[chan]=0;
tomwalters@0 754 state->isStrobe[chan]=0; /* Reset strobe flag */
tomwalters@0 755
tomwalters@0 756 }
tomwalters@0 757 }
tomwalters@0 758
tomwalters@0 759 /* Find a pulse peak routine */
tomwalters@0 760
tomwalters@0 761 if (!state->isPulse[chan]) /* Not in pulse, looking for pulse */
tomwalters@0 762 {
tomwalters@0 763 if (input[chan] > state->thresh[chan] && input[chan] > state->previnput[chan])
tomwalters@0 764 { /* Previnput check ensures threshold
tomwalters@0 765 decay does not cut into pulse */
tomwalters@0 766
tomwalters@0 767 state->isPulse[chan] = 1; /* set flag: in pulse */
tomwalters@0 768 state->thresh[chan] = input[chan]; /* start search for peak */
tomwalters@0 769 /* state->previnput[chan] = 1; in pulse till the next zero value */
tomwalters@0 770 }
tomwalters@0 771 else
tomwalters@0 772 {
tomwalters@0 773 decay_strobe_threshold(state, chan);
tomwalters@0 774 if (input[chan]==0) /* in the zeroes between nap pulses */
tomwalters@0 775 state->previnput[chan]=0; /* Free previnput */
tomwalters@0 776 }
tomwalters@0 777
tomwalters@0 778 }
tomwalters@0 779
tomwalters@0 780 if (state->isPulse[chan]) /* Else in ongoing pulse, looking for peak */
tomwalters@0 781 {
tomwalters@0 782 if (input[chan] <= state->thresh[chan] && input[chan] <= state->previnput[chan])
tomwalters@0 783 /* Pulse Peak Found */
tomwalters@0 784 {
tomwalters@0 785 state->isPulse[chan]=0; /* clear flag: not in pulse */
tomwalters@0 786
tomwalters@0 787 if (locmax_searchstart[chan]==0 )
tomwalters@0 788 /* && state->time>=((ttime[chan]-initial_strobe_candidate_time[chan])+ltime[chan])) AJD 1-2-96 */
tomwalters@0 789 { /* start local max time (for timeout)
tomwalters@0 790 and shift search window */
tomwalters@0 791 locmax_searchtime[chan]=1; /* local max time started */
tomwalters@0 792 locmax_searchstart[chan]=1; /* local max flag set */
tomwalters@0 793 print_trigger_debugging_info(state, chan, s_lag, 2);
tomwalters@0 794 initial_strobe_candidate_time[chan]=(state->time)-1; /* local max start time noted */
tomwalters@0 795
tomwalters@0 796 }
tomwalters@0 797
tomwalters@0 798 /* if (locmax_searchstart[chan]==1) */ /* 8rd March, 1995 AJayDatta */
tomwalters@0 799 if (state->thresh[chan] > state->trigheight[chan])
tomwalters@0 800 /* Check for LOCAL MAX */
tomwalters@0 801 {
tomwalters@0 802 state->trigheight[chan]=state->thresh[chan];
tomwalters@0 803 state->trigtime[chan]=(state->time)-1; /* Set strobe time */
tomwalters@0 804 if (!strcmp(exposwitch, "off"))
tomwalters@0 805 state->tlim[chan]=state->triggerdecay * state->trigheight[chan];
tomwalters@0 806 if (locmax_searchstart[chan]==1)
tomwalters@0 807 print_trigger_debugging_info(state, chan, s_lag, 3);
tomwalters@0 808 } /* if greater than thresh */
tomwalters@0 809
tomwalters@0 810
tomwalters@0 811 /* Reached end of time-out period (While in the peak finding stage !)
tomwalters@0 812 End of the timeout period can occur at two stages of the algorithm,
tomwalters@0 813 at a Nap pulse peak or at any point of the pulse train. */
tomwalters@0 814
tomwalters@0 815 if (locmax_searchtime[chan]==(state->stlag)) /* imagenwidth/state->chans)) */
tomwalters@0 816 {
tomwalters@0 817 print_trigger_debugging_info(state, chan, s_lag, 4);
tomwalters@0 818
tomwalters@0 819 state->def_strobe_candidate_time[chan]=state->trigtime[chan];
tomwalters@0 820 state->def_strobe_height[chan]=state->trigheight[chan];
tomwalters@0 821 locmax_searchtime[chan]=0;
tomwalters@0 822 locmax_searchstart[chan]=0;
tomwalters@0 823 state->trigheight[chan]=0;
tomwalters@0 824 state->trigtime[chan]=0;
tomwalters@0 825 state->isStrobe[chan]=1; /* set Strobe pending flag */
tomwalters@0 826 ltime[chan]=state->time; /* End of search time */
tomwalters@0 827 ttime[chan]=state->def_strobe_candidate_time[chan]; /* Local Max time */
tomwalters@0 828 }
tomwalters@0 829 /* reset search period to zero */
tomwalters@0 830 /* as y ms search period ends, update the info for strobe and
tomwalters@0 831 clear current_ values for the next y ms */
tomwalters@0 832 } /* Pulse Peak Loop */
tomwalters@0 833 else
tomwalters@0 834 state->thresh[chan]=input[chan];
tomwalters@0 835 } /* if (state->isPulse..) */
tomwalters@0 836
tomwalters@0 837 if (locmax_searchtime[chan] == (state->stlag)) /* imagenwidth/state->chans)) */
tomwalters@0 838 /* && state->def_strobe_candidate_time[chan]==0) */
tomwalters@0 839 { /* start local max time (for timeout) */
tomwalters@0 840 print_trigger_debugging_info(state, chan, s_lag, 5);
tomwalters@0 841
tomwalters@0 842 state->def_strobe_candidate_time[chan]=state->trigtime[chan];
tomwalters@0 843 state->def_strobe_height[chan]=state->trigheight[chan];
tomwalters@0 844 locmax_searchtime[chan]=0;
tomwalters@0 845 locmax_searchstart[chan]=0;
tomwalters@0 846 state->trigheight[chan]=0;
tomwalters@0 847 state->trigtime[chan]=0;
tomwalters@0 848 state->isStrobe[chan]=1; /* set Strobe pending flag */
tomwalters@0 849 ltime[chan]=state->time;
tomwalters@0 850 ttime[chan]=state->def_strobe_candidate_time[chan];
tomwalters@0 851 }
tomwalters@0 852 /* reset search period to zero */
tomwalters@0 853 /* as y ms search period ends, update the info for strobe and
tomwalters@0 854 clear current_ values for the next y ms */
tomwalters@0 855
tomwalters@0 856
tomwalters@0 857 if (locmax_searchstart[chan]==1)
tomwalters@0 858 (locmax_searchtime[chan])++;
tomwalters@0 859 state->previnput[chan]=input[chan];
tomwalters@0 860 output_thresh_info(state, chan);
tomwalters@0 861
tomwalters@0 862 } /* for all chans */
tomwalters@0 863 } /* if (state->Stcrit== 5) */
tomwalters@0 864
tomwalters@0 865
tomwalters@0 866 qq=insertl(state->time); /* insert time to list */
tomwalters@0 867 (state->time)++;
tomwalters@0 868 return;
tomwalters@0 869
tomwalters@0 870 } /* doColumn */
tomwalters@0 871
tomwalters@0 872
tomwalters@0 873 /****************************************************************************
tomwalters@0 874 * addIn
tomwalters@0 875 * add row cochleagram into stabilised image
tomwalters@0 876 ****************************************************************************/
tomwalters@0 877 static void addIn( input, chan, state )
tomwalters@0 878 DataType *input ;
tomwalters@0 879 int chan ;
tomwalters@0 880 struct _sai_state *state ;
tomwalters@0 881 {
tomwalters@0 882 register DataType *channel_ptr, *image_ptr, *end;
tomwalters@0 883 #ifdef FLOAT
tomwalters@0 884 register FLOAT input_scale = INPUT_SCALE ;
tomwalters@0 885 #endif
tomwalters@0 886 register ScalarType *decayfactor = state->framedecay;
tomwalters@0 887
tomwalters@0 888 /* Initialize channel_ptr to the input data to be added in. */
tomwalters@0 889 /* `input' points to a particular column in the cochleagram, */
tomwalters@0 890 /* and `chan' indexes a particular channel in this column. */
tomwalters@0 891 channel_ptr = input + chan ;
tomwalters@0 892 end = channel_ptr - state->imagewidth ;
tomwalters@0 893
tomwalters@0 894 /* Initialize image_ptr to end of sai row corresponding to `chan'.*/
tomwalters@0 895 /* `state->image' points to the start of the sai, */
tomwalters@0 896 /* so increment pointer by chan*framewidth to get to row `chan'. */
tomwalters@0 897 /* To get to end of row, increment by ((chan+1)*framewidth)-1. */
tomwalters@0 898 /* But framewidth = state->imagewidth / state->chans, and hence: */
tomwalters@0 899 /* Added fix; as new spiral.c accepts nwid AJD 17-3-95 */
tomwalters@0 900 if (state->Stcrit==4 && state->stlag==0)
tomwalters@0 901 image_ptr = (state->image + state->imagewidth / state->chans * (chan+1));
tomwalters@0 902 /* 13-3-95 removed -1; ajd */
tomwalters@0 903 else
tomwalters@0 904 image_ptr = (state->image + state->imagewidth / state->chans * (chan+1))-1;
tomwalters@0 905
tomwalters@0 906 /* Decrement channel_ptr by columns, from the initial column, */
tomwalters@0 907 /* until one complete sai row has been added into, which is when */
tomwalters@0 908 /* channel_ptr has decreased by a whole imagewidth. */
tomwalters@0 909 while( channel_ptr > end ) {
tomwalters@0 910 #ifdef FLOAT
tomwalters@0 911 *image_ptr += ( ( *channel_ptr * input_scale ) * (*decayfactor++) ) ;
tomwalters@0 912 #else
tomwalters@0 913 *image_ptr += DESCALE( ( *channel_ptr >> INPUT_SHIFT ) * (*decayfactor++) ) ;
tomwalters@0 914 #endif
tomwalters@0 915 /* if (state->chans <= 40) */
tomwalters@0 916 if (*image_ptr > 32767.0)
tomwalters@0 917 *image_ptr = 32767.0; /* 32767 */
tomwalters@0 918
tomwalters@0 919 image_ptr--;
tomwalters@0 920
tomwalters@0 921 channel_ptr -= state->chans ; /* next (ie previous) input time point */
tomwalters@0 922 }
tomwalters@0 923
tomwalters@0 924 return ;
tomwalters@0 925 }
tomwalters@0 926
tomwalters@0 927
tomwalters@0 928 /***************************************************************************
tomwalters@0 929 * Summary is not called in this module.
tomwalters@0 930 * (see SummaryEntry in model.c, which is the entry point for gensas).
tomwalters@0 931 * Summary computes a row summary spectrogram and is called during the
tomwalters@0 932 * program "gensas".
tomwalters@0 933
tomwalters@0 934 * Routines in this module it uses are:
tomwalters@0 935 * summary_callback
tomwalters@0 936 ****************************************************************************/
tomwalters@0 937
tomwalters@0 938 struct _summary_state {
tomwalters@0 939 struct _fillable_source parent ;
tomwalters@0 940 Source source;
tomwalters@0 941 int framewidth; /* number of time-points or cols in an sai */
tomwalters@0 942 int frameheight; /* number of channels or rows in an sai */
tomwalters@0 943 double scale;
tomwalters@0 944 int *llim; /* integration limits (lower & upper) for sai summary data */
tomwalters@0 945 int *ulim;
tomwalters@0 946 };
tomwalters@0 947
tomwalters@0 948
tomwalters@0 949 Source Summary( source, frameheight, scale, cfs, samplerate, llimstr, ulimstr)
tomwalters@0 950 Source source ;
tomwalters@0 951 int frameheight ;
tomwalters@0 952 double scale ;
tomwalters@0 953 double *cfs, samplerate ; /* array of channel centre frequencies */
tomwalters@0 954 char *llimstr, *ulimstr; /* lower and upper limit strings */
tomwalters@0 955 {
tomwalters@0 956 int i, framewidth, max_ulim=0, min_llim=99999999;
tomwalters@0 957
tomwalters@0 958 DeclareNew( struct _summary_state *, state ) ;
tomwalters@0 959
tomwalters@0 960 /* Allocate new arrays for integration limits */
tomwalters@0 961 state->llim = NewArray(int, frameheight, "image.c for lower limit array" );
tomwalters@0 962 state->ulim = NewArray(int, frameheight, "image.c for upper limit array" );
tomwalters@0 963
tomwalters@0 964 for (i=0 ; i<frameheight ; i++) {
tomwalters@0 965
tomwalters@0 966 /* Convert strings to sample points, allowing for cycles units */
tomwalters@0 967 state->llim[i] = Cycles( llimstr, cfs[i], Samplerate() );
tomwalters@0 968 state->ulim[i] = Cycles( ulimstr, cfs[i], Samplerate() );
tomwalters@0 969
tomwalters@0 970 /* Check that llim < ulim, and quit if not so */
tomwalters@0 971 if (state->llim[i] >= state->ulim[i])
tomwalters@0 972 stitch_error("Warning: gensas integration limits badly ordered\n");
tomwalters@0 973
tomwalters@0 974 /* Find limits on required framewidth */
tomwalters@0 975 if (state->ulim[i] > max_ulim)
tomwalters@0 976 max_ulim = state->ulim[i];
tomwalters@0 977 if (state->llim[i] < min_llim)
tomwalters@0 978 min_llim = state->llim[i];
tomwalters@0 979 }
tomwalters@0 980
tomwalters@0 981 if (min_llim > 0) min_llim = 0;
tomwalters@0 982 framewidth = max_ulim - min_llim;
tomwalters@0 983
tomwalters@0 984 /* Adjust the integration limits for an sai with triggering on the */
tomwalters@0 985 /* right. (The parameters llim <= ulim, but the resulting sai indices */
tomwalters@0 986 /* state->llim[i] > state->ulim[i]). */
tomwalters@0 987 /* This is done by subtracting from (framewidth-1), where framewidth is */
tomwalters@0 988 /* the maximum required number of points, (ie ulim in points). */
tomwalters@0 989
tomwalters@0 990 for (i=0 ; i<frameheight ; i++) {
tomwalters@0 991 state->llim[i] = framewidth - state->llim[i] ;
tomwalters@0 992 state->ulim[i] = framewidth - state->ulim[i] ;
tomwalters@0 993 }
tomwalters@0 994
tomwalters@0 995 framewidth++; /* extra point as array starts from zeroth location */
tomwalters@0 996
tomwalters@0 997 /* a blockings requests up into requests of the size specifed */
tomwalters@0 998 state->source = NewBlockingSource( source, sizeof ( DataType ) * framewidth * frameheight ) ;
tomwalters@0 999 state->framewidth = framewidth ;
tomwalters@0 1000 state->frameheight = frameheight ;
tomwalters@0 1001 state->scale = scale ;
tomwalters@0 1002
tomwalters@0 1003 return ( SetFillableSource( state, summary_callback, "image.c summarising sai" ) ) ;
tomwalters@0 1004 }
tomwalters@0 1005
tomwalters@0 1006 /*********************** Routines supporting Summary ***********************/
tomwalters@0 1007
tomwalters@0 1008 static Pointer summary_callback( state, bytes, buffer )
tomwalters@0 1009 struct _summary_state *state ;
tomwalters@0 1010 ByteCount *bytes ;
tomwalters@0 1011 DataType *buffer ;
tomwalters@0 1012 {
tomwalters@0 1013 register int last = *bytes == 0 ;
tomwalters@0 1014 register int i, j, ulim, llim, point, points=ToPoints(DataType,*bytes) ;
tomwalters@0 1015 register DataType *sairow;
tomwalters@0 1016 #ifdef FLOAT
tomwalters@0 1017 register DataType sum ;
tomwalters@0 1018 #else
tomwalters@0 1019 register long sum ;
tomwalters@0 1020 #endif
tomwalters@0 1021
tomwalters@0 1022 /* Pull an sai frame */
tomwalters@0 1023
tomwalters@0 1024 for( point=0 ; point < points ; )
tomwalters@0 1025 /* For each channel (row) in the sai, sum the row between the given limits */
tomwalters@0 1026 for(i=0 ; i<state->frameheight ; i++) {
tomwalters@0 1027
tomwalters@0 1028 sairow = PullItems(state->source,state->framewidth,DataType);
tomwalters@0 1029
tomwalters@0 1030 ulim = state->ulim[i];
tomwalters@0 1031 llim = state->llim[i];
tomwalters@0 1032 sum = 0;
tomwalters@0 1033 for (j=ulim ; j<=llim ; j++)
tomwalters@0 1034 sum += sairow[j];
tomwalters@0 1035
tomwalters@0 1036 /* store the row-sum, scaled and normalized for the range of the sum */
tomwalters@0 1037 buffer[point++] = sum*state->scale / (llim-ulim);
tomwalters@0 1038 }
tomwalters@0 1039
tomwalters@0 1040 if( !last )
tomwalters@0 1041 return ( (Pointer) buffer ) ;
tomwalters@0 1042 else {
tomwalters@0 1043 Delete( state->llim ) ;
tomwalters@0 1044 Delete( state->ulim ) ;
tomwalters@0 1045
tomwalters@0 1046 return ( DeleteFillableSource( state ) ) ;
tomwalters@0 1047 }
tomwalters@0 1048 }
tomwalters@0 1049
tomwalters@0 1050 /********************************************************************************/
tomwalters@0 1051 /* */
tomwalters@0 1052 /* initlist initialises the linked list pointer before the other list functions */
tomwalters@0 1053 /* call the list. */
tomwalters@0 1054 /* */
tomwalters@0 1055 /********************************************************************************/
tomwalters@0 1056 void initlist()
tomwalters@0 1057 {
tomwalters@0 1058 static int status=0;
tomwalters@0 1059 if (status==0)
tomwalters@0 1060 start = endl = pp = qq = (node *)malloc(sizeof(node));
tomwalters@0 1061 status=1;
tomwalters@0 1062 }
tomwalters@0 1063
tomwalters@0 1064 /********************************************************************************/
tomwalters@0 1065 /* */
tomwalters@0 1066 /* Function getnode allocates storage for a link list node and returns a */
tomwalters@0 1067 /* pointer to that node */
tomwalters@0 1068 /* */
tomwalters@0 1069 /********************************************************************************/
tomwalters@0 1070 node *getnode()
tomwalters@0 1071 {
tomwalters@0 1072 node *q;
tomwalters@0 1073 q=(node *)malloc(sizeof(node));
tomwalters@0 1074 if (q==NULL) exit(66);
tomwalters@0 1075 return q;
tomwalters@0 1076 }
tomwalters@0 1077
tomwalters@0 1078 /********************************************************************************/
tomwalters@0 1079 /* */
tomwalters@0 1080 /* The function insertl inserts the value x at the end of the linked list and */
tomwalters@0 1081 /* moves the end point by another node */
tomwalters@0 1082 /* */
tomwalters@0 1083 /********************************************************************************/
tomwalters@0 1084 node *insertl(x)
tomwalters@0 1085 int x;
tomwalters@0 1086 {
tomwalters@0 1087 node *q=endl;
tomwalters@0 1088 endl=getnode();
tomwalters@0 1089 q->next=endl;
tomwalters@0 1090 q->index=x;
tomwalters@0 1091 q->val=0;
tomwalters@0 1092 /* fprintf(testfile, "insertl: index is %d, val is %d\n", q->index, q->val); */
tomwalters@0 1093 return q;
tomwalters@0 1094 }
tomwalters@0 1095
tomwalters@0 1096 /********************************************************************************/
tomwalters@0 1097 /* */
tomwalters@0 1098 /* The function inss searches the list from the start, stops 3 nodes before the */
tomwalters@0 1099 /* value x, assigns the value -2000 to the three nodes till the (x+1)th node. */
tomwalters@0 1100 /* */
tomwalters@0 1101 /********************************************************************************/
tomwalters@0 1102 void inss(x)
tomwalters@0 1103 int x;
tomwalters@0 1104 {
tomwalters@0 1105 node *q=start;
tomwalters@0 1106 int y=x-3;
tomwalters@0 1107 int z=x;
tomwalters@0 1108 while (q!=endl)
tomwalters@0 1109 {
tomwalters@0 1110 if (q->index == y)
tomwalters@0 1111 do
tomwalters@0 1112 {
tomwalters@0 1113 q->val=-2000;
tomwalters@0 1114 q=q->next;
tomwalters@0 1115 /* fprintf(stderr, "Inss(x) index=%d\n",q->index); */
tomwalters@0 1116 } while (q->index < z);
tomwalters@0 1117 q=q->next;
tomwalters@0 1118 }
tomwalters@0 1119 }
tomwalters@0 1120
tomwalters@0 1121
tomwalters@0 1122 /********************************************************************************/
tomwalters@0 1123 /* */
tomwalters@0 1124 /* output_simple_strobe_info routine creates a file pointed by trigger file */
tomwalters@0 1125 /* which writes the points in the Nap pulse which initiates strobing */
tomwalters@0 1126 /* */
tomwalters@0 1127 /********************************************************************************/
tomwalters@0 1128 void output_simple_strobe_info(state, value)
tomwalters@0 1129 struct _sai_state *state;
tomwalters@0 1130 short value;
tomwalters@0 1131 {
tomwalters@0 1132
tomwalters@0 1133 if (!(!strcmp(state->switch_info, "off") || !strcmp(state->switch_info, "on")))
tomwalters@0 1134 fwrite(&(value), sizeof(short), 1 , trigger_file);
tomwalters@0 1135 }
tomwalters@0 1136
tomwalters@0 1137 /********************************************************************************/
tomwalters@0 1138 /* */
tomwalters@0 1139 /* doList_strobe_info creates a file (pointed by "trigger_file") which writes */
tomwalters@0 1140 /* in binary shorts the points in the Nap pulse which initiates a strobe */
tomwalters@0 1141 /* It uses a linked list data structure to keep track of the actual time which */
tomwalters@0 1142 /* causes a strobe, rather than the time when the strobing event occurs. */
tomwalters@0 1143 /* At stcrit 4 or 5, strobing occurs nwid ms after a nap pulse peak has been */
tomwalters@0 1144 /* located. */
tomwalters@0 1145 /* */
tomwalters@0 1146 /********************************************************************************/
tomwalters@0 1147 void doList_strobe_info(state, chan)
tomwalters@0 1148 struct _sai_state *state;
tomwalters@0 1149 int chan;
tomwalters@0 1150 {
tomwalters@0 1151 int storev;
tomwalters@0 1152
tomwalters@0 1153 if (state->Stcrit==2)
tomwalters@0 1154 storev=(state->time)-2;
tomwalters@0 1155 else if (state->Stcrit==5)
tomwalters@0 1156 storev=state->def_strobe_candidate_time[chan];
tomwalters@0 1157 /* fprintf(stderr, "Storev value of doList is = %d\n", storev);} */
tomwalters@0 1158 else
tomwalters@0 1159 storev=state->trigtime[chan];
tomwalters@0 1160
tomwalters@0 1161 inss(storev);
tomwalters@0 1162
tomwalters@0 1163 while (pp->index<=storev) /* (pp!=qq) */
tomwalters@0 1164 {
tomwalters@0 1165 if (!(!strcmp(state->switch_info, "off") || !strcmp(state->switch_info, "on")))
tomwalters@0 1166 fwrite(&(pp->val), sizeof(short), 1, trigger_file);
tomwalters@0 1167 /* fprintf(testfile, "doList: index is %d, val is %d\n", pp->index, pp->val); */
tomwalters@0 1168 pp=pp->next;
tomwalters@0 1169 }
tomwalters@0 1170 /* pp=qq; */
tomwalters@0 1171 }
tomwalters@0 1172
tomwalters@0 1173 /********************************************************************************/
tomwalters@0 1174 /* */
tomwalters@0 1175 /* output_thresh_info writes threshold values (in binary shorts or floats) to */
tomwalters@0 1176 /* the file opened by the file pointer "thresho_file" */
tomwalters@0 1177 /* */
tomwalters@0 1178 /********************************************************************************/
tomwalters@0 1179 void output_thresh_info(state, chan)
tomwalters@0 1180 struct _sai_state *state;
tomwalters@0 1181 int chan;
tomwalters@0 1182 {
tomwalters@0 1183 S[chan]=state->thresh[chan];
tomwalters@0 1184
tomwalters@0 1185 if (!(!strcmp(state->switch_info, "off") || !strcmp(state->switch_info, "on")))
tomwalters@0 1186 #ifdef FLOAT
tomwalters@0 1187 fwrite((S+chan), sizeof(float), 1, thresho_file);
tomwalters@0 1188 #else
tomwalters@0 1189 fwrite((S+chan), sizeof(short), 1, thresho_file);
tomwalters@0 1190 #endif
tomwalters@0 1191
tomwalters@0 1192 }
tomwalters@0 1193
tomwalters@0 1194 /********************************************************************************/
tomwalters@0 1195 /* */
tomwalters@0 1196 /* decay_strobe_threshold decays the strobe threshold at every clock */
tomwalters@0 1197 /* tick either linearly or exponentially */
tomwalters@0 1198 /* */
tomwalters@0 1199 /********************************************************************************/
tomwalters@0 1200 void decay_strobe_threshold(state, chan)
tomwalters@0 1201 struct _sai_state *state;
tomwalters@0 1202 int chan;
tomwalters@0 1203 {
tomwalters@0 1204
tomwalters@0 1205 if (!strcmp(exposwitch, "on"))
tomwalters@0 1206 state->thresh[chan] *= state->triggerdecay;
tomwalters@0 1207 else
tomwalters@0 1208 {
tomwalters@0 1209 state->thresh[chan] -= state->tlim[chan];
tomwalters@0 1210 if (state->thresh[chan] < 0)
tomwalters@0 1211 state->thresh[chan]=0;
tomwalters@0 1212 }
tomwalters@0 1213 }
tomwalters@0 1214
tomwalters@0 1215 /********************************************************************************/
tomwalters@0 1216 /* */
tomwalters@0 1217 /* This routine prints debugging information of the local max search */
tomwalters@0 1218 /* with timeout (i.e. stcrit_ai=5) */
tomwalters@0 1219 /* */
tomwalters@0 1220 /********************************************************************************/
tomwalters@0 1221 void print_trigger_debugging_info(state, chan, strobe_lag, stage)
tomwalters@0 1222 struct _sai_state *state;
tomwalters@0 1223 int chan;
tomwalters@0 1224 int strobe_lag;
tomwalters@0 1225 int stage;
tomwalters@0 1226 {
tomwalters@0 1227 if (stage==1)
tomwalters@0 1228 {
tomwalters@0 1229 if (strobe_lag > state->def_strobe_candidate_time[chan])
tomwalters@0 1230 val[chan]=strobe_lag-state->def_strobe_candidate_time[chan];
tomwalters@0 1231 if (strobe_lag == state->def_strobe_candidate_time[chan])
tomwalters@0 1232 val[chan]=0;
tomwalters@0 1233
tomwalters@0 1234 if (!strcmp(state->switch_info,"off"));
tomwalters@0 1235 else
tomwalters@0 1236 fprintf(infotxt_file, "Chan %d: :: Actual time of trigger: s_lag=%d, trigtime=%d\n", chan, strobe_lag, state->def_strobe_candidate_time[chan]);
tomwalters@0 1237 }
tomwalters@0 1238
tomwalters@0 1239 /* fprintf(infotxt_file, "Chan %d: Actual time of trigger: s_lag=%d, trigtime=%d, shift=%d\n", chan, strobe_lag, state->def_strobe_candidate_time[chan], val[chan]*state->chans); */
tomwalters@0 1240
tomwalters@0 1241
tomwalters@0 1242 if (stage==2)
tomwalters@0 1243 {
tomwalters@0 1244 if (!strcmp(state->switch_info,"off"));
tomwalters@0 1245 else
tomwalters@0 1246 fprintf(infotxt_file, "Chan %d: Loc Max Start Time = %d, trigcurrent %d, Threshold=%f, shift=%d\n", chan, state->time, state->trigheight[chan], state->thresh[chan], (ttime[chan]-initial_strobe_candidate_time[chan]));
tomwalters@0 1247 }
tomwalters@0 1248
tomwalters@0 1249 if (stage==3)
tomwalters@0 1250 {
tomwalters@0 1251 if (!strcmp(state->switch_info,"off"));
tomwalters@0 1252 else
tomwalters@0 1253 fprintf(infotxt_file, "Chan %d: Loc Max is %d Time is %d\n", chan, state->trigheight[chan], state->trigtime[chan] );
tomwalters@0 1254 }
tomwalters@0 1255
tomwalters@0 1256 if (stage==4)
tomwalters@0 1257 {
tomwalters@0 1258 if (!strcmp(state->switch_info,"off"));
tomwalters@0 1259 else
tomwalters@0 1260 fprintf(infotxt_file, "Chan %d: At the End of Search (At peak), trigtime = %d time = %d height = %d\n", chan, state->trigtime[chan], state->time, state->trigheight[chan]);
tomwalters@0 1261 }
tomwalters@0 1262 if (stage==5)
tomwalters@0 1263 {
tomwalters@0 1264 if (!strcmp(state->switch_info,"off"));
tomwalters@0 1265 else
tomwalters@0 1266 fprintf(infotxt_file, "Chan %d: At the End of Search, trigtime = %d time = %d height = %d\n", chan, state->trigtime[chan], state->time, state->trigheight[chan]);
tomwalters@0 1267 }
tomwalters@0 1268
tomwalters@0 1269
tomwalters@0 1270 }
tomwalters@0 1271