diff options
| author | gramanas <anastasis.gramm2@gmail.com> | 2023-04-20 18:24:49 +0300 | 
|---|---|---|
| committer | gramanas <anastasis.gramm2@gmail.com> | 2023-04-20 18:24:49 +0300 | 
| commit | c161e1016a04566a56b4858ea43502fed88dcc7f (patch) | |
| tree | b4b3086f000df6b63229dae6057f1aa253811b30 | |
| parent | 1e374b426b4182c7b73b35219aadaca267b9623c (diff) | |
| download | synth-project-c161e1016a04566a56b4858ea43502fed88dcc7f.tar.gz synth-project-c161e1016a04566a56b4858ea43502fed88dcc7f.tar.bz2 synth-project-c161e1016a04566a56b4858ea43502fed88dcc7f.zip | |
Add midi
| -rw-r--r-- | configure.ac | 1 | ||||
| -rw-r--r-- | src/Makefile.am | 6 | ||||
| -rw-r--r-- | src/midi.c | 91 | ||||
| -rw-r--r-- | src/midi.h | 17 | ||||
| -rw-r--r-- | src/synth.c | 10 | ||||
| -rw-r--r-- | src/synth_engine.c | 43 | ||||
| -rw-r--r-- | src/synth_engine.h | 7 | ||||
| -rw-r--r-- | src/synth_gui.c | 36 | 
8 files changed, 151 insertions, 60 deletions
| diff --git a/configure.ac b/configure.ac index 7df60c7..ebf1d63 100644 --- a/configure.ac +++ b/configure.ac @@ -27,6 +27,7 @@ AC_PROG_CC  dnl AC_CHECK_HEADERS([stdlib.h])  AC_CHECK_HEADERS([raylib.h])  AC_CHECK_HEADERS([portaudio.h]) +AC_CHECK_HEADERS([portmidi.h])  dnl AC_CHECK_FUNCS([memset])  dnl AC_CHECK_FUNCS([strcasecmp]) diff --git a/src/Makefile.am b/src/Makefile.am index 91e1be5..3aff1d3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,8 @@ common_sources = filter.c \                   lowpass.c \                   lowpass.h \                   Makefile.am \ +                 midi.c \ +                 midi.h \                   notes.h \                   raygui.h \                   synth_engine.c \ @@ -24,10 +26,10 @@ common_sources = filter.c \  # -fno-math-errno and stuff like that, without enabling  # -funsafe-math-optimizations. Some FP code can get big speedups from  # fast-math, like auto-vectorization. -AM_CFLAGS = -O3 -march=native -fno-math-errno -funroll-loops -flto +AM_CFLAGS = -O3 -march=native -fno-math-errno -funroll-loops -flto -pthread  synth_SOURCES = synth.c $(common_sources) -synth_LDADD = -lportaudio -lrt -lm -lasound -lraylib +synth_LDADD = -lportaudio -lrt -lm -lasound -lraylib -lportmidi  #cookbook_SOURCES = cookbook.c $(common_sources)  #cookbook_SOURCES = cookbook.c $(common_sources)  #cook_SOURCES = cook.c $(common_sources) diff --git a/src/midi.c b/src/midi.c new file mode 100644 index 0000000..46608cb --- /dev/null +++ b/src/midi.c @@ -0,0 +1,91 @@ +#include "midi.h" + +#include <string.h> + +void midi_decode(uint32_t msg) { +  //  printf("MIDI message: 0x%X\n", msg); +  uint8_t status = msg; +  uint8_t data1 = (msg >> 8) & 0xFF; +  uint8_t data2 = (msg >> 16) & 0xFF; +  uint8_t channel = (status & 0x0F) + 1; // convert to human +  uint8_t message = status >> 4; + +  switch (message) { +    case 0x08: +      printf("Note Off: channel=%d, note=%d, velocity=%d\n", channel, data1, data2); +      break; +    case 0x09: +      printf("Note On: channel=%d, note=%d, velocity=%d\n", channel, data1, data2); +      break; +    case 0x0A: +      printf("Aftertouch: channel=%d, note=%d, pressure=%d\n", channel, data1, data2); +      break; +    case 0x0B: +      printf("Control Change: channel=%d, controller=%d, value=%d\n", channel, data1, data2); +      break; +    case 0x0C: +      printf("Program Change: channel=%d, program=%d\n", channel, data1); +      break; +    case 0x0D: +      printf("Channel Pressure: channel=%d, pressure=%d\n", channel, data1); +      break; +    case 0x0E: +      printf("Pitch Bend: channel=%d, value=%d\n", channel, ((data2 << 7) | data1) - 8192); +      break; +    default: +      printf("Unknown MIDI message\n"); +      break; +  } +} + + +void +midiCallback(PtTimestamp timestamp, void *userData) { +  midi_t * m = (midi_t *)userData; + +  if (!m->stream) return; + +  if (!Pm_Poll(m->stream)) return; + +  PmEvent buf; +  Pm_Read(m->stream, &buf, 1); + +  //printf("%d\n", buf.message); +  midi_decode(buf.message); +   +} + +void +init_midi(midi_t *m, synth_t *synth) +{ +  m->stream = NULL; + +  Pm_Initialize(); + +  printf("midi devs: %d\n", Pm_CountDevices()); +  const PmDeviceInfo *info; +  int i; +  for (i = 0; i < Pm_CountDevices(); i++) { +    info = Pm_GetDeviceInfo(i); +    printf("%d: %s [input: %d output: %d opened: %d is_virt:%d] (interf: %s) -- %d\n", i, info->name, info->input, info->output, info->opened, info->is_virtual, info->interf, Pm_GetDefaultInputDeviceID()); +    //if (!strcmp("MPK225 MIDI", info->name) && !info->input) break; +    if (!strcmp("MPK225 Port A", info->name) && info->input == 1) break; +  } + +  Pt_Start(1, midiCallback, m); + +  Pm_OpenInput(&(m->stream), +               i, //Pm_GetDefaultInputDeviceID(), +               NULL, +               128, +               NULL, +               NULL); +} + +void +terminate_midi(midi_t *m) +{ +  Pm_Close(m->stream); +  Pt_Stop(); +  Pm_Terminate(); +} diff --git a/src/midi.h b/src/midi.h new file mode 100644 index 0000000..fd9b749 --- /dev/null +++ b/src/midi.h @@ -0,0 +1,17 @@ +#ifndef MIDI_H +#define MIDI_H + +#include <portmidi.h> +#include <porttime.h> + +#include "synth_engine.h" + +typedef struct midi_t { +  PortMidiStream * stream; +  synth_t * synth; +} midi_t; + +void init_midi(midi_t *midi, synth_t *synth); +void terminate_midi(midi_t *midi); + +#endif /* MIDI_H */ diff --git a/src/synth.c b/src/synth.c index 5ce932f..29c44e7 100644 --- a/src/synth.c +++ b/src/synth.c @@ -27,16 +27,20 @@  #include <string.h>  #include <portaudio.h> +#include <portmidi.h> +  /* graphics */  /* synth */  #include "synth_engine.h"  #include "synth_gui.h" +#include "midi.h"  #define NUM_SECONDS   (1)  #define WAVE_SIZE   (44100) +  static void  StreamFinished( void* synthData )  { @@ -44,6 +48,7 @@ StreamFinished( void* synthData )    printf( "Stream Completed\n");  } +  int  main(void) {    PaStreamParameters outputParameters; @@ -51,7 +56,10 @@ main(void) {    PaError err;    int i;    synth_t synth; +  midi_t midi; +    init_synth(&synth); +  init_midi(&midi, &synth);    err = Pa_Initialize(); @@ -107,6 +115,8 @@ main(void) {    return err;   error:    Pa_Terminate(); +  free_synth(&synth); +  terminate_midi(&midi);    fprintf( stderr, "An error occurred while using the portaudio stream\n" );    fprintf( stderr, "Error number: %d\n", err );    fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); diff --git a/src/synth_engine.c b/src/synth_engine.c index 6bd6bf6..56ab771 100644 --- a/src/synth_engine.c +++ b/src/synth_engine.c @@ -152,14 +152,11 @@ make_sample(unsigned long long phase, void *synthData, unsigned int sample_rate,    //LFO!    //if (synth->adsr.elapsed > SAMPLE_RATE / 2) synth->adsr.elapsed = 0; -  if (synth->poly) { -    int n = synth->notes_active; -    for (int i = 0; i < n; i++) { -      sample += (1.0 / n) * synth->gen[synth->geni](synth->freq[i] + synth->freq_offset, synth->freq_count[i], synth->x, sample_rate); -    } -  } else { -      sample = synth->gen[synth->geni](synth->n.freq + synth->freq_offset, phase, synth->x, sample_rate); -  } +    /* int n = synth->actual_notes_active; */ +    /* for (int i = 0; i < n; i++) { */ +    /*   sample += (1.0 / n) * synth->gen[synth->geni](synth->actual_freq[i] + synth->freq_offset, synth->actual_freq_count[i], synth->x, sample_rate); */ +    /* } */ +  sample = synth->gen[synth->geni](synth->n.freq + synth->freq_offset, phase, synth->x, sample_rate);    if (!viz && synth->filter) {      // ALLL THE FILTERS @@ -197,7 +194,7 @@ sound_gen(const void *inputBuffer, void *outputBuffer,    (void) statusFlags;    (void) inputBuffer; -  float s; +  float s = 0.0f;    for( unsigned long i=0; i<framesPerBuffer; i++ ) {      //get_portaudio_frame(outputBuffer, synth);      if (!synth->active) { @@ -205,29 +202,29 @@ sound_gen(const void *inputBuffer, void *outputBuffer,        *out++ = 0.0f;        continue;      } +      if (adsr_amplitude(synth, synth->adsr.elapsed) == 0 && synth->n.noteOff != 0) { -      //printf("SYNTH OPFF\n");        synth->active = 0;        *out++ = 0.0f;        *out++ = 0.0f;        continue;      } +      s = make_sample(synth->n.elapsed, synth, SAMPLE_RATE, 0);      *out++ = s;      *out++ = s; +      synth->adsr.elapsed++;      synth->n.elapsed++; -    for (int j = 0; j < synth->notes_active; j++) { -      synth->freq_count[j]++; -    }      if (!synth->multi) { -      for (int j = 0; j < synth->notes_active; j++) { -        if (synth->freq_count[j] >= (1.0 / synth->freq[i]) * SAMPLE_RATE) synth->freq_count[j] = 0; -      }        if (synth->n.elapsed >= (1.0 / synth->n.freq) * SAMPLE_RATE) synth->n.elapsed = 0;      } else {      } +    synth->viz.wi >= 1000199 ? synth->viz.wi = 0 : synth->viz.wi++; +    synth->viz.wave[synth->viz.wi] = s; +    synth->viz.wi >= 1000199 ? synth->viz.wi = 0 : synth->viz.wi++; +    synth->viz.wave[synth->viz.wi] = s;    }    return paContinue; @@ -239,12 +236,6 @@ init_synth(synth_t * synth)    synth->freq_offset = 0;    synth->gain = 1;    synth->x = 1; - -  synth->notes_active = 0; -  for (int i = 0; i<100;i++) { -    synth->freq[i] = 0; -    synth->freq_count[i] = 0; -  }    synth->n.freq    = 0;     synth->n.noteOn  = 0;  @@ -277,8 +268,16 @@ init_synth(synth_t * synth)    synth->active = 0;    synth->viz.sample_rate_divider = 1; +  synth->viz.wi = 0;    LowPass_Init();    synth->fff = create_bw_low_pass_filter(2, SAMPLE_RATE, 400);    synth->fff2 = create_bw_band_stop_filter(8, SAMPLE_RATE, 15000, 22000);  } + +void +free_synth(synth_t * synth) +{ +  free_bw_low_pass(synth->fff); +  free_bw_band_stop(synth->fff2); +} diff --git a/src/synth_engine.h b/src/synth_engine.h index 1191892..86cfe1a 100644 --- a/src/synth_engine.h +++ b/src/synth_engine.h @@ -40,6 +40,8 @@ typedef struct {  typedef struct {    int sample_rate_divider; +  float wave[1000200]; +  int wi;  } viz_t;  typedef struct { @@ -47,10 +49,6 @@ typedef struct {    float gain;    float x; -  int notes_active; -  float freq[100]; -  unsigned long long freq_count[100]; -    note_t n;    adsr_t adsr; @@ -78,6 +76,7 @@ typedef struct {  float adsr_amplitude(void *synthData, unsigned long long elapsed);  float make_sample(unsigned long long phase, void *synthData, unsigned int sample_rate, int viz);  void init_synth(synth_t * synth); +void free_synth(synth_t * synth);  int sound_gen(const void *inputBuffer, void *outputBuffer,                unsigned long framesPerBuffer,                const PaStreamCallbackTimeInfo* timeInfo, diff --git a/src/synth_gui.c b/src/synth_gui.c index d09a9b6..6b44595 100644 --- a/src/synth_gui.c +++ b/src/synth_gui.c @@ -14,16 +14,9 @@ set_note(void *synthData, float note, PaTime time, int key)    synth->n.noteOn = time;    synth->n.noteOff = 0;    synth->n.elapsed = 0; -  if (synth->poly) { -    if (!synth->notes_active) synth->adsr.elapsed = 0; -  } else { -    synth->adsr.elapsed = 0; -  } +  synth->adsr.elapsed = 0;    synth->active = 1; - -  synth->freq[synth->notes_active]  = note; -  synth->freq_count[synth->notes_active++] = 0;  } @@ -43,35 +36,11 @@ keyboard(void *synthData, PaStream *stream)          set_note(synth, note, Pa_GetStreamTime(stream), keys[i]);          //printf("Note On : %s[%d] %fHz\n", int_to_note(i % 12), (synth->octave + (i / 12)) % 8, note);        } -      printf("["); -      for (int j = 0; j < synth->notes_active; j++) { -        printf("%f ", synth->freq[j]); -      } -      printf("]\n");      }    }    for (int i = 0; keys[i]; i++) {      if (IsKeyReleased(keys[i])) {        note = notes[i % 12][(synth->octave + (i / 12)) % 8]; -      int j; -      for (j = 0; j < synth->notes_active; j++) { -        // printf("Comparing freq(j): %f to note: %f\n", synth->freq[j], note); -        if (synth->freq[j] == note) { -          synth->freq[j]  = 0; -          synth->notes_active--; -          //printf("Note down %f\n", note); -          break; -        } -      } -      for (int k = j; k < synth->notes_active + 1; k++) { -        //printf("moving %f <-- %f\n", synth->freq[k], synth->freq[k + 1]); -        synth->freq[k]  = synth->freq[k + 1]; -      } -      printf("["); -      for (int j = 0; j < synth->notes_active; j++) { -        printf("%f ", synth->freq[j]); -      } -      printf("]\n");        if (synth->n.key == keys[i]) {          synth->n.noteOff = Pa_GetStreamTime(stream);          //printf("Note Off: %s[%d]\n", int_to_note(i % 12), (synth->octave + (i / 12)) % 8); @@ -112,6 +81,9 @@ draw_signals(synth_t * synth, int x, int y, int width, int height)    GuiSpinner((Rectangle){ x+ 100, y - 24 - 6, 100, 24 }, "rate divider: ", &(synth->viz.sample_rate_divider), 1, 10, 0);    int period = (1 / (synth->n.freq + 1)) * SAMPLE_RATE / synth->viz.sample_rate_divider; +  for (int i = x; i < WIDTH - x; i++) { +    DrawCircle(i , y + height / 2 + floor(50 *  synth->viz.wave[x * (SAMPLE_RATE / 2)]), point_radius, MAGENTA); +  }    if (synth->multi) {      for (int i = x; i < WIDTH - x; i++) {        DrawCircle(i , y + height / 2 + floor(50 *  make_sample(i - x, synth, SAMPLE_RATE / synth->viz.sample_rate_divider, 1)), point_radius, RED); | 
