diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/sequencer.c | 171 | 
1 files changed, 171 insertions, 0 deletions
| diff --git a/src/sequencer.c b/src/sequencer.c new file mode 100644 index 0000000..5687640 --- /dev/null +++ b/src/sequencer.c @@ -0,0 +1,171 @@ +#include <stdlib.h> +#include <portmidi.h> +#include <porttime.h> +#include <stdio.h> +#include <string.h> +#include <raylib.h> +#include <pthread.h> +#include <math.h> + +#include "synth_common.h" + +#define MIDI_NOTE_ON  0x90 +#define MIDI_NOTE_OFF 0x80 +#define MIDI_CHANNEL  0 +#define SLEEP_INTERVAL_MS 2.0   // main loop sleep + + + +//------------------------------------------------- +// Helper for time math +//------------------------------------------------- + +typedef struct step_t { +  PmTimestamp note_on; +  PmTimestamp note_off; +  float duration; +  int note;  +} step_t; + +typedef struct pattert_t { +  step_t *steps; +  uint n; // total +  uint c; // current +} pattern_t; + +typedef struct sequencer_t { +  PortMidiStream *stream; +  int exitted; + +  float bpm; +  int steps; +  pattern_t *pattern; +} sequencer_t; + +sequencer_t * +init_sequencer() { +  sequencer_t *seq = (sequencer_t *)malloc(sizeof(sequencer_t)); + +  seq->exitted = 0; +  seq->bpm = 100.0f; +  seq->steps = 16; + +  seq->pattern = (pattern_t *)malloc(sizeof(pattern_t)); +  seq->pattern->steps = (step_t *)malloc(16 * sizeof(step_t)); +  seq->pattern->n = 16; +  seq->pattern->c = 0; + +  for (uint i = 0; i < seq->pattern->n; i++) { +    step_t *step = &seq->pattern->steps[i]; +    step->note = 40 + i; +  } +   +  seq->stream = NULL; +  PmError err = Pm_Initialize(); +  if (err != pmNoError) { +    fprintf(stdout, "Pm Error: %s\n", Pm_GetErrorText(err)); +  } + +  const PmDeviceInfo *info; +  int i; +  for (i = 0; i < Pm_CountDevices(); i++) { +    info = Pm_GetDeviceInfo(i); +    if (!info->output) { +      continue; +    } +    printf("%d: %s [input: %d output: %d opened: %d is_virt:%d] (interface: %s)\n", i, info->name, info->input, info->output, info->opened, info->is_virtual, info->interf); +    if (0 == strcmp("Midi Through Port-0", info->name)) +      break; +  } + +  printf("Selected device: %s [input: %d output: %d opened: %d is_virt:%d] (interf: %s)\n", info->name, info->input, info->output, info->opened, info->is_virtual, info->interf); + +  //no start for output Pt_Start(1, midiCallback, m); +  err = Pm_OpenOutput(&(seq->stream), i, NULL, 512, NULL, NULL, 0); + +  if (err != pmNoError) { +    fprintf(stdout, "Pm Error: %s\n", Pm_GetErrorText(err)); +  } + +  return seq; +} + +void +free_sequencer(sequencer_t * seq) { +  Pm_WriteShort(seq->stream, 0, Pm_Message(0xFC /* MIDI_STOP */, 0, 0)); +   +  Pm_Close(seq->stream); +  Pm_Terminate(); + +  free(seq); +} + +static inline double ms_per_beat(sequencer_t * seq) { +    return 60000.0 / seq->bpm; +} +static inline double ms_per_step(sequencer_t * seq) { +    return ms_per_beat(seq) / seq->steps; +} + +void +rayrun(sequencer_t * seq) { +  (void)seq; +  SetTraceLogLevel(LOG_ERROR); +  InitWindow(WIDTH, HEIGHT, "Raylib sequencer"); +  SetTargetFPS(60); +  while (!WindowShouldClose()) { +    // Draw +    //---------------------------------------------------------------------------------- +    BeginDrawing(); +    ClearBackground(BLACK); + + +    EndDrawing(); +    //---------------------------------------------------------------------------------- +  } +  seq->exitted = 1; +  CloseWindow(); +} + +void * +sequencer_thread(void *arg) +{ +  sequencer_t *seq = (sequencer_t *)arg; + +  while (!seq->exitted) { +    //PmTimestamp current_time = Pt_Time(); + +    step_t *step = &seq->pattern->steps[seq->pattern->c++]; +    if (seq->pattern->c >= seq->pattern->n) seq->pattern->c = 0; +     +    Pm_WriteShort(seq->stream, 0, Pm_Message(MIDI_NOTE_ON | MIDI_CHANNEL, step->note, 100)); + +    Pt_Sleep(ms_per_step(seq)*4); +    Pm_WriteShort(seq->stream, 0, Pm_Message(MIDI_NOTE_OFF | MIDI_CHANNEL, step->note, 0)); + +    //Pt_Sleep(SLEEP_INTERVAL_MS); +  } + +  printf("[Sequencer] Stopping.\n"); +  return NULL; +} + + +int +main(void) { +  sequencer_t * seq = init_sequencer(); + +  pthread_t seq_thread; + +  // start sequencer thread +  pthread_create(&seq_thread, NULL, sequencer_thread, seq); + +  // start gui +  rayrun(seq); + +  pthread_join(seq_thread, NULL); + +  free_sequencer(seq); + +  return 0; +} | 
