2 Commits 70e2a237b0 ... d20e36d6c6

Author SHA1 Message Date
  George Bartolomey d20e36d6c6 Fix Makefile 2 years ago
  George Bartolomey 65b1b92fa1 Add Solo and Pitch modes 2 years ago
3 changed files with 77 additions and 8 deletions
  1. 1 1
      Makefile
  2. 2 0
      help.txt
  3. 74 7
      w2midi.c

+ 1 - 1
Makefile

@@ -7,7 +7,7 @@ PREFIX = /usr
 w2midi: w2midi.o
 	${CC} w2midi.o -o w2midi ${LDFLAGS}
 
-w2midi.o:
+w2midi.o: w2midi.c
 	${CC} -c ${CFLAGS} w2midi.c -o w2midi.o
 
 clean:

+ 2 - 0
help.txt

@@ -6,4 +6,6 @@
 "-a [floating point]\tMax difference from ideal semitone frequency to received\n"
 "-n [client name]\tJACK client name\n"
 "-s [start] -e [end]\tAnalyzing range in semitones\n"
+"-o\tSolo mode\n"
+"-p\tPitch mode\n"
 "-h\t\t\tShow this help\n"

+ 74 - 7
w2midi.c

@@ -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;