|
@@ -38,8 +38,12 @@ jack_nframes_t sample_rate;
|
|
|
float *window;
|
|
|
/*Буфер, содержащий предыдущий сигнал и текущий; используется ПФ*/
|
|
|
float *buffer;
|
|
|
+int solo_mode;
|
|
|
+int pitch_mode;
|
|
|
unsigned int buffer_size;
|
|
|
/*Таблица полутон-диск. частота из ПФ*/
|
|
|
+unsigned short prev_pitch;
|
|
|
+unsigned short *pitch_table;
|
|
|
unsigned char *semitone_bins;
|
|
|
/*Громкости полутонов*/ unsigned char *note_pressures;
|
|
|
unsigned char *prev_note_pressures;
|
|
@@ -67,12 +71,16 @@ void generate_semitone_bins();
|
|
|
void calculate_note_pressures(float *spectral_density);
|
|
|
/*Убрать обертоны*/
|
|
|
void remove_obertones();
|
|
|
+void remove_all_other();
|
|
|
void send_events(void *output_buffer);
|
|
|
+void send_pitch(void *output_buffer, float *spectral_density);
|
|
|
void array_mul(float *a, float *b, int n);
|
|
|
/*|z|^2 Преобразовать комплексные амлитуды в спектральную плотность*/
|
|
|
void cmplx_amp_to_spectral_density(fftwf_complex *in, int n);
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
+ solo_mode = 0;
|
|
|
+ pitch_mode = 0;
|
|
|
buffer_size = DEFAULT_BUFFER_SIZE;
|
|
|
amp_threshold = DEFAULT_AMP_THRESHOLD;
|
|
|
acc_threshold = DEFAULT_ACC_THRESHOLD;
|
|
@@ -93,7 +101,7 @@ int main(int argc, char **argv) {
|
|
|
|
|
|
void parse_args(int argc, char **argv) {
|
|
|
int opt;
|
|
|
- while ((opt = getopt(argc, argv, "b:d:a:n:s:e:n:h")) != -1) {
|
|
|
+ while ((opt = getopt(argc, argv, "b:d:a:n:s:e:n:hop")) != -1) {
|
|
|
switch (opt) {
|
|
|
case 'b':
|
|
|
buffer_size = atoi(optarg);
|
|
@@ -113,6 +121,13 @@ void parse_args(int argc, char **argv) {
|
|
|
case 'e':
|
|
|
event_range_end = atoi(optarg);
|
|
|
break;
|
|
|
+ case 'o':
|
|
|
+ solo_mode = 1;
|
|
|
+ break;
|
|
|
+ case 'p':
|
|
|
+ printf("pitch\n");
|
|
|
+ pitch_mode = 1;
|
|
|
+ break;
|
|
|
case 'h':
|
|
|
printf("%s", help_text);
|
|
|
exit(0);
|
|
@@ -153,8 +168,9 @@ void init() {
|
|
|
semitone_bins = (unsigned char*)malloc(buffer_size / 2);
|
|
|
note_pressures = (unsigned char*)malloc(NOTES_BITMAP_SIZE);
|
|
|
prev_note_pressures = (unsigned char*)malloc(NOTES_BITMAP_SIZE);
|
|
|
+ pitch_table = (unsigned short*)malloc(buffer_size / 2 * sizeof(unsigned short));
|
|
|
if (!buffer || !window || !semitone_bins
|
|
|
- || !note_pressures || !prev_note_pressures) {
|
|
|
+ || !note_pressures || !prev_note_pressures || !pitch_table) {
|
|
|
fprintf(stderr, "Failed to allocate memory!\n");
|
|
|
exit(EXIT_FAILURE);
|
|
|
}
|
|
@@ -165,6 +181,7 @@ void init() {
|
|
|
generate_window(window, buffer_size);
|
|
|
memset(prev_note_pressures, 0, NOTES_BITMAP_SIZE);
|
|
|
memset(buffer, 0, buffer_size * sizeof(float));
|
|
|
+ prev_pitch = 0;
|
|
|
generate_semitone_bins();
|
|
|
}
|
|
|
|
|
@@ -190,7 +207,12 @@ int process(jack_nframes_t nframes, void *arg) {
|
|
|
cmplx_amp_to_spectral_density(fft_out, buffer_size / 2);
|
|
|
spectral_density = (float*)fft_out;
|
|
|
calculate_note_pressures(spectral_density);
|
|
|
- remove_obertones();
|
|
|
+ if (pitch_mode)
|
|
|
+ send_pitch(output_buffer, spectral_density);
|
|
|
+ if (solo_mode)
|
|
|
+ remove_all_other();
|
|
|
+ else
|
|
|
+ remove_obertones();
|
|
|
send_events(output_buffer);
|
|
|
memcpy(prev_note_pressures, note_pressures, NOTES_BITMAP_SIZE);
|
|
|
return 0;
|
|
@@ -233,17 +255,23 @@ void generate_semitone_bins() {
|
|
|
freq = (float)i * sample_rate / (float)buffer_size;
|
|
|
semitone = 12 * log2(freq / 440) + 69;
|
|
|
difference = abs(round(semitone) - semitone);
|
|
|
- if (semitone > 0 && semitone < 256 && difference < acc_threshold)
|
|
|
+ if (semitone > 0 && semitone < 256 && difference < acc_threshold) {
|
|
|
semitone_bins[i] = round(semitone);
|
|
|
- else
|
|
|
- semitone_bins[i] = 0;
|
|
|
+ if (pitch_mode)
|
|
|
+ pitch_table[i] = ((round(semitone) - semitone) * 0x2000 / 2) + 0x2000;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ semitone_bins[i] = 0;
|
|
|
+ if (pitch_mode)
|
|
|
+ pitch_table[i] = 0;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void calculate_note_pressures(float *spectral_density) {
|
|
|
int i;
|
|
|
float db;
|
|
|
- for (i = 0; i < buffer_size / 2; i++) {
|
|
|
+ for (i = event_range_start; i < buffer_size / 2 && i < event_range_end; i++) {
|
|
|
db = 10 * log10(spectral_density[i]);
|
|
|
if (db > amp_threshold) {
|
|
|
note_pressures[semitone_bins[i]] = (db < 256 ? db : 255);
|
|
@@ -263,6 +291,45 @@ void remove_obertones() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void remove_all_other() {
|
|
|
+ int i;
|
|
|
+ int max_i;
|
|
|
+ unsigned char max;
|
|
|
+ max_i = 0;
|
|
|
+ max = 0;
|
|
|
+ for (i = 0; i < NOTES_BITMAP_SIZE - 3; i++) {
|
|
|
+ if (note_pressures[i] > max) {
|
|
|
+ max_i = i;
|
|
|
+ max = note_pressures[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ memset(note_pressures, 0, NOTES_BITMAP_SIZE);
|
|
|
+ note_pressures[max_i] = max;
|
|
|
+}
|
|
|
+
|
|
|
+void send_pitch(void *output_buffer, float *spectral_density) {
|
|
|
+ int i;
|
|
|
+ int max_i;
|
|
|
+ float max;
|
|
|
+ unsigned short pitch;
|
|
|
+ unsigned char *midi;
|
|
|
+ max_i = -1;
|
|
|
+ max = -INFINITY;
|
|
|
+ for (i = 1; i < buffer_size / 2; i++) {
|
|
|
+ if (max < spectral_density[i]) {
|
|
|
+ max = spectral_density[i];
|
|
|
+ max_i = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pitch = pitch_table[max_i];
|
|
|
+ midi = jack_midi_event_reserve(output_buffer, 0, 3);
|
|
|
+ midi[0] = 0xE0;
|
|
|
+ midi[1] = pitch & 0xFF;
|
|
|
+ midi[2] = pitch >> 8 & 0xFF;
|
|
|
+ printf("%i\n", pitch);
|
|
|
+ prev_pitch = pitch;
|
|
|
+}
|
|
|
+
|
|
|
void send_events(void *output_buffer) {
|
|
|
int i;
|
|
|
unsigned char *midi;
|