aboutsummaryrefslogtreecommitdiff
path: root/voicing_detector~/voicing_detector~.c
blob: 9c143080e3c939b474c57bc2455c53cadc27be5f (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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include "m_pd.h"
#include <math.h>

static t_class *voicing_detector_tilde_class;

typedef struct _voicing_control
{
  t_float *c_input;
  t_float f_sum_abs;
  t_atom otemp[4096];
  t_int method;
} t_voicing_control;

typedef struct _voicing_detector_tilde
{
  t_object x_obj;
  t_float f_dummy, f_thresh, f_low, f_high;
  t_voicing_control x_ctl;
  t_outlet *voiced, *prob;
} t_voicing_detector_tilde;

static t_int *voicing_detector_tilde_perform(t_int *w)
{
  t_voicing_detector_tilde     *x =   (t_voicing_detector_tilde *)(w[1]);  
  t_voicing_control *ctl = (t_voicing_control *)(w[2]);  
  t_int                n =                 (int)(w[3]);
  t_float            *in = ctl->c_input;
  if (x->f_high < x->f_low)
    {
      float tmp = x->f_low;
      x->f_low = x->f_high;
      x->f_high = tmp;
    }
  t_float current, previous, next, temp0, temp1, avg, max, peak0;
  current = previous = next = temp0 = temp1 = avg = max = peak0 = 0;
  t_float min = 1000;
  t_float samplerate = sys_getsr();
  t_float start = samplerate / x->f_high;
  start = start > 1 ? start : 1;
  t_float end = samplerate / x->f_low;
  end = end < (n-1) ? end : n-1;
  t_float result, prob, diff, diff2;
  t_int i = 0;
  int j;
  int l = n;
  int maxp = 0;
  int maxi = 0;
  float temp[n];
  ctl->f_sum_abs = 0.0;
  for (i=0;i<l;i++)
    {
      ctl->f_sum_abs += fabs(in[i]); /* I have to calculate f_sum_abs for the whole block before I can calculate amdf */
      temp[i] = 0.0;
      SETFLOAT(&ctl->otemp[i], 0.0);
    }
  for (i=1;i<l;i++)
    {
      temp1 = 0;
      for (j=start;j<=end;j++) /* the Average Magnitude Difference Function */
	  {
	    temp[j] = i + j < l ? in[i+j] : 0.0;
	    temp0 = atom_getfloatarg(i, 4096, ctl->otemp);
	    temp1 += fabs(in[j] - temp[j]);
	  }
      temp1 += ((float)i / (float)l) * ctl->f_sum_abs;
      SETFLOAT(&ctl->otemp[i], temp1);
    }

  for (i=start+1;i<end;i++)
    {
      previous= atom_getfloatarg(i-1, 2048, ctl->otemp);
      current = atom_getfloatarg(i, 2048, ctl->otemp);
      next = atom_getfloatarg(i+1, 2048, ctl->otemp);
      max = current > max ? current : max;
      min = current < min ? current : min;
      avg += current;
    }
  avg = avg / (end-start);
  diff = avg - min;
  diff2 = max - min;
  result = ctl->method == 0 ? ((avg - min) > (x->f_thresh) ? 1 : 0) : ((max - min) > x->f_thresh ? 1 : 0);
  prob = diff2 / max;
  outlet_float(x->prob, prob);
  outlet_float(x->voiced, result);
  return(w+4);
}

void voicing_detector_tilde_bound(t_voicing_detector_tilde *x, t_floatarg f1, t_floatarg f2)
{
  x->f_low = f1;
  x->f_high = f2;
}

void voicing_detector_tilde_method(t_voicing_detector_tilde *x, t_floatarg f)
{
  x->x_ctl.method = f > 0 ? 1 : 0;
}

void *voicing_detector_tilde_dsp(t_voicing_detector_tilde *x, t_signal **sp)
{
  x->x_ctl.c_input = sp[0]->s_vec;
  dsp_add(voicing_detector_tilde_perform, 3, x, &x->x_ctl, sp[0]->s_n);
  return (void *)x;
}

void *voicing_detector_tilde_new(t_floatarg f)
{
  t_voicing_detector_tilde *x = (t_voicing_detector_tilde *)pd_new(voicing_detector_tilde_class);
  x->f_thresh = f < 0 ? f : 25;
  x->f_low = 60;
  x->f_high = 500;

  floatinlet_new (&x->x_obj, &x->f_thresh);  
  x->voiced = outlet_new(&x->x_obj, gensym("float"));
  x->prob = outlet_new(&x->x_obj, gensym("float"));
  return (void *)x;
}

void voicing_detector_tilde_setup(void)
{
  voicing_detector_tilde_class = class_new(gensym("voicing_detector~"), (t_newmethod)voicing_detector_tilde_new, 0, sizeof(t_voicing_detector_tilde), CLASS_DEFAULT, A_DEFFLOAT, 0);
  
  post("\n-->AMDF voicing detector v0.2");
  post("-->by Nicolas Chetry <okin@altern.org>");
  post("-->& Edward Kelly <morph_2016@yahoo.co.uk>");
  
  class_addmethod(voicing_detector_tilde_class, (t_method)voicing_detector_tilde_bound, gensym("bound"), A_DEFFLOAT, A_DEFFLOAT, 0);
  class_addmethod(voicing_detector_tilde_class, (t_method)voicing_detector_tilde_method, gensym("method"), A_DEFFLOAT, 0);
  class_addmethod(voicing_detector_tilde_class, (t_method)voicing_detector_tilde_dsp, gensym("dsp"), 0);

  CLASS_MAINSIGNALIN(voicing_detector_tilde_class, t_voicing_detector_tilde, f_dummy);
}