1 /* Calf DSP plugin pack
4 * Copyright (C) 2015 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
25 #include <calf/giface.h>
26 #include <calf/modules_pitch.h>
27 #include <calf/utils.h>
29 #if ENABLE_EXPERIMENTAL
31 // http://www.cs.otago.ac.nz/tartini/papers/A_Smarter_Way_to_Find_Pitch.pdf
33 using namespace calf_plugins
;
35 pitch_audio_module::pitch_audio_module()
39 pitch_audio_module::~pitch_audio_module()
43 void pitch_audio_module::set_sample_rate(uint32_t sr
)
48 void pitch_audio_module::params_changed()
52 void pitch_audio_module::activate()
55 for (size_t i
= 0; i
< 2 * BufferSize
; ++i
)
56 waveform
[i
] = spectrum
[i
] = autocorr
[i
] = 0;
57 for (size_t i
= 0; i
< BufferSize
; ++i
)
61 void pitch_audio_module::deactivate()
65 void pitch_audio_module::recompute()
67 // second half of the waveform always zero
68 double sumsquares_acc
= 0.;
69 for (int i
= 0; i
< BufferSize
; ++i
)
71 float val
= inputbuf
[(i
+ write_ptr
) & (BufferSize
- 1)];
72 float win
= 0.54 - 0.46 * cos(i
* M_PI
/ BufferSize
);
75 sumsquares
[i
] = sumsquares_acc
;
76 sumsquares_acc
+= val
* val
;
78 sumsquares
[BufferSize
] = sumsquares_acc
;
79 //waveform[i] = inputbuf[(i + write_ptr) & (BufferSize - 1)];
80 transform
.calculate(waveform
, spectrum
, false);
81 pfft::complex temp
[2 * BufferSize
];
82 for (int i
= 0; i
< 2 * BufferSize
; ++i
)
84 float val
= std::abs(spectrum
[i
]);
87 //temp[i] = spectrum[i] * std::conj(spectrum[i]);
88 transform
.calculate(temp
, autocorr
, true);
89 sumsquares_last
= sumsquares_acc
;
93 for (i
= 2; i
< BufferSize
/ 2; ++i
)
95 float mag
= 2.0 * autocorr
[i
].real() / (sumsquares
[BufferSize
] + sumsquares
[BufferSize
- i
] - sumsquares
[i
]);
103 for (i
= 2; i
< BufferSize
/ 2 && magarr
[i
+ 1] < magarr
[i
]; ++i
)
105 float thr
= *params
[par_pd_threshold
];
106 for (; i
< BufferSize
/ 2; ++i
)
108 if (magarr
[i
] >= thr
* maxpt
)
110 while(i
< BufferSize
/ 2 - 1 && magarr
[i
+ 1] > magarr
[i
])
117 if (maxpt
> 0 && maxpos
< BufferSize
/ 2 - 1)
119 float y1
= magarr
[maxpos
- 1];
120 float y2
= magarr
[maxpos
];
121 float y3
= magarr
[maxpos
+ 1];
122 float pos2
= maxpos
+ 0.5 * (y1
- y3
) / (y1
- 2 * y2
+ y3
);
123 dsp::note_desc desc
= dsp::hz_to_note(srate
/ pos2
, *params
[par_tune
]);
124 *params
[par_note
] = desc
.note
;
125 *params
[par_cents
] = desc
.cents
;
126 *params
[par_freq
] = desc
.freq
;
127 *params
[par_clarity
] = maxpt
;
129 *params
[par_clarity
] = maxpt
;
132 bool pitch_audio_module::get_graph(int index
, int subindex
, int phase
, float *data
, int points
, cairo_iface
*context
, int *mode
) const
134 if (index
== par_pd_threshold
&& subindex
== 0)
136 context
->set_source_rgba(1, 0, 0);
137 for (int i
= 0; i
< points
; i
++)
139 float ac
= autocorr
[i
* (BufferSize
/ 2 - 1) / (points
- 1)].real();
141 data
[i
] = sqrt(ac
/ sumsquares_last
);
143 data
[i
] = -sqrt(-ac
/ sumsquares_last
);
147 if (index
== par_pd_threshold
&& subindex
== 1)
149 context
->set_source_rgba(0, 0, 1);
150 for (int i
= 0; i
< points
; i
++)
152 data
[i
] = 0.0625 * log(std::abs(spectrum
[i
* (BufferSize
/ 4 - 1) / (points
- 1)]));
156 if (index
== par_pd_threshold
&& subindex
== 2)
158 context
->set_source_rgba(0, 0, 0);
159 for (int i
= 0; i
< points
; i
++)
161 int j
= i
* (BufferSize
/ 2 - 1) / (points
- 1);
162 float mag
= magarr
[j
];
167 if (index
== par_pd_threshold
&& subindex
== 3)
169 context
->set_source_rgba(0, 1, 1);
170 for (int i
= 0; i
< points
; i
++)
172 int j
= i
* (BufferSize
- 1) / (points
- 1);
173 float mag
= std::abs(sumsquares
[j
]);
174 data
[i
] = 0.25 * log(mag
);
181 uint32_t pitch_audio_module::process(uint32_t offset
, uint32_t numsamples
, uint32_t inputs_mask
, uint32_t outputs_mask
)
183 uint32_t endpos
= offset
+ numsamples
;
184 bool has2nd
= ins
[1] != NULL
;
186 int bperiod
= BufferSize
;
187 int sd
= *params
[par_pd_subdivide
];
188 if (sd
>= 1 && sd
<= 8)
191 // XXXKF note: not working, not optimized, just trying stuff out
192 for (uint32_t i
= offset
; i
< endpos
; ++i
)
194 float val
= ins
[0][i
];
195 inputbuf
[write_ptr
] = val
;
196 write_ptr
= (write_ptr
+ 1) & (BufferSize
- 1);
197 if (!(write_ptr
% bperiod
))
199 outs
[0][i
] = ins
[0][i
];
201 outs
[1][i
] = ins
[1][i
];