]> lisas.de Git - terminatorX.git/blob - src/tX_engine.c
Uploaded Version 3.2 into ther repository... Alex
[terminatorX.git] / src / tX_engine.c
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999  Alexander K├Ânig
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18  
19     File: tX_engine.c
20  
21     Description: Contains the code that does the real "Scratching
22                  business": XInput, DGA, Mouse and Keyboardgrabbing
23                  etc.
24
25     02 Jun 1999: Implemented high-priority/rt-FIFO-Scheduling use for
26                  engine-thread.
27                  
28     04 Jun 1999: Changed warp-feature behaviour: still connected to
29                  mouse-speed (should be changed to maybe) but now
30                  depends on sample size -> you can warp through all
31                  samples with the same mouse-distance.
32 */    
33
34 #include "tX_types.h"
35 #include "tX_engine.h"
36 #include <pthread.h>
37 #include <gtk/gtk.h>
38 #include <gdk/gdkprivate.h>
39 #include "tX_gui.h"
40 #include "tX_global.h"
41 #include "turntable.h"
42
43 #ifndef WIN32
44 #include <unistd.h>
45 #include <X11/Xlib.h>
46 #include <X11/extensions/XInput.h>
47 #include <X11/extensions/xf86dga.h>
48 #include <X11/keysym.h>
49 #endif
50
51 #include "tX_widget.h"
52 #include <config.h>
53
54 #define XWINDOW xwindow
55
56 pthread_t engine_thread=0;
57
58 pthread_mutex_t stat_lock=PTHREAD_MUTEX_INITIALIZER;
59 pthread_mutex_t thread_lock=PTHREAD_MUTEX_INITIALIZER;
60 pthread_mutex_t pos_lock=PTHREAD_MUTEX_INITIALIZER;
61 pthread_mutex_t run_lock=PTHREAD_MUTEX_INITIALIZER;
62
63 int engine_status=ENG_STOPPED;
64
65 int realpos=0;
66
67 void set_real_pos(int pos)
68 {
69         pthread_mutex_lock(&pos_lock);
70         printf("setpos to %i\n", pos);
71         fflush(stdout);
72         realpos=pos;
73         pthread_mutex_unlock(&pos_lock);
74 }
75
76 int get_real_pos()
77 {
78         int pos;
79         pthread_mutex_lock(&pos_lock);
80         pos=realpos;
81         pthread_mutex_unlock(&pos_lock);
82         return(realpos);
83 }
84
85 int get_engine_status()
86 {
87         int tmp;
88         pthread_mutex_lock(&stat_lock);
89         tmp=engine_status;
90         pthread_mutex_unlock(&stat_lock);
91         return(tmp);
92 }
93
94 void set_engine_status(int status)
95 {
96         pthread_mutex_lock(&stat_lock);
97         engine_status=status;
98         pthread_mutex_unlock(&stat_lock);
99 }
100
101
102 #ifndef WIN32
103 XID OrgXPointer;
104 XDevice *input_device;
105
106 /* XInput grrr. strange strange....
107
108    For now just opens and closes the selected Devices as it seems
109    every device produces DGA events then.
110 */
111
112 int set_xinput(Display *dpy)
113 {
114 //      XDevice *input_device=NULL;
115         XDeviceInfo *devlist;                   
116         int listmax, i;
117         int match=-1;
118         
119         if (globals.xinput_enable)
120         {       
121                 devlist=XListInputDevices(dpy, &listmax);
122         
123                 for (i=0; i<listmax; i++)
124                 {
125                         if(!strcmp(globals.xinput_device,devlist[i].name))
126                         {
127                                 match=i;
128                         }
129                 
130                         if(devlist[i].use == IsXPointer)
131                         {
132                                 OrgXPointer=devlist[i].id;
133                         }
134                 }
135                 
136                 if (match>=0)
137                 {
138                         input_device=NULL;
139                         input_device=XOpenDevice(dpy,devlist[match].id);
140 /*                      if (XChangePointerDevice(dpy,input_device, 0, 1)!=Success)
141                         {
142                                 match=-1;
143                         }*/
144                         XCloseDevice(dpy, input_device);
145                 }
146                 
147                 XFreeDeviceList(devlist);               
148         
149                 if (match>=0) return(0); 
150                 else return(1);
151         }
152         
153         return(0);
154 }
155
156 void reset_xinput(Display *dpy)
157 {
158         
159 /*      if (globals.xinput_enable)
160         {
161                 input_device=XOpenDevice(dpy, OrgXPointer);
162                 XChangePointerDevice(dpy, input_device, 0, 1);
163                 XCloseDevice(dpy,input_device); 
164         }*/
165 }
166 #endif
167
168 void *engine(void *nil)
169 {
170 #ifndef WIN32
171         XEvent xev;
172         long mask=PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask;
173         XMotionEvent *xmot=(XMotionEvent *) &xev;
174         XKeyEvent *xkey=(XKeyEvent *) &xev;
175         XButtonEvent *xbut=(XButtonEvent *) &xev;
176         Time otime, ntime, dtime;
177         Display *dpy;
178         KeySym key;
179 #endif  
180
181         int quit=0;
182         int scratch=0;          
183         int stop_sense=globals.sense_cycles;
184         f_prec warp=1.0;
185
186 #ifdef ENABLE_DEBUG_OUTPUT
187         fprintf(stderr, "[engine()] Engine thread up, PID: %i\n", getpid());
188 #endif                  
189         pthread_mutex_lock(&run_lock);
190
191 #ifndef WIN32                           
192         dpy=XOpenDisplay(NULL); // FIXME: use correct display
193         if (!dpy)
194         {
195                 set_engine_status(ENG_ERR_XOPEN);
196                 pthread_exit(NULL);
197         }
198
199         if (vtt_needle_down(vttgl))
200         {
201                 XCloseDisplay(dpy);
202
203                 set_engine_status(ENG_ERR_SOUND);
204                 pthread_exit(NULL);
205         }
206                 
207         if (globals.xinput_enable)
208         {
209                 if (set_xinput(dpy))
210                 {
211                         XCloseDisplay(dpy);
212                         vtt_needle_up(vttgl);
213
214                         set_engine_status(ENG_ERR_XINPUT);
215                         pthread_exit(NULL);
216                 }
217         }
218                                 
219 //      XSelectInput(dpy, xwindow, mask);       
220
221 //      XSetInputFocus(dpy, XWINDOW, None, CurrentTime);
222
223         if (GrabSuccess != XGrabPointer(dpy, XWINDOW, False, ButtonPressMask|ButtonReleaseMask|PointerMotionMask, GrabModeAsync,GrabModeAsync,None,None,CurrentTime))
224         {
225                 reset_xinput(dpy);
226                 XCloseDisplay(dpy);
227                 vtt_needle_up(vttgl);
228
229                 set_engine_status(ENG_ERR_GRABMOUSE);
230                 pthread_exit(NULL);             
231         }       
232         
233         if (GrabSuccess != XGrabKeyboard(dpy, XWINDOW, False, GrabModeAsync,GrabModeAsync,CurrentTime))
234         {
235                 XUngrabPointer (dpy, CurrentTime);
236                 reset_xinput(dpy);              
237                 XCloseDisplay(dpy);
238
239                 vtt_needle_up(vttgl);
240                 set_engine_status(ENG_ERR_GRABKEY);
241                 pthread_exit(NULL);             
242         }
243         
244         
245         if (!XF86DGADirectVideo(dpy,DefaultScreen(dpy),XF86DGADirectMouse))
246         {
247                 XUngrabKeyboard(dpy, CurrentTime);                              
248                 XUngrabPointer (dpy, CurrentTime);
249                 reset_xinput(dpy);              
250                 XCloseDisplay(dpy);
251
252                 vtt_needle_up(vttgl);
253                 set_engine_status(ENG_ERR_DGA);
254                 pthread_exit(NULL);                     
255         }
256
257         XAutoRepeatOff(dpy);    
258         otime=CurrentTime;
259 #endif // WIN32
260
261         if (vttgl->mode == MODE_RECORD_SCRATCH)
262         {
263                 vtt_reset_rec_pos(vttgl);
264         }
265
266         set_engine_status(ENG_RUNNING);
267
268         while (!quit)
269         {
270                 if (scratch)
271                 {
272                         stop_sense--;
273         
274                         if (stop_sense<0)
275                         {
276                                 vttgl->speed=0;
277                         }
278                 }
279
280 #ifndef WIN32   
281                 if (XCheckWindowEvent(dpy, XWINDOW, mask, &xev))
282                 {
283                         switch (xev.type)
284                         {                               
285                                 case MotionNotify:
286                                 /*if (scratch)*/
287                                 {
288                                         ntime=xmot->time;
289                                         dtime=ntime-otime;
290                                         if (dtime<=0) dtime=1; //these happens if you move multiple devices at the same time
291                                         otime=ntime;
292                                         
293                                         if (globals.use_y)
294                                         {
295                                                 if (scratch) vttgl->speed=((f_prec) xmot->y_root/dtime)*warp*globals.mouse_speed;
296                                                 if (xmot->x_root != 0)
297                                                 vtt_lowpass_setfreq (vttgl, 0.05*((f_prec) xmot->x_root/dtime)*globals.mouse_speed);
298                                         }
299                                         else
300                                         {
301                                                 if (scratch) vttgl->speed=((f_prec) xmot->x_root/dtime)*warp*globals.mouse_speed;       
302                                                 if (xmot->y_root != 0)
303                                                 vtt_lowpass_setfreq (vttgl, 0.05*((f_prec) xmot->y_root/dtime)*globals.mouse_speed);                            
304                                         }
305                                         stop_sense=globals.sense_cycles;
306                                 }
307                                 break;
308                                 
309                                 case ButtonPress:
310                                         switch(xbut->button)
311                                         {
312                                                 case 1:
313                                                 vttgl->speed=0;
314                                                 scratch=1;                                                      
315                                                 break;
316                                                 
317                                                 case 3:
318                                                 vttgl->mute_scratch=1;
319                                                 break;
320                                                 
321                                                 case 2:
322                                                 quit=1;
323                                                 break;
324                                         }
325                                 break;
326                                 
327                                 case ButtonRelease:
328                                         switch(xbut->button)
329                                         {
330                                                 case 1:
331                                                 vttgl->speed=globals.vtt_default_speed;
332                                                 scratch=0;                                                      
333                                                 break;
334                                                 
335                                                 case 3:
336                                                 vttgl->mute_scratch=0;
337                                                 break;
338                                         }
339                                 break;
340                                 
341                                 case KeyPress:
342                                         key=XKeycodeToKeysym (dpy, xkey->keycode, 0);
343                                 
344                                         switch(key)
345                                         {
346                                                 case XK_space:
347                                                 vttgl->speed=0;
348                                                 scratch=1;
349                                                 break;
350                                         
351                                                 case XK_Escape:
352                                                 case XK_Return:
353                                                 quit=1;
354                                                 break;
355                                         
356                                                 case XK_m:
357                                                 case XK_Control_L:
358                                                 case XK_Control_R:                                              
359                                                 vttgl->mute_scratch=1;
360                                                 break;
361                                                 
362                                                 case XK_Alt_L:
363                                                 case XK_Alt_R:
364                                                 vttgl->mute_scratch=0;
365                                                 break;
366                                                 
367                                                 case XK_f:
368                                                 warp=((float) globals.scratch_size)/50000.0;                                            
369                                         }
370                                         break;
371                                 
372                                 case KeyRelease:
373                                         key=XKeycodeToKeysym (dpy, xkey->keycode, 0);
374                                 
375                                         switch(key)
376                                         {
377                                                 case XK_space:
378                                                 vttgl->speed=globals.vtt_default_speed;
379                                                 scratch=0;
380                                                 break;
381                                         
382                                                 case XK_Escape:
383                                                 quit=1;
384                                                 break;
385                                         
386                                                 case XK_m:
387                                                 case XK_Control_L:
388                                                 case XK_Control_R:                                              
389                                                 vttgl->mute_scratch=0;
390                                                 break;
391                                                 
392                                                 case XK_Alt_L:
393                                                 case XK_Alt_R:
394                                                 vttgl->mute_scratch=1;
395                                                 break;
396                                                 
397                                                 case XK_f:
398                                                 warp=1.0;
399                                                 break;
400                                         }
401                                         break;
402                         }
403                 }
404 #endif // WIN32         
405                 if (vtt_block_action(vttgl)) quit=2;
406         }
407
408 #ifndef WIN32
409         XF86DGADirectVideo(dpy,DefaultScreen(dpy),0);
410
411         XUngrabKeyboard(dpy, CurrentTime);              
412         XUngrabPointer (dpy, CurrentTime);
413         XAutoRepeatOn(dpy);
414
415         reset_xinput(dpy);      
416         
417         XCloseDisplay(dpy);
418 #endif  
419
420         if (vttgl->mode == MODE_RECORD_SCRATCH)
421         {
422                 vtt_store_rec_pos(vttgl);
423         }
424         
425         vtt_needle_up(vttgl);
426
427         if (quit==1) set_engine_status(ENG_STOPPED);
428         else set_engine_status(ENG_FINISHED);
429
430         pthread_mutex_unlock(&run_lock);
431                 
432         pthread_exit(NULL);
433 }
434
435 int run_engine()
436 {
437 #ifdef USE_SCHEDULER
438         pthread_attr_t pattr;
439         struct sched_param sparm;
440 #endif
441         pthread_mutex_lock(&run_lock);
442         
443         pthread_mutex_lock(&thread_lock);
444
445         if (engine_thread)
446         {
447                 pthread_mutex_unlock(&thread_lock);
448                 return(ENG_ERR_BUSY);
449         }
450 #ifdef USE_SCHEDULER    
451         if (!geteuid())
452         {
453 #ifdef ENABLE_DEBUG_OUTPUT
454                 fprintf(stderr, "[run_engine()] enabling fifo scheduling.\n");
455 #endif
456                 pthread_attr_init(&pattr);
457                 pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);
458                 pthread_attr_setschedpolicy(&pattr, SCHED_FIFO);
459         
460                 sched_getparam(getpid(), &sparm);
461                 sparm.sched_priority=sched_get_priority_max(SCHED_FIFO);
462         
463                 pthread_attr_setschedparam(&pattr, &sparm);
464                 pthread_attr_setinheritsched(&pattr, PTHREAD_EXPLICIT_SCHED);
465                 pthread_attr_setscope(&pattr, PTHREAD_SCOPE_SYSTEM);
466                 
467                 pthread_create(&engine_thread, &pattr, engine, NULL);
468         }
469         else
470         {
471 #ifdef ENABLE_DEBUG_OUTPUT
472                 fprintf(stderr, "[run_engine()] NO fifo scheduling.\n");
473 #endif
474                 pthread_create(&engine_thread, NULL, engine, NULL);             
475         }
476 #else
477         pthread_create(&engine_thread, NULL, engine, NULL);     
478 #endif
479         
480         if (!engine_thread)
481         {
482                 pthread_mutex_unlock(&thread_lock);
483                 return(ENG_ERR_THREAD);
484         }
485
486         gtk_label_set(GTK_LABEL(GTK_BUTTON(action_btn)->child), "Stop");        
487
488         pthread_detach(engine_thread);
489
490         set_engine_status(ENG_INIT);
491         
492         pthread_mutex_unlock(&thread_lock);
493         
494         pthread_mutex_unlock(&run_lock);
495                 
496         return (ENG_RUNNING);
497 }
498
499 int stop_engine()
500 {
501         void *ret;
502         
503         pthread_mutex_lock(&thread_lock);       
504         if (!engine_thread)
505         {
506                 pthread_mutex_lock(&thread_lock);
507                 return(1);
508         }
509         
510         pthread_join(engine_thread, &ret);
511         
512         engine_thread=0;
513         
514         pthread_mutex_unlock(&thread_lock);
515         
516         gtk_label_set(GTK_LABEL(GTK_BUTTON(action_btn)->child), "Start");       
517         
518         return (0);
519 }