2 terminatorX - realtime audio scratching software
3 Copyright (C) 1999-2002 Alexander König
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.
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.
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.
21 Description: Contains the code that does the real "Scratching
22 business": XInput, DGA, Mouse and Keyboardgrabbing
25 02 Jun 1999: Implemented high-priority/rt-FIFO-Scheduling use for
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.
35 #include "tX_engine.h"
36 #include "tX_audiodevice.h"
41 #include <gdk/gdkprivate.h>
42 #include "tX_mastergui.h"
43 #include "tX_global.h"
45 #include "tX_widget.h"
47 #include "tX_sequencer.h"
51 #include <sys/resource.h>
53 tX_engine *engine=NULL;
55 tx_mouse *mouse=new tx_mouse();
56 tX_audiodevice *device=NULL;
57 tx_tapedeck *tape=new tx_tapedeck();
59 void tX_engine :: set_grab_request() {
63 void tX_engine :: loop() {
67 while (!thread_terminate) {
68 /* Waiting for the trigger */
69 pthread_mutex_lock(&start);
71 pthread_mutex_unlock(&start);
73 /* Render first block */
75 temp=vtt_class::render_all_turntables();
78 /* Checking whether to grab or not */
79 if (grab_request!=grab_active) {
81 /* Activating grab... */
84 tX_error("tX_engine::loop(): failed to grab mouse - error %i", result);
86 /* Reseting grab_request, too - doesn't help keeping it, does it ? ;) */
88 // mouse->ungrab() // do we need this?
93 /* Deactivating grab... */
96 grab_off(); // for the mastergui this is...
100 /* Handling input events... */
102 if (mouse->check_event()) {
103 /* If we're here the user pressed ESC */
108 /* Playback the audio... */
111 /* Record the audio if necessary... */
112 if (is_recording()) tape->eat(temp);
114 /* Forward the sequencer... */
117 /* Render the next block... */
118 temp=vtt_class::render_all_turntables();
121 /* Stopping engine... */
122 loop_is_active=false;
126 void *engine_thread_entry(void *engine_void) {
127 tX_engine *engine=(tX_engine*) engine_void;
130 /* Dropping root privileges for the engine thread - if running suid. */
132 if ((!geteuid()) && (getuid() != geteuid())) {
133 tX_debug("engine_thread_entry() - Running suid root - dropping privileges.");
135 result=setuid(getuid());
138 tX_error("engine_thread_entry() - Failed to drop root privileges.");
146 tX_engine :: tX_engine() {
149 pthread_mutex_init(&start, NULL);
150 pthread_mutex_lock(&start);
151 thread_terminate=false;
153 /* Creating the actual engine thread.. */
156 pthread_attr_t pattr;
157 struct sched_param sparm;
159 tX_debug("tX_engine() - Have root privileges - using SCHED_FIFO.");
161 pthread_attr_init(&pattr);
162 pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);
163 pthread_attr_setschedpolicy(&pattr, SCHED_FIFO);
165 sched_getparam(getpid(), &sparm);
166 sparm.sched_priority=sched_get_priority_max(SCHED_FIFO);
168 pthread_attr_setschedparam(&pattr, &sparm);
169 pthread_attr_setinheritsched(&pattr, PTHREAD_EXPLICIT_SCHED);
170 pthread_attr_setscope(&pattr, PTHREAD_SCOPE_SYSTEM);
172 result=pthread_create(&thread, &pattr, engine_thread_entry, (void *) this);
174 tX_debug("tX_engine() - Lacking root privileges - no realtime scheduling!");
176 result=pthread_create(&thread, NULL, engine_thread_entry, (void *) this);
180 tX_error("tX_engine() - Failed to create engine thread. Errno is %i.", errno);
184 /* Dropping root privileges for the main thread - if running suid. */
186 if ((!geteuid()) && (getuid() != geteuid())) {
187 tX_debug("tX_engine() - Running suid root - dropping privileges.");
189 result=setuid(getuid());
192 tX_error("tX_engine() - Failed to drop root privileges.");
197 mouse=new tx_mouse();
198 tape=new tx_tapedeck();
201 recording_request=false;
202 loop_is_active=false;
207 void tX_engine :: set_recording_request (bool recording) {
208 this->recording_request=recording;
211 tX_engine_error tX_engine :: run() {
212 list <vtt_class *> :: iterator vtt;
214 if (loop_is_active) return ERROR_BUSY;
216 switch (globals.audiodevice_type) {
218 case TX_AUDIODEVICE_TYPE_OSS:
219 device=new tX_audiodevice_oss(); break;
223 case TX_AUDIODEVICE_TYPE_ALSA:
224 device=new tX_audiodevice_alsa(); break;
228 device=NULL; return ERROR_AUDIO;
231 if (device->open()) {
238 vtt_class::set_mix_buffer_size(device->get_buffersize()/2); //mixbuffer is mono
240 if (recording_request) {
241 if (tape->start_record(globals.record_filename, device->get_buffersize()*sizeof(int16_t))) {
250 for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++) {
251 if ((*vtt)->autotrigger) (*vtt)->trigger();
254 sequencer.forward_to_start_timestamp(1);
256 /* Trigger the engine thread... */
257 pthread_mutex_unlock(&start);
260 void tX_engine :: stop() {
261 list <vtt_class *> :: iterator vtt;
263 if (!loop_is_active) {
264 tX_error("tX_engine::stop() - but loop's not running?");
267 pthread_mutex_lock(&start);
270 tX_debug("tX_engine::stop() - waiting for loop to stop.");
272 while (loop_is_active) {
276 tX_debug("tX_engine::stop() - loop has stopped.");
282 for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++) {
284 (*vtt)->ec_clear_buffer();
287 if (is_recording()) tape->stop_record();
291 tX_engine :: ~tX_engine() {