1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
|
/* 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;
}
|