1d5ac70f0Sopenharmony_ci#include <stdio.h>
2d5ac70f0Sopenharmony_ci#include <stdlib.h>
3d5ac70f0Sopenharmony_ci#include <ctype.h>
4d5ac70f0Sopenharmony_ci#include "../include/asoundlib.h"
5d5ac70f0Sopenharmony_ci#include <signal.h>
6d5ac70f0Sopenharmony_ci
7d5ac70f0Sopenharmony_cistatic void usage(void)
8d5ac70f0Sopenharmony_ci{
9d5ac70f0Sopenharmony_ci	fprintf(stderr, "usage: rawmidi [options]\n");
10d5ac70f0Sopenharmony_ci	fprintf(stderr, "  options:\n");
11d5ac70f0Sopenharmony_ci	fprintf(stderr, "    -v: verbose mode\n");
12d5ac70f0Sopenharmony_ci	fprintf(stderr, "    -i device-id : test ALSA input device\n");
13d5ac70f0Sopenharmony_ci	fprintf(stderr, "    -o device-id : test ALSA output device\n");
14d5ac70f0Sopenharmony_ci	fprintf(stderr, "    -I node      : test input node\n");
15d5ac70f0Sopenharmony_ci	fprintf(stderr, "    -O node      : test output node\n");
16d5ac70f0Sopenharmony_ci	fprintf(stderr, "    -c clock     : kernel clock type (0=none, 1=realtime, 2=monotonic, 3=monotonic raw)\n");
17d5ac70f0Sopenharmony_ci	fprintf(stderr, "    -t: test midi thru\n");
18d5ac70f0Sopenharmony_ci	fprintf(stderr, "  example:\n");
19d5ac70f0Sopenharmony_ci	fprintf(stderr, "    rawmidi -i hw:0,0 -O /dev/midi1\n");
20d5ac70f0Sopenharmony_ci	fprintf(stderr, "    tests input for card 0, device 0, using snd_rawmidi API\n");
21d5ac70f0Sopenharmony_ci	fprintf(stderr, "    and /dev/midi1 using file descriptors\n");
22d5ac70f0Sopenharmony_ci}
23d5ac70f0Sopenharmony_ci
24d5ac70f0Sopenharmony_ciint stop=0;
25d5ac70f0Sopenharmony_ci
26d5ac70f0Sopenharmony_civoid sighandler(int dum)
27d5ac70f0Sopenharmony_ci{
28d5ac70f0Sopenharmony_ci	stop=1;
29d5ac70f0Sopenharmony_ci}
30d5ac70f0Sopenharmony_ci
31d5ac70f0Sopenharmony_ciint main(int argc,char** argv)
32d5ac70f0Sopenharmony_ci{
33d5ac70f0Sopenharmony_ci	int i;
34d5ac70f0Sopenharmony_ci	int err;
35d5ac70f0Sopenharmony_ci	int thru=0;
36d5ac70f0Sopenharmony_ci	int verbose = 0;
37d5ac70f0Sopenharmony_ci	char *device_in = NULL;
38d5ac70f0Sopenharmony_ci	char *device_out = NULL;
39d5ac70f0Sopenharmony_ci	char *node_in = NULL;
40d5ac70f0Sopenharmony_ci	char *node_out = NULL;
41d5ac70f0Sopenharmony_ci	int clock_type = -1;
42d5ac70f0Sopenharmony_ci
43d5ac70f0Sopenharmony_ci	int fd_in = -1,fd_out = -1;
44d5ac70f0Sopenharmony_ci	snd_rawmidi_t *handle_in = 0,*handle_out = 0;
45d5ac70f0Sopenharmony_ci
46d5ac70f0Sopenharmony_ci	if (argc==1) {
47d5ac70f0Sopenharmony_ci		usage();
48d5ac70f0Sopenharmony_ci		exit(0);
49d5ac70f0Sopenharmony_ci	}
50d5ac70f0Sopenharmony_ci
51d5ac70f0Sopenharmony_ci	for (i = 1 ; i<argc ; i++) {
52d5ac70f0Sopenharmony_ci		if (argv[i][0]=='-') {
53d5ac70f0Sopenharmony_ci			switch (argv[i][1]) {
54d5ac70f0Sopenharmony_ci				case 'h':
55d5ac70f0Sopenharmony_ci					usage();
56d5ac70f0Sopenharmony_ci					break;
57d5ac70f0Sopenharmony_ci				case 'v':
58d5ac70f0Sopenharmony_ci					verbose = 1;
59d5ac70f0Sopenharmony_ci					break;
60d5ac70f0Sopenharmony_ci				case 't':
61d5ac70f0Sopenharmony_ci					thru = 1;
62d5ac70f0Sopenharmony_ci					break;
63d5ac70f0Sopenharmony_ci				case 'c':
64d5ac70f0Sopenharmony_ci					if (i + 1 < argc)
65d5ac70f0Sopenharmony_ci						clock_type = atoi(argv[++i]);
66d5ac70f0Sopenharmony_ci					break;
67d5ac70f0Sopenharmony_ci				case 'i':
68d5ac70f0Sopenharmony_ci					if (i + 1 < argc)
69d5ac70f0Sopenharmony_ci						device_in = argv[++i];
70d5ac70f0Sopenharmony_ci					break;
71d5ac70f0Sopenharmony_ci				case 'I':
72d5ac70f0Sopenharmony_ci					if (i + 1 < argc)
73d5ac70f0Sopenharmony_ci						node_in = argv[++i];
74d5ac70f0Sopenharmony_ci					break;
75d5ac70f0Sopenharmony_ci				case 'o':
76d5ac70f0Sopenharmony_ci					if (i + 1 < argc)
77d5ac70f0Sopenharmony_ci						device_out = argv[++i];
78d5ac70f0Sopenharmony_ci					break;
79d5ac70f0Sopenharmony_ci				case 'O':
80d5ac70f0Sopenharmony_ci					if (i + 1 < argc)
81d5ac70f0Sopenharmony_ci						node_out = argv[++i];
82d5ac70f0Sopenharmony_ci					break;
83d5ac70f0Sopenharmony_ci			}
84d5ac70f0Sopenharmony_ci		}
85d5ac70f0Sopenharmony_ci	}
86d5ac70f0Sopenharmony_ci
87d5ac70f0Sopenharmony_ci	if (verbose) {
88d5ac70f0Sopenharmony_ci		fprintf(stderr,"Using: \n");
89d5ac70f0Sopenharmony_ci		fprintf(stderr,"Input: ");
90d5ac70f0Sopenharmony_ci		if (device_in) {
91d5ac70f0Sopenharmony_ci			fprintf(stderr,"device %s\n",device_in);
92d5ac70f0Sopenharmony_ci		}else if (node_in){
93d5ac70f0Sopenharmony_ci			fprintf(stderr,"%s\n",node_in);
94d5ac70f0Sopenharmony_ci		}else{
95d5ac70f0Sopenharmony_ci			fprintf(stderr,"NONE\n");
96d5ac70f0Sopenharmony_ci		}
97d5ac70f0Sopenharmony_ci		fprintf(stderr,"Output: ");
98d5ac70f0Sopenharmony_ci		if (device_out) {
99d5ac70f0Sopenharmony_ci			fprintf(stderr,"device %s\n",device_out);
100d5ac70f0Sopenharmony_ci		}else if (node_out){
101d5ac70f0Sopenharmony_ci			fprintf(stderr,"%s\n",node_out);
102d5ac70f0Sopenharmony_ci		}else{
103d5ac70f0Sopenharmony_ci			fprintf(stderr,"NONE\n");
104d5ac70f0Sopenharmony_ci		}
105d5ac70f0Sopenharmony_ci	}
106d5ac70f0Sopenharmony_ci
107d5ac70f0Sopenharmony_ci	if (device_in) {
108d5ac70f0Sopenharmony_ci		err = snd_rawmidi_open(&handle_in,NULL,device_in,0);
109d5ac70f0Sopenharmony_ci		if (err) {
110d5ac70f0Sopenharmony_ci			fprintf(stderr,"snd_rawmidi_open %s failed: %d\n",device_in,err);
111d5ac70f0Sopenharmony_ci		}
112d5ac70f0Sopenharmony_ci	}
113d5ac70f0Sopenharmony_ci	if (node_in && (!node_out || strcmp(node_out,node_in))) {
114d5ac70f0Sopenharmony_ci		fd_in = open(node_in,O_RDONLY);
115d5ac70f0Sopenharmony_ci		if (fd_in<0) {
116d5ac70f0Sopenharmony_ci			fprintf(stderr,"open %s for input failed\n",node_in);
117d5ac70f0Sopenharmony_ci		}
118d5ac70f0Sopenharmony_ci	}
119d5ac70f0Sopenharmony_ci
120d5ac70f0Sopenharmony_ci	signal(SIGINT,sighandler);
121d5ac70f0Sopenharmony_ci
122d5ac70f0Sopenharmony_ci	if (device_out) {
123d5ac70f0Sopenharmony_ci		err = snd_rawmidi_open(NULL,&handle_out,device_out,0);
124d5ac70f0Sopenharmony_ci		if (err) {
125d5ac70f0Sopenharmony_ci			fprintf(stderr,"snd_rawmidi_open %s failed: %d\n",device_out,err);
126d5ac70f0Sopenharmony_ci		}
127d5ac70f0Sopenharmony_ci	}
128d5ac70f0Sopenharmony_ci	if (node_out && (!node_in || strcmp(node_out,node_in))) {
129d5ac70f0Sopenharmony_ci		fd_out = open(node_out,O_WRONLY);
130d5ac70f0Sopenharmony_ci		if (fd_out<0) {
131d5ac70f0Sopenharmony_ci			fprintf(stderr,"open %s for output failed\n",node_out);
132d5ac70f0Sopenharmony_ci		}
133d5ac70f0Sopenharmony_ci	}
134d5ac70f0Sopenharmony_ci
135d5ac70f0Sopenharmony_ci	if (node_in && node_out && strcmp(node_out,node_in)==0) {
136d5ac70f0Sopenharmony_ci		fd_in = fd_out = open(node_out,O_RDWR);
137d5ac70f0Sopenharmony_ci		if (fd_out<0) {
138d5ac70f0Sopenharmony_ci			fprintf(stderr,"open %s for input and output failed\n",node_out);
139d5ac70f0Sopenharmony_ci		}
140d5ac70f0Sopenharmony_ci	}
141d5ac70f0Sopenharmony_ci
142d5ac70f0Sopenharmony_ci	if (!thru) {
143d5ac70f0Sopenharmony_ci		if (handle_in || fd_in!=-1) {
144d5ac70f0Sopenharmony_ci			if (clock_type != -1) {
145d5ac70f0Sopenharmony_ci				snd_rawmidi_params_t *params;
146d5ac70f0Sopenharmony_ci				snd_rawmidi_params_malloc(&params);
147d5ac70f0Sopenharmony_ci				if (!handle_in) {
148d5ac70f0Sopenharmony_ci					fprintf(stderr, "-c only usable with -i");
149d5ac70f0Sopenharmony_ci					clock_type = -1;
150d5ac70f0Sopenharmony_ci				}
151d5ac70f0Sopenharmony_ci				if (clock_type != -1) {
152d5ac70f0Sopenharmony_ci					fprintf(stderr, "Enable kernel clock type %d\n", clock_type);
153d5ac70f0Sopenharmony_ci					snd_rawmidi_params_current(handle_in, params);
154d5ac70f0Sopenharmony_ci					err = snd_rawmidi_params_set_read_mode(handle_in, params, SND_RAWMIDI_READ_TSTAMP);
155d5ac70f0Sopenharmony_ci					if (err) {
156d5ac70f0Sopenharmony_ci						fprintf(stderr,"snd_rawmidi_params_set_read_mode failed: %d\n", err);
157d5ac70f0Sopenharmony_ci						clock_type = -1;
158d5ac70f0Sopenharmony_ci					}
159d5ac70f0Sopenharmony_ci				}
160d5ac70f0Sopenharmony_ci				if (clock_type != -1) {
161d5ac70f0Sopenharmony_ci					err = snd_rawmidi_params_set_clock_type(handle_in, params, clock_type);
162d5ac70f0Sopenharmony_ci					if (err) {
163d5ac70f0Sopenharmony_ci						fprintf(stderr, "snd_rawmidi_params_set_clock_type failed: %d\n", err);
164d5ac70f0Sopenharmony_ci						clock_type = -1;
165d5ac70f0Sopenharmony_ci					}
166d5ac70f0Sopenharmony_ci				}
167d5ac70f0Sopenharmony_ci				if (clock_type != -1) {
168d5ac70f0Sopenharmony_ci					err = snd_rawmidi_params(handle_in, params);
169d5ac70f0Sopenharmony_ci					if (err) {
170d5ac70f0Sopenharmony_ci						fprintf(stderr, "snd_rawmidi_params failed: %d\n", err);
171d5ac70f0Sopenharmony_ci						clock_type = -1;
172d5ac70f0Sopenharmony_ci					}
173d5ac70f0Sopenharmony_ci				}
174d5ac70f0Sopenharmony_ci				snd_rawmidi_params_free(params);
175d5ac70f0Sopenharmony_ci			}
176d5ac70f0Sopenharmony_ci
177d5ac70f0Sopenharmony_ci			fprintf(stderr,"Read midi in\n");
178d5ac70f0Sopenharmony_ci			fprintf(stderr,"Press ctrl-c to stop\n");
179d5ac70f0Sopenharmony_ci		}
180d5ac70f0Sopenharmony_ci
181d5ac70f0Sopenharmony_ci		if (handle_in) {
182d5ac70f0Sopenharmony_ci			unsigned char buf[1024];
183d5ac70f0Sopenharmony_ci			ssize_t ret;
184d5ac70f0Sopenharmony_ci			while (!stop) {
185d5ac70f0Sopenharmony_ci				if (clock_type != -1) {
186d5ac70f0Sopenharmony_ci					struct timespec tstamp;
187d5ac70f0Sopenharmony_ci					ret = snd_rawmidi_tread(handle_in, &tstamp, buf, sizeof(buf));
188d5ac70f0Sopenharmony_ci					if (ret < 0)
189d5ac70f0Sopenharmony_ci						fprintf(stderr, "read timestamp error: %d - %s\n", (int)ret, snd_strerror(ret));
190d5ac70f0Sopenharmony_ci					if (ret > 0 && verbose) {
191d5ac70f0Sopenharmony_ci						fprintf(stderr, "read [%lld:%09lld]", (long long)tstamp.tv_sec, (long long)tstamp.tv_nsec);
192d5ac70f0Sopenharmony_ci						for (i = 0; i < ret; i++)
193d5ac70f0Sopenharmony_ci							fprintf(stderr, " %02x", buf[i]);
194d5ac70f0Sopenharmony_ci						fprintf(stderr, "\n");
195d5ac70f0Sopenharmony_ci					}
196d5ac70f0Sopenharmony_ci				} else {
197d5ac70f0Sopenharmony_ci					ret = snd_rawmidi_read(handle_in, buf, sizeof(buf));
198d5ac70f0Sopenharmony_ci					if (ret < 0)
199d5ac70f0Sopenharmony_ci						fprintf(stderr, "read error: %d - %s\n", (int)ret, snd_strerror(ret));
200d5ac70f0Sopenharmony_ci					if (ret > 0 && verbose)
201d5ac70f0Sopenharmony_ci						for (i = 0; i < ret; i++)
202d5ac70f0Sopenharmony_ci							fprintf(stderr,"read %02x\n",buf[i]);
203d5ac70f0Sopenharmony_ci				}
204d5ac70f0Sopenharmony_ci			}
205d5ac70f0Sopenharmony_ci		}
206d5ac70f0Sopenharmony_ci		if (fd_in!=-1) {
207d5ac70f0Sopenharmony_ci			unsigned char ch;
208d5ac70f0Sopenharmony_ci			while (!stop) {
209d5ac70f0Sopenharmony_ci				read(fd_in,&ch,1);
210d5ac70f0Sopenharmony_ci				if (verbose) {
211d5ac70f0Sopenharmony_ci					fprintf(stderr,"read %02x\n",ch);
212d5ac70f0Sopenharmony_ci				}
213d5ac70f0Sopenharmony_ci			}
214d5ac70f0Sopenharmony_ci		}
215d5ac70f0Sopenharmony_ci
216d5ac70f0Sopenharmony_ci		if (handle_out || fd_out!=-1) {
217d5ac70f0Sopenharmony_ci			fprintf(stderr,"Writing note on / note off\n");
218d5ac70f0Sopenharmony_ci		}
219d5ac70f0Sopenharmony_ci
220d5ac70f0Sopenharmony_ci		if (handle_out) {
221d5ac70f0Sopenharmony_ci			unsigned char ch;
222d5ac70f0Sopenharmony_ci			ch=0x90; snd_rawmidi_write(handle_out,&ch,1);
223d5ac70f0Sopenharmony_ci			ch=60;   snd_rawmidi_write(handle_out,&ch,1);
224d5ac70f0Sopenharmony_ci			ch=100;  snd_rawmidi_write(handle_out,&ch,1);
225d5ac70f0Sopenharmony_ci			snd_rawmidi_drain(handle_out);
226d5ac70f0Sopenharmony_ci			sleep(1);
227d5ac70f0Sopenharmony_ci			ch=0x90; snd_rawmidi_write(handle_out,&ch,1);
228d5ac70f0Sopenharmony_ci			ch=60;   snd_rawmidi_write(handle_out,&ch,1);
229d5ac70f0Sopenharmony_ci			ch=0;    snd_rawmidi_write(handle_out,&ch,1);
230d5ac70f0Sopenharmony_ci			snd_rawmidi_drain(handle_out);
231d5ac70f0Sopenharmony_ci		}
232d5ac70f0Sopenharmony_ci		if (fd_out!=-1) {
233d5ac70f0Sopenharmony_ci			unsigned char ch;
234d5ac70f0Sopenharmony_ci			ch=0x90; write(fd_out,&ch,1);
235d5ac70f0Sopenharmony_ci			ch=60;   write(fd_out,&ch,1);
236d5ac70f0Sopenharmony_ci			ch=100;  write(fd_out,&ch,1);
237d5ac70f0Sopenharmony_ci			sleep(1);
238d5ac70f0Sopenharmony_ci			ch=0x90; write(fd_out,&ch,1);
239d5ac70f0Sopenharmony_ci			ch=60;   write(fd_out,&ch,1);
240d5ac70f0Sopenharmony_ci			ch=0;    write(fd_out,&ch,1);
241d5ac70f0Sopenharmony_ci		}
242d5ac70f0Sopenharmony_ci	} else {
243d5ac70f0Sopenharmony_ci		if ((handle_in || fd_in!=-1) && (handle_out || fd_out!=-1)) {
244d5ac70f0Sopenharmony_ci			if (verbose) {
245d5ac70f0Sopenharmony_ci				fprintf(stderr,"Testing midi thru in\n");
246d5ac70f0Sopenharmony_ci			}
247d5ac70f0Sopenharmony_ci			while (!stop) {
248d5ac70f0Sopenharmony_ci				unsigned char ch;
249d5ac70f0Sopenharmony_ci
250d5ac70f0Sopenharmony_ci				if (handle_in) {
251d5ac70f0Sopenharmony_ci					snd_rawmidi_read(handle_in,&ch,1);
252d5ac70f0Sopenharmony_ci				}
253d5ac70f0Sopenharmony_ci				if (fd_in!=-1) {
254d5ac70f0Sopenharmony_ci					read(fd_in,&ch,1);
255d5ac70f0Sopenharmony_ci				}
256d5ac70f0Sopenharmony_ci				if (verbose) {
257d5ac70f0Sopenharmony_ci					fprintf(stderr,"thru: %02x\n",ch);
258d5ac70f0Sopenharmony_ci				}
259d5ac70f0Sopenharmony_ci
260d5ac70f0Sopenharmony_ci				if (handle_out) {
261d5ac70f0Sopenharmony_ci					snd_rawmidi_write(handle_out,&ch,1);
262d5ac70f0Sopenharmony_ci					snd_rawmidi_drain(handle_out);
263d5ac70f0Sopenharmony_ci				}
264d5ac70f0Sopenharmony_ci				if (fd_out!=-1) {
265d5ac70f0Sopenharmony_ci					write(fd_out,&ch,1);
266d5ac70f0Sopenharmony_ci				}
267d5ac70f0Sopenharmony_ci			}
268d5ac70f0Sopenharmony_ci		}else{
269d5ac70f0Sopenharmony_ci				fprintf(stderr,"Testing midi thru needs both input and output\n");
270d5ac70f0Sopenharmony_ci				exit(-1);
271d5ac70f0Sopenharmony_ci		}
272d5ac70f0Sopenharmony_ci	}
273d5ac70f0Sopenharmony_ci
274d5ac70f0Sopenharmony_ci	if (verbose) {
275d5ac70f0Sopenharmony_ci		fprintf(stderr,"Closing\n");
276d5ac70f0Sopenharmony_ci	}
277d5ac70f0Sopenharmony_ci
278d5ac70f0Sopenharmony_ci	if (handle_in) {
279d5ac70f0Sopenharmony_ci		snd_rawmidi_drain(handle_in);
280d5ac70f0Sopenharmony_ci		snd_rawmidi_close(handle_in);
281d5ac70f0Sopenharmony_ci	}
282d5ac70f0Sopenharmony_ci	if (handle_out) {
283d5ac70f0Sopenharmony_ci		snd_rawmidi_drain(handle_out);
284d5ac70f0Sopenharmony_ci		snd_rawmidi_close(handle_out);
285d5ac70f0Sopenharmony_ci	}
286d5ac70f0Sopenharmony_ci	if (fd_in!=-1) {
287d5ac70f0Sopenharmony_ci		close(fd_in);
288d5ac70f0Sopenharmony_ci	}
289d5ac70f0Sopenharmony_ci	if (fd_out!=-1) {
290d5ac70f0Sopenharmony_ci		close(fd_out);
291d5ac70f0Sopenharmony_ci	}
292d5ac70f0Sopenharmony_ci
293d5ac70f0Sopenharmony_ci	return 0;
294d5ac70f0Sopenharmony_ci}
295