aboutsummaryrefslogtreecommitdiff
path: root/gemnotes_0.2.3/src/polyquant.c
blob: 4d79e3b749f29ca526768cecf8a7556f4da74dee (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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*                                                                              
 *  polyquant: polyrhythmic notelength parser
 *  Copyright (C) 2010 edward kelly <morph_2016@yahoo.co.uk>
 *
 * This software is BSD licensed. See LICENSE.txt for more details
 */

#include "m_pd.h"
#include <math.h>

t_class *polyquant_class;

typedef struct _polyquant {
  t_object x_obj;
  float dmatrix[18][9];
  float tmatrix[18][9][64];
  t_float bpm, qtime, wtime, plimit, dlimit, mode, sim_win, sim_sign, simile, bestsim, bestdiv, besttime, bestnum, bestsign, startoff, startnow;
  t_outlet *time, *div, *num, *sign;//, *sta;
} t_polyquant;

static float primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61};

void polyquant_float(t_polyquant *x, t_floatarg f) {
  int i, j, k;
  float sim_min;
  x->bestsim = 0;
  // x->sim_win = x->sim_win > 0 ? x->sim_win : 0.01; /* defaults to 0.01 so that we avoid /0 errors */
  for(i = 0;i < x->plimit;i++) {
    for(j = x->dlimit;j < 9;j++) {
      for(k=0;k<64;k++) {
	float tvalue = x->tmatrix[i][j][k];
	sim_min = (f > tvalue) ? (f - tvalue) : (tvalue - f);
	x->sim_sign = (f >= tvalue) ? 1 : -1;
	x->simile = 1 / ((sim_min / x->sim_win) + 1);
	if(x->mode == 0) {
	  if(x->simile >= x->bestsim){
	    x->bestsim = x->simile;
	    x->bestdiv = x->dmatrix[i][j];
	    x->besttime = tvalue;
	    x->bestnum = (float)k+1;
	    x->bestsign = x->sim_sign;
	  }
	}
	else if(x->mode == 1) {
	  if(x->simile >= x->bestsim && x->sim_sign == -1){
	    x->bestsim = x->simile;
	    x->bestdiv = x->dmatrix[i][j];
	    x->besttime = tvalue;
	    x->bestnum = (float)k+1;
	    x->bestsign = x->sim_sign;
	  }
	}
	else if(x->mode == 2) {
	  if(x->simile >= x->bestsim && x->sim_sign == 1){
	    x->bestsim = x->simile;
	    x->bestdiv = x->dmatrix[i][j];
	    x->besttime = tvalue;
	    x->bestnum = (float)k+1;
	    x->bestsign = x->sim_sign;
	  }
	}
      }
    }
    //so...the start time quantized, and then the quantized start becomes 0
    //so that the duration alone is quantized.
    //build it into the gemnotes_counter, so that you can make a gemnotes_counter_live
  }
  outlet_float(x->sign, x->bestsign);
  outlet_float(x->num, x->bestnum);
  outlet_float(x->div, x->bestdiv);
  outlet_float(x->time, x->besttime);
}

/*
 * The rarity of vintage instruments is a musician's cartel
 */

void polyquant_bang(t_polyquant *x) {
  outlet_float(x->sign, x->bestsign);
  outlet_float(x->num, x->bestnum);
  outlet_float(x->div, x->bestdiv);
  outlet_float(x->time, x->besttime);
}

void polyquant_bpm(t_polyquant *x, t_floatarg f) {
  x->bpm = f > 0 ? f : 120;
  x->qtime = 60000/x->bpm;
  x->wtime = 4 * x->qtime;
}

void polyquant_plimit(t_polyquant *x, t_floatarg f) {
  x->plimit = f < 1 ? 1 : f > 18 ? 18 : f;
}

void polyquant_dlimit(t_polyquant *x, t_floatarg f) {
  x->dlimit = f < 0 ? 0 : f > 8 ? 8 : f;
}

void polyquant_mode(t_polyquant *x, t_floatarg f) {
  x->mode = f < 0 ? 0 : f > 2 ? 2 : f;
}

void polyquant_win(t_polyquant *x, t_floatarg f) {
  x->sim_win = f > 0 ? f : 10;
}

void *polyquant_new(t_floatarg ibpm, t_floatarg flim)
{
  t_polyquant *x = (t_polyquant *)pd_new(polyquant_class);
  x->mode = 0;
  x->bpm = ibpm > 0 ? ibpm : 120;
  x->qtime = 60000 / x->bpm;
  x->wtime = x->qtime * 4;
  x->plimit = flim < 1 ? 1 : flim > 18 ? 18 : flim;
  x->dlimit = 4;
  x->sim_win = 10;
  x->time = outlet_new(&x->x_obj, gensym("float"));
  x->div = outlet_new(&x->x_obj, gensym("float"));
  x->num = outlet_new(&x->x_obj, gensym("float"));
  x->sign = outlet_new(&x->x_obj, gensym("float"));

  int i, j, k;
  float div, time;
  //init dmatrix
  for(i=0;i<18;i++) {
    for(j=0;j<9;j++) {
      x->dmatrix[i][j] = 0;
    }
  }

  j = 0;
  div = 0;
  for(i=0;i<18;i++) {
    div = primes[i];
    while(div<=128) {
      div *= 2;
    }
    x->dmatrix[i][0] = div;
    while(div>=1) {
      j++;
      div *= 0.5;
      x->dmatrix[i][j] = div;
    }
  }
  //init tmatrix
  for(i=0;i<18;i++) {
    for(j=0;j<9;j++) {
      div = x->dmatrix[i][j];
      if(div>0) {
	k = 0;
	time = x->wtime / div;
	for(k=0;k<64;k++) {
	  x->tmatrix[i][j][k] = time * (k + 1);
	}
      }
    }
  }
  return(void *)x;
}


void polyquant_setup(void) {
  polyquant_class = class_new(gensym("polyquant"),
  (t_newmethod)polyquant_new,
  0, sizeof(t_polyquant),
  0, A_DEFFLOAT, A_DEFFLOAT, 0);
  post("|---------->polyquant<----------|");
  post("|---->polyrhythmic quantize<----|");
  post("|-->edward<--->kelly<--->2010<--|");

  class_addbang(polyquant_class, polyquant_bang);
  class_addfloat(polyquant_class, polyquant_float);
  class_addmethod(polyquant_class, (t_method)polyquant_bpm, gensym("bpm"), A_DEFFLOAT, 0);
  class_addmethod(polyquant_class, (t_method)polyquant_plimit, gensym("plimit"), A_DEFFLOAT, 0);
  class_addmethod(polyquant_class, (t_method)polyquant_dlimit, gensym("dlimit"), A_DEFFLOAT, 0);
  class_addmethod(polyquant_class, (t_method)polyquant_mode, gensym("mode"), A_DEFFLOAT, 0);
  class_addmethod(polyquant_class, (t_method)polyquant_win, gensym("win"), A_DEFFLOAT, 0);
}