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