Guess what - Alex
[terminatorX.git] / aseqjoy / aseqjoy.c
1 /**
2  * aseqjoy - Tiny Jostick -> MIDI Controller Tool
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  * Note: that these sources contain a few lines of Vojtech Pavlik's jstest.c 
20  * example, which is GPL'd, too and available from:
21  * http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/
22  */
23
24 #include <sys/ioctl.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <stdlib.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <limits.h>
34
35 #include <linux/joystick.h>
36 #include <alsa/asoundlib.h>
37
38 #define NAME_LENGTH 128
39
40 #define TOOL_NAME "aseqjoy"
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46 int joystick_no=0;
47
48 typedef struct {
49         int controller;
50         int last_value;
51 }  val;
52
53 snd_seq_t *seq_handle;
54 snd_seq_event_t ev;
55 int controllers[4];
56 int verbose=0;
57
58 int open_alsa_seq()
59 {
60         char client_name[32];
61         char port_name[48];
62         snd_seq_addr_t src;
63         
64         /* Create the sequencer port. */
65         
66         sprintf(client_name, "Joystick%i", joystick_no);
67         sprintf(port_name , "%s Output", client_name);
68
69         if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_OUTPUT, 0) < 0) {
70                 puts("Error: Failed to access the ALSA sequencer.");
71                 exit(-1);
72         }
73
74         snd_seq_set_client_name(seq_handle, client_name);
75         src.client = snd_seq_client_id(seq_handle);
76         src.port = snd_seq_create_simple_port(seq_handle, "Joystick Output",
77                 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION);
78
79         /* Init the event structure */
80         
81         snd_seq_ev_clear(&ev);
82         snd_seq_ev_set_source(&ev, src.port);
83         snd_seq_ev_set_subs(&ev);
84         snd_seq_ev_set_direct(&ev);
85
86         return 0;
87 }
88
89 int axes;
90 int joy_fd;
91 int buttons;
92
93 int open_joystick()
94 {
95         char device[256];
96         char name[NAME_LENGTH] = "Unknown";     
97         
98         sprintf(device, "/dev/js%i", joystick_no);
99
100         if ((joy_fd = open(device, O_RDONLY)) < 0) {
101                 fprintf(stderr, "%s: ", TOOL_NAME); perror(device);
102                 sprintf(device, "/dev/input/js%i", joystick_no);
103                 
104                 if ((joy_fd = open(device, O_RDONLY)) < 0) {    
105                         fprintf(stderr, "%s: ", TOOL_NAME); perror(device);
106                         exit(-3);
107                 }
108         }
109
110         ioctl(joy_fd, JSIOCGAXES, &axes);
111         ioctl(joy_fd, JSIOCGBUTTONS, &buttons);
112         ioctl(joy_fd, JSIOCGNAME(NAME_LENGTH), name);
113
114         printf("Using Joystick (%s) through device %s with %i axes and %i buttons.\n", name, device, axes, buttons);
115
116         return 0;
117 }
118
119 void loop()
120 {
121         struct js_event js;
122         int current_channel=1;
123         double val_d;
124         int val_i;
125         int i;
126         val *values;
127         
128         values = calloc(axes, sizeof(val));
129         
130         puts("Axis -> MIDI controller mapping:");
131         
132         for (i=0; i<axes; i++) {
133                 if (i<4) {
134                         values[i].controller=controllers[i];
135                 } else {
136                         values[i].controller=10+i;
137                 }
138                 printf("  %2i -> %3i\n", i, values[i].controller);
139                 values[i].last_value=0;         
140         }
141         
142         puts("Ready, entering loop - use Ctrl-C to exit.");     
143
144         while (1) {
145                 if (read(joy_fd, &js, sizeof(struct js_event)) != sizeof(struct js_event)) {
146                         perror(TOOL_NAME ": error reading from joystick device");
147                         exit (-5);
148                 }
149
150                 switch(js.type & ~JS_EVENT_INIT) {              
151                         case JS_EVENT_BUTTON:
152                                 if (js.value) {                 
153                                         current_channel=js.number+1;
154                                 
155                                         if (verbose) {
156                                                 printf("Switched to MIDI channel %i.\n", current_channel);
157                                         }
158                                 }
159                         break;
160                         
161                         case JS_EVENT_AXIS:
162                                 val_d=(double) js.value;
163                                 val_d+=SHRT_MAX;
164                                 val_d=val_d/((double) USHRT_MAX);
165                                 val_d*=127.0;
166                         
167                                 val_i=(int) val_d;
168                         
169                                 if (values[js.number].last_value!=val_i) {
170                                         values[js.number].last_value!=val_i;
171                                         snd_seq_ev_set_controller(&ev, current_channel, values[js.number].controller, val_i);
172                                         snd_seq_event_output_direct(seq_handle, &ev);
173                                         
174                                         if (verbose) {
175                                                 printf("Sent controller %i with value: %i.\n", values[js.number].controller, val_i);
176                                         }
177                                 }
178                         break;
179                 }
180         }
181 }
182
183 int main (int argc, char **argv)
184 {
185         int i;
186         fprintf(stderr, "%s Version %s - Copyright (C) 2003 by Alexander K├Ânig\n",  TOOL_NAME, VERSION);
187         fprintf(stderr, "%s comes with ABSOLUTELY NO WARRANTY - for details read the license.\n", TOOL_NAME);
188
189         for (i=0; i<4; i++) {
190                 controllers[i]=10+i;
191         }
192         
193         while (1) {
194                 int i=getopt(argc, argv, "vhd:1:2:3:4:");
195                 if (i==-1) break;
196                 
197                 switch (i) {
198                         case '?':
199                         case 'h':
200                                 printf("usage: %s [-d joystick_no] [-v] [-0 ctrl0] [-1 ctrl1] [-2 ctrl2] [-3 ctrl3]\n\n", TOOL_NAME);
201                                 puts("\t-d Select the Joystick to use: 0..3");
202                                 puts("\t-0 Select the Controller for Axis 0 (1-127).");
203                                 puts("\t-1 Select the Controller for Axis 1 (1-127). Etc.");
204                                 puts("\t-v Verbose mode.");
205                                 exit(-2);
206                         break;
207                         
208                         case '0':
209                                 controllers[0]=atoi(optarg);
210                         break;
211
212                         case '1':
213                                 controllers[1]=atoi(optarg);
214                         break;
215
216                         case '2':
217                                 controllers[2]=atoi(optarg);
218                         break;
219
220                         case '3':
221                                 controllers[3]=atoi(optarg);
222                         break;
223                         
224                         case 'v':
225                                 verbose=1;
226                         break;
227                         
228                         case 'd':
229                                 joystick_no=atoi(optarg);
230                         break;
231                 }
232         }
233
234
235         snd_seq_addr_t dest;
236
237         open_joystick();
238         open_alsa_seq();
239         
240         loop();
241
242         return 0;
243 }