Alex: Added the new sources for terminatorX 3.5
[terminatorX.git] / src / tX_engine.cc
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 "tX_audiodevice.h"
37 #include "tX_mouse.h"
38 #include "tX_vtt.h"
39 #include <pthread.h>
40 #include <gtk/gtk.h>
41 #include <gdk/gdkprivate.h>
42 #include "tX_mastergui.h"
43 #include "tX_global.h"
44 #include "tX_tape.h"
45 #include "tX_widget.h"
46 #include <config.h>
47
48 pthread_t engine_thread=0;
49
50 pthread_mutex_t stat_lock=PTHREAD_MUTEX_INITIALIZER;
51 pthread_mutex_t thread_lock=PTHREAD_MUTEX_INITIALIZER;
52 pthread_mutex_t pos_lock=PTHREAD_MUTEX_INITIALIZER;
53 pthread_mutex_t run_lock=PTHREAD_MUTEX_INITIALIZER;
54
55 tx_mouse *mouse=new tx_mouse();
56 audiodevice *device=new audiodevice();
57 tx_tapedeck *tape=new tx_tapedeck();
58
59 int engine_quit=0;
60
61 int engine_status=ENG_STOPPED;
62
63 int realpos=0;
64
65 int do_grab_mouse=0;
66 int new_grab_mouse=0;
67
68 int want_recording=0;
69 int is_recording=0;
70
71 int grab_mouse(int newstate)
72 {
73         new_grab_mouse=newstate;
74 }
75
76 int get_engine_status()
77 {
78         int tmp;
79         pthread_mutex_lock(&stat_lock);
80         tmp=engine_status;
81         pthread_mutex_unlock(&stat_lock);
82         return(tmp);
83 }
84
85 void set_engine_status(int status)
86 {
87         pthread_mutex_lock(&stat_lock);
88         engine_status=status;
89         pthread_mutex_unlock(&stat_lock);
90 }
91
92 void *engine(void *nil)
93 {
94         int scratch=0;          
95         int stop_sense=globals.sense_cycles;
96         f_prec warp=1.0;
97         int16_t *temp;
98         
99 /*      want_recording=0;
100         is_recording=0; */
101         
102 #ifdef ENABLE_DEBUG_OUTPUT
103         fprintf(stderr, "[engine()] Engine thread up, PID: %i\n", getpid());
104 #endif                  
105         pthread_mutex_lock(&run_lock);
106
107         set_engine_status(ENG_RUNNING);
108
109         while (!engine_quit)
110         {       
111                 if (new_grab_mouse!=do_grab_mouse)
112                 {
113                 
114                         do_grab_mouse=new_grab_mouse;
115                         
116                         if (do_grab_mouse) mouse->grab();
117                         else
118                         {
119                                 mouse->ungrab();
120                                 grab_off();
121                         }
122                 }
123                 
124                 if (do_grab_mouse)
125                 if (mouse->check_event())
126                 {
127                         new_grab_mouse=0;
128                 }
129                 
130                 if (is_recording)
131                 {
132                         temp=vtt_class::render_all_turntables();
133                         device->eat(temp);
134                         tape->eat(temp);                        
135                 }
136                 else
137                 {
138                         device->eat(vtt_class::render_all_turntables());                
139                 }
140         }
141         
142 //      device->dev_close();
143
144         if (engine_quit==1) set_engine_status(ENG_STOPPED);
145         else set_engine_status(ENG_FINISHED);
146
147         pthread_mutex_unlock(&run_lock);
148                 
149         pthread_exit(NULL);
150 }
151
152 int run_engine()
153 {
154 #ifdef USE_SCHEDULER
155         pthread_attr_t pattr;
156         struct sched_param sparm;
157 #endif
158         char buffer[PATH_MAX];
159         list <vtt_class *> :: iterator vtt;
160
161         pthread_mutex_lock(&run_lock);
162         
163         pthread_mutex_lock(&thread_lock);
164
165         device->dev_open(0);
166         
167         is_recording=0;
168         
169         if (want_recording)
170         {
171                 if (!tape->start_record(globals.record_filename, device->getblocksize()))
172                         is_recording=1;
173         }
174
175         vtt_class::set_mix_buffer_size(device->getblocksize()/sizeof(int16_t));
176
177         if (engine_thread)
178         {
179                 pthread_mutex_unlock(&thread_lock);
180                 return(ENG_ERR_BUSY);
181         }
182         
183         engine_quit=0;
184 #ifdef USE_SCHEDULER    
185         if (!geteuid())
186         {
187 #ifdef ENABLE_DEBUG_OUTPUT
188                 fprintf(stderr, "[run_engine()] enabling fifo scheduling.\n");
189 #endif
190                 pthread_attr_init(&pattr);
191                 pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);
192                 pthread_attr_setschedpolicy(&pattr, SCHED_FIFO);
193         
194                 sched_getparam(getpid(), &sparm);
195                 sparm.sched_priority=sched_get_priority_max(SCHED_FIFO);
196         
197                 pthread_attr_setschedparam(&pattr, &sparm);
198                 pthread_attr_setinheritsched(&pattr, PTHREAD_EXPLICIT_SCHED);
199                 pthread_attr_setscope(&pattr, PTHREAD_SCOPE_SYSTEM);
200                 
201                 pthread_create(&engine_thread, &pattr, engine, NULL);
202         }
203         else
204         {
205 #ifdef ENABLE_DEBUG_OUTPUT
206                 fprintf(stderr, "[run_engine()] NO fifo scheduling.\n");
207 #endif
208                 pthread_create(&engine_thread, NULL, engine, NULL);             
209         }
210 #else
211         pthread_create(&engine_thread, NULL, engine, NULL);     
212 #endif
213         
214         if (!engine_thread)
215         {
216                 pthread_mutex_unlock(&thread_lock);
217                 return(ENG_ERR_THREAD);
218         }
219
220 //      gtk_label_set(GTK_LABEL(GTK_BUTTON(action_btn)->child), "Stop");        
221
222         for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++)
223         {
224                 if ((*vtt)->autotrigger) (*vtt)->trigger();
225         }
226
227         pthread_detach(engine_thread);
228
229         set_engine_status(ENG_INIT);
230         
231         pthread_mutex_unlock(&thread_lock);
232         
233         pthread_mutex_unlock(&run_lock);
234                 
235         return (ENG_RUNNING);
236 }
237
238 int stop_engine()
239 {
240         list <vtt_class *> :: iterator vtt;
241         void *ret;
242
243         pthread_mutex_lock(&thread_lock);       
244         if (!engine_thread)
245         {
246                 pthread_mutex_unlock(&thread_lock);
247                 return(1);
248         }
249         
250         engine_quit=1;
251         
252         pthread_join(engine_thread, &ret);
253         
254         engine_thread=0;
255         
256         pthread_mutex_unlock(&thread_lock);
257         device->dev_close();
258         
259         for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++)
260         {
261                 (*vtt)->stop();
262                 (*vtt)->ec_clear_buffer();
263         }
264         
265         if (is_recording) tape->stop_record();
266         is_recording=0;
267         return (0);
268 }