mame/3rdparty/portmidi/pm_test/virttest.c
2025-04-20 08:16:03 +10:00

340 lines
9.9 KiB
C

/* virttest.c -- test for creating/deleting virtual ports */
/*
* Roger B. Dannenberg
* Oct 2021
This test is performed by running 2 instances of the program. The
first instance makes input and output ports named portmidi and waits
for a message. The second tries to do the same, but will fail because
portmidi already exists. It then opens portmidi (both input and
output). In greater detail:
FIRST INSTANCE SECOND INSTANCE
-------------- ---------------
initialize PortMidi initialize PortMidi
create portmidi in
create portmidi out
wait for input
create portmidi in -> fails
open portmidi in/out
send to portmidi
recv from portmidi
send to portmidi
wait 1s recv from portmidi
close portmidi in and out
terminate PortMidi
list all devices:
- check for correct number
- check for good description of portmidi in port (open)
- check for good description of portmidi out port (open)
close portmidi in
list all devices:
- check for correct number
- check for good description of portmidi in port (closed)
- check for good description of portmidi out port (open)
close portmidi out
list all devices:
- check for correct number
- check for good description of portmidi in port (closed)
- check for good description of portmidi out port (closed)
delete portmidi in
- check for correct number
- check for NULL description of portmidi in port
- check for good description of portmidi out port (closed)
delete portmidi out
- check for correct number
- check for NULL description of portmidi in port
- check for NULL description of portmidi out port
terminate portmidi
REPEAT 3 TIMES wait 2 seconds to give head start to other instance
REPEAT 3 TIMES
*/
#include "portmidi.h"
#include "porttime.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "assert.h"
#define OUTPUT_BUFFER_SIZE 0
#define INPUT_BUFFER_SIZE 10
#define DEVICE_INFO NULL
#define DRIVER_INFO NULL
#define TIME_PROC ((PmTimeProcPtr) Pt_Time)
#define TIME_INFO NULL
#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
static void prompt_and_exit(void)
{
printf("type ENTER...");
while (getchar() != '\n') ;
/* this will clean up open ports: */
exit(-1);
}
static PmError printerror(PmError err, const char *msg)
{
if (err == pmHostError) {
/* it seems pointless to allocate memory and copy the string,
* so I will do the work of Pm_GetHostErrorText directly
*/
char errmsg[80];
Pm_GetHostErrorText(errmsg, 80);
printf("%s\n %s\n", msg, errmsg);
} else if (err < 0) {
printf("%s\n %s\n", msg, Pm_GetErrorText(err));
}
return err;
}
static PmError checkerror(PmError err)
{
if (err < 0) {
printerror(err, "PortMidi call failed...");
prompt_and_exit();
}
return err;
}
void wait_until(PmTimestamp when)
{
PtTimestamp now = Pt_Time();
if (when > now) {
Pt_Sleep(when - now);
}
}
void show_usage()
{
printf("Usage: virttest\n"
" run two instances to test virtual port create/delete\n");
}
void check_info(int id, char stat, int input, int virtual)
{
const PmDeviceInfo *info = Pm_GetDeviceInfo(id);
if (stat == 'd') {
if (info) {
printf("Expected device %d to be deleted.\n", id);
prompt_and_exit();
}
return;
}
if (!info) {
printf("Expected device %d to not be deleted.\n", id);
prompt_and_exit();
}
if (strcmp("portmidi", info->name) != 0) {
printf("Device %d name is %s, not \"portmidi\".\n", id, info->name);
prompt_and_exit();
}
if (info->input != input || (!info->output) != input) {
printf("Device %d input/output fields are wrong.\n", id);
prompt_and_exit();
}
if ((!info->opened && stat == 'o') || (info->opened && stat == 'c')) {
printf("Device %d opened==%d, status should be %c.\n", id,
info->opened, stat);
prompt_and_exit();
}
if (info->is_virtual != virtual) {
printf("Expected device %d to be virtual.\n", id);
prompt_and_exit();
}
}
/* stat is 'o' for open, 'c' for closed, 'd' for deleted device */
void check_ports(int cnt, int in_id, char in_stat,
int out_id, char out_stat, int virtual)
{
if (cnt != Pm_CountDevices()) {
printf("Device count changed from %d to %d.\n", cnt, Pm_CountDevices());
prompt_and_exit();
}
check_info(in_id, in_stat, TRUE, virtual);
check_info(out_id, out_stat, FALSE, virtual);
}
void devices_list()
{
int i;
for (i = 0; i < Pm_CountDevices(); i++) {
const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
if (info) {
printf("%d: %s %s %s %s\n", i, info->name,
(info->input ? "input" : "output"),
(info->is_virtual ? "virtual" : "real_device"),
(info->opened ? "opened" : "closed"));
}
}
}
void test2()
{
PmStream *out = NULL;
PmStream *in = NULL;
int out_id;
int in_id;
PmEvent buffer[1];
PmTimestamp timestamp;
int pitch = 60;
int device_count = 0;
int i;
printf("This must be virttest instance #2\n");
/* find and open portmidi in and out */
device_count = Pm_CountDevices();
for (i = 0; i < device_count; i++) {
const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
if (info && strcmp(info->name, "portmidi") == 0) {
if (info->input) {
checkerror(Pm_OpenInput(&in, i, DRIVER_INFO,
INPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO));
in_id = i;
} else {
checkerror(Pm_OpenOutput(&out, i, DRIVER_INFO,
OUTPUT_BUFFER_SIZE, NULL, NULL, 0));
out_id = i;
}
}
}
if (!in) {
printf("Did not open portmidi as input (virtual output).\n");
prompt_and_exit();
}
if (!out) {
printf("Did not open portmidi as output (virtual input).\n");
prompt_and_exit();
}
printf("Input device %d and output device %d are open.\n", in_id, out_id);
/* send a message */
buffer[0].timestamp = 0;
buffer[0].message = Pm_Message(0x90, pitch, 100);
checkerror(Pm_Write(out, buffer, 1));
/* wait for reply */
printf("Sent message, waiting for reply...\n");
while (Pm_Read(in, buffer, 1) < 1) Pt_Sleep(10);
printf("********** GOT THE MESSAGE, SHUTTING DOWN ************\n");
/* close in */
checkerror(Pm_Close(in));
check_ports(device_count, in_id, 'c', out_id, 'o', FALSE);
printf("Closed input %d\n", in_id);
/* close out */
checkerror(Pm_Close(out));
check_ports(device_count, in_id, 'c', out_id, 'c', FALSE);
printf("Closed output %d\n", out_id);
Pt_Sleep(1000);
/* wrap it up */
Pm_Terminate();
printf("Got reply and terminated...\n");
Pt_Sleep(2000); /* 2 seconds because other is waiting 1s. */
/* 1 more second to make sure other shuts down before test repeats. */
}
extern int pm_check_errors;
void test()
{
PmStream *out;
PmStream *in;
int out_id;
int in_id;
PmEvent buffer[1];
PmTimestamp timestamp;
int device_count = 0;
TIME_START;
printf("******** INITIALIZING PORTMIDI ***********\n");
timestamp = Pt_Time();
Pm_Initialize();
printf("Pm_Initialize took %dms\n", Pt_Time() - timestamp);
devices_list();
pm_check_errors = FALSE; /* otherwise, PM_CHECK_ERRORS, if defined, */
/* can cause this program to report an error and exit on pmNameConflict. */
in_id = Pm_CreateVirtualInput("portmidi", NULL, DEVICE_INFO);
pm_check_errors = TRUE; /* there should be no other errors */
if (in_id < 0) {
printerror(in_id, "Pm_CreateVirtualInput failed...");
test2();
return;
}
printf("Created portmidi virtual input; this is virttest instance #1\n");
out_id = checkerror(Pm_CreateVirtualOutput("portmidi", NULL, DRIVER_INFO));
device_count = Pm_CountDevices();
checkerror(Pm_OpenInput(&in, in_id, NULL, 0, NULL, NULL));
checkerror(Pm_OpenOutput(&out, out_id, DRIVER_INFO, OUTPUT_BUFFER_SIZE,
TIME_PROC, TIME_INFO, 0));
printf("Created/Opened input %d and output %d\n", in_id, out_id);
Pm_SetFilter(in, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX);
/* empty the buffer after setting filter, just in case anything
got through */
while (Pm_Read(in, buffer, 1)) ;
/* wait for input */
printf("Waiting for input...\n");
while (Pm_Read(in, buffer, 1) < 1) Pt_Sleep(10);
/* send two replies (only one would be fine) */
checkerror(Pm_Write(out, buffer, 1));
printf("Received input, writing output...\n");
/* wait 1s so receiver can get the message before we shut down */
Pt_Sleep(1000);
printf("****** Closing everything and shutting down...\n");
/* expect 2 open ports */
check_ports(device_count, in_id, 'o', out_id, 'o', TRUE);
/* close in */
checkerror(Pm_Close(in));
check_ports(device_count, in_id, 'c', out_id, 'o', TRUE);
/* close out */
checkerror(Pm_Close(out));
check_ports(device_count, in_id, 'c', out_id, 'c', TRUE);
/* delete in */
checkerror(Pm_DeleteVirtualDevice(in_id));
check_ports(device_count, in_id, 'd', out_id, 'c', TRUE);
/* delete out */
checkerror(Pm_DeleteVirtualDevice(out_id));
check_ports(device_count, in_id, 'd', out_id, 'd', TRUE);
/* we are done */
Pm_Terminate();
}
int main(int argc, char *argv[])
{
int i;
show_usage();
for (i = 0; i < 3; i++) {
test();
}
printf("finished virttest (SUCCESS). Type ENTER to quit...");
while (getchar() != '\n') ;
return 0;
}