Files

144 lines
3.3 KiB
C

/*
* mt32-pi-control
*
* An mt32-pi control program for DOS PCs, Atari ST,
* and Amiga computers
*
* Copyright (C) 2021 Andreas Zdziarstek
*
*/
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include "windows.h"
#include "midi_dev.h"
int output_port = -1;
HMIDIOUT midi_handle = NULL;
static char *dev_optstr = "lp:";
static void list_midi_outputs(void);
int mididev_init(void) {
if(output_port == -1) {
fprintf(stderr, "ERROR: You must specify the MIDI output port number with \"-p PORT\". You can list available ports with \"-l\".\n");
return -1;
}
if(midiOutOpen(&midi_handle, output_port, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR) {
fprintf(stderr, "ERROR: Could not open MIDI output port %d.\n", output_port);
return -1;
}
return 0;
}
int mididev_deinit(void) {
midiOutClose(midi_handle);
return 0;
}
int mididev_send_bytes(const unsigned char *buf, int len) {
if(len==0) return 0;
if(buf[0] == 0xF0 && buf[len-1] == 0xF7) {
MIDIHDR mheader;
char *tempbuf = (char *) malloc(len);
if(tempbuf == NULL) {
fprintf(stderr, "Error allocating memory for MIDI output buffer.\n");
return -1;
}
memcpy(tempbuf, buf, len);
mheader.lpData = tempbuf;
mheader.dwBufferLength = len;
mheader.dwFlags = 0;
mheader.dwBytesRecorded = len;
if(midiOutPrepareHeader(midi_handle, &mheader, sizeof(mheader)) != MMSYSERR_NOERROR) {
free(tempbuf);
fprintf(stderr, "ERROR: Failed to prepare MIDI header.\n");
return -1;
}
if(midiOutLongMsg(midi_handle, &mheader, sizeof(mheader)) != MMSYSERR_NOERROR) {
midiOutUnprepareHeader(midi_handle, &mheader, sizeof(mheader));
free(tempbuf);
fprintf(stderr, "ERROR: Failed to send SysEx message.\n");
return -1;
}
// Wait for message to be fully sent.
while(MIDIERR_STILLPLAYING == midiOutUnprepareHeader(midi_handle, &mheader, sizeof(mheader))) {
Sleep(10);
}
free(tempbuf);
return 0;
}
if(len==2) {
DWORD out = ((DWORD)buf[1])<<8 | (DWORD)buf[0];
if(midiOutShortMsg(midi_handle, out) != MMSYSERR_NOERROR) {
fprintf(stderr, "Error sending MIDI message: %02X %02X\n", buf[0], buf[1]);
return -1;
}
return 0;
}
if(len==3) {
DWORD out = ((DWORD)buf[2])<<16 | ((DWORD)buf[1])<<8 | (DWORD)buf[0];
if(midiOutShortMsg(midi_handle, out) != MMSYSERR_NOERROR) {
fprintf(stderr, "Error sending MIDI message: %02X %02X %02X\n", buf[0], buf[1], buf[2]);
return -1;
}
return 0;
}
fprintf(stderr, "ERROR: Invalid MIDI message.\n");
return -1;
}
void mididev_print_usage(void) {
printf("-p PORT : Set MIDI output port number (*MANDATORY*).\n");
printf("-l : List available MIDI output ports and exit.\n");
}
void mididev_add_optstr(char *optstr) {
int main_len = strlen(optstr);
strcpy(optstr+main_len, dev_optstr);
}
int mididev_parse_arg(int c, const char *optarg) {
if(c=='l') {
list_midi_outputs();
exit(EXIT_SUCCESS);
}
if(c=='p') {
output_port = (int) strtoul(optarg, NULL, 10);
return 0;
}
fprintf(stderr, "ERROR: Unknown option \'%c\'.\n", c);
return -1;
}
static void list_midi_outputs(void) {
UINT n_outs = 0;
MIDIOUTCAPS c;
n_outs = midiOutGetNumDevs();
if (!n_outs) {
fprintf(stderr, "ERROR: No MIDI output ports found.\n");
return;
}
printf("MIDI output ports:\n");
for(UINT i=0; i < n_outs; i++) {
midiOutGetDevCaps(i, &c, sizeof(MIDIOUTCAPS));
fprintf(stderr, "%d: %s\n", i, c.szPname);
}
}