Workbench Library  0.1b
midi_monitor.c

Example of using the Workbench library to monitor MIDI messages.This dead simple rudimentary example demonstrates how to use the Workbench library to initialize the MIDI system and monitor incoming MIDI messages. It is a simplified version of the MIDI monitor example provided in the PortMidi library (https://github.com/PortMidi/portmidi/blob/master/pm_test/mm.c). The example configures the system to use a custom MIDI callback function that processes and prints various types of MIDI messages such as Note On, Note Off, Control Change, Program Change, and System Exclusive messages.

The example includes:

The main function initializes the configuration with the custom MIDI callback and enters an infinite loop to keep the application running. This setup allows the application to continuously monitor and print incoming MIDI messages.

#include "workbench.h"
#include <stdio.h>
Config *cfg;
static bool in_sysex = false;
static char *ptos[] = {"C", "C#", "D", "D#", "E", "F",
"F#", "G", "G#", "A", "A#", "B"};
static void print_pitch(int p) { printf("%s%d", ptos[p % 12], (p / 12) - 1); }
static void print_velocity(int p, int v) {
printf(" %sVel: %d\n", strlen(ptos[p % 12]) == 1 ? " " : "", v);
}
static int midi_cb(const void *in, void *out, unsigned long length,
void *user_data) {
const PmEvent *in_buffer = (const PmEvent *)in;
for (unsigned long i = 0; i < length; ++i) {
PmEvent event = in_buffer[i];
PmMessage message = event.message;
int status = Pm_MessageStatus(message);
int data1 = Pm_MessageData1(message);
int data2 = Pm_MessageData2(message);
int command = status & MIDI_CODE_MASK;
int chan = status & MIDI_CHN_MASK;
printf("%x\t", message);
if (in_sysex || status == MIDI_SYSEX) {
int i;
PmMessage data_copy = Pm_Message(status, data1, data2);
in_sysex = true;
for (i = 0; (i < 4) && ((data_copy & 0xFF) != MIDI_EOX); i++)
data_copy >>= 8;
if (i < 4) {
in_sysex = false;
i++;
}
printf("System Exclusive\n");
} else if (command == MIDI_ON_NOTE && data2 != 0) {
printf("NoteOn Chan %2d Key %3d ", chan, data1);
print_pitch(data1);
print_velocity(data1, data2);
} else if ((command == MIDI_ON_NOTE || command == MIDI_OFF_NOTE)) {
printf("NoteOff Chan %2d Key %3d ", chan, data1);
print_pitch(data1);
print_velocity(data1, data2);
} else if (command == MIDI_CH_PROGRAM) {
printf("ProgChg Chan %2d Prog %2d\n", chan, data1 + 1);
} else if (command == MIDI_CTRL) {
/* controls 121 (MIDI_RESET_CONTROLLER) to 127 are channel
* mode messages. */
if (data1 < MIDI_ALL_SOUND_OFF) {
printf("CtrlChg Chan %2d Ctrl %2d Val %2d\n", chan, data1, data2);
} else {
switch (data1) {
printf("All Sound Off, Chan %2d\n", chan);
break;
printf("Reset All Controllers, Chan %2d\n", chan);
break;
case MIDI_LOCAL:
printf("LocCtrl Chan %2d %s\n", chan, data2 ? "On" : "Off");
break;
printf("All Off Chan %2d\n", chan);
break;
printf("OmniOff Chan %2d\n", chan);
break;
printf("Omni On Chan %2d\n", chan);
break;
printf("Mono On Chan %2d", chan);
if (data2) {
printf(" to %d received channels\n", data2);
} else {
printf(" to all received channels\n");
}
break;
printf("Poly On Chan %2d\n", chan);
break;
}
}
} else if (command == MIDI_POLY_TOUCH) {
printf("P.Touch Chan %2d Key %2d ", chan, data1);
print_pitch(data1);
printf("\n");
} else if (command == MIDI_TOUCH) {
printf("A.Touch Chan %2d Val %2d\n", chan, data1);
} else if (command == MIDI_BEND) {
printf("P.Bend Chan %2d Val %2d\n", chan, (data1 + (data2 << 7)));
} else if (status == MIDI_SONG_POINTER) {
printf(" Song Position %d\n", (data1 + (data2 << 7)));
} else if (status == MIDI_SONG_SELECT) {
printf(" Song Select %d\n", data1);
} else if (status == MIDI_TUNE_REQ) {
printf(" Tune Request\n");
} else if (status == MIDI_Q_FRAME) {
printf(" Time Code Quarter Frame Type %d Values %d\n",
(data1 & 0x70) >> 4, data1 & 0xf);
} else if (status == MIDI_START) {
printf(" Start\n");
} else if (status == MIDI_CONTINUE) {
printf(" Continue\n");
} else if (status == MIDI_STOP) {
printf(" Stop\n");
} else if (status == MIDI_SYS_RESET) {
printf(" System Reset\n");
} else if (status == MIDI_TIME_CLOCK) {
printf(" Clock\n");
} else if (status == MIDI_ACTIVE_SENSING) {
printf(" Active Sensing\n");
}
}
return 0;
}
int main(int argc, char **argv) {
cfg = config_init(argc, argv, NULL, &midi_cb, NULL);
while (true) {
Pa_Sleep(1000);
}
config_deinit();
return 0;
}
Config * config_init(int argc, char **argv, AudioCallback audio_cb, MidiCallback midi_cb, void *user_data)
Initializes the configuration with the specified audio and MIDI callbacks.
Definition: workbench_config.c:41
Defines the structure for configuration settings.
Definition: workbench.h:287
#define MIDI_BEND
MIDI Pitch Bend Change message.
Definition: workbench_midi.h:28
#define MIDI_EOX
MIDI End of Exclusive (EOX) message.
Definition: workbench_midi.h:36
#define MIDI_SYS_RESET
MIDI System Reset message.
Definition: workbench_midi.h:42
#define MIDI_STOP
MIDI Stop message.
Definition: workbench_midi.h:40
#define MIDI_TOUCH
MIDI Channel Pressure (Aftertouch) message.
Definition: workbench_midi.h:26
#define MIDI_ALL_OFF
MIDI All Notes Off message.
Definition: workbench_midi.h:48
#define MIDI_ALL_SOUND_OFF
MIDI All Sound Off message.
Definition: workbench_midi.h:44
#define MIDI_OMNI_OFF
MIDI Omni Mode Off message.
Definition: workbench_midi.h:49
#define MIDI_CTRL
MIDI Control Change message.
Definition: workbench_midi.h:24
#define MIDI_RESET_CONTROLLERS
MIDI Reset All Controllers message.
Definition: workbench_midi.h:45
#define MIDI_OMNI_ON
MIDI Omni Mode On message.
Definition: workbench_midi.h:50
#define MIDI_START
MIDI Start message.
Definition: workbench_midi.h:38
#define MIDI_ON_NOTE
MIDI Note On message.
Definition: workbench_midi.h:21
#define MIDI_CHN_MASK
Mask to extract the MIDI channel number.
Definition: workbench_midi.h:14
#define MIDI_ACTIVE_SENSING
MIDI Active Sensing message.
Definition: workbench_midi.h:41
#define MIDI_SONG_SELECT
MIDI Song Select message.
Definition: workbench_midi.h:34
#define MIDI_LOCAL
MIDI Local Control On/Off message.
Definition: workbench_midi.h:47
#define MIDI_SYSEX
MIDI System Exclusive (Sysex) message.
Definition: workbench_midi.h:30
#define MIDI_TUNE_REQ
MIDI Tune Request message.
Definition: workbench_midi.h:35
#define MIDI_SONG_POINTER
MIDI Song Position Pointer message.
Definition: workbench_midi.h:32
#define MIDI_CONTINUE
MIDI Continue message.
Definition: workbench_midi.h:39
#define MIDI_TIME_CLOCK
MIDI Timing Clock message.
Definition: workbench_midi.h:37
#define MIDI_CH_PROGRAM
MIDI Program Change message.
Definition: workbench_midi.h:25
#define MIDI_POLY_ON
MIDI Poly Mode On message.
Definition: workbench_midi.h:52
#define MIDI_OFF_NOTE
MIDI Note Off message.
Definition: workbench_midi.h:20
#define MIDI_CODE_MASK
Mask to extract the MIDI message type.
Definition: workbench_midi.h:12
#define MIDI_MONO_ON
MIDI Mono Mode On message.
Definition: workbench_midi.h:51
#define MIDI_Q_FRAME
MIDI Time Code Quarter Frame message.
Definition: workbench_midi.h:31
#define MIDI_POLY_TOUCH
MIDI Polyphonic Key Pressure (Aftertouch) message.
Definition: workbench_midi.h:22