summaryrefslogtreecommitdiff
path: root/heuristics.c
blob: 429a612a23f8e2f9722cf7e2dda8abe761c2b9ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <stdio.h>

#include "vubars.h"

static void heuristics_getGesture( int const amount, int const off, int const * const values,
   int *dxl, int *dyl, int *dxr, int *dyr );

int heuristics_getEnergy( int const amount, int const * const values ) {
  int energy = 0;
  int i;

  for( i = 0; i < amount-1; ++i )
    energy += values[i]*values[i+1];

  return energy;
}

// Gets the two longest consecutive gestures found
// in frames. -1 in off[ab] means no gesture found

// Here what counts: the bigger abs(dx[ab]),   the longer the gesture
//                   the bigger dy[ab]/dx[ab], the slower the gesture
void heuristics_getGestures( int const amount, int const * const values,
  int *offa, int *dxa, int *dya, int *dda,
  int *offb, int *dxb, int *dyb, int *ddb )
{
  int    i, l = 0;
  int dxl [ amount ], dyl [ amount ], dxr [ amount ], dyr [ amount ];

  // Get the longest gestures for each point - both into left and rite
  for( i=0; i<amount; ++i )
    heuristics_getGesture( amount, i, values, dxl + i, dyl + i, dxr + i, dyr + i );

  // "Sort" gesture by length
  *offa = *dxa = *dya = 0;
  for( i=0; i<amount; ++i ) {
    if( dxr[ i ] > *dxa ) { *offa = i; *dxa = dxr[ i ]; *dya = dyr[ i ]; *dda = 1; }
    if( dxl[ i ] > *dxa ) { *offa = i; *dxa = dxl[ i ]; *dya = dyl[ i ]; *dda =-1; }
  }

  // If no gesture found at all, invalidate off
  // and return... second run wouldnt suddenly find a gesture
  if( *dxa == 0 ) { *offa = *offb = -1; return; }

  // Now clear the best result - this will find us the second best result
  i = *offa;
  if( *dda == 1 ) {
    for( i=*offa; i < *offa + dxr[ *offa ]; ++i )
      dxr[ i ] = 0;
  } else {
    for( i=*offa; i > *offa - dxl[ *offa ]; --i )
      dxl[ i ] = 0;
  }

  // "Sort" remaining gestures by length
  *offb = *dxb = *dyb = 0;
  for( i=0; i<amount; ++i ) {
    if( dxr[ i ] > *dxb ) { *offb = i; *dxb =  dxr[ i ]; *dyb = dyr[ i ]; *ddb = 1;}
    if( dxl[ i ] > *dxb ) { *offb = i; *dxb = -dxl[ i ]; *dyb = dyl[ i ]; *ddb =-1;}
  }

  // If no secondary gesture found, invalidate off
  if( *dxb == 0 ) *offb = -1;
}

static void heuristics_getGesture( int const amount, int const off, int const * const values,
   int * const dxl, int * const dyl, int * const dxr, int * const dyr )
{
  int i;

  // Initialize as "nothing happened"
  *dxl = *dxr = *dyl = *dyr = 0;

  // if this didn't peak in last frame, we're not starting
  // a gesture here.
  if( values[off] != VU_PEAK ) return;

  if( off > 0 )        *dyl = values[off]-values[off-1];
  if( off < amount-1 ) *dyr = values[off]-values[off+1];

  if( !*dyl && !*dyr ) return;

  // Depending on where this peaks seems to have come from,
  // chose direction where to follow it
  // try to collect enough monotonic samples and calculate a
  // slope. Since our sample peaks, all others cant be larger 
  if( (*dyl) && (*dyl < *dyr) ) {
    (*dxl)++;
    for( i=off-1; i>=0; --i ) {
      int dy = values[i+1] - values[i];

      // If it scrolled out of scope, ignore it
      if( !values[i] || dy < 0 ) break;

      (*dxl)++;
      (*dyl) += dy;
    }
  } else {
    (*dxr)++;
    // Do the same when going right
    for( i=off+1; i<amount; ++i ) {
      int dy = values[i-1] - values[i];

      // If it scrolled out of scope, ignore it
      if( !values[i] || dy < 0 ) break;

      (*dxr)++;
      (*dyr) += dy;
    }
  }
}