Fix readme
[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 int cc14=0;
58
59 int open_alsa_seq()
60 {
61         char client_name[32];
62         char port_name[48];
63         snd_seq_addr_t src;
64         
65         /* Create the sequencer port. */
66         
67         sprintf(client_name, "Joystick%i", joystick_no);
68         sprintf(port_name , "%s Output", client_name);
69
70         if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_OUTPUT, 0) < 0) {
71                 puts("Error: Failed to access the ALSA sequencer.");
72                 exit(-1);
73         }
74
75         snd_seq_set_client_name(seq_handle, client_name);
76         src.client = snd_seq_client_id(seq_handle);
77         src.port = snd_seq_create_simple_port(seq_handle, "Joystick Output",
78                 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION);
79
80         /* Init the event structure */
81         
82         snd_seq_ev_clear(&ev);
83         snd_seq_ev_set_source(&ev, src.port);
84         snd_seq_ev_set_subs(&ev);
85         snd_seq_ev_set_direct(&ev);
86
87         return 0;
88 }
89
90 int axes;
91 int joy_fd;
92 int buttons;
93
94 int open_joystick()
95 {
96         char device[256];
97         char name[NAME_LENGTH] = "Unknown";     
98         
99         sprintf(device, "/dev/js%i", joystick_no);
100
101         if ((joy_fd = open(device, O_RDONLY)) < 0) {
102                 fprintf(stderr, "%s: ", TOOL_NAME); perror(device);
103                 sprintf(device, "/dev/input/js%i", joystick_no);
104                 
105                 if ((joy_fd = open(device, O_RDONLY)) < 0) {    
106                         fprintf(stderr, "%s: ", TOOL_NAME); perror(device);
107                         exit(-3);
108                 }
109         }
110
111         ioctl(joy_fd, JSIOCGAXES, &axes);
112         ioctl(joy_fd, JSIOCGBUTTONS, &buttons);
113         ioctl(joy_fd, JSIOCGNAME(NAME_LENGTH), name);
114
115         printf("Using Joystick (%s) through device %s with %i axes and %i buttons.\n", name, device, axes, buttons);
116
117         return 0;
118 }
119
120 void loop()
121 {
122         struct js_event js;
123         int current_channel=1;
124         double val_d;
125         int val_i;
126         int i;
127         val *values;
128         
129         values = calloc(axes, sizeof(val));
130         
131         puts("Axis -> MIDI controller mapping:");
132         
133         for (i=0; i<axes; i++) {
134                 if (i<4) {
135                         values[i].controller=controllers[i];
136                 } else {
137                         values[i].controller=10+i;
138                 }
139                 printf("  %2i -> %3i\n", i, values[i].controller);
140                 values[i].last_value=0;         
141         }
142         
143         puts("Ready, entering loop - use Ctrl-C to exit.");     
144
145         while (1) {
146                 if (read(joy_fd, &js, sizeof(struct js_event)) != sizeof(struct js_event)) {
147                         perror(TOOL_NAME ": error reading from joystick device");
148                         exit (-5);
149                 }
150
151                 switch(js.type & ~JS_EVENT_INIT) {              
152                         case JS_EVENT_BUTTON:
153                                 if (js.value) {                 
154                                         current_channel=js.number+1;
155                                 
156                                         if (verbose) {
157                                                 printf("Switched to MIDI channel %i.\n", current_channel);
158                                         }
159                                 }
160                         break;
161                         
162                         case JS_EVENT_AXIS:
163                                 val_d=(double) js.value;
164                                 val_d+=SHRT_MAX;
165                                 val_d=val_d/((double) USHRT_MAX);
166                                 
167                                 if (cc14) {
168                                         val_d*=16383.0;
169                                 } else {
170                                         val_d*=127.0;
171                                 }
172                         
173                                 val_i=(int) val_d;
174                         
175                                 if (values[js.number].last_value!=val_i) {
176                                         values[js.number].last_value!=val_i;
177                                         
178                                         if (cc14) {
179                                                 ev.type = SND_SEQ_EVENT_CONTROL14;
180                                         } else {                                        
181                                                 ev.type = SND_SEQ_EVENT_CONTROLLER;
182                                         }
183
184                                         snd_seq_ev_set_fixed(&ev);
185                                         ev.data.control.channel=current_channel;
186                                         ev.data.control.param=values[js.number].controller;
187                                         ev.data.control.value=val_i;
188
189                                         
190                                         // snd_seq_ev_set_controller(&ev, current_channel, values[js.number].controller, val_i);
191                                         snd_seq_event_output_direct(seq_handle, &ev);
192                                         
193                                         if (verbose) {
194                                                 printf("Sent controller %i with value: %i.\n", values[js.number].controller, val_i);
195                                         }
196                                 }
197                         break;
198                 }
199         }
200 }
201
202 int main (int argc, char **argv)
203 {
204         int i;
205         fprintf(stderr, "%s Version %s - Copyright (C) 2003 by Alexander K├Ânig\n",  TOOL_NAME, VERSION);
206         fprintf(stderr, "%s comes with ABSOLUTELY NO WARRANTY - for details read the license.\n", TOOL_NAME);
207
208         for (i=0; i<4; i++) {
209                 controllers[i]=10+i;
210         }
211         
212         while (1) {
213                 int i=getopt(argc, argv, "vhrd:0:1:2:3:");
214                 if (i==-1) break;
215                 
216                 switch (i) {
217                         case '?':
218                         case 'h':
219                                 printf("usage: %s [-d joystick_no] [-v] [-0 ctrl0] [-1 ctrl1] [-2 ctrl2] [-3 ctrl3]\n\n", TOOL_NAME);
220                                 puts("\t-d Select the Joystick to use: 0..3");
221                                 puts("\t-0 Select the Controller for Axis 0 (1-127).");
222                                 puts("\t-1 Select the Controller for Axis 1 (1-127). Etc.");
223                                 puts("\t-v Verbose mode.");
224                                 exit(-2);
225                         break;
226                         
227                         case '0':
228                                 controllers[0]=atoi(optarg);
229                         break;
230
231                         case '1':
232                                 controllers[1]=atoi(optarg);
233                         break;
234
235                         case '2':
236                                 controllers[2]=atoi(optarg);
237                         break;
238
239                         case '3':
240                                 controllers[3]=atoi(optarg);
241                         break;
242                         
243                         case 'v':
244                                 verbose=1;
245                         break;
246
247                         case 'r':
248                                 cc14=1;
249                         break;
250                         
251                         case 'd':
252                                 joystick_no=atoi(optarg);
253                         break;
254                 }
255         }
256
257
258         snd_seq_addr_t dest;
259
260         open_joystick();
261         open_alsa_seq();
262         
263         loop();
264
265         return 0;
266 }