Adding a manpage - Alex
[terminatorX.git] / aseqjoy / aseqjoy.c
1 /**
2  * aseqjoy - Tiny Jostick -> MIDI Controller
3  * Copyright 2003 by Alexander Koenig - alex@lisas.de
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19
20 #include <sys/ioctl.h>
21 #include <sys/time.h>
22 #include <sys/types.h>
23 #include <stdlib.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <limits.h>
30
31 #include <linux/joystick.h>
32 #include <alsa/asoundlib.h>
33
34 #define NAME_LENGTH 128
35
36 #define TOOL_NAME "aseqjoy"
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 int joystick_no=0;
43
44 typedef struct {
45         int controller;
46         int last_value;
47 }  val;
48
49 snd_seq_t *seq_handle;
50 snd_seq_event_t ev;
51 int controllers[4];
52 int verbose=0;
53
54 int open_alsa_seq() {
55         char client_name[32];
56         char port_name[48];
57         snd_seq_addr_t src;
58         
59         /* Create the sequencer port. */
60         
61         sprintf(client_name, "Joystick%i", joystick_no);
62         sprintf(port_name , "%s Output", client_name);
63
64         if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_OUTPUT, 0) < 0) {
65                 puts("Error: Failed to access the ALSA sequencer.");
66                 exit(-1);
67         }
68
69         snd_seq_set_client_name(seq_handle, client_name);
70         src.client = snd_seq_client_id(seq_handle);
71         src.port = snd_seq_create_simple_port(seq_handle, "Joystick Output",
72                 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION);
73
74         /* Init the event structure */
75         
76         snd_seq_ev_clear(&ev);
77         snd_seq_ev_set_source(&ev, src.port);
78         snd_seq_ev_set_subs(&ev);
79         snd_seq_ev_set_direct(&ev);
80
81         return 0;
82 }
83
84 int axes;
85 int joy_fd;
86 int buttons;
87
88 int open_joystick() {
89         char device[256];
90         char name[NAME_LENGTH] = "Unknown";     
91         
92         sprintf(device, "/dev/js%i", joystick_no);
93
94         if ((joy_fd = open(device, O_RDONLY)) < 0) {
95                 fprintf(stderr, "%s: ", TOOL_NAME); perror(device);
96                 sprintf(device, "/dev/input/js%i", joystick_no);
97                 
98                 if ((joy_fd = open(device, O_RDONLY)) < 0) {    
99                         fprintf(stderr, "%s: ", TOOL_NAME); perror(device);
100                         exit(-3);
101                 }
102         }
103
104         ioctl(joy_fd, JSIOCGAXES, &axes);
105         ioctl(joy_fd, JSIOCGBUTTONS, &buttons);
106         ioctl(joy_fd, JSIOCGNAME(NAME_LENGTH), name);
107
108         printf("Using Joystick (%s) through device %s with %i axes and %i buttons.\n", name, device, axes, buttons);
109
110         return 0;
111 }
112
113 void loop() {
114         struct js_event js;
115         int current_channel=1;
116         double val_d;
117         int val_i;
118         int i;
119         val *values;
120         
121         values = calloc(axes, sizeof(val));
122         
123         puts("Axis -> MIDI controller mapping:");
124         
125         for (i=0; i<axes; i++) {
126                 if (i<4) {
127                         values[i].controller=controllers[i];
128                 } else {
129                         values[i].controller=10+i;
130                 }
131                 printf("  %2i -> %3i\n", i, values[i].controller);
132                 values[i].last_value=0;         
133         }
134         
135         
136         
137         puts("Ready, entering loop - use Ctrl-C to exit.");     
138
139         while (1) {
140                 if (read(joy_fd, &js, sizeof(struct js_event)) != sizeof(struct js_event)) {
141                         perror(TOOL_NAME ": error reading from joystick device");
142                         exit (-5);
143                 }
144
145                 switch(js.type & ~JS_EVENT_INIT) {
146                 
147                         case JS_EVENT_BUTTON:
148                                 if (js.value) {                 
149                                         current_channel=js.number+1;
150                                 
151                                         if (verbose) {
152                                                 printf("Switched to MIDI channel %i.\n", current_channel);
153                                         }
154                                 }
155                         break;
156                         
157                         case JS_EVENT_AXIS:
158                                 val_d=(double) js.value;
159                                 val_d+=SHRT_MAX;
160                                 val_d=val_d/((double) USHRT_MAX);
161                                 val_d*=127.0;
162                         
163                                 val_i=(int) val_d;
164                         
165                                 if (values[js.number].last_value!=val_i) {
166                                         values[js.number].last_value!=val_i;
167                                         snd_seq_ev_set_controller(&ev, current_channel, values[js.number].controller, val_i);
168                                         snd_seq_event_output_direct(seq_handle, &ev);
169                                         
170                                         if (verbose) {
171                                                 printf("Sent controller %i with value: %i.\n", values[js.number].controller, val_i);
172                                         }
173                                 }
174                         break;
175                 }
176         }
177 }
178
179 int main (int argc, char **argv)
180 {
181         int i;
182         fprintf(stderr, "%s Version %s - Copyright (C) 2003 by Alexander K├Ânig\n",  TOOL_NAME, VERSION);
183         fprintf(stderr, "%s comes with ABSOLUTELY NO WARRANTY - for details read the license.\n", TOOL_NAME);
184
185         for (i=0; i<4; i++) {
186                 controllers[i]=10+i;
187         }
188         
189         while (1) {
190                 int i=getopt(argc, argv, "vhd:1:2:3:4:");
191                 if (i==-1) break;
192                 
193                 switch (i) {
194                         case '?':
195                         case 'h':
196                                 printf("usage: %s [-d joystick_no] [-v] [-0 ctrl0] [-1 ctrl1] [-2 ctrl2] [-3 ctrl3]\n\n", TOOL_NAME);
197                                 puts("\t-d Select the Joystick to use: 0..3");
198                                 puts("\t-0 Select the Controller for Axis 0 (1-127).");
199                                 puts("\t-1 Select the Controller for Axis 1 (1-127). Etc.");
200                                 puts("\t-v Verbose mode.");
201                                 exit(-2);
202                         break;
203                         
204                         case '0':
205                                 controllers[0]=atoi(optarg);
206                         break;
207
208                         case '1':
209                                 controllers[1]=atoi(optarg);
210                         break;
211
212                         case '2':
213                                 controllers[2]=atoi(optarg);
214                         break;
215
216                         case '3':
217                                 controllers[3]=atoi(optarg);
218                         break;
219                         
220                         case 'v':
221                                 verbose=1;
222                         break;
223                         
224                         case 'd':
225                                 joystick_no=atoi(optarg);
226                         break;
227                 }
228         }
229
230
231         snd_seq_addr_t dest;
232
233         open_joystick();
234         open_alsa_seq();
235         
236         loop();
237
238         return 0;
239 }