2 terminatorX - realtime audio scratching software
3 Copyright (C) 1999-2003 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.
33 12 Aug 2002: Complete rewrite - tX_engine is now a class and the thread
34 is created on startup and kept alive until termination
39 #include "tX_engine.h"
40 #include "tX_audiodevice.h"
45 #include <gdk/gdkprivate.h>
46 #include "tX_mastergui.h"
47 #include "tX_global.h"
49 #include "tX_widget.h"
51 #include "tX_sequencer.h"
55 #include <sys/resource.h>
57 tX_engine *engine=NULL;
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 */
76 temp=vtt_class::render_all_turntables();
80 /* Checking whether to grab or not */
81 if (grab_request!=grab_active) {
83 /* Activating grab... */
86 tX_error("tX_engine::loop(): failed to grab mouse - error %i", result);
88 /* Reseting grab_request, too - doesn't help keeping it, does it ? ;) */
96 /* Deactivating grab... */
99 grab_off(); // for the mastergui this is...
103 /* Handling input events... */
105 if (mouse->check_event()) {
106 /* If we're here the user pressed ESC */
111 #ifdef USE_ALSA_MIDI_IN
112 if (midi->get_is_open()) midi->check_event();
115 /* Playback the audio... */
118 /* Record the audio if necessary... */
119 if (is_recording()) tape->eat(temp);
121 /* Forward the sequencer... */
124 /* Render the next block... */
125 temp=vtt_class::render_all_turntables();
128 /* Stopping engine... */
129 loop_is_active=false;
133 void *engine_thread_entry(void *engine_void) {
134 tX_engine *engine=(tX_engine*) engine_void;
137 /* Dropping root privileges for the engine thread - if running suid. */
139 if ((!geteuid()) && (getuid() != geteuid())) {
140 tX_debug("engine_thread_entry() - Running suid root - dropping privileges.");
142 result=setuid(getuid());
145 tX_error("engine_thread_entry() - Failed to drop root privileges.");
152 tX_debug("engine_thread_entry() - Engine thread terminating.");
157 tX_engine :: tX_engine() {
160 pthread_mutex_init(&start, NULL);
161 pthread_mutex_lock(&start);
162 thread_terminate=false;
164 /* Creating the actual engine thread.. */
167 pthread_attr_t pattr;
168 struct sched_param sparm;
170 tX_debug("tX_engine() - Have root privileges - using SCHED_FIFO.");
172 pthread_attr_init(&pattr);
173 pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);
174 pthread_attr_setschedpolicy(&pattr, SCHED_FIFO);
176 sched_getparam(getpid(), &sparm);
177 sparm.sched_priority=sched_get_priority_max(SCHED_FIFO);
179 pthread_attr_setschedparam(&pattr, &sparm);
180 pthread_attr_setinheritsched(&pattr, PTHREAD_EXPLICIT_SCHED);
181 pthread_attr_setscope(&pattr, PTHREAD_SCOPE_SYSTEM);
183 result=pthread_create(&thread, &pattr, engine_thread_entry, (void *) this);
185 tX_debug("tX_engine() - Lacking root privileges - no realtime scheduling!");
187 result=pthread_create(&thread, NULL, engine_thread_entry, (void *) this);
193 tX_error("tX_engine() - Failed to create engine thread. Errno is %i.", errno);
197 /* Dropping root privileges for the main thread - if running suid. */
199 if ((!geteuid()) && (getuid() != geteuid())) {
200 tX_debug("tX_engine() - Running suid root - dropping privileges.");
202 result=setuid(getuid());
205 tX_error("tX_engine() - Failed to drop root privileges.");
210 mouse=new tx_mouse();
211 #ifdef USE_ALSA_MIDI_IN
212 midi=new tX_midiin();
214 tape=new tx_tapedeck();
217 recording_request=false;
218 loop_is_active=false;
223 void tX_engine :: set_recording_request (bool recording) {
224 this->recording_request=recording;
227 tX_engine_error tX_engine :: run() {
228 list <vtt_class *> :: iterator vtt;
230 if (loop_is_active) return ERROR_BUSY;
232 switch (globals.audiodevice_type) {
235 puts("Using OSS output...");
236 device=new tX_audiodevice_oss();
242 puts("Using ALSA output...");
243 device=new tX_audiodevice_alsa();
248 device=NULL; return ERROR_AUDIO;
251 if (device->open()) {
258 vtt_class::set_mix_buffer_size(device->get_buffersize()/2); //mixbuffer is mono
260 if (recording_request) {
261 if (tape->start_record(globals.record_filename, device->get_buffersize()*sizeof(int16_t))) {
271 for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++) {
272 if ((*vtt)->autotrigger) (*vtt)->trigger();
275 sequencer.forward_to_start_timestamp(1);
277 /* Trigger the engine thread... */
278 pthread_mutex_unlock(&start);
283 void tX_engine :: stop() {
284 list <vtt_class *> :: iterator vtt;
286 if (!loop_is_active) {
287 tX_error("tX_engine::stop() - but loop's not running?");
290 pthread_mutex_lock(&start);
293 tX_debug("tX_engine::stop() - waiting for loop to stop.");
295 while (loop_is_active) {
299 tX_debug("tX_engine::stop() - loop has stopped.");
305 for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++) {
307 (*vtt)->ec_clear_buffer();
310 if (is_recording()) tape->stop_record();
314 tX_engine :: ~tX_engine() {
317 thread_terminate=true;
319 pthread_mutex_unlock(&start);
320 tX_debug("~tX_engine() - Waiting for engine thread to terminate.");
321 pthread_join(thread, &dummy);