1d5ac70f0Sopenharmony_ci#include <stdlib.h>
2d5ac70f0Sopenharmony_ci#include <stdio.h>
3d5ac70f0Sopenharmony_ci#include <ctype.h>
4d5ac70f0Sopenharmony_ci#include <sys/time.h>
5d5ac70f0Sopenharmony_ci#include "../include/asoundlib.h"
6d5ac70f0Sopenharmony_ci#include <string.h>
7d5ac70f0Sopenharmony_ci#include <signal.h>
8d5ac70f0Sopenharmony_ci
9d5ac70f0Sopenharmony_cistatic void usage(void)
10d5ac70f0Sopenharmony_ci{
11d5ac70f0Sopenharmony_ci	fprintf(stderr, "Usage: midiloop [options]\n");
12d5ac70f0Sopenharmony_ci	fprintf(stderr, "  options:\n");
13d5ac70f0Sopenharmony_ci	fprintf(stderr, "    -v: verbose mode\n");
14d5ac70f0Sopenharmony_ci	fprintf(stderr, "    -i <rawmidi device> : test input device\n");
15d5ac70f0Sopenharmony_ci	fprintf(stderr, "    -o <rawmidi device> : test output device\n");
16d5ac70f0Sopenharmony_ci}
17d5ac70f0Sopenharmony_ci
18d5ac70f0Sopenharmony_ciint stop = 0;
19d5ac70f0Sopenharmony_ci
20d5ac70f0Sopenharmony_civoid sighandler(int dummy ATTRIBUTE_UNUSED)
21d5ac70f0Sopenharmony_ci{
22d5ac70f0Sopenharmony_ci	stop=1;
23d5ac70f0Sopenharmony_ci}
24d5ac70f0Sopenharmony_ci
25d5ac70f0Sopenharmony_cilong long timediff(struct timeval t1, struct timeval t2)
26d5ac70f0Sopenharmony_ci{
27d5ac70f0Sopenharmony_ci	signed long l;
28d5ac70f0Sopenharmony_ci
29d5ac70f0Sopenharmony_ci	t1.tv_sec -= t2.tv_sec;
30d5ac70f0Sopenharmony_ci	l = (signed long) t1.tv_usec - (signed long) t2.tv_usec;
31d5ac70f0Sopenharmony_ci	if (l < 0) {
32d5ac70f0Sopenharmony_ci		t1.tv_sec--;
33d5ac70f0Sopenharmony_ci		l = -l;
34d5ac70f0Sopenharmony_ci		l %= 1000000;
35d5ac70f0Sopenharmony_ci	}
36d5ac70f0Sopenharmony_ci	return ((long long)t1.tv_sec * (long long)1000000) + (long long)l;
37d5ac70f0Sopenharmony_ci}
38d5ac70f0Sopenharmony_ci
39d5ac70f0Sopenharmony_ciint writepattern(snd_rawmidi_t *handle_out, unsigned char *obuf)
40d5ac70f0Sopenharmony_ci{
41d5ac70f0Sopenharmony_ci	int patsize, i;
42d5ac70f0Sopenharmony_ci
43d5ac70f0Sopenharmony_ci	patsize = 0;
44d5ac70f0Sopenharmony_ci	for (i = 0; i < 15; i++) {
45d5ac70f0Sopenharmony_ci		obuf[patsize++] = 0x90 + i;
46d5ac70f0Sopenharmony_ci		obuf[patsize++] = 0x40;
47d5ac70f0Sopenharmony_ci		obuf[patsize++] = 0x3f;
48d5ac70f0Sopenharmony_ci		obuf[patsize++] = 0xb0 + i;
49d5ac70f0Sopenharmony_ci		obuf[patsize++] = 0x2e;
50d5ac70f0Sopenharmony_ci		obuf[patsize++] = 0x7a;
51d5ac70f0Sopenharmony_ci		obuf[patsize++] = 0x80 + i;
52d5ac70f0Sopenharmony_ci		obuf[patsize++] = 0x23;
53d5ac70f0Sopenharmony_ci		obuf[patsize++] = 0x24;
54d5ac70f0Sopenharmony_ci		obuf[patsize++] = 0xf0;
55d5ac70f0Sopenharmony_ci		obuf[patsize++] = i;
56d5ac70f0Sopenharmony_ci		obuf[patsize++] = 0xf7;
57d5ac70f0Sopenharmony_ci	}
58d5ac70f0Sopenharmony_ci	i = snd_rawmidi_write(handle_out, obuf, patsize);
59d5ac70f0Sopenharmony_ci	if (i != patsize) {
60d5ac70f0Sopenharmony_ci		printf("Written only %i bytes from %i bytes\n", i, patsize);
61d5ac70f0Sopenharmony_ci		exit(EXIT_FAILURE);
62d5ac70f0Sopenharmony_ci	}
63d5ac70f0Sopenharmony_ci	return patsize;
64d5ac70f0Sopenharmony_ci}
65d5ac70f0Sopenharmony_ci
66d5ac70f0Sopenharmony_ciint main(int argc, char** argv)
67d5ac70f0Sopenharmony_ci{
68d5ac70f0Sopenharmony_ci	int i, j, k, opos, ipos, patsize;
69d5ac70f0Sopenharmony_ci	int err;
70d5ac70f0Sopenharmony_ci	int verbose = 0;
71d5ac70f0Sopenharmony_ci	snd_rawmidi_t *handle_in = NULL, *handle_out = NULL;
72d5ac70f0Sopenharmony_ci	unsigned char ibuf[512], obuf[512];
73d5ac70f0Sopenharmony_ci	char *iname = "hw:0,0", *oname = "hw:0,0";
74d5ac70f0Sopenharmony_ci	struct timeval start, end;
75d5ac70f0Sopenharmony_ci	long long diff;
76d5ac70f0Sopenharmony_ci	snd_rawmidi_status_t *istat, *ostat;
77d5ac70f0Sopenharmony_ci
78d5ac70f0Sopenharmony_ci	for (i = 1 ; i<argc ; i++) {
79d5ac70f0Sopenharmony_ci		if (argv[i][0]=='-') {
80d5ac70f0Sopenharmony_ci			if (!strcmp(argv[i], "--help")) {
81d5ac70f0Sopenharmony_ci				usage();
82d5ac70f0Sopenharmony_ci				return 0;
83d5ac70f0Sopenharmony_ci			}
84d5ac70f0Sopenharmony_ci			switch (argv[i][1]) {
85d5ac70f0Sopenharmony_ci				case 'h':
86d5ac70f0Sopenharmony_ci					usage();
87d5ac70f0Sopenharmony_ci					return 0;
88d5ac70f0Sopenharmony_ci				case 'v':
89d5ac70f0Sopenharmony_ci					verbose = 1;
90d5ac70f0Sopenharmony_ci					break;
91d5ac70f0Sopenharmony_ci				case 'i':
92d5ac70f0Sopenharmony_ci					if (i + 1 < argc)
93d5ac70f0Sopenharmony_ci						iname = argv[++i];
94d5ac70f0Sopenharmony_ci					break;
95d5ac70f0Sopenharmony_ci				case 'o':
96d5ac70f0Sopenharmony_ci					if (i + 1 < argc)
97d5ac70f0Sopenharmony_ci						oname = argv[++i];
98d5ac70f0Sopenharmony_ci					break;
99d5ac70f0Sopenharmony_ci			}
100d5ac70f0Sopenharmony_ci		}
101d5ac70f0Sopenharmony_ci	}
102d5ac70f0Sopenharmony_ci
103d5ac70f0Sopenharmony_ci	if (iname == NULL)
104d5ac70f0Sopenharmony_ci		iname = oname;
105d5ac70f0Sopenharmony_ci	if (oname == NULL)
106d5ac70f0Sopenharmony_ci		oname = iname;
107d5ac70f0Sopenharmony_ci
108d5ac70f0Sopenharmony_ci	if (verbose) {
109d5ac70f0Sopenharmony_ci		fprintf(stderr, "Using: \n");
110d5ac70f0Sopenharmony_ci		fprintf(stderr, "  Input: %s  Output: %s\n", iname, oname);
111d5ac70f0Sopenharmony_ci	}
112d5ac70f0Sopenharmony_ci
113d5ac70f0Sopenharmony_ci	err = snd_rawmidi_open(&handle_in, NULL, iname, SND_RAWMIDI_NONBLOCK);
114d5ac70f0Sopenharmony_ci	if (err) {
115d5ac70f0Sopenharmony_ci		fprintf(stderr,"snd_rawmidi_open %s failed: %d\n",iname,err);
116d5ac70f0Sopenharmony_ci		exit(EXIT_FAILURE);
117d5ac70f0Sopenharmony_ci	}
118d5ac70f0Sopenharmony_ci
119d5ac70f0Sopenharmony_ci	err = snd_rawmidi_open(NULL, &handle_out, oname, 0);
120d5ac70f0Sopenharmony_ci	if (err) {
121d5ac70f0Sopenharmony_ci		fprintf(stderr,"snd_rawmidi_open %s failed: %d\n",oname,err);
122d5ac70f0Sopenharmony_ci		exit(EXIT_FAILURE);
123d5ac70f0Sopenharmony_ci	}
124d5ac70f0Sopenharmony_ci
125d5ac70f0Sopenharmony_ci	signal(SIGINT, sighandler);
126d5ac70f0Sopenharmony_ci
127d5ac70f0Sopenharmony_ci	i = snd_rawmidi_read(handle_in, ibuf, sizeof(ibuf));
128d5ac70f0Sopenharmony_ci	if (i > 0) {
129d5ac70f0Sopenharmony_ci		printf("Read ahead: %i\n", i);
130d5ac70f0Sopenharmony_ci		for (j = 0; j < i; j++)
131d5ac70f0Sopenharmony_ci			printf("%02x:", ibuf[j]);
132d5ac70f0Sopenharmony_ci		printf("\n");
133d5ac70f0Sopenharmony_ci		exit(EXIT_FAILURE);
134d5ac70f0Sopenharmony_ci	}
135d5ac70f0Sopenharmony_ci
136d5ac70f0Sopenharmony_ci	snd_rawmidi_nonblock(handle_in, 0);
137d5ac70f0Sopenharmony_ci
138d5ac70f0Sopenharmony_ci	patsize = writepattern(handle_out, obuf);
139d5ac70f0Sopenharmony_ci	gettimeofday(&start, NULL);
140d5ac70f0Sopenharmony_ci	patsize = writepattern(handle_out, obuf);
141d5ac70f0Sopenharmony_ci
142d5ac70f0Sopenharmony_ci	k = ipos = opos = err = 0;
143d5ac70f0Sopenharmony_ci	while (!stop) {
144d5ac70f0Sopenharmony_ci		i = snd_rawmidi_read(handle_in, ibuf, sizeof(ibuf));
145d5ac70f0Sopenharmony_ci		for (j = 0; j < i; j++, ipos++)
146d5ac70f0Sopenharmony_ci			if (obuf[k] != ibuf[j]) {
147d5ac70f0Sopenharmony_ci				printf("ipos = %i, i[0x%x] != o[0x%x]\n", ipos, ibuf[j], obuf[k]);
148d5ac70f0Sopenharmony_ci				if (opos > 0)
149d5ac70f0Sopenharmony_ci					stop = 1;
150d5ac70f0Sopenharmony_ci			} else {
151d5ac70f0Sopenharmony_ci				printf("match success: ipos = %i, opos = %i [%i:0x%x]\n", ipos, opos, k, obuf[k]);
152d5ac70f0Sopenharmony_ci				k++; opos++;
153d5ac70f0Sopenharmony_ci				if (k >= patsize) {
154d5ac70f0Sopenharmony_ci					patsize = writepattern(handle_out, obuf);
155d5ac70f0Sopenharmony_ci					k = 0;
156d5ac70f0Sopenharmony_ci				}
157d5ac70f0Sopenharmony_ci			}
158d5ac70f0Sopenharmony_ci	}
159d5ac70f0Sopenharmony_ci
160d5ac70f0Sopenharmony_ci	gettimeofday(&end, NULL);
161d5ac70f0Sopenharmony_ci
162d5ac70f0Sopenharmony_ci	printf("End...\n");
163d5ac70f0Sopenharmony_ci
164d5ac70f0Sopenharmony_ci	snd_rawmidi_status_alloca(&istat);
165d5ac70f0Sopenharmony_ci	snd_rawmidi_status_alloca(&ostat);
166d5ac70f0Sopenharmony_ci	err = snd_rawmidi_status(handle_in, istat);
167d5ac70f0Sopenharmony_ci	if (err < 0)
168d5ac70f0Sopenharmony_ci		fprintf(stderr, "input stream status error: %d\n", err);
169d5ac70f0Sopenharmony_ci	err = snd_rawmidi_status(handle_out, ostat);
170d5ac70f0Sopenharmony_ci	if (err < 0)
171d5ac70f0Sopenharmony_ci		fprintf(stderr, "output stream status error: %d\n", err);
172d5ac70f0Sopenharmony_ci	printf("input.status.avail = %zi\n", snd_rawmidi_status_get_avail(istat));
173d5ac70f0Sopenharmony_ci	printf("input.status.xruns = %zi\n", snd_rawmidi_status_get_xruns(istat));
174d5ac70f0Sopenharmony_ci	printf("output.status.avail = %zi\n", snd_rawmidi_status_get_avail(ostat));
175d5ac70f0Sopenharmony_ci	printf("output.status.xruns = %zi\n", snd_rawmidi_status_get_xruns(ostat));
176d5ac70f0Sopenharmony_ci
177d5ac70f0Sopenharmony_ci	diff = timediff(end, start);
178d5ac70f0Sopenharmony_ci	printf("Time diff: %lliusec (%lli bytes/sec)\n", diff, ((long long)opos * 1000000) / diff);
179d5ac70f0Sopenharmony_ci
180d5ac70f0Sopenharmony_ci	if (verbose) {
181d5ac70f0Sopenharmony_ci		fprintf(stderr,"Closing\n");
182d5ac70f0Sopenharmony_ci	}
183d5ac70f0Sopenharmony_ci
184d5ac70f0Sopenharmony_ci	snd_rawmidi_drain(handle_in);
185d5ac70f0Sopenharmony_ci	snd_rawmidi_close(handle_in);
186d5ac70f0Sopenharmony_ci	snd_rawmidi_drain(handle_out);
187d5ac70f0Sopenharmony_ci	snd_rawmidi_close(handle_out);
188d5ac70f0Sopenharmony_ci
189d5ac70f0Sopenharmony_ci	return 0;
190d5ac70f0Sopenharmony_ci}
191