├── .gitignore ├── src ├── icons │ ├── knob0.png │ ├── knob1.png │ ├── knob10.png │ ├── knob11.png │ ├── knob12.png │ ├── knob13.png │ ├── knob14.png │ ├── knob15.png │ ├── knob16.png │ ├── knob17.png │ ├── knob18.png │ ├── knob19.png │ ├── knob2.png │ ├── knob20.png │ ├── knob21.png │ ├── knob22.png │ ├── knob23.png │ ├── knob24.png │ ├── knob25.png │ ├── knob26.png │ ├── knob27.png │ ├── knob28.png │ ├── knob29.png │ ├── knob3.png │ ├── knob30.png │ ├── knob31.png │ ├── knob32.png │ ├── knob33.png │ ├── knob34.png │ ├── knob35.png │ ├── knob36.png │ ├── knob37.png │ ├── knob38.png │ ├── knob39.png │ ├── knob4.png │ ├── knob40.png │ ├── knob41.png │ ├── knob42.png │ ├── knob43.png │ ├── knob44.png │ ├── knob45.png │ ├── knob46.png │ ├── knob47.png │ ├── knob48.png │ ├── knob49.png │ ├── knob5.png │ ├── knob6.png │ ├── knob7.png │ ├── knob8.png │ ├── knob9.png │ ├── tX_logo.jpg │ ├── tX_dialog.gresource.xml │ └── tX_knob.gresource.xml ├── tX_ui_interface.h ├── tX_ui_callbacks.h ├── tX_prelis.h ├── tX_dialog.h ├── tX_ui_support.h ├── tX_capabilities.h ├── tX_types.h ├── tX_tape.h ├── tX_loaddlg.h ├── tX_knobloader.h ├── tX_endian.c ├── wav_file.h ├── tX_endian.h ├── tX_pbutton.h ├── tX_extdial.h ├── tX_event.h ├── tX_legacy_global.c ├── tX_knobloader.c ├── tX_event.cc ├── tX_capabilities.cc ├── tX_tape.cc ├── tX_panel.h ├── tX_flash.h ├── tX_dial.h ├── tX_ladspa_class.h ├── tX_ladspa.h ├── wav_write.c ├── tX_maingui.h ├── .clang-format ├── tX_sequencer.h ├── tX_engine.h ├── tX_widget.h ├── tX_prelis.cc ├── tX_ui_support.cc ├── tX_midiin.h ├── tX_extdial.cc ├── tX_vttgui.h ├── wav_read.c ├── tX_audiofile.h ├── tX_mouse.h ├── tX_pbutton.cc ├── tX_vttfx.h ├── tX_ui_callbacks.cc ├── tX_audiodevice.h ├── tX_loaddlg.cc ├── tX_panel.cc ├── tX_ladspa.cc ├── tX_engine.cc └── tX_sequencer.cc ├── help ├── C │ └── figures │ │ ├── signalflow.dia │ │ └── signalflow.png ├── meson.build └── terminatorX.1.in ├── data ├── icons │ ├── org.terminatorx.terminatorX.png │ ├── org.terminatorx.terminatorX.Set.png │ ├── meson.build │ └── org.terminatorx.terminatorX.xpm ├── org.terminatorx.terminatorX.desktop.in ├── org.terminatorx.terminatorX-mime.xml.in ├── meson.build └── org.terminatorx.terminatorX.metainfo.xml.in ├── .github └── workflows │ ├── ci.yml │ └── tarbuild.yml ├── AUTHORS.md ├── meson_options.txt ├── README.md ├── INSTALL.md ├── meson.build └── terminatorX.spec.in /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | build/ -------------------------------------------------------------------------------- /src/icons/knob0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob0.png -------------------------------------------------------------------------------- /src/icons/knob1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob1.png -------------------------------------------------------------------------------- /src/icons/knob10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob10.png -------------------------------------------------------------------------------- /src/icons/knob11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob11.png -------------------------------------------------------------------------------- /src/icons/knob12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob12.png -------------------------------------------------------------------------------- /src/icons/knob13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob13.png -------------------------------------------------------------------------------- /src/icons/knob14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob14.png -------------------------------------------------------------------------------- /src/icons/knob15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob15.png -------------------------------------------------------------------------------- /src/icons/knob16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob16.png -------------------------------------------------------------------------------- /src/icons/knob17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob17.png -------------------------------------------------------------------------------- /src/icons/knob18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob18.png -------------------------------------------------------------------------------- /src/icons/knob19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob19.png -------------------------------------------------------------------------------- /src/icons/knob2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob2.png -------------------------------------------------------------------------------- /src/icons/knob20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob20.png -------------------------------------------------------------------------------- /src/icons/knob21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob21.png -------------------------------------------------------------------------------- /src/icons/knob22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob22.png -------------------------------------------------------------------------------- /src/icons/knob23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob23.png -------------------------------------------------------------------------------- /src/icons/knob24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob24.png -------------------------------------------------------------------------------- /src/icons/knob25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob25.png -------------------------------------------------------------------------------- /src/icons/knob26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob26.png -------------------------------------------------------------------------------- /src/icons/knob27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob27.png -------------------------------------------------------------------------------- /src/icons/knob28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob28.png -------------------------------------------------------------------------------- /src/icons/knob29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob29.png -------------------------------------------------------------------------------- /src/icons/knob3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob3.png -------------------------------------------------------------------------------- /src/icons/knob30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob30.png -------------------------------------------------------------------------------- /src/icons/knob31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob31.png -------------------------------------------------------------------------------- /src/icons/knob32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob32.png -------------------------------------------------------------------------------- /src/icons/knob33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob33.png -------------------------------------------------------------------------------- /src/icons/knob34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob34.png -------------------------------------------------------------------------------- /src/icons/knob35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob35.png -------------------------------------------------------------------------------- /src/icons/knob36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob36.png -------------------------------------------------------------------------------- /src/icons/knob37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob37.png -------------------------------------------------------------------------------- /src/icons/knob38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob38.png -------------------------------------------------------------------------------- /src/icons/knob39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob39.png -------------------------------------------------------------------------------- /src/icons/knob4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob4.png -------------------------------------------------------------------------------- /src/icons/knob40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob40.png -------------------------------------------------------------------------------- /src/icons/knob41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob41.png -------------------------------------------------------------------------------- /src/icons/knob42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob42.png -------------------------------------------------------------------------------- /src/icons/knob43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob43.png -------------------------------------------------------------------------------- /src/icons/knob44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob44.png -------------------------------------------------------------------------------- /src/icons/knob45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob45.png -------------------------------------------------------------------------------- /src/icons/knob46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob46.png -------------------------------------------------------------------------------- /src/icons/knob47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob47.png -------------------------------------------------------------------------------- /src/icons/knob48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob48.png -------------------------------------------------------------------------------- /src/icons/knob49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob49.png -------------------------------------------------------------------------------- /src/icons/knob5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob5.png -------------------------------------------------------------------------------- /src/icons/knob6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob6.png -------------------------------------------------------------------------------- /src/icons/knob7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob7.png -------------------------------------------------------------------------------- /src/icons/knob8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob8.png -------------------------------------------------------------------------------- /src/icons/knob9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/knob9.png -------------------------------------------------------------------------------- /src/icons/tX_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/src/icons/tX_logo.jpg -------------------------------------------------------------------------------- /help/C/figures/signalflow.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/help/C/figures/signalflow.dia -------------------------------------------------------------------------------- /help/C/figures/signalflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/help/C/figures/signalflow.png -------------------------------------------------------------------------------- /data/icons/org.terminatorx.terminatorX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/data/icons/org.terminatorx.terminatorX.png -------------------------------------------------------------------------------- /data/icons/org.terminatorx.terminatorX.Set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axkg/terminatorX/HEAD/data/icons/org.terminatorx.terminatorX.Set.png -------------------------------------------------------------------------------- /src/icons/tX_dialog.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ../../data/icons/org.terminatorx.terminatorX.png 5 | tX_logo.jpg 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /help/meson.build: -------------------------------------------------------------------------------- 1 | # man page 2 | 3 | man_page = configure_file(input: 'terminatorX.1.in', 4 | output: 'terminatorX.1', 5 | configuration: doc_config 6 | ) 7 | 8 | install_man(man_page) 9 | 10 | # GNOME help 11 | 12 | gnome.yelp('terminatorX-manual', 13 | sources: 'index.docbook', 14 | media: 'figures/signalflow.png' 15 | ) -------------------------------------------------------------------------------- /src/tX_ui_interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is no longer being generated by Glade and contains hand 3 | * crafted code. 4 | */ 5 | 6 | #pragma once 7 | 8 | GtkWidget* create_tx_adjust(void); 9 | GtkWidget* create_tx_options(GtkWindow* parent); 10 | GtkWidget* create_tx_del_mode(void); 11 | GtkWidget* create_tX_midilearn(void); 12 | GtkWidget* create_tX_color_chooser(GtkWidget* parentS); 13 | -------------------------------------------------------------------------------- /data/org.terminatorx.terminatorX.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Exec=terminatorX 4 | Name=terminatorX 5 | GenericName=Virtual turntable 6 | Comment=Versatile DJ scratching and mixing application 7 | Terminal=false 8 | Type=Application 9 | Icon=org.terminatorx.terminatorX 10 | Categories=AudioVideo; 11 | Keywords=music;alsa;realtime;standalone; 12 | StartupNotify=true 13 | MimeType=application/x-terminatorx -------------------------------------------------------------------------------- /data/org.terminatorx.terminatorX-mime.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | terminatorX set file 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /data/icons/meson.build: -------------------------------------------------------------------------------- 1 | pixmaps_dir = join_paths(get_option('datadir'), 'pixmaps') 2 | icon_dir = join_paths(get_option('datadir'), 'icons', 'hicolor', '512x512') 3 | app_icon_dir = join_paths(icon_dir, 'apps') 4 | mime_icon_dir = join_paths(icon_dir, 'mimetypes') 5 | 6 | install_data('org.terminatorx.terminatorX.xpm', install_dir: pixmaps_dir) 7 | install_data('org.terminatorx.terminatorX.png', install_dir: app_icon_dir) 8 | install_data('org.terminatorx.terminatorX.Set.png', install_dir: mime_icon_dir) -------------------------------------------------------------------------------- /src/tX_ui_callbacks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void on_tx_options_destroy(GObject* object, 6 | gpointer user_data); 7 | 8 | void on_alsa_buffer_time_value_changed(GtkRange* range, 9 | gpointer user_data); 10 | 11 | void on_pref_reset_clicked(GtkButton* button, 12 | gpointer user_data); 13 | 14 | void on_pref_cancel_clicked(GtkButton* button, 15 | gpointer user_data); 16 | 17 | void on_pref_apply_clicked(GtkButton* button, 18 | gpointer user_data); 19 | 20 | void on_pref_ok_clicked(GtkButton* button, 21 | gpointer user_data); 22 | 23 | void on_del_mode_cancel_clicked(GtkButton* button, 24 | gpointer user_data); 25 | 26 | void on_del_mode_ok_clicked(GtkButton* button, 27 | gpointer user_data); 28 | 29 | void color_clicked(GtkButton* button, 30 | gpointer user_data); 31 | 32 | void on_color_chooser_ok_clicked(GtkButton* button, 33 | gpointer user_data); 34 | 35 | void color_response(GtkDialog* dialog, gint response_id, gpointer user_data); 36 | -------------------------------------------------------------------------------- /src/tX_prelis.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_prelis.h 19 | 20 | Description: Header to tX_prelis.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | extern void prelis_stop(); 26 | extern void prelis_start(char* name); 27 | -------------------------------------------------------------------------------- /help/terminatorX.1.in: -------------------------------------------------------------------------------- 1 | .TH terminatorX "1" "May 2002" "terminatorX @VERSION@" "User Commands" 2 | .SH NAME 3 | terminatorX \- Realtime Audio Synthesizer 4 | .SH SYNOPSIS 5 | .B terminatorX 6 | [\fIoptions\fR] 7 | .SH DESCRIPTION 8 | terminatorX is a realtime audio synthesizer that allows you to "scratch" on 9 | digitally sampled audio data (*.wav, *.au, *.mp3, etc.) the way hiphop-DJs 10 | scratch on vinyl records. It features multiple turntables, realtime effects 11 | (buit-in as well as LADSPA plugin effects), a sequencer and an easy-to-use 12 | gtk+ GUI. 13 | .SS "Options:" 14 | .TP 15 | \fB\-h\fR, \fB\-\-help\fR 16 | Display help info 17 | .TP 18 | \fB\-f\fR, \fB\-\-file\fR 19 | Load saved terminatorX set file 20 | .TP 21 | \fB\-r\fR, \fB\-\-rc-file [file]\fR 22 | Load alternate rc file 23 | .TP 24 | \fB\-d\fR, \fB\-\-dont-save\fR 25 | Do not save settings at exit 26 | .TP 27 | \fB\-s\fR, \fB\-\-std-out\fR 28 | Use stdout for sound output 29 | .TP 30 | \fB\-\-device=[output device]\fR 31 | Use alternate device for sound output 32 | .SH AUTHOR 33 | This manual page was created by Adrian Reber . The software itself was created by 34 | Alexander Koenig . 35 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-22.04 8 | strategy: 9 | matrix: 10 | target: ["CC=clang CXX=clang++", "CC=gcc CXX=g++"] 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Install build dependencies 15 | run: | 16 | sudo apt update 17 | sudo apt -y install ladspa-sdk libasound2-dev libatk1.0-dev libaudiofile-dev \ 18 | libcap2-dev libglib2.0-dev libgtk-3-dev libice-dev \ 19 | libjack-dev liblrdf0-dev libmad0-dev libpango1.0-dev \ 20 | libpulse-dev libsm-dev libvorbis-dev libx11-dev libxext-dev \ 21 | libxi-dev libxml2-dev mpg321 sox vorbis-tools yelp-tools zlib1g-dev \ 22 | xxd meson ninja-build appstream desktop-file-utils gettext clang-format 23 | - name: Run compile test using ${{ matrix.target }} 24 | run: | 25 | ${{ matrix.target }} meson setup build 26 | meson compile -C build 27 | - name: Run built-in tests 28 | if: matrix.target == 'CC=clang CXX=clang++' 29 | run: meson test -C build 30 | -------------------------------------------------------------------------------- /src/tX_dialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_dialog.h 19 | 20 | Description: Header to tX_dialog.c 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | extern GtkWidget* opt_dialog; 27 | 28 | extern void display_options(); 29 | extern void show_about(int nag); 30 | extern void destroy_about(); 31 | extern void init_tx_options(GtkWidget* dialog); 32 | extern void tX_set_icon(GtkWidget* widget); 33 | extern void apply_options(GtkWidget*); 34 | -------------------------------------------------------------------------------- /src/tX_ui_support.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is no longer being generated by Glade and contains hand 3 | * crafted code. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | /* 12 | * Public Functions. 13 | */ 14 | 15 | /* 16 | * This function returns a widget in a component created by Glade. 17 | * Call it with the toplevel widget in the component (i.e. a window/dialog), 18 | * or alternatively any widget in the component, and the name of the widget 19 | * you want returned. 20 | */ 21 | GtkWidget* lookup_widget(GtkWidget* widget, 22 | const gchar* widget_name); 23 | 24 | /* Use this function to set the directory containing installed pixmaps. */ 25 | void add_pixmap_directory(const gchar* directory); 26 | 27 | /* 28 | * Private Functions. 29 | */ 30 | 31 | /* This is used to create the pixmaps used in the interface. */ 32 | GtkWidget* create_pixmap(GtkWidget* widget, 33 | const gchar* filename); 34 | 35 | /* This is used to create the pixbufs used in the interface. */ 36 | GdkPixbuf* create_pixbuf(const gchar* filename); 37 | 38 | /* This is used to set ATK action descriptions. */ 39 | void ui_set_atk_action_description(AtkAction* action, 40 | const gchar* action_name, 41 | const gchar* description); 42 | -------------------------------------------------------------------------------- /src/tX_capabilities.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_capabilities.h 19 | 20 | Description: Aquire CAP_SYS_NICE through Linux' capabilities. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #ifdef USE_CAPABILITIES 28 | #include 29 | 30 | #undef _POSIX_SOURCE 31 | #include 32 | 33 | extern bool have_nice_capability(); 34 | extern void set_nice_capability(cap_flag_t cap_flag); 35 | 36 | #endif // USE_CAPABILITIES 37 | -------------------------------------------------------------------------------- /src/tX_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_types.h 19 | 20 | Description: Use correct type sizes. If is not 21 | available define USE_X86_TYPES on i386 machines 22 | */ 23 | 24 | #pragma once 25 | 26 | #define f_prec float 27 | #define d_prec double 28 | 29 | #ifndef USE_X86_TYPES 30 | 31 | #include 32 | 33 | #else 34 | 35 | #define int8_t char 36 | #define int16_t short 37 | #define int32_t long 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/tX_tape.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_tape.h 19 | 20 | Description: Header to tX_tape.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "tX_types.h" 26 | #include "wav_file.h" 27 | 28 | class tx_tapedeck { 29 | wav_sig file; 30 | int is_recording; 31 | unsigned int written_bytes; 32 | int blocksize; 33 | 34 | public: 35 | int start_record(char* name, int bs, int samplerate); 36 | void stop_record(); 37 | void eat(int16_t*); 38 | 39 | tx_tapedeck(); 40 | }; 41 | -------------------------------------------------------------------------------- /src/tX_loaddlg.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_loaddlg.h 19 | 20 | Description: Header to tX_loaddlg.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #define TX_LOADDLG_MODE_SINGLE 0 26 | #define TX_LOADDLG_MODE_MULTI 1 27 | 28 | #include 29 | extern GtkWidget* ld_loaddlg; 30 | 31 | extern int ld_create_loaddlg(int mode, int count); 32 | extern void ld_set_setname(char* name); 33 | extern void ld_set_filename(char* name); 34 | extern void ld_set_progress(gfloat progress); 35 | extern void ld_destroy(); 36 | extern char* strip_path(char* name); 37 | -------------------------------------------------------------------------------- /src/tX_knobloader.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_knobloader.h 19 | 20 | Description: Header to tX_knobloader.c 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif /* __cplusplus */ 32 | 33 | #define MAX_KNOB_PIX 50 34 | #define TX_MAX_KNOB_PIX 49 35 | 36 | extern int tX_knob_size; 37 | 38 | extern GdkPixbuf* knob_pixmaps[MAX_KNOB_PIX]; 39 | 40 | extern void load_knob_pixs(int fontHeight, int scaleFactor); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif /* __cplusplus */ 45 | -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | # desktop file 2 | 3 | desktop_file = configure_file(input: 'org.terminatorx.terminatorX.desktop.in', 4 | output: 'org.terminatorx.terminatorX.desktop', 5 | configuration: doc_config, 6 | install: true, 7 | install_dir: join_paths(get_option('datadir'), 'applications') 8 | ) 9 | 10 | desktop_validator = find_program('desktop-file-validate', required: false) 11 | if desktop_validator.found() 12 | test('Validating desktop file', desktop_validator, args: [desktop_file]) 13 | endif 14 | 15 | # appdata 16 | 17 | metainfo = configure_file(input: 'org.terminatorx.terminatorX.metainfo.xml.in', 18 | output: 'org.terminatorx.terminatorX.metainfo.xml', 19 | configuration: doc_config, 20 | install: true, 21 | install_dir: join_paths(get_option('datadir'), 'metainfo') 22 | ) 23 | 24 | appdata_validator = find_program('appstreamcli', required: false) 25 | if appdata_validator.found() 26 | test('Validating desktop file', appdata_validator, 27 | args: ['validate', '--no-net', '--explain', metainfo]) 28 | endif 29 | 30 | # mimetype 31 | 32 | mimetype = configure_file(input: 'org.terminatorx.terminatorX-mime.xml.in', 33 | output: 'org.terminatorx.terminatorX-mime.xml', 34 | configuration: doc_config, 35 | install: true, 36 | install_dir: join_paths(get_option('datadir'), 'mime', 'packages') 37 | ) 38 | 39 | # handle icons 40 | 41 | subdir('icons') -------------------------------------------------------------------------------- /.github/workflows/tarbuild.yml: -------------------------------------------------------------------------------- 1 | name: tarbuild 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | relver: 7 | description: 'Release version to build' 8 | required: true 9 | type: string 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Install build dependencies 18 | run: | 19 | sudo apt update 20 | sudo apt -y install ladspa-sdk libasound2-dev libatk1.0-dev libaudiofile-dev \ 21 | libcap2-dev libglib2.0-dev libgtk-3-dev libice-dev \ 22 | libjack-dev liblrdf0-dev libmad0-dev libpango1.0-dev \ 23 | libpulse-dev libsm-dev libvorbis-dev libx11-dev libxext-dev \ 24 | libxi-dev libxml2-dev mpg321 sox vorbis-tools yelp-tools zlib1g-dev \ 25 | meson ninja-build 26 | - name: Tag release 27 | uses: mathieudutour/github-tag-action@v6.0 28 | with: 29 | github_token: ${{ secrets.GITHUB_TOKEN }} 30 | custom_tag: ${{ inputs.relver }} 31 | - name: Build tarball 32 | run: | 33 | meson setup build 34 | meson dist --no-tests -C build 35 | - name: Collect artifacts 36 | uses: actions/upload-artifact@v2 37 | with: 38 | name: tarballs 39 | path: build/meson-dist/terminatorX-*.tar.* -------------------------------------------------------------------------------- /src/tX_endian.c: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_endian.c 19 | 20 | Description: swap byte order for big endian systems/audiohardware. 21 | */ 22 | 23 | #include "tX_endian.h" 24 | #include "tX_global.h" 25 | 26 | #ifdef WORDS_BIGENDIAN 27 | 28 | void swap16(int16_t* val) { 29 | int8_t temp; 30 | int8_t* p; 31 | 32 | p = (int8_t*)val; 33 | temp = p[0]; 34 | p[0] = p[1]; 35 | p[1] = temp; 36 | } 37 | 38 | void swap32(int32_t* val) { 39 | int8_t temp; 40 | int8_t* p; 41 | 42 | p = (int8_t*)val; 43 | temp = p[0]; 44 | p[0] = p[3]; 45 | p[3] = temp; 46 | 47 | temp = p[1]; 48 | p[1] = p[2]; 49 | p[2] = temp; 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/wav_file.h: -------------------------------------------------------------------------------- 1 | /* 2 | wav_file.h - taken from wav-tools 1.1 3 | Copyright (C) by Colin Ligertwood 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, see . 17 | */ 18 | 19 | #pragma once 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif /* __cplusplus */ 24 | 25 | #include "tX_global.h" 26 | #include "tX_types.h" 27 | 28 | typedef struct { 29 | int32_t srate; 30 | int8_t chans; 31 | int8_t depth; 32 | int32_t bps; 33 | int8_t blkalign; 34 | int32_t len; 35 | int32_t sofar; 36 | 37 | FILE* handle; 38 | char name[PATH_MAX]; 39 | char head[44]; 40 | } wav_sig; 41 | 42 | FILE* init_wav_read(char file_name[], wav_sig* info); 43 | FILE* open_wav_rec(wav_sig* info); 44 | extern int rewrite_head(wav_sig* info); 45 | extern void wav_close(FILE* wav); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif /* __cplusplus */ 50 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # terminatorX AUTHORS 2 | 3 | ## Author 4 | 5 | Alexander König 6 | 7 | ## Contributors 8 | 9 | * Adam King 10 | - bug fixes and enhancements 11 | 12 | * Adrian Reber 13 | - bug fixes 14 | - various enhancements 15 | - RPM packaging 16 | - CI support 17 | - giving terminatorX.org a home 18 | 19 | * "Andrew C. Bul+hac?k" 20 | - tX_wavfunc.c patch 21 | 22 | * Andy Lo A Foe 23 | - development support 24 | 25 | * Arthur Peters 26 | - ALSA MIDI interface 27 | 28 | * Benno Senoner 29 | - mmap() patch 30 | 31 | * Christian 32 | - licmak.awk (now replaced with xxd) 33 | 34 | * Darrick Servis 35 | - support for the anti-clipping code 36 | 37 | * Josh Steiner 38 | - new startup switches 39 | 40 | * Matthew Evans 41 | - piped OGG support 42 | 43 | * Michael Kahl 44 | - MK II icon (now replaced) 45 | 46 | * Paul Kellett 47 | - design for the built-in low pass filter (reso_lop.txt) 48 | 49 | * Robert Dale 50 | - support for the now obsolete 3dnow code 51 | 52 | * Scott C. Knight 53 | - support for big endian architectures 54 | 55 | **Thank each and everyone of you for your contributions!** 56 | 57 | In addition, thanks to everyone who contributed [scratches](https://terminatorx.org/scratches/), 58 | everyone who provided feedback and of course to the *real* Terminator X! 59 | 60 | 61 | -------------------------------------------------------------------------------- /data/org.terminatorx.terminatorX.metainfo.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.terminatorx.terminatorX 4 | terminatorX 5 | CC0 6 | GPL-2.0+ 7 | terminatorX is a realtime audio synthesizer 8 | 9 |

10 | terminatorX facilitates loading sampled audio data of various formats 11 | (*.wav, *.au, *.ogg, *.mp3, etc.) into virtual turntables for 12 | synchronized playback. The user can operate these turntables using 13 | mouse and keyboard inputs in order to "scratch" the way 14 | hiphop-DJs scratch on vinyl records. 15 |

16 |

17 | It features realtime effects (buit-in as well as LADSPA plugin 18 | effects), a sequencer and a MIDI interface - all accessible through 19 | an easy-to-use gtk+ user interface. Audio can be played back either 20 | directly through the hardware using the ALSA and OSS backends or via 21 | an audio routing daemon through the JACK and PulseAudio backends. 22 |

23 |
24 | 25 | 26 | https://terminatorX.org/appdata/screenshot.png 27 | terminatorX with three virtual turntables 28 | 29 | 30 | https://terminatorX.org 31 | https://github.com/axkg/terminatorX/issues 32 | org.terminatorx.terminatorX.desktop 33 | 34 | alex@lisas.de 35 |
36 | 37 | -------------------------------------------------------------------------------- /src/tX_endian.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_endian.h 19 | 20 | Description: header to tX_endian.c 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #ifdef WORDS_BIGENDIAN 27 | #define BIG_ENDIAN_MACHINE 1 28 | #else 29 | #undef BIG_ENDIAN_MACHINE 30 | #endif 31 | 32 | #ifdef WORDS_BIGENDIAN 33 | #include "tX_types.h" 34 | #include 35 | #define swapbuffer(b, s) swab((void*)b, (void*)b, (ssize_t)s << 1) 36 | 37 | static inline void swap32_inline(int32_t* val) { 38 | int8_t temp; 39 | int8_t* p = (int8_t*)val; 40 | 41 | temp = p[0]; 42 | p[0] = p[3]; 43 | p[3] = temp; 44 | 45 | temp = p[1]; 46 | p[1] = p[2]; 47 | p[2] = temp; 48 | } 49 | 50 | #ifdef __cplusplus 51 | extern "C" { 52 | #endif /* __cplusplus */ 53 | 54 | extern void swap16(int16_t* val); 55 | extern void swap32(int32_t* val); 56 | 57 | #ifdef __cplusplus 58 | } 59 | #endif /* __cplusplus */ 60 | 61 | #endif /* WORDS_BIGENDIAN */ 62 | -------------------------------------------------------------------------------- /src/tX_pbutton.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_pbutton.h 19 | 20 | Description: Header to tX_pbutton.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | typedef enum { 28 | AUDIOENGINE, 29 | POWER, 30 | GRAB, 31 | SEQUENCER, 32 | PLAY, 33 | STOP, 34 | RECORD, 35 | MIN_AUDIO, 36 | MIN_CONTROL, 37 | MINIMIZE, 38 | MAXIMIZE, 39 | FX_UP, 40 | FX_DOWN, 41 | FX_CLOSE, 42 | ADD_ITEM, 43 | ADD_DRYWET, 44 | REMOVE_DRYWET, 45 | ALL_ICONS 46 | } tX_icon; 47 | 48 | extern const char* tx_icons[]; 49 | extern GtkWidget* tx_pixmap_widget(tX_icon id); 50 | extern void tx_icons_init(int size); 51 | extern GtkWidget* create_top_button(int icon_id); 52 | extern GtkWidget* tx_xpm_label_box(tX_icon id, const gchar* label_text, GtkWidget** labelwidget = (GtkWidget**)NULL); 53 | extern GtkWidget* tx_xpm_button_new(tX_icon id, const char* label, int toggle, GtkWidget** labelwidget = (GtkWidget**)NULL); 54 | -------------------------------------------------------------------------------- /src/icons/tX_knob.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | knob0.png 5 | knob1.png 6 | knob2.png 7 | knob3.png 8 | knob4.png 9 | knob5.png 10 | knob6.png 11 | knob7.png 12 | knob8.png 13 | knob9.png 14 | knob10.png 15 | knob11.png 16 | knob12.png 17 | knob13.png 18 | knob14.png 19 | knob15.png 20 | knob16.png 21 | knob17.png 22 | knob18.png 23 | knob19.png 24 | knob20.png 25 | knob21.png 26 | knob22.png 27 | knob23.png 28 | knob24.png 29 | knob25.png 30 | knob26.png 31 | knob27.png 32 | knob28.png 33 | knob29.png 34 | knob30.png 35 | knob31.png 36 | knob32.png 37 | knob33.png 38 | knob34.png 39 | knob35.png 40 | knob36.png 41 | knob37.png 42 | knob38.png 43 | knob39.png 44 | knob40.png 45 | knob41.png 46 | knob42.png 47 | knob43.png 48 | knob44.png 49 | knob45.png 50 | knob46.png 51 | knob47.png 52 | knob48.png 53 | knob49.png 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('sox', type: 'feature', value: 'auto', description: 'use sox as input converter') 2 | option('mpg123', type: 'feature', value: 'auto', description: 'use mpg123 as input converter') 3 | option('ogg123', type: 'feature', value: 'auto', description: 'use ogg123 as input converter') 4 | option('scheduler', type: 'feature', value: 'enabled', description: 'enable rt-scheduling') 5 | option('tX_debug', type: 'feature', value: 'disabled', description: 'enable debug output') 6 | option('wav', type: 'feature', value: 'enabled', description: 'enables the built-in wav-loader') 7 | option('alsa', type: 'feature', value: 'auto', description: 'use ALSA for sound output') 8 | option('jack', type: 'feature', value: 'auto', description: 'use JACK for sound output') 9 | option('oss', type: 'feature', value: 'auto', description: 'use OSS for sound output') 10 | option('pulse', type: 'feature', value: 'auto', description: 'use PulseAudio for sound output') 11 | option('x11', type: 'feature', value: 'auto', description: 'include X11 specific code') 12 | option('mad', type: 'feature', value: 'auto', description: 'use libmad as input converter') 13 | option('vorbis', type: 'feature', value: 'auto', description: 'use libvorbis as input converter') 14 | option('audiofile', type: 'feature', value: 'auto', description: 'use audiofile as input converter') 15 | option('legacy', type: 'feature', value: 'disabled', description: 'enable support for old terminatorX files') 16 | option('alsamidi', type: 'feature', value: 'enabled', description: 'use ALSA MIDI input') 17 | option('lrdf', type: 'feature', value: 'auto', description: 'liblrdf support') 18 | option('capabilities', type: 'feature', value: 'enabled', description: 'use rt-scheduling via libpcap') 19 | option('deprecated', type: 'feature', value: 'disabled', description: 'compile without deprecated G*-headers') 20 | option('suidroot', type: 'feature', value: 'auto', description: 'install terminatorX setuid root ') 21 | -------------------------------------------------------------------------------- /src/tX_extdial.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_extdial.h 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "tX_dial.h" 24 | #include 25 | #include 26 | 27 | class tX_seqpar; 28 | 29 | class tX_extdial { 30 | GtkWidget* eventbox; 31 | GtkWidget* mainbox; 32 | GtkWidget* subbox; 33 | GtkWidget* dial; 34 | GtkWidget* label; 35 | GtkWidget* entry; 36 | GtkAdjustment* adj; 37 | int ignore_adj; 38 | float fval; 39 | char sval[30]; 40 | 41 | private: 42 | void s2f() { sscanf(sval, "%f", &fval); /*printf("s2f(): s:%s, f%f\n", sval, fval);*/ }; 43 | void f2s() { 44 | sprintf(sval, "%3f", fval); 45 | sval[4] = 0; /* printf("f2s(): s:%s, f%f\n", sval, fval); */ 46 | }; 47 | 48 | public: 49 | tX_extdial(const char* l, GtkAdjustment* a, tX_seqpar* sp, bool text_below = false, bool hide_entry = false); 50 | ~tX_extdial(); 51 | GtkWidget* get_widget() { return eventbox; }; 52 | GtkWidget* get_dial() { return dial; } 53 | GtkWidget* get_entry() { return entry; } 54 | 55 | static GCallback f_entry(GtkWidget* w, tX_extdial* ed); 56 | static GCallback f_adjustment(GtkWidget* w, tX_extdial* ed); 57 | }; 58 | -------------------------------------------------------------------------------- /src/tX_event.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_event.h 19 | 20 | Description: Header to tX_event.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "tX_seqpar.h" 26 | #include "tX_types.h" 27 | #include "tX_vtt.h" 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | class tX_event { 35 | private: 36 | guint32 timestamp; 37 | tX_seqpar* sp; 38 | float value; 39 | 40 | public: 41 | tX_event(guint32 time, tX_seqpar* sp_in, float val) 42 | : timestamp(time) 43 | , sp(sp_in) 44 | , value(val) {} 45 | 46 | #ifdef ENABLE_TX_LEGACY 47 | tX_event(FILE* input); 48 | #endif 49 | static tX_event* load_event(xmlDocPtr, xmlNodePtr); 50 | 51 | void store(FILE* rc, gzFile rz, char* indent); 52 | 53 | tX_seqpar* get_sp() { return sp; } 54 | guint32 get_timestamp() { return timestamp; } 55 | float get_value() { return value; } 56 | void set_value(float val) { value = val; } 57 | 58 | const char* get_vtt_name() { return sp->get_vtt_name(); } 59 | const char* get_seqpar_name() { return sp->get_name(); } 60 | 61 | void playback() { 62 | if (sp->is_untouched()) 63 | sp->exec_value(value); 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /src/tX_legacy_global.c: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_legacy_global.cc 19 | */ 20 | 21 | #include 22 | 23 | #ifdef ENABLE_TX_LEGACY 24 | 25 | #include "tX_global.h" 26 | #include 27 | #include 28 | #include 29 | 30 | void get_rc_name_old(char* buffer) { 31 | strcpy(buffer, ""); 32 | 33 | if (getenv("HOME")) { 34 | strcpy(buffer, getenv("HOME")); 35 | if (buffer[strlen(buffer) - 1] != '/') 36 | strcat(buffer, "/"); 37 | } 38 | 39 | strcat(buffer, ".terminatorX3rc.bin"); 40 | } 41 | 42 | void load_globals_old() { 43 | char rc_name[PATH_MAX + 256] = ""; 44 | FILE* rc; 45 | get_rc_name_old(rc_name); 46 | 47 | rc = fopen(rc_name, "r"); 48 | if (rc) { 49 | fread(&globals, sizeof(tx_global), 1, rc); 50 | fclose(rc); 51 | } else { 52 | fprintf(stderr, "tX: .rc-file '%s' doesn't exist, reverting to defaults\n", rc_name); 53 | } 54 | 55 | /* i'll have to keep these as they're in the code 56 | everywhere but I think it doesn't make sense resetting 57 | to old values on startup.... 58 | */ 59 | globals.use_stdout_cmdline = 0; 60 | globals.current_path[0] = 0; 61 | globals.pitch = 1.0; 62 | globals.volume = 1.0; 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/tX_knobloader.c: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_knobloader.c 19 | 20 | Description: This code loads the knob-images required for tX_dial widget. 21 | */ 22 | 23 | #include "tX_knobloader.h" 24 | #include "tX_global.h" 25 | #include "tX_knob_resource.h" 26 | #include 27 | #include 28 | 29 | int tX_knob_size; 30 | GdkPixbuf* knob_pixmaps[MAX_KNOB_PIX]; 31 | 32 | void load_knob_pixs(int fontHeight, int scaleFactor) { 33 | int i; 34 | GError* error = NULL; 35 | 36 | tX_knob_get_resource(); 37 | if (error) { 38 | tX_error("failed accessing tX_dial resources: %s\n", error->message); 39 | } 40 | 41 | if (globals.knob_size_override > 0) { 42 | tX_knob_size = globals.knob_size_override; 43 | } else { 44 | tX_knob_size = fontHeight * 3 * scaleFactor; 45 | } 46 | tX_debug("load_knob_pix(): knob size is %i", tX_knob_size); 47 | 48 | for (i = 0; i < MAX_KNOB_PIX; i++) { 49 | char resource_path[256]; 50 | snprintf(resource_path, 256, "/org/terminatorX/tX_dial/knob%i.png", i); 51 | knob_pixmaps[i] = gdk_pixbuf_new_from_resource_at_scale(resource_path, tX_knob_size, tX_knob_size, TRUE, &error); 52 | 53 | if (error) { 54 | tX_error("failed rendering knob image: %s\n", error->message); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/tX_event.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_event.cc 19 | 20 | Description: This implements the sequencer events. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | void tX_event ::store(FILE* rc, gzFile rz, char* indent) { 27 | tX_store("%s\n", indent, sp->get_persistence_id(), value, timestamp); 28 | } 29 | 30 | tX_event* tX_event ::load_event(xmlDocPtr doc, xmlNodePtr node) { 31 | unsigned int sp_persistence_id; 32 | char* buffer; 33 | float value; 34 | guint32 timestamp; 35 | tX_event* event = NULL; 36 | tX_seqpar* sp = NULL; 37 | 38 | buffer = (char*)xmlGetProp(node, (xmlChar*)"pid"); 39 | if (buffer) 40 | sscanf(buffer, "%i", &sp_persistence_id); 41 | 42 | buffer = (char*)xmlGetProp(node, (xmlChar*)"value"); 43 | if (buffer) 44 | sscanf(buffer, "%f", &value); 45 | 46 | buffer = (char*)xmlGetProp(node, (xmlChar*)"time"); 47 | if (buffer) 48 | sscanf(buffer, "%i", ×tamp); 49 | 50 | sp = tX_seqpar::get_sp_by_persistence_id(sp_persistence_id); 51 | 52 | if (sp) { 53 | event = new tX_event(timestamp, sp, value); 54 | } else { 55 | tX_error("failed to resolve event at %i - pid [%i]. Event lost.", timestamp, sp_persistence_id); 56 | } 57 | 58 | return event; 59 | } 60 | -------------------------------------------------------------------------------- /src/tX_capabilities.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_capabilities.cc 19 | 20 | Description: Aquire CAP_SYS_NICE through Linux' capabilities. 21 | */ 22 | #include "tX_capabilities.h" 23 | #include "tX_global.h" 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef USE_CAPABILITIES 29 | 30 | bool have_nice_capability() { 31 | cap_t caps; 32 | cap_flag_value_t cap; 33 | 34 | caps = cap_get_proc(); 35 | 36 | if (!caps) { 37 | tX_error("have_nice_capability(): failed to get caps: %s.", strerror(errno)); 38 | return false; 39 | } 40 | 41 | cap_get_flag(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &cap); 42 | 43 | if (cap == CAP_CLEAR) { 44 | return false; 45 | } 46 | 47 | return true; 48 | } 49 | 50 | void set_nice_capability(cap_flag_t cap_flag) { 51 | cap_t caps; 52 | const unsigned caps_size = 1; 53 | cap_value_t cap_list[] = { CAP_SYS_NICE }; 54 | 55 | caps = cap_get_proc(); 56 | 57 | if (!caps) { 58 | tX_error("set_capabilities(): failed to get caps: %s.", strerror(errno)); 59 | return; 60 | } 61 | 62 | cap_set_flag(caps, cap_flag, caps_size, cap_list, CAP_SET); 63 | 64 | if (cap_set_proc(caps)) { 65 | tX_error("set_capabilities(): failed to set caps: %s.", strerror(errno)); 66 | } 67 | } 68 | 69 | #endif // USE_CAPABILITIES 70 | -------------------------------------------------------------------------------- /src/tX_tape.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_tape.cc 19 | 20 | Description: This implements a "harddisk recording tapedeck" - simply dumps 21 | the generated audio into a plain mono wav-file. 22 | */ 23 | 24 | #include "tX_tape.h" 25 | #include 26 | 27 | tx_tapedeck ::tx_tapedeck() { 28 | is_recording = 0; 29 | written_bytes = 0; 30 | } 31 | 32 | int tx_tapedeck ::start_record(char* name, int bs, int samplerate) { 33 | if (is_recording) 34 | return 1; 35 | 36 | strcpy(file.name, name); 37 | file.srate = samplerate; 38 | file.chans = 2; 39 | file.depth = 16; 40 | file.bps = samplerate * 2; 41 | file.blkalign = 2; 42 | file.len = 0; 43 | file.sofar = 0; 44 | 45 | blocksize = bs * sizeof(int16_t) * 2; 46 | 47 | written_bytes = 0; 48 | 49 | if (!open_wav_rec(&file)) { 50 | return 1; 51 | } 52 | 53 | is_recording = 1; 54 | 55 | return 0; 56 | } 57 | 58 | void tx_tapedeck ::eat(int16_t* buffer) { 59 | written_bytes += fwrite((void*)buffer, blocksize, 1, file.handle); 60 | } 61 | 62 | void tx_tapedeck ::stop_record() { 63 | if (!is_recording) 64 | return; 65 | 66 | written_bytes *= blocksize; 67 | 68 | file.len = written_bytes; 69 | file.sofar = written_bytes; 70 | 71 | rewrite_head(&file); 72 | fclose(file.handle); 73 | 74 | is_recording = 0; 75 | } 76 | -------------------------------------------------------------------------------- /src/tX_panel.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | class vtt_fx; 25 | 26 | class tX_panel { 27 | GtkWidget* list_box_row; 28 | GtkWidget* drag_handle; 29 | GtkWidget* mainbox; 30 | GtkWidget* topbox; 31 | GtkWidget* clientbox; 32 | GtkWidget* clientframe; 33 | GtkWidget* labelbutton; 34 | GtkWidget* minimize_button; 35 | GtkWidget* maximize_button; 36 | GtkWidget* close_button; 37 | GtkWidget* button_box; 38 | GtkWidget* controlbox; 39 | GtkWidget* add_drywet_button; 40 | GtkWidget* remove_drywet_button; 41 | int client_hidden; 42 | 43 | public: 44 | tX_panel(const char* name, GtkWidget* controlbox, GCallback close_callback = NULL, vtt_fx* effect = NULL); 45 | ~tX_panel(); 46 | 47 | GtkWidget* get_widget() { return mainbox; }; 48 | GtkWidget* get_list_box_row() { return list_box_row; }; 49 | GtkWidget* get_labelbutton() { return labelbutton; } 50 | GtkWidget* get_add_drywet_button() { return add_drywet_button; } 51 | GtkWidget* get_remove_drywet_button() { return remove_drywet_button; } 52 | 53 | void add_client_widget(GtkWidget* w); 54 | int is_hidden() { return client_hidden; } 55 | void hide(int i) { 56 | client_hidden = i; 57 | tX_panel::minimize(NULL, this); 58 | } 59 | 60 | static void minimize(GtkWidget* w, tX_panel* p); 61 | }; 62 | 63 | extern void tX_panel_make_label_bold(GtkWidget* widget); 64 | -------------------------------------------------------------------------------- /src/tX_flash.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_flash.h 19 | 20 | Description: Header to tX_flash.c 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | #include "tX_types.h" 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif /* __cplusplus */ 33 | 34 | #define GTK_TX_FLASH(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, gtk_tx_flash_get_type(), GtkTxFlash) 35 | #define GTK_TX_FLASH_CLASS(klass) GTK_CHECK_CLASS_CAST(klass, gtk_tx_flash_get_type(), GtkTxFlashClass) 36 | #define GTK_IS_TX_FLASH(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, gtk_tx_flash_get_type()) 37 | 38 | typedef struct _GtkTxFlash GtkTxFlash; 39 | typedef struct _GtkTxFlashClass GtkTxFlashClass; 40 | 41 | struct flash_channel { 42 | int last_level; 43 | int max; 44 | int x1; 45 | int x2; 46 | }; 47 | 48 | struct _GtkTxFlash { 49 | GtkWidget widget; 50 | GdkRGBA colors[5]; 51 | int levels; 52 | int red_level; 53 | f_prec level_value; 54 | int max_cycles; 55 | int center_expand; 56 | struct flash_channel channel[2]; 57 | cairo_surface_t* surface; 58 | }; 59 | 60 | struct _GtkTxFlashClass { 61 | GtkWidgetClass parent_class; 62 | }; 63 | 64 | GtkWidget* gtk_tx_flash_new(); 65 | GType gtk_tx_flash_get_type(void); 66 | void gtk_tx_flash_set_level(GtkWidget* widget, f_prec left_channel, f_prec right_channel); 67 | void gtk_tx_flash_clear(GtkWidget* widget); 68 | void gtk_tx_flash_update_colors(GtkTxFlash* tx); 69 | 70 | #ifdef __cplusplus 71 | } 72 | #endif /* __cplusplus */ 73 | -------------------------------------------------------------------------------- /src/tX_dial.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_dial.h 19 | 20 | Description: Header to tX_dial.c - this widget is based on the gtk_dial 21 | example from the gtk+ tutorial which is 22 | Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald 23 | */ 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif /* __cplusplus */ 34 | 35 | #define GTK_TX_DIAL(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, gtk_tx_dial_get_type(), GtkTxDial) 36 | #define GTK_TX_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST(klass, gtk_tx_dial_get_type(), GtkTxDialClass) 37 | #define GTK_IS_TX_DIAL(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, gtk_tx_dial_get_type()) 38 | 39 | typedef struct _GtkTxDial GtkTxDial; 40 | typedef struct _GtkTxDialClass GtkTxDialClass; 41 | 42 | struct _GtkTxDial { 43 | GtkWidget widget; 44 | 45 | /* Button currently pressed or 0 if none */ 46 | guint8 button; 47 | 48 | /* Old values from adjustment stored so we know when something changes */ 49 | gfloat old_value; 50 | gfloat old_lower; 51 | gfloat old_upper; 52 | gfloat old_range; 53 | 54 | /* The adjustment object that stores the data for this tx_dial */ 55 | GtkAdjustment* adjustment; 56 | 57 | gint x, y; 58 | gint xofs, yofs; 59 | 60 | gint old_image; 61 | }; 62 | 63 | struct _GtkTxDialClass { 64 | GtkWidgetClass parent_class; 65 | }; 66 | 67 | GtkWidget* gtk_tx_dial_new(GtkAdjustment* adjustment); 68 | GType gtk_tx_dial_get_type(void); 69 | GtkAdjustment* gtk_tx_dial_get_adjustment(GtkTxDial* tx_dial); 70 | 71 | void gtk_tx_dial_set_adjustment(GtkTxDial* tx_dial, GtkAdjustment* adjustment); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif /* __cplusplus */ 76 | -------------------------------------------------------------------------------- /src/tX_ladspa_class.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_ladspa_class.h 19 | 20 | Description: Header to tX_ladspa_class.cc - see there for more info 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "tX_ladspa.h" 26 | #include "tX_vtt.h" 27 | #include 28 | #include 29 | #include 30 | 31 | typedef enum { 32 | MONO, 33 | STEREO 34 | } LADSPA_Plugin_Type; 35 | 36 | class LADSPA_Class { // Yeah, I know "class" name for C++ class - but it just seems to fit best... 37 | protected: 38 | static LADSPA_Class* root; 39 | static LADSPA_Class* unclassified; 40 | 41 | static std::list rdf_files; 42 | static vtt_class* current_vtt; 43 | static bool liblrdf_error; 44 | 45 | const char* label; 46 | bool accept_all; 47 | std::list subclasses; 48 | std::list registered_ids; 49 | std::list plugins; 50 | std::list stereo_plugins; 51 | 52 | static void scandir(char* dir); 53 | bool add_plugin_instance(LADSPA_Plugin*, LADSPA_Plugin_Type); 54 | void insert_class(LADSPA_Class*); 55 | void insert_plugin(LADSPA_Plugin*, LADSPA_Plugin_Type); 56 | int plugins_in_class(LADSPA_Plugin_Type type); 57 | void list(char*); 58 | GtkWidget* get_menu(LADSPA_Plugin_Type); 59 | 60 | public: 61 | LADSPA_Class(const char* uri); 62 | LADSPA_Class(); // For the unclassified class; 63 | 64 | static bool add_plugin(LADSPA_Plugin* plugin); 65 | static bool add_stereo_plugin(LADSPA_Stereo_Plugin* plugin); 66 | 67 | static void init(); 68 | static void dump(); 69 | static GtkWidget* get_ladspa_menu(); 70 | static GtkWidget* get_stereo_ladspa_menu(); 71 | static void set_current_vtt(vtt_class* vtt) { current_vtt = vtt; } 72 | static vtt_class* get_current_vtt() { return current_vtt; } 73 | }; 74 | -------------------------------------------------------------------------------- /src/tX_ladspa.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_ladspa.h 19 | 20 | Description: Header to ladspa.cc - see there for more info 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | using namespace std; 29 | 30 | class LADSPA_Plugin { 31 | protected: 32 | const LADSPA_Descriptor* ladspa_descriptor; 33 | LADSPA_Plugin(const LADSPA_Descriptor* ld, char* filename); 34 | LADSPA_Plugin() {} 35 | char info_string[4096]; 36 | char file[1024]; 37 | 38 | private: 39 | static list plugin_list; 40 | static void scandir(char* dir); 41 | static void handlelib(void* lib, LADSPA_Descriptor_Function desc_func, char* filename); 42 | 43 | public: 44 | static void init(); 45 | static void status(); 46 | static void debug_display(); 47 | virtual bool is_stereo(); 48 | char* get_info_string() { return info_string; } 49 | char* get_file_name() { return file; } 50 | 51 | long getUniqueID() { return ladspa_descriptor->UniqueID; } 52 | const char* getName() { return ladspa_descriptor->Name; } 53 | const char* getLabel() { return ladspa_descriptor->Label; } 54 | long getPortCount() { return ladspa_descriptor->PortCount; } 55 | 56 | static int getPluginCount() { return plugin_list.size(); } 57 | static LADSPA_Plugin* getPluginByIndex(int i); 58 | static LADSPA_Plugin* getPluginByUniqueID(long ID); 59 | const LADSPA_Descriptor* getDescriptor() { return ladspa_descriptor; } 60 | virtual ~LADSPA_Plugin(){}; 61 | }; 62 | 63 | class LADSPA_Stereo_Plugin : public LADSPA_Plugin { 64 | private: 65 | static list stereo_plugin_list; 66 | 67 | public: 68 | LADSPA_Stereo_Plugin(const LADSPA_Descriptor* ld, char* filename); 69 | 70 | public: 71 | virtual bool is_stereo(); 72 | static LADSPA_Stereo_Plugin* getPluginByIndex(int i); 73 | static LADSPA_Stereo_Plugin* getPluginByUniqueID(long ID); 74 | }; 75 | -------------------------------------------------------------------------------- /src/wav_write.c: -------------------------------------------------------------------------------- 1 | /* 2 | wav_write.c - taken from wav-tools 1.1 3 | Copyright (C) by Colin Ligertwood 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, see . 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #ifndef WIN32 24 | #include 25 | #include 26 | #endif 27 | 28 | #include "wav_file.h" 29 | 30 | #include "tX_endian.h" 31 | #include 32 | 33 | void init_head(wav_sig* info) { 34 | int32_t tmp32; 35 | 36 | strcpy(info->head, "RIFF WAVEfmt data "); 37 | 38 | tmp32 = (info->sofar + 32); 39 | #ifdef BIG_ENDIAN_MACHINE 40 | swap32(&tmp32); 41 | #endif 42 | *(int32_t*)&info->head[4] = tmp32; 43 | 44 | tmp32 = 16; 45 | #ifdef BIG_ENDIAN_MACHINE 46 | swap32(&tmp32); 47 | #endif 48 | *(int32_t*)&info->head[16] = tmp32; 49 | 50 | /* tmp16=1; 51 | #ifdef BIG_ENDIAN_MACHINE 52 | swap16(&tmp16); 53 | #endif 54 | *(int16_t *)&info->head[20] = tmp16; 55 | */ 56 | info->head[20] = 1; 57 | info->head[21] = 0; 58 | 59 | info->head[22] = info->chans; 60 | info->head[23] = 0; 61 | 62 | tmp32 = info->srate; 63 | #ifdef BIG_ENDIAN_MACHINE 64 | swap32(&tmp32); 65 | #endif 66 | *(int32_t*)&info->head[24] = tmp32; 67 | 68 | tmp32 = info->bps; 69 | #ifdef BIG_ENDIAN_MACHINE 70 | swap32(&tmp32); 71 | #endif 72 | *(int32_t*)&info->head[28] = tmp32; 73 | 74 | info->head[32] = info->blkalign; 75 | info->head[33] = 0; 76 | 77 | info->head[34] = info->depth; 78 | info->head[35] = 0; 79 | 80 | tmp32 = info->sofar; 81 | #ifdef BIG_ENDIAN_MACHINE 82 | swap32(&tmp32); 83 | #endif 84 | *(int32_t*)&info->head[40] = tmp32; 85 | } 86 | 87 | FILE* open_wav_rec(wav_sig* info) { 88 | info->handle = fopen(info->name, "w"); 89 | if (!info->handle) 90 | return NULL; 91 | init_head(info); 92 | fwrite(info->head, 44, 1, info->handle); 93 | return info->handle; 94 | } 95 | 96 | int rewrite_head(wav_sig* info) { 97 | rewind(info->handle); 98 | init_head(info); 99 | fwrite(info->head, 44, 1, info->handle); 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /src/tX_maingui.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_maingui.h 19 | 20 | Description: Header to tX_maingui.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include "tX_mouse.h" 28 | #include "tX_seqpar.h" 29 | 30 | extern int audioon; 31 | extern tx_mouse mouse; 32 | extern GdkWindow* top_window; 33 | 34 | extern GtkWidget* main_window; 35 | 36 | extern GtkAdjustment* volume_adj; 37 | extern GtkAdjustment* pitch_adj; 38 | extern GtkWidget* main_flash; 39 | 40 | extern tX_seqpar_main_volume sp_main_volume; 41 | extern tX_seqpar_main_pitch sp_main_pitch; 42 | 43 | extern void create_maingui(int x, int y); 44 | extern void wav_progress_update(gfloat percent); 45 | extern void note_destroy(GtkWidget* widget, GtkWidget* mbox); 46 | extern void tx_note(const char* message, bool isError = false, GtkWindow* window = NULL); 47 | extern void tx_l_note(const char* message); 48 | extern void display_maingui(); 49 | extern void grab_off(); 50 | extern void mg_update_status(); 51 | extern void load_tt_part(char*); 52 | extern void seq_update(); 53 | 54 | extern GtkWidget* control_parent; 55 | extern GtkWidget* audio_parent; 56 | 57 | extern void gui_set_tooltip(GtkWidget* wid, const char* tip); 58 | 59 | extern GtkWidget* panel_bar; 60 | 61 | void add_to_panel_bar(GtkWidget*); 62 | void remove_from_panel_bar(GtkWidget*); 63 | 64 | typedef enum { 65 | ALL_EVENTS_ALL_TURNTABLES, 66 | ALL_EVENTS_FOR_TURNTABLE, 67 | ALL_EVENTS_FOR_SP 68 | } tx_menu_del_mode; 69 | 70 | extern GtkWidget* del_dialog; 71 | extern tx_menu_del_mode menu_del_mode; 72 | extern tX_seqpar* del_sp; 73 | extern vtt_class* del_vtt; 74 | 75 | class tX_cursor { 76 | public: 77 | enum cursor_shape { 78 | DEFAULT_CURSOR, 79 | WAIT_CURSOR, 80 | WAIT_A_SECOND_CURSOR, 81 | MAX_CURSOR 82 | }; 83 | 84 | private: 85 | static GdkCursor* cursors[MAX_CURSOR]; 86 | static cursor_shape current_shape; 87 | 88 | public: 89 | static void set_cursor(cursor_shape shape); 90 | static void reset_cursor(); 91 | static GdkCursor* get_cursor(); 92 | }; 93 | 94 | extern GCallback menu_delete_all_events_for_sp(GtkWidget*, tX_seqpar* sp); 95 | extern bool tX_shutdown; 96 | -------------------------------------------------------------------------------- /src/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: WebKit 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: DontAlign 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlinesLeft: false 9 | AlignOperands: false 10 | AlignTrailingComments: false 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: false 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: false 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | BeforeCatch: false 33 | BeforeElse: false 34 | IndentBraces: false 35 | BreakBeforeBinaryOperators: All 36 | BreakBeforeBraces: Custom 37 | BreakBeforeTernaryOperators: true 38 | BreakConstructorInitializersBeforeComma: true 39 | ColumnLimit: 0 40 | CommentPragmas: '^ IWYU pragma:' 41 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 42 | ConstructorInitializerIndentWidth: 4 43 | ContinuationIndentWidth: 4 44 | Cpp11BracedListStyle: false 45 | DerivePointerAlignment: false 46 | DisableFormat: false 47 | ExperimentalAutoDetectBinPacking: false 48 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 49 | IncludeCategories: 50 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 51 | Priority: 2 52 | - Regex: '^(<|"(gtest|isl|json)/)' 53 | Priority: 3 54 | - Regex: '.*' 55 | Priority: 1 56 | IndentCaseLabels: false 57 | IndentWidth: 4 58 | IndentWrappedFunctionNames: false 59 | KeepEmptyLinesAtTheStartOfBlocks: true 60 | MacroBlockBegin: '' 61 | MacroBlockEnd: '' 62 | MaxEmptyLinesToKeep: 1 63 | NamespaceIndentation: All 64 | ObjCBlockIndentWidth: 4 65 | ObjCSpaceAfterProperty: true 66 | ObjCSpaceBeforeProtocolList: true 67 | PenaltyBreakBeforeFirstCallParameter: 19 68 | PenaltyBreakComment: 300 69 | PenaltyBreakFirstLessLess: 120 70 | PenaltyBreakString: 1000 71 | PenaltyExcessCharacter: 1000000 72 | PenaltyReturnTypeOnItsOwnLine: 60 73 | PointerAlignment: Left 74 | ReflowComments: true 75 | SortIncludes: true 76 | SpaceAfterCStyleCast: false 77 | SpaceBeforeAssignmentOperators: true 78 | SpaceBeforeParens: ControlStatements 79 | SpaceInEmptyParentheses: false 80 | SpacesBeforeTrailingComments: 1 81 | SpacesInAngles: false 82 | SpacesInContainerLiterals: true 83 | SpacesInCStyleCastParentheses: false 84 | SpacesInParentheses: false 85 | SpacesInSquareBrackets: false 86 | Standard: Cpp03 87 | TabWidth: 8 88 | UseTab: Never 89 | ... 90 | 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terminatorX 2 | 3 | Copyright (C) 1999-2024 by Alexander König - https://terminatorX.org 4 | 5 | ## About 6 | 7 | terminatorX is a realtime audio synthesizer that allows “scratching” on 8 | digitally sampled audio data (*.wav, *.mp3, etc.) the way hip-hop DJs scratch on 9 | vinyl records. 10 | 11 | The GTK+ user interface provides many features, most notably: 12 | * multiple turntables 13 | * realtime effects (buit-in as well as [LADSPA plugin effects](https://www.ladspa.org/)) 14 | * a sequencer and MIDI interface 15 | 16 | This software is designed to run under Linux, FreeBSD and the like. 17 | 18 | terminatorX is **free software**; see the [COPYING file](COPYING) that came with this 19 | distribution for details. 20 | 21 | WARNING: terminatorX comes with *ABSOLUTELY NO WARRANTY*. This software may 22 | lock up your machine or cause other problems under rare conditions. It is not 23 | recommended to run it on production servers. 24 | 25 | ## Documentation 26 | 27 | * [INSTALL](INSTALL.md) 28 | Information on installing terminatorX 29 | * [help/C/index.docbook](help/C/index.docbook) 30 | The user manual browsable with "yelp" (yelp is the gnome help browser). 31 | * [COPYING](COPYING) 32 | The license (GPL V2) 33 | 34 | ## Performance 35 | 36 | The following measures can help to improve the responsiveness as well as the 37 | precision when using terminatorX. 38 | 39 | ### Install Setuid 'root' 40 | 41 | DISCLAIMER: *Installing a program suid-root is always potentially dangerous*. 42 | However, a program will require root privileges to acquire realtime scheduling 43 | (which improves playback quality signifcantly). Only when running suid-root can 44 | terminatorX acquire realtime scheduling priorty to avoid buffer underruns with 45 | low latency settings and the mouse motion events can be captured directly from 46 | the hardware improving scratching precision. 47 | 48 | When running setuid-root, terminatorX makes use of Linux' POSIX capabilities: 49 | Right after start-up it acquires the CAP_SYS_NICE capabilty and accesses the 50 | Linux input interface before dropping root privileges for good. 51 | 52 | While the capabilities based approach seems much more secure than the approach 53 | that was previously implemented, it might still be exploitable. So, for 100% 54 | security you have to do without realtime scheduling and not install terminatorX 55 | suid root. 56 | 57 | ### Compile an Optimized Binary 58 | 59 | This issue is covered in the seperate [INSTALL file](INSTALL.md). Setting good 60 | optimization flags is a good idea although this step will proabably have the 61 | least effect and the defaults should be reasonable. 62 | 63 | ### Optimize Your terminatorX Setup 64 | 65 | The default settings for the GUI updates provide good realtime feedback. This 66 | may cause problems on slower machines or slow gtk+-themes. If the GUI-thread 67 | causes dropouts in the audio-engine you should increase the Update-Delay value 68 | in the options dialog. 69 | 70 | If you experience issues with the performance of the user interface, consider 71 | using a simpler GTK+ theme. -------------------------------------------------------------------------------- /src/tX_sequencer.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_sequencer.h 19 | 20 | Description: Header to tX_sequencer.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "tX_event.h" 30 | #include "tX_seqpar.h" 31 | 32 | #define TX_SEQMODE_PLAYONLY 1 33 | #define TX_SEQMODE_PLAYREC 0 34 | 35 | #include 36 | #include 37 | 38 | class tX_sequencer { 39 | public: 40 | typedef enum { 41 | DELETE_ALL, 42 | DELETE_UPTO_CURRENT, 43 | DELETE_FROM_CURRENT 44 | } del_mode; 45 | 46 | private: 47 | list song_list; 48 | list record_list; 49 | pthread_mutex_t record_lock; 50 | 51 | guint32 current_timestamp; 52 | guint32 start_timestamp; 53 | guint32 max_timestamp; 54 | guint32 record_start_timestamp; 55 | guint32 record_stop_timestamp; 56 | 57 | list::iterator next_event; 58 | 59 | int mode; 60 | int run; 61 | 62 | public: 63 | tX_sequencer(); 64 | ~tX_sequencer(); 65 | 66 | void set_timestamp(guint32 timestamp); 67 | int is_recording() { return (mode == TX_SEQMODE_PLAYREC); } 68 | 69 | guint32 get_timestamp() { return current_timestamp; } 70 | float get_timestamp_as_float() { return ((float)(((float)current_timestamp) / ((float)max_timestamp)) * 100.0); } 71 | 72 | void step(); 73 | 74 | int trig_rec(); 75 | int trig_play(); 76 | void trig_stop(); 77 | 78 | tX_event* record_event(tX_seqpar* sp, float value); 79 | 80 | tX_event* record(tX_seqpar* sp, float value) { 81 | if (mode == TX_SEQMODE_PLAYREC) 82 | return record_event(sp, value); 83 | else 84 | return NULL; 85 | } 86 | 87 | void delete_all_events_for_vtt(vtt_class* vtt, del_mode mode); 88 | void delete_all_events_for_sp(tX_seqpar* sp, del_mode mode); 89 | void delete_all_events(del_mode); 90 | 91 | void save(FILE*, gzFile, char* indent); 92 | #ifdef ENABLE_TX_LEGACY 93 | void load(FILE*); 94 | #endif 95 | void load(xmlDocPtr, xmlNodePtr); 96 | 97 | guint32 set_start_timestamp(float pos); 98 | void forward_to_start_timestamp(int dont_fake); 99 | bool is_empty() { return song_list.empty(); } 100 | }; 101 | 102 | extern tX_sequencer sequencer; 103 | -------------------------------------------------------------------------------- /src/tX_engine.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_engine.h 19 | 20 | Description: Header to tX_engine.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "tX_audiodevice.h" 26 | #include "tX_midiin.h" 27 | #include "tX_tape.h" 28 | #include 29 | 30 | #define ENG_ERR 4 31 | 32 | #define ENG_RUNNING 0 33 | #define ENG_INIT 1 34 | #define ENG_STOPPED 2 35 | #define ENG_FINISHED 3 36 | #define ENG_ERR_XOPEN 4 37 | #define ENG_ERR_XINPUT 5 38 | #define ENG_ERR_DGA 6 39 | #define ENG_ERR_SOUND 7 40 | #define ENG_ERR_THREAD 8 41 | /* #define ENG_ERR_GRABMOUSE 9 42 | #define ENG_ERR_GRABKEY 10 */ 43 | #define ENG_ERR_BUSY 11 44 | 45 | #include 46 | enum tX_engine_error { 47 | NO_ERROR, 48 | ERROR_TAPE, 49 | ERROR_AUDIO, 50 | ERROR_BACKEND, 51 | ERROR_BUSY 52 | }; 53 | 54 | enum tX_engine_status { 55 | RUNNING, 56 | STOPPED 57 | }; 58 | 59 | class tX_engine { 60 | private: 61 | static tX_engine* engine; 62 | 63 | pthread_t thread; 64 | pthread_mutex_t start; 65 | bool thread_terminate; 66 | tX_audiodevice* device; 67 | tx_tapedeck* tape; 68 | bool recording; 69 | bool recording_request; 70 | bool stop_flag; 71 | bool loop_is_active; 72 | /* bool grab_request; 73 | bool grab_active; */ 74 | bool runtime_error; 75 | bool overload_error; 76 | int cycles_ctr; 77 | 78 | #ifdef USE_ALSA_MIDI_IN 79 | private: 80 | tX_midiin* midi; 81 | 82 | public: 83 | tX_midiin* get_midi() { return midi; } 84 | #endif 85 | public: 86 | pthread_t get_thread_id() { return thread; } 87 | bool check_error() { return runtime_error || overload_error; } 88 | bool get_runtime_error() { return runtime_error; } 89 | bool get_overload_error() { return overload_error; } 90 | void reset_cycles_ctr() { /*tX_msg("cycles reset at %i.", cycles_ctr);*/ 91 | cycles_ctr = 0; 92 | } // locking? 93 | static tX_engine* get_instance(); 94 | tX_engine(); 95 | ~tX_engine(); 96 | 97 | tX_engine_error run(); 98 | void stop(); 99 | void loop(); 100 | 101 | void set_recording_request(bool recording); 102 | bool get_recording_request() { return recording_request; } 103 | bool is_recording() { return recording; } 104 | int16_t* render_cycle(); 105 | 106 | /* void set_grab_request(); */ 107 | bool is_stopped() { return stop_flag; } 108 | }; 109 | -------------------------------------------------------------------------------- /src/tX_widget.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_widget.h 19 | 20 | Description: Header to tX_widget.c 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | #include "tX_types.h" 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif /* __cplusplus */ 33 | 34 | #define GTK_TX(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, gtk_tx_get_type(), GtkTx) 35 | #define GTK_TX_CLASS(klass) GTK_CHECK_CLASS_CAST(klass, gtk_tx_get_type(), GtkTxClass) 36 | #define GTK_IS_TX(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, gtk_tx_get_type()) 37 | 38 | typedef struct _GtkTx GtkTx; 39 | typedef struct _GtkTxClass GtkTxClass; 40 | 41 | typedef enum tx_widget_motion { 42 | NO_MOTION, 43 | MOTION_LEFT, 44 | MOTION_RIGHT 45 | } tx_widget_motion; 46 | 47 | #define GTK_TX_HISTORY_LENGTH 4 48 | 49 | struct _GtkTx { 50 | GtkWidget widget; 51 | 52 | int16_t* disp_data; 53 | int16_t* data; 54 | int samples; 55 | 56 | GdkRGBA colors[6]; 57 | GdkRGBA history_colors[GTK_TX_HISTORY_LENGTH]; 58 | 59 | GdkRGBA* current_fg; 60 | GdkRGBA* current_bg; 61 | 62 | GdkRGBA* audio_colors_focus; 63 | GdkRGBA* audio_colors_nofocus; 64 | 65 | int spp; 66 | int xc; 67 | int xmax; 68 | int yc; 69 | int ymax; 70 | 71 | f_prec zoom; 72 | 73 | int cursor_pos; 74 | int cursor_x_pos; 75 | int mute; 76 | int cursor_history[GTK_TX_HISTORY_LENGTH]; 77 | int cursor_history_offset; 78 | 79 | int display_width; 80 | int display_x_offset; 81 | 82 | #ifdef USE_DISPLAY_NORMALIZE 83 | f_prec max_value; 84 | #endif 85 | 86 | cairo_surface_t* render_buffer_surface_a; 87 | cairo_surface_t* render_buffer_surface_b; 88 | 89 | cairo_surface_t* current_render_buffer_surface; 90 | cairo_surface_t* previous_render_buffer_surface; 91 | 92 | int render_buffer_x_offset; 93 | int render_buffer_display_width; 94 | GdkRGBA* render_buffer_fg; 95 | }; 96 | 97 | struct _GtkTxClass { 98 | GtkWidgetClass parent_class; 99 | }; 100 | 101 | GtkWidget* gtk_tx_new(int16_t* wavdata, int wavsamples); 102 | GType gtk_tx_get_type(void); 103 | void gtk_tx_set_data(GtkTx* tx, int16_t* wavdata, int wavsamples); 104 | void gtk_tx_cleanup_pos_display(GtkTx* tx); 105 | void gtk_tx_update_pos_display(GtkTx* tx, int sample, int mute); 106 | void gtk_tx_show_focus(GtkTx* tx, int show); 107 | void gtk_tx_set_zoom(GtkTx* tx, f_prec zoom, int is_playing); 108 | void gtk_tx_update_colors(GtkTx* tx, GdkRGBA* vtt_color); 109 | f_prec gtk_tx_get_zoom(GtkTx* tx); 110 | 111 | #ifdef __cplusplus 112 | } 113 | #endif /* __cplusplus */ 114 | -------------------------------------------------------------------------------- /src/tX_prelis.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_prelis.cc 19 | 20 | Description: This takes care of the "pre-listening" of audiofiles 21 | in the load dialog. 22 | */ 23 | 24 | extern "C" { 25 | #include 26 | #include 27 | }; 28 | 29 | #include "tX_global.h" 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | pid_t player_pid = 0; 39 | 40 | void prelis_stop() { 41 | int status; 42 | 43 | if (player_pid) { 44 | kill(player_pid, SIGTERM); 45 | waitpid(player_pid, &status, 0); 46 | player_pid = 0; 47 | usleep(200); 48 | } 49 | } 50 | 51 | void prelis_start(char* name) { 52 | char* ext; 53 | pid_t temp; 54 | #ifdef USE_MPG123_INPUT 55 | int usempg123 = 0; 56 | #endif 57 | #ifdef USE_OGG123_INPUT 58 | int useogg123 = 0; 59 | #endif 60 | char dev[PATH_MAX]; 61 | char ogg123_dev[PATH_MAX] = "dev:"; 62 | char nm[PATH_MAX]; 63 | 64 | if (!globals.prelis) 65 | return; 66 | 67 | if (player_pid) 68 | prelis_stop(); 69 | 70 | ext = strrchr(name, (int)'.'); 71 | if (ext) { 72 | if (strlen(ext) > 3) { 73 | ext++; 74 | #ifdef USE_OGG123_INPUT 75 | if (!strncasecmp("ogg", ext, 2)) 76 | useogg123 = 1; 77 | else 78 | #endif 79 | #ifdef USE_MPG123_INPUT 80 | if (!strncasecmp("mp", ext, 2)) 81 | usempg123 = 1; 82 | else 83 | #endif 84 | #if defined(USE_SOX_INPUT) && defined(USE_MPG123_INPUT) 85 | usempg123 = 0; 86 | #else 87 | return; 88 | #endif 89 | } 90 | } 91 | 92 | temp = fork(); 93 | 94 | if (temp == -1) /* error */ 95 | { 96 | return; 97 | } else if (temp == 0) /* CHILD */ 98 | { 99 | strcpy(dev, globals.oss_device); 100 | strcat(ogg123_dev, dev); 101 | strcpy(nm, name); 102 | #ifdef USE_OGG123_INPUT 103 | if (useogg123) 104 | execlp("ogg123", "ogg123", "-q", "-d", "oss", "-o", ogg123_dev, nm, NULL); 105 | else 106 | #endif 107 | #ifdef USE_MPG123_INPUT 108 | if (usempg123) 109 | execlp("mpg123", "mpg123", "-q", "-o", "oss", "-a", dev, nm, NULL); 110 | else 111 | #endif 112 | #ifdef USE_SOX_INPUT 113 | execlp("play", "play", "-q", nm, NULL); 114 | #else 115 | exit(0); 116 | #endif 117 | 118 | perror("Pre-Listen Error:"); 119 | exit(0); 120 | } else /* PARENT */ 121 | { 122 | player_pid = temp; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/tX_ui_support.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is no longer being generated by Glade and contains hand 3 | * crafted code. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include "tX_ui_support.h" 16 | 17 | GtkWidget* 18 | lookup_widget(GtkWidget* widget, 19 | const gchar* widget_name) { 20 | GtkWidget *parent, *found_widget; 21 | 22 | for (;;) { 23 | if (GTK_IS_MENU(widget)) 24 | parent = gtk_menu_get_attach_widget(GTK_MENU(widget)); 25 | else 26 | parent = gtk_widget_get_parent(widget); 27 | if (!parent) 28 | parent = (GtkWidget*)g_object_get_data(G_OBJECT(widget), "tXUiParentKey"); 29 | if (parent == NULL) 30 | break; 31 | widget = parent; 32 | } 33 | 34 | found_widget = (GtkWidget*)g_object_get_data(G_OBJECT(widget), 35 | widget_name); 36 | if (!found_widget) 37 | g_warning("Widget not found: %s", widget_name); 38 | return found_widget; 39 | } 40 | 41 | static GList* pixmaps_directories = NULL; 42 | 43 | /* Use this function to set the directory containing installed pixmaps. */ 44 | void add_pixmap_directory(const gchar* directory) { 45 | pixmaps_directories = g_list_prepend(pixmaps_directories, 46 | g_strdup(directory)); 47 | } 48 | 49 | /* This is an internally used function to find pixmap files. */ 50 | static gchar* 51 | find_pixmap_file(const gchar* filename) { 52 | GList* elem; 53 | 54 | /* We step through each of the pixmaps directory to find it. */ 55 | elem = pixmaps_directories; 56 | while (elem) { 57 | gchar* pathname = g_strdup_printf("%s%s%s", (gchar*)elem->data, 58 | G_DIR_SEPARATOR_S, filename); 59 | if (g_file_test(pathname, G_FILE_TEST_EXISTS)) 60 | return pathname; 61 | g_free(pathname); 62 | elem = elem->next; 63 | } 64 | return NULL; 65 | } 66 | 67 | /* This is an internally used function to create pixmaps. */ 68 | GtkWidget* 69 | create_pixmap(GtkWidget* widget, 70 | const gchar* filename) { 71 | gchar* pathname = NULL; 72 | GtkWidget* pixmap; 73 | 74 | if (!filename || !filename[0]) 75 | return gtk_image_new(); 76 | 77 | pathname = find_pixmap_file(filename); 78 | 79 | if (!pathname) { 80 | g_warning("Couldn't find pixmap file: %s", filename); 81 | return gtk_image_new(); 82 | } 83 | 84 | pixmap = gtk_image_new_from_file(pathname); 85 | g_free(pathname); 86 | return pixmap; 87 | } 88 | 89 | /* This is an internally used function to create pixmaps. */ 90 | GdkPixbuf* 91 | create_pixbuf(const gchar* filename) { 92 | gchar* pathname = NULL; 93 | GdkPixbuf* pixbuf; 94 | GError* error = NULL; 95 | 96 | if (!filename || !filename[0]) 97 | return NULL; 98 | 99 | pathname = find_pixmap_file(filename); 100 | 101 | if (!pathname) { 102 | g_warning("Couldn't find pixmap file: %s", filename); 103 | return NULL; 104 | } 105 | 106 | pixbuf = gdk_pixbuf_new_from_file(pathname, &error); 107 | if (!pixbuf) { 108 | fprintf(stderr, "Failed to load pixbuf file: %s: %s\n", 109 | pathname, error->message); 110 | g_error_free(error); 111 | } 112 | g_free(pathname); 113 | return pixbuf; 114 | } 115 | 116 | /* This is used to set ATK action descriptions. */ 117 | void ui_set_atk_action_description(AtkAction* action, 118 | const gchar* action_name, 119 | const gchar* description) { 120 | gint n_actions, i; 121 | 122 | n_actions = atk_action_get_n_actions(action); 123 | for (i = 0; i < n_actions; i++) { 124 | if (!strcmp(atk_action_get_name(action, i), action_name)) 125 | atk_action_set_description(action, i, description); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/tX_midiin.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 2002 Arthur Peters 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, see . 17 | 18 | File: tX_midiin.h 19 | 20 | Description: Header to tX_midiin.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | class vtt_class; 31 | class tX_seqpar; 32 | 33 | class tX_midievent { 34 | public: 35 | int channel; 36 | enum { 37 | NONE = 0, 38 | CC = 1, 39 | NOTE, 40 | PITCHBEND, 41 | CC14, 42 | RPN, 43 | NRPN 44 | } type; 45 | int number; // note # or controller # 46 | 47 | float value; // controller value or note velocity 48 | bool is_noteon; // note on or off? 49 | 50 | bool type_matches(const tX_midievent& other) const { 51 | return channel == other.channel && type == other.type && number == other.number; 52 | } 53 | 54 | void clear_non_type() { 55 | value = 0; 56 | is_noteon = false; 57 | } 58 | 59 | tX_midievent() 60 | : channel(0) 61 | , type(NONE) 62 | , number(0) 63 | , value(0.0) 64 | , is_noteon(false) {} 65 | }; 66 | 67 | #include 68 | #ifdef USE_ALSA_MIDI_IN 69 | 70 | #include 71 | #include 72 | 73 | class tX_midiin { 74 | snd_seq_t* ALSASeqHandle; 75 | tX_midievent last_event; 76 | bool is_open; 77 | tX_seqpar* sp_to_learn; 78 | GtkWidget* learn_dialog; 79 | int portid; 80 | 81 | public: 82 | tX_midiin(); 83 | ~tX_midiin(); 84 | 85 | bool get_is_open() { 86 | return is_open; 87 | } 88 | 89 | int check_event(); 90 | 91 | void configure_bindings(vtt_class*); 92 | 93 | const tX_midievent& get_last_event() { 94 | return last_event; 95 | } 96 | 97 | void set_midi_learn_sp(tX_seqpar*); 98 | void cancel_midi_learn(); 99 | void store_connections(FILE* rc, char* indent); 100 | void restore_connections(xmlNodePtr node); 101 | 102 | static gboolean midi_learn_cancel(GtkWidget*, tX_midiin*); 103 | static gboolean midi_learn_destroy(GtkWidget*, tX_midiin*); 104 | static void auto_assign_midi_mappings(GtkWidget*, gpointer); 105 | static void clear_midi_mappings(GtkWidget*, gpointer); 106 | 107 | private: 108 | class midi_binding_gui { 109 | public: 110 | midi_binding_gui(GtkTreeModel* _model, tX_midiin* _midi); 111 | ~midi_binding_gui(); 112 | 113 | GtkWidget* window; 114 | 115 | GtkWidget* parameter_treeview; 116 | GtkWidget* midi_event_info; 117 | GtkWidget* bind_button; 118 | 119 | GtkTreeModel* model; 120 | 121 | tX_midiin* midi; 122 | 123 | tX_midievent last_event; 124 | 125 | static void window_closed(GtkWidget* widget, gpointer _this); 126 | static void unbind_clicked(GtkButton* button, gpointer _this); 127 | static void bind_clicked(GtkButton* button, gpointer _this); 128 | static void close_clicked(GtkButton* button, gpointer _this); 129 | static gint timer(gpointer _this); 130 | 131 | private: 132 | char tempstr[128]; 133 | 134 | gint timer_tag; 135 | }; 136 | }; 137 | 138 | #endif // USE_ALSA_MIDI_IN 139 | -------------------------------------------------------------------------------- /src/tX_extdial.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | */ 19 | 20 | #include "tX_extdial.h" 21 | #include "tX_seqpar.h" 22 | #include 23 | 24 | #define WID_DYN TRUE, TRUE, 0 25 | #define WID_FIX FALSE, FALSE, 0 26 | 27 | GCallback tX_extdial ::f_entry(GtkWidget* w, tX_extdial* ed) { 28 | strcpy(ed->sval, gtk_entry_get_text(GTK_ENTRY(ed->entry))); 29 | ed->s2f(); 30 | gtk_adjustment_set_value(ed->adj, ed->fval); 31 | return NULL; 32 | } 33 | 34 | GCallback tX_extdial ::f_adjustment(GtkWidget* w, tX_extdial* ed) { 35 | ed->fval = gtk_adjustment_get_value(ed->adj); 36 | ed->f2s(); 37 | gtk_entry_set_text(GTK_ENTRY(ed->entry), ed->sval); 38 | return NULL; 39 | } 40 | 41 | tX_extdial ::tX_extdial(const char* l, GtkAdjustment* a, tX_seqpar* sp, bool text_below, bool hide_entry) { 42 | adj = a; 43 | fval = gtk_adjustment_get_value(adj); 44 | f2s(); 45 | if (l) { 46 | label = gtk_label_new(NULL); 47 | gtk_label_set_markup(GTK_LABEL(label), l); 48 | } 49 | dial = gtk_tx_dial_new(adj); 50 | entry = gtk_entry_new(); 51 | gtk_entry_set_max_length(GTK_ENTRY(entry), 5); 52 | gtk_entry_set_text(GTK_ENTRY(entry), sval); 53 | #if GTK_CHECK_VERSION(2, 4, 0) 54 | gtk_entry_set_alignment(GTK_ENTRY(entry), 0.5); 55 | #endif 56 | ignore_adj = 0; 57 | 58 | eventbox = gtk_event_box_new(); 59 | mainbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, text_below ? 5 : 0); 60 | 61 | gtk_container_add(GTK_CONTAINER(eventbox), mainbox); 62 | 63 | subbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); 64 | gtk_box_set_homogeneous(GTK_BOX(subbox), TRUE); 65 | gtk_box_pack_start(GTK_BOX(subbox), dial, WID_FIX); 66 | gtk_box_pack_start(GTK_BOX(mainbox), subbox, WID_FIX); 67 | if (text_below) { 68 | gtk_box_pack_start(GTK_BOX(mainbox), entry, WID_DYN); 69 | } else { 70 | gtk_box_pack_start(GTK_BOX(subbox), entry, TRUE, TRUE, 3); 71 | } 72 | if (l) 73 | gtk_box_pack_start(GTK_BOX(mainbox), label, WID_FIX); 74 | 75 | if (l) 76 | gtk_widget_show(label); 77 | if (!hide_entry) { 78 | gtk_widget_show(entry); 79 | } 80 | gtk_entry_set_width_chars(GTK_ENTRY(entry), 4); 81 | gtk_entry_set_max_width_chars(GTK_ENTRY(entry), 4); 82 | gtk_widget_show(dial); 83 | gtk_widget_show(subbox); 84 | gtk_widget_show(mainbox); 85 | gtk_widget_show(eventbox); 86 | 87 | g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(tX_extdial::f_entry), (void*)this); 88 | g_signal_connect(G_OBJECT(adj), "value_changed", G_CALLBACK(tX_extdial::f_adjustment), (void*)this); 89 | 90 | if (sp) { 91 | g_signal_connect(G_OBJECT(dial), "button_press_event", G_CALLBACK(tX_seqpar::tX_seqpar_press), sp); 92 | g_signal_connect(G_OBJECT(entry), "button_press_event", G_CALLBACK(tX_seqpar::tX_seqpar_press), sp); 93 | g_signal_connect(G_OBJECT(eventbox), "button_press_event", G_CALLBACK(tX_seqpar::tX_seqpar_press), sp); 94 | } 95 | } 96 | 97 | tX_extdial ::~tX_extdial() { 98 | gtk_widget_destroy(entry); 99 | gtk_widget_destroy(label); 100 | gtk_widget_destroy(dial); 101 | gtk_widget_destroy(subbox); 102 | gtk_widget_destroy(mainbox); 103 | gtk_widget_destroy(eventbox); 104 | } 105 | -------------------------------------------------------------------------------- /src/tX_vttgui.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_vttgui.h 19 | 20 | Description: Header to tX_vttgui.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "tX_extdial.h" 26 | #include "tX_panel.h" 27 | #include "tX_seqpar.h" 28 | #include "tX_types.h" 29 | #include 30 | #include 31 | #include 32 | 33 | struct vtt_gui { 34 | GtkWidget* control_box; 35 | GtkWidget* audio_box; 36 | GtkWidget* adjust_dialog; 37 | 38 | /* Control Box Widgets */ 39 | GtkWidget* control_label; 40 | GtkWidget* control_minimize; 41 | GtkWidget* scrolled_win; 42 | GtkWidget* control_subbox; 43 | GtkWidget* static_box; 44 | GtkWidget* fx_box; 45 | GtkWidget* stereo_fx_box; 46 | GtkWidget* ladspa_menu; 47 | GtkWidget* par_menu; 48 | 49 | /* Main */ 50 | tX_panel* main_panel; 51 | GtkWidget* name; 52 | GtkWidget* color_button; 53 | GtkCssProvider* css_provider; 54 | GtkWidget* show_audio; 55 | GtkWidget* del; 56 | GtkWidget* adjust_button; 57 | GtkWidget* fx_button; 58 | GtkWidget* stereo_fx_button; 59 | 60 | /* Trigger */ 61 | tX_panel* trigger_panel; 62 | GtkWidget* trigger; 63 | GtkWidget* stop; 64 | GtkWidget* autotrigger; 65 | GtkWidget* loop; 66 | GtkWidget* sync_leader; 67 | GtkWidget* sync_follower; 68 | GtkAdjustment* cycles; 69 | 70 | /* Output Panel */ 71 | tX_extdial* pitchd; 72 | tX_extdial* pand; 73 | GtkAdjustment* pitch; 74 | GtkAdjustment* pan; 75 | GtkAdjustment* volume; 76 | GtkWidget* mute; 77 | GtkWidget* solo; 78 | GtkWidget* flash; 79 | 80 | /* Widgets in Lowpass Panel */ 81 | tX_panel* lp_panel; 82 | GtkWidget* lp_enable; 83 | tX_extdial* lp_gaind; 84 | tX_extdial* lp_resod; 85 | tX_extdial* lp_freqd; 86 | GtkAdjustment* lp_gain; 87 | GtkAdjustment* lp_reso; 88 | GtkAdjustment* lp_freq; 89 | 90 | /* Widgets in Echo Panel */ 91 | tX_panel* ec_panel; 92 | GtkWidget* ec_enable; 93 | tX_extdial* ec_lengthd; 94 | tX_extdial* ec_feedbackd; 95 | tX_extdial* ec_pand; 96 | tX_extdial* ec_volumed; 97 | GtkAdjustment* ec_length; 98 | GtkAdjustment* ec_feedback; 99 | GtkAdjustment* ec_pan; 100 | GtkAdjustment* ec_volume; 101 | 102 | int32_t current_gui; 103 | 104 | /* Audio Box Widgets */ 105 | GtkWidget* audio_label; 106 | GtkWidget* audio_minimize; 107 | GtkWidget* display; 108 | GtkWidget* zoom; 109 | GtkWidget* file; 110 | GtkWidget* file_menu; 111 | 112 | GtkWidget* mouse_mapping; 113 | GtkWidget* mouse_mapping_menu; 114 | GtkWidget* mouse_mapping_menu_x; 115 | GtkWidget* mouse_mapping_menu_y; 116 | 117 | char style_class[32]; 118 | 119 | #ifdef USE_ALSA_MIDI_IN 120 | GtkWidget* midi_mapping; 121 | #endif 122 | 123 | GtkWidget* audio_minimized_panel_bar_button; 124 | GtkWidget* control_minimized_panel_bar_button; 125 | 126 | GtkWidget* audio_minimized_panel_bar_label; 127 | GtkWidget* control_minimized_panel_bar_label; 128 | }; 129 | 130 | extern void update_vtt_css(vtt_class* vtt, GdkRGBA* rgba); 131 | extern void cleanup_all_vtts(); 132 | extern void update_all_vtts(); 133 | extern void vg_enable_critical_buttons(int enable); 134 | extern void vg_init_all_non_seqpars(); 135 | extern void vg_adjust_zoom(GtkWidget* wid, vtt_class* vtt); 136 | extern void gui_scroll_callback(GtkWidget* tx, GdkEventScroll* eventScroll, gpointer userdata); 137 | extern GCallback load_file(GtkWidget* wid, vtt_class* vtt); 138 | -------------------------------------------------------------------------------- /src/wav_read.c: -------------------------------------------------------------------------------- 1 | /* 2 | wav_read.c - taken from wav-tools 1.1 3 | Copyright (C) by Colin Ligertwood 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, see . 17 | */ 18 | 19 | /* operations for verifying and reading wav files. */ 20 | 21 | #include "wav_file.h" 22 | #include 23 | #include 24 | #include 25 | #ifndef WIN32 26 | #include 27 | #endif 28 | #include "tX_endian.h" 29 | #include "tX_types.h" 30 | #include 31 | 32 | /* Read little endian 16bit values little endian 33 | */ 34 | #ifdef BIG_ENDIAN_MACHINE 35 | 36 | #define read16(x) \ 37 | ; \ 38 | p = (int8_t*)&tmp; \ 39 | p[0] = info->head[x]; \ 40 | p[1] = info->head[x + 1]; \ 41 | swap16(&tmp); \ 42 | return tmp; 43 | 44 | #else 45 | 46 | #define read16(x) \ 47 | ; \ 48 | p = (int8_t*)&tmp; \ 49 | p[0] = info->head[x]; \ 50 | p[1] = info->head[x + 1]; \ 51 | return tmp; 52 | 53 | #endif 54 | 55 | /* Read little endian 32bit values little endian 56 | */ 57 | #ifdef BIG_ENDIAN_MACHINE 58 | 59 | #define read32(x) \ 60 | ; \ 61 | p = (int8_t*)&tmp; \ 62 | p[0] = info->head[x]; \ 63 | p[1] = info->head[x + 1]; \ 64 | p[2] = info->head[x + 2]; \ 65 | p[3] = info->head[x + 3]; \ 66 | swap32(&tmp); \ 67 | return tmp; 68 | 69 | #else 70 | 71 | #define read32(x) \ 72 | ; \ 73 | p = (int8_t*)&tmp; \ 74 | p[0] = info->head[x]; \ 75 | p[1] = info->head[x + 1]; \ 76 | p[2] = info->head[x + 2]; \ 77 | p[3] = info->head[x + 3]; \ 78 | return tmp; 79 | 80 | #endif 81 | 82 | /* wav header is 44 bytes long */ 83 | FILE* open_wav(char* header, char file_name[], int* mode) { 84 | FILE* handle; 85 | handle = fopen(file_name, "r"); 86 | if (handle) 87 | if (fread((char*)header, 1, 44, handle) != 44) { 88 | fclose(handle); 89 | handle = NULL; 90 | } 91 | return handle; 92 | } 93 | 94 | int16_t get_wav_format(wav_sig* info) { 95 | int16_t tmp; 96 | int8_t* p; 97 | 98 | read16(20); 99 | } 100 | 101 | /* mono or stereo */ 102 | int8_t get_wav_channels(wav_sig* info) { 103 | return info->head[22]; 104 | // read16(22); 105 | } 106 | 107 | /* sample rate */ 108 | int32_t get_wav_srate(wav_sig* info) { 109 | int32_t tmp; 110 | int8_t* p; 111 | 112 | read32(24); 113 | } 114 | 115 | int32_t get_wav_bps(wav_sig* info) { 116 | int32_t tmp; 117 | int8_t* p; 118 | 119 | read32(28); 120 | } 121 | 122 | int8_t get_wav_blkalign(wav_sig* info) { 123 | return info->head[32]; 124 | // read16(32); 125 | } 126 | 127 | /* sample depth (8bit or 16bit) */ 128 | int8_t get_wav_depth(wav_sig* info) { 129 | return info->head[34]; 130 | // read16(34); 131 | } 132 | 133 | /* data section only == totalfile - 44 */ 134 | int32_t get_wav_len(wav_sig* info) { 135 | int32_t tmp; 136 | int8_t* p; 137 | 138 | read32(40); 139 | } 140 | 141 | FILE* init_wav_read(char file_name[], wav_sig* info) { 142 | int mode = 0; 143 | 144 | info->handle = open_wav(info->head, file_name, &mode); 145 | strcpy(info->name, file_name); 146 | info->chans = get_wav_channels(info); 147 | info->srate = get_wav_srate(info); 148 | info->bps = get_wav_bps(info); 149 | info->blkalign = get_wav_blkalign(info); 150 | info->depth = get_wav_depth(info); 151 | info->len = get_wav_len(info); 152 | return info->handle; 153 | } 154 | 155 | void wav_close(FILE* wav) { 156 | if (wav) { 157 | fclose(wav); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/tX_audiofile.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_audiofile.h 19 | 20 | Description: Header to audiofile.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #define SOX_BLOCKSIZE 32000 26 | 27 | #include 28 | #include 29 | 30 | #ifdef USE_SOX_INPUT 31 | #define SOX_STR "sox \"%s\" -t raw -c 1 -r 44100 -s -2 -" 32 | #endif 33 | 34 | #ifdef USE_MPG123_INPUT 35 | /* The Original MPG123_STR - probably slightly faster than the one above but 36 | but mpg321 doesn't support -m yet. 37 | #define MPG123_STR "mpg123 -qms \"%s\"" 38 | */ 39 | 40 | #ifdef BIG_ENDIAN_MACHINE 41 | /* This works with mpg321 only... */ 42 | #define MPG123_STR "mpg123 -qs \"%s\" | sox -x -t raw -s -2 -r 44100 -c 2 - -t raw -c 1 -r 44100 -s -2 -" 43 | #else 44 | #define MPG123_STR "mpg123 -qs \"%s\" | sox -t raw -s -2 -r 44100 -c 2 - -t raw -c 1 -r 44100 -s -2 -" 45 | #endif 46 | #endif 47 | 48 | #ifdef USE_OGG123_INPUT 49 | #define OGG123_STR "ogg123 -q -d wav -f - \"%s\" | sox -t wav - -t raw -c 1 -r 44100 -s -2 -" 50 | /* -o file:/dev/stdout because ogg123 doesn't interpret - as stdout */ 51 | /* 20010907: i take that back, it seems that newer versions don't 52 | * have that problem */ 53 | #endif /* USE_OGG123_INPUT */ 54 | 55 | enum tX_audio_error { 56 | TX_AUDIO_SUCCESS, 57 | TX_AUDIO_ERR_ALLOC, 58 | TX_AUDIO_ERR_PIPE_READ, 59 | TX_AUDIO_ERR_SOX, 60 | TX_AUDIO_ERR_MPG123, 61 | TX_AUDIO_ERR_WAV_NOTFOUND, 62 | TX_AUDIO_ERR_NOT_16BIT, 63 | TX_AUDIO_ERR_NOT_MONO, 64 | TX_AUDIO_ERR_WAV_READ, 65 | TX_AUDIO_ERR_NOT_SUPPORTED, 66 | TX_AUDIO_ERR_OGG123, 67 | TX_AUDIO_ERR_MAD_OPEN, 68 | TX_AUDIO_ERR_MAD_STAT, 69 | TX_AUDIO_ERR_MAD_DECODE, 70 | TX_AUDIO_ERR_MAD_MMAP, 71 | TX_AUDIO_ERR_MAD_MUNMAP, 72 | TX_AUDIO_ERR_VORBIS_OPEN, 73 | TX_AUDIO_ERR_VORBIS_NODATA, 74 | TX_AUDIO_ERR_AF_OPEN, 75 | TX_AUDIO_ERR_AF_NODATA 76 | }; 77 | 78 | enum tX_audio_storage_type { 79 | TX_AUDIO_UNDEFINED, 80 | TX_AUDIO_MMAP, 81 | TX_AUDIO_LOAD 82 | }; 83 | 84 | enum tX_audio_file_type { 85 | TX_FILE_UNDEFINED, 86 | TX_FILE_WAV, 87 | TX_FILE_MPG123, 88 | TX_FILE_OGG123 89 | }; 90 | 91 | #include "tX_types.h" 92 | #include 93 | #include 94 | 95 | class tx_audiofile { 96 | private: 97 | tX_audio_storage_type mem_type; 98 | tX_audio_file_type file_type; 99 | 100 | FILE* file; 101 | char filename[PATH_MAX]; 102 | int16_t* mem; 103 | size_t memsize; 104 | long no_samples; 105 | unsigned int sample_rate; // in HZ 106 | 107 | #ifdef USE_BUILTIN_WAV 108 | tX_audio_error load_wav(); 109 | #endif 110 | 111 | #ifdef USE_SOX_INPUT 112 | tX_audio_error load_sox(); 113 | #define NEED_PIPED 1 114 | #endif 115 | 116 | #ifdef USE_AUDIOFILE_INPUT 117 | tX_audio_error load_af(); 118 | #endif 119 | 120 | #ifdef USE_MAD_INPUT 121 | tX_audio_error load_mad(); 122 | int mad_decode(unsigned char const* start, unsigned long length); 123 | #endif 124 | 125 | #ifdef USE_MPG123_INPUT 126 | tX_audio_error load_mpg123(); 127 | #define NEED_PIPED 1 128 | #endif 129 | 130 | #ifdef USE_VORBIS_INPUT 131 | tX_audio_error load_vorbis(); 132 | #endif 133 | 134 | #ifdef USE_OGG123_INPUT 135 | tX_audio_error load_ogg123(); 136 | #define NEED_PIPED 1 137 | #endif 138 | 139 | #ifdef NEED_PIPED 140 | tX_audio_error load_piped(); 141 | #endif 142 | void figure_file_type(); 143 | 144 | public: 145 | tx_audiofile(); 146 | unsigned int get_sample_rate() { return sample_rate; } 147 | 148 | tX_audio_error load(char* p_file_name); 149 | int16_t* get_buffer() { return mem; }; 150 | long get_no_samples() { return no_samples; }; 151 | 152 | ~tx_audiofile(); 153 | }; 154 | -------------------------------------------------------------------------------- /src/tX_mouse.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_mouse.h 19 | 20 | Description: Header to tX_mouse.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #define KEY_Alt_L 1 36 | #define KEY_Alt_R 2 37 | #define KEY_BackSpace 3 38 | #define KEY_Control_L 4 39 | #define KEY_Control_R 5 40 | #define KEY_Escape 6 41 | #define KEY_f 7 42 | #define KEY_F1 8 43 | #define KEY_F10 9 44 | #define KEY_F11 10 45 | #define KEY_F12 11 46 | #define KEY_F2 12 47 | #define KEY_F3 13 48 | #define KEY_F4 14 49 | #define KEY_F5 15 50 | #define KEY_F6 16 51 | #define KEY_F7 17 52 | #define KEY_F8 18 53 | #define KEY_F9 19 54 | #define KEY_m 20 55 | #define KEY_Return 21 56 | #define KEY_s 22 57 | #define KEY_space 23 58 | #define KEY_Tab 24 59 | #define KEY_w 25 60 | #define MAX_KEY 26 61 | 62 | typedef struct __attribute__((__packed__)) { 63 | uint8_t buttons; 64 | int8_t x_motion; 65 | int8_t y_motion; 66 | } tx_input_event; 67 | 68 | class tx_mouse { 69 | bool warp_override; 70 | GdkEventMask savedEventMask; 71 | 72 | gboolean enable_auto_mnemonics; 73 | gboolean enable_compression; 74 | guint last_button_press; 75 | guint last_button_release; 76 | 77 | GdkDisplay* display; 78 | GdkDevice* pointer; 79 | GdkSeat* seat; 80 | GdkScreen* screen; 81 | GdkWindow* window; 82 | GdkCursor* cursor; 83 | gdouble x_abs; 84 | gdouble y_abs; 85 | gint x_restore; 86 | gint y_restore; 87 | 88 | float warp; 89 | 90 | int grabbed; 91 | bool key_pressed[MAX_KEY]; 92 | 93 | enum { 94 | FALLBACK, 95 | LINUX_INPUT 96 | } grab_mode; 97 | 98 | guint32 motion_timestamp; 99 | 100 | GIOChannel* linux_input_channel; 101 | guint linux_input_watch; 102 | 103 | bool press_key(int keycode) { 104 | if (!key_pressed[keycode]) { 105 | key_pressed[keycode] = true; 106 | return true; 107 | } 108 | return false; 109 | } 110 | 111 | bool release_key(int keycode) { 112 | if (key_pressed[keycode]) { 113 | key_pressed[keycode] = false; 114 | return true; 115 | } 116 | return false; 117 | } 118 | 119 | public: 120 | int set_xinput(); 121 | void reset_xinput(); 122 | bool is_grabbed() { return grabbed != 0; } 123 | 124 | int grab(); 125 | int grab_linux_input(); 126 | 127 | int check_event(); 128 | void ungrab(); 129 | void ungrab_linux_input(); 130 | tx_mouse(); 131 | GError* open_channel(); 132 | void close_channel(); 133 | 134 | void motion_notify(GtkWidget* widget, GdkEventMotion* eventMotion); 135 | void button_press(GtkWidget* widget, GdkEventButton* eventButton); 136 | void button_release(GtkWidget* widget, GdkEventButton* eventButton); 137 | void key_press(GtkWidget* widget, GdkEventKey* eventKey); 138 | void key_release(GtkWidget* widget, GdkEventKey* eventKey); 139 | void linux_input(tx_input_event* event); 140 | 141 | static gboolean motion_notify_wrap(GtkWidget* widget, GdkEventMotion* eventMotion, void* data); 142 | static gboolean button_press_wrap(GtkWidget* widget, GdkEventButton* eventButton, void* data); 143 | static gboolean button_release_wrap(GtkWidget* widget, GdkEventButton* eventButton, void* data); 144 | static gboolean key_press_wrap(GtkWidget* widget, GdkEventKey* eventKey, void* data); 145 | static gboolean key_release_wrap(GtkWidget* widget, GdkEventKey* eventKey, void* data); 146 | static gboolean linux_input_wrap(GIOChannel* source, GIOCondition condition, gpointer data); 147 | }; 148 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # terminatorX INSTALL 2 | 3 | Copyright (C) 1999-2024 by Alexander König - https://terminatorX.org 4 | 5 | ## Quickstart 6 | 7 | If you want enhanced audio-file support or optimization don't 8 | "quickstart" but read the rest of this file. 9 | 10 | To build terminatorX with default options run the following commands (using 11 | 'build' as the build directory): 12 | 13 | ``` 14 | $ meson setup build 15 | $ meson compile -C build 16 | $ sudo meson install -C build 17 | ``` 18 | 19 | The following sections descripe the installation steps in more detail. 20 | 21 | ## Step 1: Configure the terminatorX Build 22 | 23 | The Meson Build system supports a number of [built-in 24 | options](https://mesonbuild.com/Builtin-options.html). The default build type 25 | for terminatorX is 'debugoptimized'. You may want to change that, e.g. if you 26 | you don't want the binary to carry debug information you could select 'release' 27 | instead: 28 | 29 | ``` 30 | $ meson setup build --buildtype=release 31 | ``` 32 | 33 | In addition to the built-in options, the terminatorX meson build 34 | supports a number of additional [options](meson.options) to customize 35 | the build. These features can be either en- or disabled: 36 | 37 | ``` 38 | $ meson setup build -Dfeature=enabled 39 | ``` 40 | 41 | Where 'feature' can be anyone of the features listed in the following 42 | section. It is possible to probide the '-D' argument multiple times to 43 | configure multiple features. 44 | 45 | ## Meson Build Options 46 | 47 | ### File support options 48 | 49 | All of these are enabled by default. Nevertheless the configure 50 | script checks for the availability of the helper application 51 | and if it's not found disables support for it. Check the 52 | terminatorX homepage for links to those apps if you don't have 53 | them - or check your distribution first, AFAIK all bring these 54 | tools nowaday. 55 | 56 | #### mad 57 | 58 | This will make terminatorX use the MPEG Audio Decoder library if 59 | it's detected. This allows terminatorX to load mp3 files 60 | significantly faster than with the mpg123 method. Additionally 61 | terminatorX will find out about the sampling rate of an mp3 file 62 | and adjust the playback speed accordingly. 63 | 64 | #### vorbis 65 | 66 | This will make terminatorX use the OGG Vobris libraries to load 67 | OGG files directly. This method has the same advantages over 68 | loading through ogg123 as the "mad" method has over loading 69 | through mpg123. 70 | 71 | #### audiofile 72 | 73 | This enables the use of libaudiofile on loading audio files. 74 | The library supports a wide range of common audio file formats 75 | (eg WAV/AIFF/AU etc) therefor its use highly recommended. 76 | 77 | #### wav 78 | 79 | This enables the builtin wav routines. They load 16Bit/44Khz 80 | MONO RIFF/WAV files only but they do that significantly faster 81 | than using sox. If these routines fail and sox support is 82 | enabled, terminatorX will try to load the file with sox as 83 | a fallback. Disable them only if they don't load your files 84 | correctly. 85 | 86 | #### sox 87 | 88 | This enables sox support. As sox can load nearly any audio file 89 | it makes sense to use it. You have to have sox installed of 90 | course. 91 | 92 | #### mpg123 93 | 94 | This enables mpg123 support. If you want to be able to load mp3 95 | files keep this option enabled. You have to have mpg123 96 | installed of course. 97 | 98 | #### ogg123 99 | 100 | With this option you can turn on/off support for Ogg Vorbis 101 | soundfiles. This requires ogg123 (Version >= 1.0RC2) and 102 | sox to be installed. 103 | 104 | ## Other options 105 | 106 | #### suidroot 107 | 108 | When set, this option sets the setuid bits for the root user when 109 | installing the binary, note that this will require root privileges 110 | upon installation. 111 | 112 | #### capabilities 113 | 114 | Allows running terminatorX suid-root to gain realtime scheduling 115 | (see [README](README.md)). 116 | 117 | #### debug 118 | 119 | This will cause terminatorX to display some debug messages on 120 | your console. 121 | 122 | ## Step 2: Build the binary 123 | 124 | This one's easy: 125 | 126 | ``` 127 | $ meson compile -C build 128 | ``` 129 | 130 | ## Step 3: Install the binary 131 | 132 | Just as easy: 133 | 134 | ``` 135 | $ sudo meson install -C build 136 | ``` 137 | 138 | The above example uses 'sudo' to gain root privileges, assuming the standard 139 | installation prefix was used (typically '/usr/local'). Other installation 140 | prefixes might not require root privileges, however if you chose the 'suidroot' 141 | option, root will be required in any case. 142 | -------------------------------------------------------------------------------- /src/tX_pbutton.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_pbutton.cc 19 | 20 | Description: This implements the pixmaped buttons - based on 21 | gtk+ tutorial. 22 | 23 | */ 24 | 25 | #include "tX_pbutton.h" 26 | #include "tX_global.h" 27 | #include "tX_maingui.h" 28 | #include 29 | #include 30 | #include 31 | 32 | const char* tx_icons[ALL_ICONS]; 33 | 34 | int tx_icon_size = 20; 35 | 36 | static const char tx_css[] = "#close:hover { background-color: #FF5555; color: #FFFFFF; }"; 37 | 38 | void tx_icons_init(int size) { 39 | tx_icon_size = size; 40 | 41 | tx_icons[AUDIOENGINE] = "audio-speakers-symbolic"; 42 | tx_icons[POWER] = "system-shutdown-symbolic"; 43 | tx_icons[GRAB] = "input-mouse-symbolic"; 44 | 45 | tx_icons[SEQUENCER] = "emblem-music-symbolic"; 46 | 47 | tx_icons[PLAY] = "media-playback-start-symbolic"; 48 | tx_icons[STOP] = "media-playback-stop-symbolic"; 49 | tx_icons[RECORD] = "media-record-symbolic"; 50 | tx_icons[MIN_AUDIO] = "audio-speakers-symbolic"; 51 | tx_icons[MIN_CONTROL] = "audio-x-generic-symbolic"; 52 | 53 | tx_icons[MINIMIZE] = "window-minimize-symbolic"; 54 | tx_icons[MAXIMIZE] = "view-more-symbolic"; 55 | tx_icons[FX_UP] = "go-up-symbolic"; 56 | tx_icons[FX_DOWN] = "go-down-symbolic"; 57 | tx_icons[FX_CLOSE] = "window-close-symbolic"; 58 | tx_icons[ADD_ITEM] = "list-add-symbolic"; 59 | tx_icons[ADD_DRYWET] = "list-add-symbolic"; 60 | tx_icons[REMOVE_DRYWET] = "list-remove-symbolic"; 61 | 62 | GtkCssProvider* provider = gtk_css_provider_new(); 63 | gtk_css_provider_load_from_data(provider, tx_css, -1, NULL); 64 | gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); 65 | } 66 | 67 | GtkWidget* tx_pixmap_widget(tX_icon id) { 68 | return gtk_image_new_from_icon_name(tx_icons[id], GTK_ICON_SIZE_SMALL_TOOLBAR); 69 | } 70 | 71 | GtkWidget* tx_xpm_label_box(tX_icon id, const gchar* label_text, GtkWidget** labelwidget) { 72 | GtkWidget* box1; 73 | GtkWidget* label; 74 | GtkWidget* pixmapwid; 75 | 76 | switch (globals.button_type) { 77 | case BUTTON_TYPE_TEXT: 78 | label = gtk_label_new(label_text); 79 | gtk_widget_show(label); 80 | if (labelwidget != NULL) 81 | *labelwidget = label; 82 | return label; 83 | break; 84 | case BUTTON_TYPE_ICON: 85 | pixmapwid = tx_pixmap_widget(id); 86 | gtk_widget_show(pixmapwid); 87 | return pixmapwid; 88 | break; 89 | default: 90 | box1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); 91 | gtk_container_set_border_width(GTK_CONTAINER(box1), 2); 92 | pixmapwid = tx_pixmap_widget(id); 93 | gtk_box_pack_start(GTK_BOX(box1), pixmapwid, FALSE, FALSE, 0); 94 | gtk_widget_show(pixmapwid); 95 | label = gtk_label_new(label_text); 96 | gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0); 97 | gtk_widget_show(label); 98 | if (labelwidget != NULL) 99 | *labelwidget = label; 100 | return box1; 101 | } 102 | } 103 | 104 | extern GtkWidget* tx_xpm_button_new(tX_icon id, const char* label, int toggle, GtkWidget** labelwidget) { 105 | GtkWidget* box; 106 | GtkWidget* button; 107 | 108 | if (toggle) 109 | button = gtk_toggle_button_new(); 110 | else 111 | button = gtk_button_new(); 112 | 113 | box = tx_xpm_label_box(id, label, labelwidget); 114 | gtk_widget_show(box); 115 | gtk_container_add(GTK_CONTAINER(button), box); 116 | 117 | return button; 118 | } 119 | 120 | GtkWidget* create_top_button(int icon_id) { 121 | GtkWidget* button = gtk_button_new_from_icon_name(tx_icons[icon_id], GTK_ICON_SIZE_SMALL_TOOLBAR); 122 | gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); 123 | gtk_widget_set_margin_end(button, 0); 124 | gtk_container_set_border_width(GTK_CONTAINER(button), 0); 125 | return button; 126 | } 127 | -------------------------------------------------------------------------------- /src/tX_vttfx.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_vttfx.h 19 | 20 | Description: Header to tX_vttfx.cc - see there for more info 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "tX_ladspa.h" 26 | #include "tX_panel.h" 27 | #include "tX_seqpar.h" 28 | #include 29 | #include 30 | #include 31 | 32 | /* Ids to guarantee positioning of builtin */ 33 | #define TX_FX_BUILTINCUTOFF 1 34 | #define TX_FX_BUILTINECHO 2 35 | #define TX_FX_LADSPA 3 36 | 37 | #include 38 | #include 39 | 40 | /* abstract super class vtt_fx */ 41 | 42 | typedef enum { 43 | NOT_DRYWET_CAPABLE, 44 | DRYWET_AVAILABLE, 45 | DRYWET_ACTIVE 46 | } tX_drywet_type; 47 | 48 | class vtt_fx { 49 | protected: 50 | void* vtt; 51 | GtkWidget* panel_widget; 52 | tX_panel* panel; 53 | 54 | public: 55 | vtt_fx() { vtt = NULL; } 56 | virtual ~vtt_fx(); 57 | void set_vtt(void* v) { vtt = v; } 58 | void* get_vtt() { return vtt; } 59 | 60 | virtual void activate() = 0; 61 | virtual void deactivate() = 0; 62 | virtual void run() = 0; 63 | virtual int isEnabled() = 0; 64 | virtual void reconnect_buffer(); 65 | virtual void toggle_drywet(); 66 | virtual bool is_stereo(); 67 | virtual tX_drywet_type has_drywet_feature(); 68 | 69 | virtual const char* get_info_string() = 0; 70 | 71 | virtual void save(FILE* rc, gzFile rz, char* indent) = 0; 72 | 73 | GtkWidget* get_panel_widget() { return panel_widget; } 74 | void set_panel_widget(GtkWidget* widget) { panel_widget = widget; } 75 | 76 | void set_panel(tX_panel* p) { panel = p; } 77 | tX_panel* get_panel() { return panel; } 78 | }; 79 | 80 | /*********************************/ 81 | /* builtin fx */ 82 | 83 | /* lowpass */ 84 | class vtt_fx_lp : public vtt_fx { 85 | public: 86 | virtual void activate(); 87 | virtual void deactivate(); 88 | virtual void run(); 89 | virtual int isEnabled(); 90 | 91 | virtual void save(FILE* rc, gzFile rz, char* indent); 92 | virtual const char* get_info_string(); 93 | }; 94 | 95 | /* echo */ 96 | class vtt_fx_ec : public vtt_fx { 97 | public: 98 | virtual void activate(); 99 | virtual void deactivate(); 100 | virtual void run(); 101 | virtual int isEnabled(); 102 | 103 | virtual void save(FILE* rc, gzFile rz, char* indent); 104 | virtual const char* get_info_string(); 105 | }; 106 | 107 | /********************************/ 108 | /* LADSPA plugin fx */ 109 | 110 | class vtt_fx_ladspa : public vtt_fx { 111 | public: 112 | list controls; 113 | 114 | protected: 115 | tX_seqpar_vttfx* sp_enable; 116 | tX_seqpar_vttfx* sp_wet; 117 | f_prec* wet_buffer; 118 | int input_port, output_port; 119 | LADSPA_Handle* instance; 120 | LADSPA_Plugin* plugin; 121 | 122 | public: 123 | vtt_fx_ladspa(LADSPA_Plugin*, void*); 124 | virtual ~vtt_fx_ladspa(); 125 | 126 | public: 127 | virtual void activate(); 128 | virtual void deactivate(); 129 | virtual void run(); 130 | virtual int isEnabled(); 131 | virtual void reconnect_buffer(); 132 | virtual const char* get_info_string(); 133 | virtual void realloc_drywet(); 134 | virtual void free_drywet(); 135 | virtual void toggle_drywet(); 136 | void add_drywet(); 137 | void remove_drywet(); 138 | virtual tX_drywet_type has_drywet_feature(); 139 | 140 | virtual void save(FILE* rc, gzFile rz, char* indent); 141 | #ifdef ENABLE_TX_LEGACY 142 | virtual void load(FILE*); 143 | #endif 144 | virtual void load(xmlDocPtr, xmlNodePtr); 145 | }; 146 | 147 | class vtt_fx_stereo_ladspa : public vtt_fx_ladspa { 148 | private: 149 | f_prec* wet_buffer2; 150 | int input2_port, output2_port; 151 | 152 | protected: 153 | virtual void reconnect_buffer(); 154 | virtual void realloc_drywet(); 155 | virtual void free_drywet(); 156 | 157 | public: 158 | vtt_fx_stereo_ladspa(LADSPA_Stereo_Plugin*, void*); 159 | virtual bool is_stereo(); 160 | virtual void run(); 161 | virtual ~vtt_fx_stereo_ladspa(); 162 | }; 163 | -------------------------------------------------------------------------------- /data/icons/org.terminatorx.terminatorX.xpm: -------------------------------------------------------------------------------- 1 | /* XPM */ 2 | static char *terminatorX[] = { 3 | /* columns rows colors chars-per-pixel */ 4 | "32 32 127 2", 5 | " c #000000", 6 | ". c #010101", 7 | "X c #020202", 8 | "o c #030303", 9 | "O c #040404", 10 | "+ c #050505", 11 | "@ c #060606", 12 | "# c #070707", 13 | "$ c #080808", 14 | "% c #090909", 15 | "& c #0A0A0A", 16 | "* c #0B0B0B", 17 | "= c #0C0C0C", 18 | "- c #0D0D0D", 19 | "; c #0E0E0E", 20 | ": c #0F0F0F", 21 | "> c #101010", 22 | ", c #111111", 23 | "< c #121212", 24 | "1 c #131313", 25 | "2 c #141414", 26 | "3 c #151515", 27 | "4 c #161616", 28 | "5 c #171717", 29 | "6 c #181818", 30 | "7 c #191919", 31 | "8 c #1A1A1A", 32 | "9 c #1B1B1B", 33 | "0 c #1C1C1C", 34 | "q c #1D1D1D", 35 | "w c #1E1E1E", 36 | "e c #1F1F1F", 37 | "r c #202020", 38 | "t c #212121", 39 | "y c #232323", 40 | "u c #242424", 41 | "i c #252525", 42 | "p c #262626", 43 | "a c #272727", 44 | "s c #282828", 45 | "d c #292929", 46 | "f c #2A2A2A", 47 | "g c #2B2B2B", 48 | "h c #2C2C2C", 49 | "j c #2D2D2D", 50 | "k c #2E2E2E", 51 | "l c #2F2F2F", 52 | "z c #303030", 53 | "x c #323232", 54 | "c c #343434", 55 | "v c #353535", 56 | "b c #363636", 57 | "n c #383838", 58 | "m c #3A3A3A", 59 | "M c #3B3B3B", 60 | "N c #3D3D3D", 61 | "B c #3F3F3F", 62 | "V c #414141", 63 | "C c #434343", 64 | "Z c #444444", 65 | "A c #454545", 66 | "S c #4C4C4C", 67 | "D c #4E4E4E", 68 | "F c #545454", 69 | "G c #555555", 70 | "H c #585858", 71 | "J c #5C5C5C", 72 | "K c #5D5D5D", 73 | "L c #5E5E5E", 74 | "P c #616161", 75 | "I c #616262", 76 | "U c #626262", 77 | "Y c #656565", 78 | "T c #6B6B6B", 79 | "R c #717171", 80 | "E c #727272", 81 | "W c #737373", 82 | "Q c #747474", 83 | "! c #797979", 84 | "~ c #7B7C7C", 85 | "^ c #919090", 86 | "/ c #939393", 87 | "( c #9C9C9C", 88 | ") c #9E9E9E", 89 | "_ c #A1A1A1", 90 | "` c #A5A5A5", 91 | "' c #A6A6A6", 92 | "] c #ABABAB", 93 | "[ c #AEAEAE", 94 | "{ c #B2B2B2", 95 | "} c #B5B5B5", 96 | "| c #BCBCBB", 97 | " . c #C3C3C3", 98 | ".. c #C5C5C5", 99 | "X. c #C7C7C7", 100 | "o. c #C8C8C8", 101 | "O. c #CBCBCB", 102 | "+. c #CCCCCC", 103 | "@. c #D0D0D0", 104 | "#. c #D2D2D2", 105 | "$. c #D8D8D9", 106 | "%. c #DADADA", 107 | "&. c #DDDEDE", 108 | "*. c #E1E0E1", 109 | "=. c #E1E1E1", 110 | "-. c #E4E4E4", 111 | ";. c #E6E6E6", 112 | ":. c #E8E8E8", 113 | ">. c #E8E8E9", 114 | ",. c #EBE9ED", 115 | "<. c #ECEBEC", 116 | "1. c #ECECEC", 117 | "2. c #EFEFF1", 118 | "3. c #F1F0F0", 119 | "4. c #F1F0F1", 120 | "5. c #F1F1F3", 121 | "6. c #F5F4F5", 122 | "7. c #F6F6F6", 123 | "8. c #F6F6F7", 124 | "9. c #F8F7F9", 125 | "0. c #F8F8F8", 126 | "q. c #FAF9F9", 127 | "w. c #FBFBFB", 128 | "e. c #FDFDFD", 129 | "r. c #FEFEFE", 130 | "t. c gray100", 131 | "y. c None", 132 | /* pixels */ 133 | "y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.", 134 | "y.y.y.y.y.y.y.y.y.y.y.y. O O O O y.y.y.y.y.y.y.y.y.y.y.y.y.", 135 | "y.y.y.y.y.y.y.y.y.> > 5 > 5 * : > > > : y.y.y.y.y.y.y.y.y.y.", 136 | "y.y.y.y.y.y.y.: x l 5 * O O O * : * y.y.y.y.y.y.y.y.", 137 | "y.y.y.y.y.y.f U B y 2 * O O * : y.y.y.y.y.y.", 138 | "y.y.y.y.y.y.G G B i > * O o * O y.y.y.y.y.y.", 139 | "y.y.y.y.l J T G n f 8 * o O O y.y.y.y.", 140 | "y.y.y.y.Q R U D V l > * * O y.y.y.y.", 141 | "y.y.y.l G J D D B q > * * y.y.y.", 142 | "y.y.* x Z V Z Z f q 5 * O O y.y.", 143 | "y.y.q l x l c f q 8 5 * * q i 5 * y.y.", 144 | "y.y.f q q q q > > 5 : i ~ | O.[ U 8 * O y.y.", 145 | "y.y.5 > : : * * * * t ) 3.e.e.e.-.R > O O y.y.", 146 | "y.y.> * O O O O U :.q.6.8.e.$.' n O O y.", 147 | "y.O > O O : / 3.3.&...$.} @.J O y.", 148 | "y.O > * / 5.,.*.{ ' @.-.U O O O y.", 149 | "y.y.> U :.q.<.[ o.q.X.n O O o y.", 150 | "y.y.: t _ <.o.O.q.*.E 5 * # O O O O y.", 151 | "y.y.5 O l ! ) ..[ U 0 1 8 > : = # O o O y.", 152 | "y.y.8 : : i l t * : i f a y 2 * # $ * y.y.", 153 | "y.y.* : O > r z V x 9 1 * : # y.y.", 154 | "y.y.y.* * O * 8 c M g t 8 1 : y.y.", 155 | "y.y.y. : O o * 5 i y i i q 8 O y.y.", 156 | "y.y.y.y.O : O : 1 9 q i q * y.y.y.", 157 | "y.y.y.y. O O * : > q q * y.y.y.y.", 158 | "y.y.y.y.y. * * * > 5 O y.y.y.y.", 159 | "y.y.y.y.y.y. * O * O * * O y.y.y.y.y.y.", 160 | "y.y.y.y.y.y.y. * O * O O O * O y.y.y.y.y.y.y.", 161 | "y.y.y.y.y.y.y.y.y. O y.y.y.y.y.y.y.y.", 162 | "y.y.y.y.y.y.y.y.y.y. y.y.y.y.y.y.y.y.y.y.", 163 | "y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.", 164 | "y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y." 165 | }; 166 | -------------------------------------------------------------------------------- /src/tX_ui_callbacks.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | */ 19 | 20 | #include 21 | 22 | #include "tX_dialog.h" 23 | #include "tX_global.h" 24 | #include "tX_maingui.h" 25 | #include "tX_sequencer.h" 26 | #include "tX_ui_callbacks.h" 27 | #include "tX_ui_interface.h" 28 | #include "tX_ui_support.h" 29 | #include 30 | 31 | void on_pref_cancel_clicked(GtkButton* button, 32 | gpointer user_data) { 33 | gtk_widget_destroy(opt_dialog); 34 | } 35 | 36 | void on_pref_apply_clicked(GtkButton* button, 37 | gpointer user_data) { 38 | apply_options(opt_dialog); 39 | } 40 | 41 | void on_pref_ok_clicked(GtkButton* button, 42 | gpointer user_data) { 43 | apply_options(opt_dialog); 44 | gtk_widget_destroy(opt_dialog); 45 | } 46 | 47 | void on_tx_options_destroy(GObject* object, 48 | gpointer user_data) { 49 | opt_dialog = NULL; 50 | } 51 | 52 | void on_alsa_buffer_time_value_changed(GtkRange* range, 53 | gpointer user_data) { 54 | GtkAdjustment* buffer_time = gtk_range_get_adjustment(GTK_RANGE(user_data)); 55 | GtkAdjustment* period_time = gtk_range_get_adjustment(GTK_RANGE(range)); 56 | 57 | gtk_adjustment_set_upper(period_time, gtk_adjustment_get_value(buffer_time)); 58 | } 59 | 60 | void on_pref_reset_clicked(GtkButton* button, 61 | gpointer user_data) { 62 | GtkWidget* dialog = gtk_message_dialog_new(GTK_WINDOW(gtk_widget_get_toplevel(opt_dialog)), 63 | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, 64 | "Loose all your settings and set default values?"); 65 | 66 | int res = gtk_dialog_run(GTK_DIALOG(dialog)); 67 | gtk_widget_destroy(dialog); 68 | 69 | if (res != GTK_RESPONSE_YES) { 70 | return; 71 | } 72 | 73 | set_global_defaults(); 74 | init_tx_options(opt_dialog); 75 | } 76 | 77 | void on_del_mode_cancel_clicked(GtkButton* button, 78 | gpointer user_data) { 79 | gtk_widget_destroy(del_dialog); 80 | del_dialog = NULL; 81 | } 82 | 83 | void on_del_mode_ok_clicked(GtkButton* button, 84 | gpointer user_data) { 85 | tX_sequencer::del_mode mode; 86 | 87 | if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(del_dialog, "all_events")))) { 88 | mode = tX_sequencer::DELETE_ALL; 89 | } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(del_dialog, "upto_current")))) { 90 | mode = tX_sequencer::DELETE_UPTO_CURRENT; 91 | } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(del_dialog, "from_current")))) { 92 | mode = tX_sequencer::DELETE_FROM_CURRENT; 93 | } else { 94 | tX_error("Invalid tX_sequencer::del_mode selected."); 95 | return; 96 | } 97 | 98 | switch (menu_del_mode) { 99 | case ALL_EVENTS_ALL_TURNTABLES: 100 | sequencer.delete_all_events(mode); 101 | break; 102 | case ALL_EVENTS_FOR_TURNTABLE: 103 | sequencer.delete_all_events_for_vtt(del_vtt, mode); 104 | break; 105 | case ALL_EVENTS_FOR_SP: 106 | sequencer.delete_all_events_for_sp(del_sp, mode); 107 | break; 108 | default: 109 | tX_error("Invalid del_mode"); 110 | } 111 | 112 | gtk_widget_destroy(del_dialog); 113 | del_dialog = NULL; 114 | } 115 | 116 | void color_clicked(GtkButton* button, 117 | gpointer user_data) { 118 | GdkRGBA p; 119 | GtkWidget* dialog = create_tX_color_chooser(gtk_widget_get_toplevel(GTK_WIDGET(button))); 120 | GtkWidget* sel = lookup_widget(dialog, "tX_color_chooser"); 121 | g_object_set_data(G_OBJECT(dialog), "Button", button); 122 | 123 | gdk_rgba_parse(&p, (const char*)g_object_get_data(G_OBJECT(button), "Color")); 124 | gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(sel), &p); 125 | gtk_widget_show(dialog); 126 | } 127 | 128 | void color_response(GtkDialog* dialog, gint response_id, gpointer user_data) { 129 | if (response_id == GTK_RESPONSE_OK) { 130 | char tmp[128]; 131 | GtkWidget* c_but = (GtkWidget*)g_object_get_data(G_OBJECT(dialog), "Button"); 132 | char* col = (char*)g_object_get_data(G_OBJECT(c_but), "Color"); 133 | GdkRGBA p; 134 | 135 | gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &p); 136 | sprintf(col, "#%02X%02X%02X", (int)(p.red * 255.0), (int)(p.green * 255.0), (int)(p.blue * 255.0)); 137 | sprintf(tmp, "%s", col, col); 138 | gtk_label_set_markup(GTK_LABEL(gtk_container_get_children(GTK_CONTAINER(c_but))->data), tmp); 139 | } 140 | 141 | gtk_widget_hide(GTK_WIDGET(dialog)); 142 | gtk_widget_destroy(GTK_WIDGET(dialog)); 143 | } 144 | -------------------------------------------------------------------------------- /src/tX_audiodevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_audiodevice.h 19 | 20 | Description: Header to tX_maingui.cc 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "pthread.h" 26 | #include "tX_global.h" 27 | #include "tX_types.h" 28 | #include 29 | 30 | #include 31 | 32 | #define NON_RT_BUFF 12 33 | 34 | #ifdef USE_ALSA 35 | #include 36 | #endif 37 | 38 | #ifdef USE_JACK 39 | #include 40 | #endif 41 | 42 | #ifdef USE_PULSE 43 | #include 44 | #endif 45 | 46 | class tX_engine; 47 | 48 | class tX_audiodevice { 49 | protected: 50 | int samples_per_buffer; 51 | int16_t* sample_buffer[2]; 52 | int current_buffer; 53 | int buffer_pos; 54 | int vtt_buffer_size; 55 | tX_engine* engine; 56 | bool is_open; 57 | 58 | int sample_rate; 59 | tX_audiodevice(); 60 | 61 | public: 62 | int get_buffersize() { return samples_per_buffer; } /* call only valid *after* open() */ 63 | int get_sample_rate() { return sample_rate; } 64 | 65 | virtual int open() = 0; 66 | virtual int close() = 0; 67 | 68 | void fill_buffer(int16_t* target_buffer, int16_t* next_target_buffer); 69 | 70 | bool get_is_open() { return is_open; } 71 | virtual void start(); 72 | virtual void play(int16_t*) = 0; /* play blocked */ 73 | virtual ~tX_audiodevice() {} 74 | }; 75 | 76 | #ifdef USE_OSS 77 | 78 | class tX_audiodevice_oss : public tX_audiodevice { 79 | int fd; 80 | int blocksize; 81 | 82 | public: 83 | virtual int open(); 84 | virtual int close(); 85 | virtual void play(int16_t*); 86 | 87 | tX_audiodevice_oss(); 88 | }; 89 | 90 | #endif 91 | 92 | #ifdef USE_ALSA 93 | 94 | class tX_audiodevice_alsa : public tX_audiodevice { 95 | snd_pcm_t* pcm_handle; 96 | snd_pcm_uframes_t period_size; 97 | 98 | public: 99 | virtual int open(); 100 | virtual int close(); 101 | virtual void play(int16_t*); 102 | 103 | tX_audiodevice_alsa(); 104 | }; 105 | 106 | #endif 107 | 108 | #ifdef USE_PULSE 109 | 110 | class tX_audiodevice_pulse : public tX_audiodevice { 111 | pa_mainloop* mainloop; 112 | pa_mainloop_api* mainloop_api; 113 | pa_context* context; 114 | pa_stream* stream; 115 | int16_t* overrun_buffer; 116 | unsigned int samples_in_overrun_buffer; 117 | 118 | public: 119 | virtual int open(); 120 | virtual int close(); 121 | virtual void start(); 122 | virtual void play(int16_t*); 123 | 124 | tX_audiodevice_pulse(); 125 | ~tX_audiodevice_pulse(); 126 | 127 | private: 128 | // context callbacks 129 | static void wrap_context_state_callback(pa_context* context, void* userdata); 130 | void context_state_callback(pa_context* context); 131 | 132 | static void wrap_context_drain_complete_callback(pa_context* context, void* userdata); 133 | void context_drain_complete_callback(pa_context* context); 134 | 135 | // stream callbacks 136 | static void wrap_stream_started_callback(pa_stream* stream, void* userdata); 137 | void stream_started_callback(pa_stream* stream); 138 | 139 | static void wrap_stream_underflow_callback(pa_stream* stream, void* userdata); 140 | void stream_underflow_callback(pa_stream* stream); 141 | 142 | static void wrap_stream_overflow_callback(pa_stream* stream, void* userdata); 143 | void stream_overflow_callback(pa_stream* stream); 144 | 145 | static void wrap_stream_drain_complete_callback(pa_stream* stream, int success, void* userdata); 146 | void stream_drain_complete_callback(pa_stream* stream, int success); 147 | 148 | static void wrap_stream_trigger_success_callback(pa_stream* stream, int success, void* userdata); 149 | void stream_trigger_success_callback(pa_stream* stream, int success); 150 | 151 | static void wrap_stream_write_callback(pa_stream* stream, size_t length, void* userdata); 152 | void stream_write_callback(pa_stream* stream, size_t length); 153 | }; 154 | 155 | #endif 156 | 157 | #ifdef USE_JACK 158 | 159 | class tX_jack_client; 160 | 161 | class tX_audiodevice_jack : public tX_audiodevice { 162 | private: 163 | tX_jack_client* client; 164 | jack_default_audio_sample_t* overrun_buffer; 165 | unsigned int samples_in_overrun_buffer; 166 | 167 | public: 168 | virtual int open(); 169 | virtual int close(); 170 | virtual void play(int16_t*); 171 | virtual void start(); 172 | void fill_frames(jack_default_audio_sample_t* left, jack_default_audio_sample_t* right, jack_nframes_t nframes); 173 | 174 | tX_audiodevice_jack(); 175 | }; 176 | 177 | class tX_jack_client { 178 | public: 179 | static tX_jack_client* get_instance() { return &instance; }; 180 | bool init(); 181 | ~tX_jack_client(); 182 | 183 | private: 184 | tX_jack_client(); 185 | static tX_jack_client instance; 186 | static void error(const char* desc); 187 | static int srate(jack_nframes_t nframes, void* arg); 188 | static void shutdown(void* arg); 189 | static int process(jack_nframes_t nframes, void* arg); 190 | 191 | jack_client_t* client; 192 | tX_audiodevice_jack* device; 193 | jack_port_t* left_port; 194 | jack_port_t* right_port; 195 | bool jack_shutdown; 196 | bool client_initialized; 197 | int play(jack_nframes_t nframes); 198 | 199 | public: 200 | int get_sample_rate(); 201 | bool get_jack_shutdown() { return jack_shutdown; } 202 | void set_device(tX_audiodevice_jack* dev) { device = dev; } 203 | }; 204 | 205 | #endif 206 | -------------------------------------------------------------------------------- /src/tX_loaddlg.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_loaddlg.cc 19 | 20 | Description: Displays the progress indicator dialog for file 21 | loading. 22 | */ 23 | #include "tX_loaddlg.h" 24 | #include "tX_maingui.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | GtkWidget* ld_loaddlg = (GtkWidget*)NULL; 31 | GtkWidget* ld_single_l = (GtkWidget*)NULL; 32 | GtkWidget* ld_single_p = (GtkWidget*)NULL; 33 | GtkWidget* ld_multi_l = (GtkWidget*)NULL; 34 | GtkWidget* ld_multi_p = (GtkWidget*)NULL; 35 | // GtkWindow *ld_window=(GtkWindow *)NULL; 36 | 37 | int ld_mode; 38 | int ld_count; 39 | int ld_current; 40 | 41 | gfloat ld_old_prog; 42 | 43 | #define WID_DYN TRUE, TRUE, 0 44 | #define WID_FIX FALSE, FALSE, 0 45 | #define add_widget_dyn(wid) \ 46 | ; \ 47 | gtk_box_pack_start(GTK_BOX(vbox), wid, WID_DYN); \ 48 | gtk_widget_show(wid); 49 | 50 | #define add_widget_fix(wid) \ 51 | ; \ 52 | gtk_box_pack_start(GTK_BOX(vbox), wid, WID_FIX); \ 53 | gtk_widget_show(wid); 54 | 55 | #define gtk_flush() \ 56 | ; \ 57 | { \ 58 | int ctr = 0; \ 59 | while (gtk_events_pending()) { \ 60 | ctr++; \ 61 | if (ctr > 5) \ 62 | break; \ 63 | gtk_main_iteration(); \ 64 | gdk_display_flush(gdk_display_get_default()); \ 65 | } \ 66 | } 67 | 68 | int ld_create_loaddlg(int mode, int count) { 69 | GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); 70 | GtkWidget* dummy; 71 | 72 | if (ld_loaddlg) 73 | return 1; 74 | 75 | ld_mode = mode; 76 | ld_count = count; 77 | 78 | ld_loaddlg = gtk_window_new(GTK_WINDOW_TOPLEVEL); 79 | gtk_window_set_position(GTK_WINDOW(ld_loaddlg), GTK_WIN_POS_CENTER_ON_PARENT); 80 | gtk_window_set_title(GTK_WINDOW(ld_loaddlg), "terminatorX - loading"); 81 | gtk_window_set_transient_for(GTK_WINDOW(ld_loaddlg), GTK_WINDOW(main_window)); 82 | 83 | gtk_container_set_border_width(GTK_CONTAINER(ld_loaddlg), 5); 84 | gtk_container_add(GTK_CONTAINER(ld_loaddlg), vbox); 85 | gtk_widget_set_size_request(vbox, 400, -1); 86 | gtk_widget_show(vbox); 87 | 88 | if (mode == TX_LOADDLG_MODE_MULTI) { 89 | ld_multi_l = gtk_label_new("Loading Set"); 90 | add_widget_fix(ld_multi_l); 91 | 92 | ld_multi_p = gtk_progress_bar_new(); 93 | add_widget_fix(ld_multi_p); 94 | 95 | dummy = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); 96 | add_widget_fix(dummy); 97 | 98 | ld_current = 0; 99 | } 100 | 101 | ld_single_l = gtk_label_new("Loading File"); 102 | add_widget_fix(ld_single_l); 103 | 104 | ld_single_p = gtk_progress_bar_new(); 105 | add_widget_fix(ld_single_p); 106 | 107 | gtk_window_set_modal(GTK_WINDOW(ld_loaddlg), TRUE); 108 | gtk_widget_realize(ld_loaddlg); 109 | gdk_window_set_decorations(gtk_widget_get_window(ld_loaddlg), (GdkWMDecoration)0); 110 | gtk_widget_show(ld_loaddlg); 111 | gdk_window_set_cursor(gtk_widget_get_window(ld_loaddlg), tX_cursor::get_cursor()); 112 | 113 | gtk_flush(); 114 | 115 | return 0; 116 | } 117 | 118 | char* strip_path(char* name) { 119 | char* tmp; 120 | 121 | if (!name) 122 | return NULL; 123 | 124 | tmp = strrchr(name, (int)'/'); 125 | 126 | if (tmp) { 127 | if (strlen(tmp) > 1) { 128 | tmp++; 129 | } 130 | } else 131 | tmp = name; 132 | 133 | return tmp; 134 | } 135 | 136 | void ld_set_setname(char* name) { 137 | char* setname; 138 | char buffer[1024]; 139 | 140 | setname = strip_path(name); 141 | sprintf(buffer, "Loading tX-set [%s]", setname); 142 | gtk_label_set_text(GTK_LABEL(ld_multi_l), buffer); 143 | gtk_flush(); 144 | } 145 | 146 | void ld_set_filename(char* name) { 147 | char* filename; 148 | char buffer[1024]; 149 | gfloat setprog; 150 | 151 | ld_current++; 152 | ld_old_prog = -1; 153 | filename = strip_path(name); 154 | if (ld_mode == TX_LOADDLG_MODE_MULTI) { 155 | sprintf(buffer, "Loading file No. %i of %i [%s]", ld_current, ld_count, filename); 156 | } else { 157 | sprintf(buffer, "Loading file [%s]", filename); 158 | } 159 | gtk_label_set_text(GTK_LABEL(ld_single_l), buffer); 160 | 161 | if (ld_mode == TX_LOADDLG_MODE_MULTI) { 162 | setprog = (((float)ld_current) / ((float)ld_count)); 163 | gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ld_multi_p), setprog); 164 | gtk_flush(); 165 | } 166 | gtk_flush(); 167 | } 168 | 169 | void ld_set_progress(gfloat progress) { 170 | progress = floor(progress * 200.0) / 200.0; 171 | if (progress > 1.0) 172 | progress = 1.0; 173 | 174 | if (progress != ld_old_prog) { 175 | gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ld_single_p), progress); 176 | gtk_flush(); 177 | } 178 | 179 | ld_old_prog = progress; 180 | } 181 | 182 | void ld_destroy() { 183 | if (ld_loaddlg) { 184 | gtk_widget_hide(ld_loaddlg); 185 | gtk_widget_destroy(ld_loaddlg); 186 | } 187 | 188 | ld_loaddlg = NULL; 189 | mg_update_status(); 190 | } 191 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('terminatorX', 2 | ['c', 'cpp'], 3 | version : '4.2.1', 4 | license: 'GPL2+', 5 | default_options: [ 6 | 'buildtype=debugoptimized' 7 | ] 8 | ) 9 | 10 | gnome = import('gnome') 11 | cc = meson.get_compiler('c') 12 | cpp = meson.get_compiler('cpp') 13 | 14 | src = [ 15 | 'src/main.cc', 16 | 'src/tX_audiodevice.cc', 17 | 'src/tX_audiofile.cc', 18 | 'src/tX_capabilities.cc', 19 | 'src/tX_dial.c', 20 | 'src/tX_dialog.cc', 21 | 'src/tX_endian.c', 22 | 'src/tX_engine.cc', 23 | 'src/tX_event.cc', 24 | 'src/tX_extdial.cc', 25 | 'src/tX_flash.c', 26 | 'src/tX_global.c', 27 | 'src/tX_knobloader.c', 28 | 'src/tX_ladspa.cc', 29 | 'src/tX_ladspa_class.cc', 30 | 'src/tX_legacy_global.c', 31 | 'src/tX_legacy_vtt.cc', 32 | 'src/tX_loaddlg.cc', 33 | 'src/tX_maingui.cc', 34 | 'src/tX_midiin.cc', 35 | 'src/tX_mouse.cc', 36 | 'src/tX_panel.cc', 37 | 'src/tX_pbutton.cc', 38 | 'src/tX_prelis.cc', 39 | 'src/tX_seqpar.cc', 40 | 'src/tX_sequencer.cc', 41 | 'src/tX_tape.cc', 42 | 'src/tX_ui_callbacks.cc', 43 | 'src/tX_ui_interface.cc', 44 | 'src/tX_ui_support.cc', 45 | 'src/tX_vtt.cc', 46 | 'src/tX_vttfx.cc', 47 | 'src/tX_vttgui.cc', 48 | 'src/tX_widget.c', 49 | 'src/wav_read.c', 50 | 'src/wav_write.c' 51 | ] 52 | 53 | hdr = [ 54 | 'src/tX_audiodevice.h', 55 | 'src/tX_audiofile.h', 56 | 'src/tX_capabilities.h', 57 | 'src/tX_dial.h', 58 | 'src/tX_dialog.h', 59 | 'src/tX_endian.h', 60 | 'src/tX_engine.h', 61 | 'src/tX_event.h', 62 | 'src/tX_extdial.h', 63 | 'src/tX_flash.h', 64 | 'src/tX_global.h', 65 | 'src/tX_knobloader.h', 66 | 'src/tX_ladspa_class.h', 67 | 'src/tX_ladspa.h', 68 | 'src/tX_loaddlg.h', 69 | 'src/tX_maingui.h', 70 | 'src/tX_midiin.h', 71 | 'src/tX_mouse.h', 72 | 'src/tX_panel.h', 73 | 'src/tX_pbutton.h', 74 | 'src/tX_prelis.h', 75 | 'src/tX_seqpar.h', 76 | 'src/tX_sequencer.h', 77 | 'src/tX_tape.h', 78 | 'src/tX_types.h', 79 | 'src/tX_ui_callbacks.h', 80 | 'src/tX_ui_interface.h', 81 | 'src/tX_ui_support.h', 82 | 'src/tX_vttfx.h', 83 | 'src/tX_vttgui.h', 84 | 'src/tX_vtt.h', 85 | 'src/tX_widget.h', 86 | 'src/wav_file.h' 87 | ] 88 | 89 | includes = include_directories('src') 90 | 91 | xxd = find_program('xxd') 92 | copying_src = custom_target('license header', 93 | input: ['COPYING'], 94 | output: ['copying.h'], 95 | command: [xxd, '-i', '@INPUT@', '@OUTPUT@']) 96 | 97 | tX_knob_src = gnome.compile_resources( 98 | 'tX_knob_resource', 'src/icons/tX_knob.gresource.xml', 99 | source_dir: 'src/icons', 100 | c_name: 'tX_knob' 101 | ) 102 | 103 | tX_dialog_src = gnome.compile_resources( 104 | 'tX_dialog_resource', 'src/icons/tX_dialog.gresource.xml', 105 | source_dir: 'src/icons', 106 | c_name: 'tX_dialog' 107 | ) 108 | 109 | gtk_dep = dependency('gtk+-3.0', version : '>= 3.0', required: true) 110 | xml_dep = dependency('libxml-2.0', version : '>= 2.3.9', required: true) 111 | z_dep = dependency('zlib', version: '>= 1.2', required: true) 112 | threads_dep = dependency('threads') 113 | dl_dep = cc.find_library('dl', required : false) 114 | m_dep = cc.find_library('m', required : false) 115 | mad_dep = dependency('mad', version : '>= 0.15', required: get_option('mad')) 116 | vorbis_dep = dependency('vorbis', version : '>= 1.3', required: get_option('vorbis')) 117 | vorbisfile_dep = dependency('vorbisfile', version : '>= 1.3', required: get_option('vorbis')) 118 | audiofile_dep = dependency('audiofile', version : '>= 0.3', required: get_option('audiofile')) 119 | alsa_dep = dependency('alsa', version : '>= 1.2', required: get_option('alsa')) 120 | jack_dep = dependency('jack', version : '>= 0.120', required: get_option('jack')) 121 | pulse_dep = dependency('libpulse', version : '>= 15', required: get_option('pulse')) 122 | x11_dep = dependency('x11', version : '>= 1.7', required: get_option('x11')) 123 | cap_dep = dependency('libcap', version : '>= 2', required: get_option('capabilities')) 124 | lrdf_dep = dependency('lrdf', version : '>= 0.2.4', required: get_option('lrdf')) 125 | deps = [ gtk_dep, xml_dep, z_dep, threads_dep, dl_dep, mad_dep, vorbis_dep, vorbisfile_dep, audiofile_dep, alsa_dep, jack_dep, pulse_dep, x11_dep, cap_dep, lrdf_dep ] 126 | 127 | ladspa = cc.has_header('ladspa.h', required: true) 128 | 129 | if cc.has_argument('-finput-charset=utf-8') 130 | add_global_arguments('-finput-charset=utf-8', language: 'cpp') 131 | endif 132 | 133 | config = configuration_data() 134 | config.set('VERSION', '"'+meson.project_version()+'"') 135 | 136 | config.set('PACKAGE', '"'+meson.project_name()+'"') 137 | config.set('USE_STARTUP_NOTIFICATION', true) 138 | 139 | if host_machine.endian() == 'big' 140 | config.set('WORDS_BIGENDIAN', true) 141 | endif 142 | 143 | sox = find_program('sox', required: get_option('sox')) 144 | if sox.found() 145 | config.set('USE_SOX_INPUT', true) 146 | endif 147 | 148 | mpg123 = find_program('mpg123', required: get_option('mpg123')) 149 | if mpg123.found() and sox.found() 150 | config.set('USE_MPG123_INPUT', true) 151 | endif 152 | 153 | ogg123 = find_program('ogg123', required: get_option('ogg123')) 154 | if ogg123.found() 155 | config.set('USE_OGG123_INPUT', true) 156 | endif 157 | 158 | if mad_dep.found() 159 | config.set('USE_MAD_INPUT', true) 160 | endif 161 | 162 | if vorbis_dep.found() and vorbisfile_dep.found() 163 | config.set('USE_VORBIS_INPUT', true) 164 | endif 165 | 166 | if audiofile_dep.found() 167 | config.set('USE_AUDIOFILE_INPUT', true) 168 | endif 169 | 170 | if alsa_dep.found() 171 | config.set('USE_ALSA', true) 172 | config.set('USE_ALSA_MIDI_IN', true) 173 | endif 174 | 175 | if jack_dep.found() 176 | config.set('USE_JACK', true) 177 | endif 178 | 179 | if pulse_dep.found() 180 | config.set('USE_PULSE', true) 181 | endif 182 | 183 | oss_dep = cc.has_header('sys/soundcard.h', required: false) 184 | if oss_dep 185 | config.set('USE_OSS', true) 186 | endif 187 | 188 | if x11_dep.found() 189 | config.set('USE_X11', true) 190 | endif 191 | 192 | if cap_dep.found() 193 | config.set('USE_CAPABILITIES', true) 194 | endif 195 | 196 | if lrdf_dep.found() 197 | config.set('USE_LRDF', true) 198 | endif 199 | 200 | if not get_option('scheduler').disabled() 201 | config.set('USE_SCHEDULER', true) 202 | endif 203 | 204 | if not get_option('tX_debug').disabled() 205 | config.set('ENABLE_DEBUG_OUTPUT', true) 206 | endif 207 | 208 | if get_option('deprecated').enabled() 209 | add_global_arguments('-DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DG_DISABLE_DEPRECATED', language: 'c') 210 | endif 211 | 212 | if not get_option('wav').disabled() 213 | config.set('USE_BUILTIN_WAV', true) 214 | endif 215 | 216 | if get_option('legacy').enabled() 217 | config.set('ENABLE_TX_LEGACY', true) 218 | endif 219 | 220 | tX_mode = [ 'rwxr-xr-x' ] 221 | if not get_option('suidroot').disabled() 222 | tX_mode = [ 'rwSr-xr-x', 'root' ] 223 | endif 224 | 225 | assert(alsa_dep.found() or jack_dep.found() or pulse_dep.found() or oss_dep, 'no supported audio driver found') 226 | 227 | configure_file(output : 'config.h', 228 | configuration : config) 229 | 230 | executable(meson.project_name(), 231 | src, 232 | copying_src, 233 | tX_knob_src, 234 | tX_dialog_src, 235 | include_directories: includes, 236 | dependencies: deps, 237 | install: true, 238 | install_mode: tX_mode 239 | ) 240 | 241 | clang_format = find_program('clang-format', required: false) 242 | if clang_format.found() 243 | test('Validating coding style', clang_format, 244 | args: ['--dry-run', '-Werror'] + src + hdr, 245 | workdir: meson.project_source_root()) 246 | endif 247 | 248 | # docs and supporting files 249 | 250 | doc_config = configuration_data() 251 | doc_config.set('VERSION', meson.project_version()) 252 | 253 | # RPM spec file 254 | 255 | spec_file = configure_file(input: 'terminatorX.spec.in', 256 | output: 'terminatorX.spec', 257 | configuration: doc_config 258 | ) 259 | 260 | # GNOME help and manpage 261 | 262 | subdir('help') 263 | 264 | # data 265 | 266 | subdir('data') 267 | -------------------------------------------------------------------------------- /src/tX_panel.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | */ 19 | 20 | #include "tX_panel.h" 21 | #include "tX_maingui.h" 22 | #include "tX_pbutton.h" 23 | #include "tX_vtt.h" 24 | #include "tX_vttfx.h" 25 | #include 26 | #include 27 | 28 | #define WID_DYN TRUE, TRUE, 0 29 | #define WID_FIX FALSE, FALSE, 0 30 | 31 | // workaround GtkEntry not having target set to const for some reason 32 | static gchar entries_type[] = "GTK_LIST_BOX_ROW"; 33 | static const GtkTargetEntry entries[] = { { entries_type, GTK_TARGET_SAME_APP, 0 } }; 34 | 35 | static vtt_fx* dragged_effect = NULL; 36 | static GtkWidget* dragged_list_box = NULL; 37 | 38 | void panel_begin_drag(GtkWidget* widget, GdkDragContext* context, gpointer data) { 39 | dragged_effect = (vtt_fx*)data; 40 | 41 | GtkWidget* row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW); 42 | dragged_list_box = gtk_widget_get_ancestor(row, GTK_TYPE_LIST_BOX); 43 | GtkAllocation allocation; 44 | gtk_widget_get_allocation(row, &allocation); 45 | cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height); 46 | cairo_t* cr = cairo_create(surface); 47 | 48 | gtk_style_context_add_class(gtk_widget_get_style_context(row), "dragging"); 49 | gtk_widget_draw(row, cr); 50 | gtk_style_context_remove_class(gtk_widget_get_style_context(row), "dragging"); 51 | 52 | int x, y; 53 | gtk_widget_translate_coordinates(widget, row, 0, 0, &x, &y); 54 | cairo_surface_set_device_offset(surface, -x, -y); 55 | gtk_drag_set_icon_surface(context, surface); 56 | 57 | cairo_destroy(cr); 58 | cairo_surface_destroy(surface); 59 | } 60 | 61 | void panel_get_drag_data(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selection_data, guint info, guint time, gpointer data) { 62 | gtk_selection_data_set(selection_data, gdk_atom_intern_static_string("GTK_LIST_BOX_ROW"), 32, (const guchar*)&widget, sizeof(gpointer)); 63 | } 64 | 65 | void panel_receive_drag_data(GtkWidget* widget, GdkDragContext* context, gint x, gint y, GtkSelectionData* selection_data, guint info, guint32 time, gpointer data) { 66 | int pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(widget)); 67 | GtkWidget* list_box = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX); 68 | GtkWidget* row = GTK_WIDGET((gpointer) * (gpointer*)gtk_selection_data_get_data(selection_data)); 69 | GtkWidget* source = gtk_widget_get_ancestor(row, GTK_TYPE_LIST_BOX_ROW); 70 | 71 | if (list_box == dragged_list_box) { 72 | if (source != widget) { 73 | g_object_ref(source); 74 | gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(source)), source); 75 | gtk_list_box_insert(GTK_LIST_BOX(gtk_widget_get_parent(widget)), source, pos); 76 | if (dragged_effect) { 77 | vtt_class* vtt = (vtt_class*)dragged_effect->get_vtt(); 78 | vtt->effect_move(dragged_effect, pos); 79 | } 80 | g_object_unref(source); 81 | } 82 | } else { 83 | tx_note("Effects can be reordered within the\nsame FX or Stereo FX queue only."); 84 | } 85 | dragged_effect = NULL; 86 | dragged_list_box = NULL; 87 | } 88 | 89 | void tX_panel ::minimize(GtkWidget* w, tX_panel* p) { 90 | if (!p->client_hidden) { 91 | gtk_widget_hide(p->minimize_button); 92 | gtk_widget_show(p->maximize_button); 93 | gtk_widget_hide(p->clientframe); 94 | p->client_hidden = 1; 95 | } else { 96 | gtk_widget_hide(p->maximize_button); 97 | gtk_widget_show(p->minimize_button); 98 | gtk_widget_show(p->clientframe); 99 | p->client_hidden = 0; 100 | } 101 | 102 | if (p->controlbox) { 103 | gtk_widget_queue_draw(p->controlbox); 104 | } 105 | } 106 | 107 | void tX_panel_make_label_bold(GtkWidget* widget) { 108 | char label[4096]; 109 | snprintf(label, sizeof(label), "%s", gtk_label_get_text(GTK_LABEL(widget))); 110 | gtk_label_set_markup(GTK_LABEL(widget), label); 111 | } 112 | 113 | void tX_panel_make_tooltip(GtkWidget* widget, vtt_fx* effect) { 114 | char label[4096]; 115 | snprintf(label, sizeof(label), "%s\n\nDrag this handle to reorder effects queue.", effect->get_info_string()); 116 | gtk_widget_set_tooltip_text(widget, label); 117 | } 118 | 119 | tX_panel ::tX_panel(const char* name, GtkWidget* controlbox, GCallback close_callback, vtt_fx* effect) { 120 | client_hidden = 0; 121 | this->controlbox = controlbox; 122 | add_drywet_button = NULL; 123 | remove_drywet_button = NULL; 124 | 125 | list_box_row = gtk_list_box_row_new(); 126 | 127 | drag_handle = gtk_event_box_new(); 128 | 129 | labelbutton = gtk_label_new(name); 130 | gtk_widget_set_halign(labelbutton, GTK_ALIGN_START); 131 | tX_panel_make_label_bold(labelbutton); 132 | gtk_container_add(GTK_CONTAINER(drag_handle), labelbutton); 133 | 134 | topbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); 135 | g_object_set(topbox, "margin-start", 10, "margin-end", 0, "border-width", 0, NULL); 136 | gtk_container_add_with_properties(GTK_CONTAINER(topbox), drag_handle, "expand", TRUE, NULL); 137 | 138 | minimize_button = create_top_button(MINIMIZE); 139 | gtk_container_add(GTK_CONTAINER(topbox), minimize_button); 140 | maximize_button = create_top_button(MAXIMIZE); 141 | gtk_container_add(GTK_CONTAINER(topbox), maximize_button); 142 | 143 | if (close_callback) { 144 | close_button = create_top_button(FX_CLOSE); 145 | gtk_widget_set_name(close_button, "close"); 146 | g_object_set(close_button, "border-width", 0, NULL); 147 | gtk_container_add(GTK_CONTAINER(topbox), close_button); 148 | } else { 149 | close_button = NULL; 150 | } 151 | 152 | gtk_container_set_border_width(GTK_CONTAINER(topbox), 0); 153 | 154 | mainbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); 155 | gtk_container_add(GTK_CONTAINER(list_box_row), mainbox); 156 | 157 | clientbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); 158 | clientframe = gtk_frame_new((char*)NULL); 159 | gtk_container_set_border_width(GTK_CONTAINER(clientframe), 0); 160 | gtk_container_add(GTK_CONTAINER(clientframe), clientbox); 161 | 162 | gtk_box_pack_start(GTK_BOX(mainbox), topbox, WID_FIX); 163 | gtk_box_pack_start(GTK_BOX(mainbox), clientframe, WID_FIX); 164 | 165 | gtk_widget_show(labelbutton); 166 | gtk_widget_show(minimize_button); 167 | gtk_widget_show(topbox); 168 | gtk_widget_show(clientbox); 169 | gtk_widget_show(clientframe); 170 | gtk_widget_show(mainbox); 171 | gtk_widget_show(list_box_row); 172 | gtk_widget_show(drag_handle); 173 | 174 | if (close_callback) { 175 | gtk_widget_show(close_button); 176 | g_signal_connect(G_OBJECT(close_button), "clicked", (GCallback)close_callback, (gpointer)effect); 177 | } 178 | 179 | if (effect) { 180 | tX_panel_make_tooltip(drag_handle, effect); 181 | 182 | if (effect->has_drywet_feature() != NOT_DRYWET_CAPABLE) { 183 | add_drywet_button = create_top_button(ADD_DRYWET); 184 | remove_drywet_button = create_top_button(REMOVE_DRYWET); 185 | } 186 | 187 | gtk_drag_source_set(drag_handle, GDK_BUTTON1_MASK, entries, 1, GDK_ACTION_MOVE); 188 | g_signal_connect(drag_handle, "drag-begin", G_CALLBACK(panel_begin_drag), effect); 189 | g_signal_connect(drag_handle, "drag-data-get", G_CALLBACK(panel_get_drag_data), NULL); 190 | 191 | gtk_drag_dest_set(list_box_row, GTK_DEST_DEFAULT_ALL, entries, 1, GDK_ACTION_MOVE); 192 | g_signal_connect(list_box_row, "drag-data-received", G_CALLBACK(panel_receive_drag_data), (gpointer)effect); 193 | } 194 | 195 | g_signal_connect(G_OBJECT(minimize_button), "clicked", (GCallback)tX_panel::minimize, (void*)this); 196 | g_signal_connect(G_OBJECT(maximize_button), "clicked", (GCallback)tX_panel::minimize, (void*)this); 197 | } 198 | 199 | void tX_panel ::add_client_widget(GtkWidget* w) { 200 | gtk_box_pack_start(GTK_BOX(clientbox), w, WID_FIX); 201 | gtk_widget_show(w); 202 | } 203 | 204 | tX_panel ::~tX_panel() { 205 | gtk_widget_destroy(clientbox); 206 | gtk_widget_destroy(clientframe); 207 | gtk_widget_destroy(topbox); 208 | gtk_widget_destroy(mainbox); 209 | } 210 | -------------------------------------------------------------------------------- /src/tX_ladspa.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_ladspa.cc 19 | 20 | Description: LADSPA_Plugin takes care of loading LADSPA plugins. 21 | Most of this code is based on the LADSPA SDK code by 22 | Richard W.E. Furse. For more information about ladspa 23 | checkout http://www.ladspa.org 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | std::list LADSPA_Plugin ::plugin_list; 35 | std::list LADSPA_Stereo_Plugin ::stereo_plugin_list; 36 | 37 | void LADSPA_Plugin ::init() { 38 | char* ladspa_path_ptr; 39 | char ladspa_path[PATH_MAX]; 40 | char *start, *end, *buffer; 41 | 42 | /* Finding the LADSPA Path */ 43 | ladspa_path_ptr = getenv("LADSPA_PATH"); 44 | 45 | if (!ladspa_path_ptr) { 46 | tX_warning("LADSPA_PATH not set. Trying /usr/lib/ladspa:/usr/local/lib/ladspa"); 47 | strcpy(ladspa_path, "/usr/lib/ladspa:/usr/local/lib/ladspa"); 48 | } else 49 | strncpy(ladspa_path, ladspa_path_ptr, sizeof(ladspa_path) - 1); 50 | 51 | /* Scanning every dir in path */ 52 | start = ladspa_path; 53 | 54 | while (*start != '\0') { 55 | end = start; 56 | while (*end != ':' && *end != '\0') 57 | end++; 58 | 59 | buffer = (char*)malloc(1 + end - start); 60 | if (end > start) 61 | strncpy(buffer, start, end - start); 62 | 63 | buffer[end - start] = '\0'; 64 | LADSPA_Plugin::scandir(buffer); 65 | free(buffer); 66 | 67 | start = end; 68 | if (*start == ':') 69 | start++; 70 | } 71 | } 72 | 73 | /* This routine expects to get *valid* port descriptors. 74 | There's no error checking as in the LADSPA SDK's "analyseplugin". 75 | */ 76 | 77 | void LADSPA_Plugin ::handlelib(void* lib, LADSPA_Descriptor_Function desc_func, char* filename) { 78 | long i; 79 | unsigned long port; 80 | const LADSPA_Descriptor* descriptor; 81 | int in_audio, out_audio, in_ctrl; 82 | 83 | for (i = 0; (descriptor = desc_func(i)) != NULL; i++) { 84 | if (LADSPA_IS_INPLACE_BROKEN(descriptor->Properties)) { 85 | tX_plugin_warning("Plugin \"%s\" [%li] disabled: No in-place processing support.", descriptor->Label, descriptor->UniqueID); 86 | } else if (!LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties) && !globals.force_nonrt_plugins) { 87 | tX_plugin_warning("Plugin \"%s\" [%li] disabled: Not realtime capable.", descriptor->Label, descriptor->UniqueID); 88 | } else { 89 | if (!LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties)) { 90 | tX_warning("Plugin \"%s\" [%li] is classified as non-rt capable: loading forced.", descriptor->Label, descriptor->UniqueID); 91 | } 92 | in_audio = 0; 93 | out_audio = 0; 94 | in_ctrl = 0; 95 | 96 | for (port = 0; port < descriptor->PortCount; port++) { 97 | if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[port])) { 98 | if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port])) 99 | in_audio++; 100 | else if (LADSPA_IS_PORT_OUTPUT(descriptor->PortDescriptors[port])) 101 | out_audio++; 102 | } else if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[port]) && LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port])) 103 | in_ctrl++; 104 | } 105 | 106 | if ((in_audio == 1) && (out_audio == 1)) { 107 | new LADSPA_Plugin(descriptor, filename); 108 | } 109 | if ((in_audio == 2) && (out_audio == 2)) { 110 | new LADSPA_Stereo_Plugin(descriptor, filename); 111 | } else { 112 | tX_plugin_warning("Plugin \"%s\" [%li] disabled: Neither mono nor stereo.", descriptor->Label, descriptor->UniqueID); 113 | } 114 | } 115 | } 116 | } 117 | 118 | void LADSPA_Plugin ::scandir(char* dirname) { 119 | int dirlen = strlen(dirname); 120 | int needslash = 0; 121 | DIR* dir; 122 | struct dirent* entry; 123 | char* filename; 124 | void* handle; 125 | LADSPA_Descriptor_Function desc_func; 126 | 127 | if (!dirlen) { 128 | tX_error("empty directory name?"); 129 | return; 130 | }; 131 | 132 | if (dirname[dirlen - 1] != '/') 133 | needslash = 1; 134 | 135 | dir = opendir(dirname); 136 | 137 | if (!dir) { 138 | tX_error("couldn't access directory \"%s\".", dirname); 139 | return; 140 | }; 141 | 142 | while (1) { 143 | entry = readdir(dir); 144 | if (!entry) { 145 | closedir(dir); 146 | return; 147 | } 148 | 149 | filename = (char*)malloc(dirlen + strlen(entry->d_name) + 1 + needslash); 150 | 151 | strcpy(filename, dirname); 152 | if (needslash) 153 | strcat(filename, "/"); 154 | strcat(filename, entry->d_name); 155 | 156 | handle = dlopen(filename, RTLD_LAZY); 157 | 158 | if (handle) { 159 | /* clear dlerror */ 160 | dlerror(); 161 | 162 | /* check wether this is a LADSPA lib */ 163 | desc_func = (LADSPA_Descriptor_Function)dlsym(handle, "ladspa_descriptor"); 164 | 165 | if (dlerror() == NULL && desc_func) { 166 | LADSPA_Plugin ::handlelib(handle, desc_func, entry->d_name); 167 | } else { 168 | tX_error("\"%s\" is not a LADSPA plugin library.", filename); 169 | dlclose(handle); 170 | } 171 | } 172 | 173 | free(filename); 174 | } 175 | } 176 | 177 | void LADSPA_Plugin ::status() { 178 | debug_display(); 179 | } 180 | 181 | void LADSPA_Plugin ::debug_display() { 182 | std::list::iterator plugin; 183 | 184 | for (plugin = plugin_list.begin(); plugin != plugin_list.end(); plugin++) { 185 | printf("plugin: %60s | id: %5li | ports: %2li\n", (*plugin)->getName(), (*plugin)->getUniqueID(), (*plugin)->getPortCount()); 186 | } 187 | } 188 | 189 | LADSPA_Plugin ::LADSPA_Plugin(const LADSPA_Descriptor* ld, char* filename) { 190 | ladspa_descriptor = ld; 191 | 192 | plugin_list.push_back(this); 193 | strcpy(file, filename); 194 | sprintf(info_string, "LADSPA-Plugin: %s\nLabel: %s\nFile: %s\nUnique ID: %li\nMaker: %s\nCopyright: %s", ld->Name, ld->Label, file, ld->UniqueID, ld->Maker, ld->Copyright); 195 | LADSPA_Class::add_plugin(this); 196 | } 197 | 198 | LADSPA_Plugin* LADSPA_Plugin ::getPluginByIndex(int i) { 199 | std::list::iterator plugin; 200 | int p; 201 | 202 | plugin = plugin_list.begin(); 203 | for (p = 0; (p < i) && (plugin != plugin_list.end()); p++, plugin++) 204 | ; 205 | 206 | if (plugin == plugin_list.end()) 207 | return NULL; 208 | 209 | else 210 | return *plugin; 211 | } 212 | 213 | LADSPA_Plugin* LADSPA_Plugin ::getPluginByUniqueID(long ID) { 214 | std::list::iterator plugin; 215 | 216 | for (plugin = plugin_list.begin(); plugin != plugin_list.end(); plugin++) { 217 | if ((*plugin)->getUniqueID() == ID) 218 | return *plugin; 219 | } 220 | 221 | return NULL; 222 | } 223 | 224 | /* STEREO */ 225 | 226 | LADSPA_Stereo_Plugin ::LADSPA_Stereo_Plugin(const LADSPA_Descriptor* ld, char* filename) { 227 | ladspa_descriptor = ld; 228 | 229 | stereo_plugin_list.push_back(this); 230 | strcpy(file, filename); 231 | sprintf(info_string, "LADSPA-Stereo-Plugin: %s\nLabel: %s\nFile: %s\nUnique ID: %li\nMaker: %s\nCopyright: %s", ld->Name, ld->Label, file, ld->UniqueID, ld->Maker, ld->Copyright); 232 | LADSPA_Class::add_stereo_plugin(this); 233 | } 234 | 235 | LADSPA_Stereo_Plugin* LADSPA_Stereo_Plugin ::getPluginByIndex(int i) { 236 | std::list::iterator plugin; 237 | int p; 238 | 239 | plugin = stereo_plugin_list.begin(); 240 | for (p = 0; (p < i) && (plugin != stereo_plugin_list.end()); p++, plugin++) 241 | ; 242 | 243 | if (plugin == stereo_plugin_list.end()) 244 | return NULL; 245 | 246 | else 247 | return *plugin; 248 | } 249 | 250 | LADSPA_Stereo_Plugin* LADSPA_Stereo_Plugin ::getPluginByUniqueID(long ID) { 251 | std::list::iterator plugin; 252 | 253 | for (plugin = stereo_plugin_list.begin(); plugin != stereo_plugin_list.end(); plugin++) { 254 | if ((*plugin)->getUniqueID() == ID) 255 | return *plugin; 256 | } 257 | 258 | return NULL; 259 | } 260 | 261 | bool LADSPA_Stereo_Plugin::is_stereo() { return true; } 262 | bool LADSPA_Plugin::is_stereo() { return false; } 263 | -------------------------------------------------------------------------------- /terminatorX.spec.in: -------------------------------------------------------------------------------- 1 | Summary: Real-time Audio Synthesizer 2 | Name: terminatorX 3 | Version: @VERSION@ 4 | Release: 1%{?dist} 5 | Group: Applications/Multimedia 6 | License: GPLv2+ and GFDL 7 | URL: http://terminatorx.org/ 8 | Source0: http://terminatorx.org/dist/%{name}-%{version}.tar.xz 9 | 10 | BuildRequires: alsa-lib-devel 11 | BuildRequires: audiofile-devel 12 | BuildRequires: desktop-file-utils 13 | BuildRequires: libappstream-glib 14 | BuildRequires: gcc-c++ 15 | BuildRequires: gtk3-devel 16 | BuildRequires: itstool 17 | BuildRequires: jack-audio-connection-kit-devel 18 | BuildRequires: ladspa-devel 19 | BuildRequires: libcap-devel 20 | BuildRequires: liblrdf-devel 21 | BuildRequires: libmad-devel 22 | BuildRequires: libvorbis-devel 23 | BuildRequires: libxml2-devel 24 | BuildRequires: libX11-devel 25 | BuildRequires: mpg123 26 | BuildRequires: pulseaudio-libs-devel 27 | BuildRequires: sox 28 | BuildRequires: vorbis-tools 29 | BuildRequires: meson 30 | BuildRequires: ninja-build 31 | BuildRequires: xxd 32 | 33 | Requires: hicolor-icon-theme 34 | Requires: mpg123 35 | Requires: sox 36 | Requires: vorbis-tools 37 | 38 | %define fqn org.terminatorx.terminatorX 39 | 40 | %description 41 | terminatorX is a real-time audio synthesizer that allows you to "scratch" on 42 | digitally sampled audio data (*.wav, *.au, *.ogg, *.mp3, etc.) the way 43 | hiphop-DJs scratch on vinyl records. It features multiple turntables, real-time 44 | effects (buit-in as well as LADSPA plug-in effects), a sequencer and MIDI 45 | interface - all accessible through an easy-to-use gtk+ GUI. 46 | 47 | %prep 48 | %setup -q 49 | 50 | # Fix Ladspa path 51 | sed -i 's|/lib/|/%{_lib}/|g' src/tX_ladspa.cc 52 | 53 | %build 54 | %meson 55 | %meson_build 56 | 57 | %install 58 | %meson_install 59 | 60 | # desktop file categories 61 | ADD="Audio X-Jack X-DJTools X-DigitalProcessing Sequencer" 62 | REMOVE="Application" 63 | desktop-file-install \ 64 | --dir %{buildroot}%{_datadir}/applications \ 65 | `for c in ${ADD} ; do echo "--add-category $c " ; done` \ 66 | `for c in ${REMOVE} ; do echo "--remove-category $c " ; done` \ 67 | %{buildroot}%{_datadir}/applications/%{fqn}.desktop 68 | 69 | appstream-util validate-relax --nonet %{buildroot}/%{_datadir}/metainfo/%{fqn}.metainfo.xml 70 | 71 | %files 72 | %doc AUTHORS.md README* 73 | %license COPYING* 74 | %{_bindir}/%{name} 75 | %{_mandir}/man1/%{name}.1* 76 | %{_datadir}/help/C/%{name}-manual/ 77 | %{_datadir}/pixmaps/%{fqn}.xpm 78 | %{_datadir}/icons/hicolor/512x512/apps/%{fqn}.png 79 | %{_datadir}/icons/hicolor/512x512/mimetypes/%{fqn}.Set.png 80 | %{_datadir}/applications/%{fqn}.desktop 81 | %{_datadir}/mime/packages/%{fqn}-mime.xml 82 | %{_datadir}/metainfo/%{fqn}.metainfo.xml 83 | 84 | %changelog 85 | * Fri Apr 05 2024 Alexander Koenig 86 | - Merge RPM Fusion downstream 87 | - Adapt to meson build 88 | 89 | * Sun Feb 04 2024 RPM Fusion Release Engineering - 4.2.0-3 90 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild 91 | 92 | * Wed Aug 02 2023 RPM Fusion Release Engineering - 4.2.0-2 93 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild 94 | 95 | * Sat Oct 01 2022 Leigh Scott - 4.2.0-1 96 | - Update to 4.2.0 97 | 98 | * Mon Aug 08 2022 RPM Fusion Release Engineering - 4.1.0-3 99 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild and ffmpeg 100 | 5.1 101 | 102 | * Wed Feb 09 2022 RPM Fusion Release Engineering - 4.1.0-2 103 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild 104 | 105 | * Sat Oct 30 2021 Orcan Ogetbil - 4.1.0-1 106 | - Version updae 107 | 108 | * Tue Aug 03 2021 RPM Fusion Release Engineering - 4.0.1-12 109 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild 110 | 111 | * Thu Feb 04 2021 RPM Fusion Release Engineering - 4.0.1-11 112 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild 113 | 114 | * Tue Aug 18 2020 RPM Fusion Release Engineering - 4.0.1-10 115 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild 116 | 117 | * Wed Feb 05 2020 RPM Fusion Release Engineering - 4.0.1-9 118 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild 119 | 120 | * Fri Aug 09 2019 RPM Fusion Release Engineering - 4.0.1-8 121 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild 122 | 123 | * Mon Mar 04 2019 RPM Fusion Release Engineering - 4.0.1-7 124 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild 125 | 126 | * Sun Aug 19 2018 Leigh Scott - 4.0.1-6 127 | - Rebuilt for Fedora 29 Mass Rebuild binutils issue 128 | 129 | * Fri Jul 27 2018 RPM Fusion Release Engineering - 4.0.1-5 130 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild 131 | 132 | * Thu Mar 01 2018 RPM Fusion Release Engineering - 4.0.1-4 133 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild 134 | 135 | * Thu Aug 31 2017 RPM Fusion Release Engineering - 4.0.1-3 136 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild 137 | 138 | * Mon Mar 20 2017 RPM Fusion Release Engineering - 4.0.1-2 139 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild 140 | 141 | * Tue Jul 26 2016 Adrian Reber - 4.0.1-1 142 | - Update to 4.0.1 143 | - Added pulseaudio-devel BR 144 | - Removed unneeded BRs 145 | 146 | * Tue Jul 19 2016 Leigh Scott - 4.0.0-1 147 | - Update to 4.0.0 148 | - Change from gtk2 to gtk3 149 | 150 | * Sat Dec 06 2014 Nicolas Chauvet - 3.90-3 151 | - Switch to mpg123 152 | 153 | * Mon Sep 01 2014 Sérgio Basto - 3.90-2 154 | - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild 155 | 156 | * Thu Feb 13 2014 Orcan Ogetbil - 3.90-1 157 | - Update to 3.90 158 | 159 | * Sun Dec 08 2013 Nicolas Chauvet - 3.84-5 160 | - Rebuilt 161 | 162 | * Sun Mar 24 2013 Orcan Ogetbil - 3.84-4 163 | - Build fix against newer zlib 164 | - Spec file cleanup 165 | 166 | * Sun Mar 03 2013 Nicolas Chauvet - 3.84-3 167 | - Mass rebuilt for Fedora 19 Features 168 | 169 | * Fri Mar 02 2012 Nicolas Chauvet - 3.84-2 170 | - Rebuilt for c++ ABI breakage 171 | 172 | * Sat Nov 26 2011 Orcan Ogetbil - 3.84-1 173 | - Update to 3.84 174 | 175 | * Tue Mar 01 2011 Orcan Ogetbil - 3.83-1 176 | - Update to 3.83 177 | 178 | * Fri Oct 23 2009 Orcan Ogetbil - 3.82-4 179 | - Update desktop file according to F-12 FedoraStudio feature 180 | 181 | * Sat Apr 04 2009 Orcan Ogetbil - 3.82-3 182 | - Fix ppc/ppc64 build failure 183 | 184 | * Wed Apr 01 2009 Orcan Ogetbil - 3.82-2 185 | - Prepared package for RPMFusion submission (originates from planetccrma) 186 | 187 | * Tue Dec 11 2007 Fernando Lopez-Lezcano 188 | - spec file cleanup 189 | 190 | * Wed Feb 16 2005 Fernando Lopez-Lezcano 191 | - declare do_save_tables before using it (for <= fc1) 192 | 193 | * Fri Dec 31 2004 Fernando Lopez-Lezcano 3.82-1 194 | - updated to 3.82 195 | - update doc file list 196 | 197 | * Mon Dec 27 2004 Fernando Lopez-Lezcano 198 | - spec file cleanup 199 | 200 | * Thu May 20 2004 Fernando Lopez-Lezcano 201 | - added build dependencies 202 | 203 | * Sun Feb 29 2004 Fernando Lopez-Lezcano 3.81-2 204 | - rebuild for liblrdf 0.3.5 205 | 206 | * Mon Oct 20 2003 Patrice Tisserand 3.81-1 207 | - updated for terminatorX-3.81 208 | - fixed building as non root user 209 | - still need to bez built with --define='_unpackaged_files_terminate_build 0', 210 | don't knwo what to do with scrollkeeper 211 | 212 | * Wed May 7 2003 Fernando Lopez-Lezcano 3.80-1 213 | - updated to 3.80 214 | - added proper desktop entry 215 | - updated file list (what to do with scrollkeeper?) 216 | - added clean target 217 | - make it build under gcc 2.96 218 | 219 | * Mon Dec 9 2002 Fernando Lopez-Lezcano 220 | - added patch to compile under redhat 8.0 and gcc 3.2 221 | - erased post warning about suid root executable 222 | 223 | * Sat Sep 14 2002 Alexander Konig 224 | - Switch from xpm to pngs for GNOME icons 225 | 226 | * Fri May 31 2002 Alexander Konig 227 | - Added Adrian's man page 228 | 229 | * Tue Mar 20 2001 Adrian Reber 230 | - Updated to 3.71 231 | 232 | * Sat Dec 09 2000 Adrian Reber 233 | - Updated to 3.70 234 | 235 | * Wed Apr 12 2000 Adrian Reber 236 | - Updated to 3.60 237 | 238 | * Wed Feb 23 2000 Adrian Reber 239 | - Mandrake adaptations. 240 | 241 | * Mon Feb 14 2000 Adrian Reber 242 | - Updated to 3.55 243 | 244 | * Fri Dec 17 1999 Adrian Reber 245 | - Updated to 3.5 246 | 247 | * Thu Jul 29 1999 Adrian Reber 248 | - Updated to 3.2 249 | 250 | * Fri May 07 1999 Adrian Reber 251 | - Initial release 252 | 253 | -------------------------------------------------------------------------------- /src/tX_engine.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_engine.c 19 | 20 | Description: Contains the code that does the real "Scratching 21 | business": XInput, DGA, Mouse and Keyboardgrabbing 22 | etc. 23 | */ 24 | 25 | #include "tX_engine.h" 26 | #include "tX_audiodevice.h" 27 | #include "tX_capabilities.h" 28 | #include "tX_global.h" 29 | #include "tX_maingui.h" 30 | #include "tX_mouse.h" 31 | #include "tX_sequencer.h" 32 | #include "tX_tape.h" 33 | #include "tX_types.h" 34 | #include "tX_vtt.h" 35 | #include "tX_widget.h" 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | #include 45 | 46 | tX_engine* tX_engine::engine = NULL; 47 | 48 | tX_engine* tX_engine::get_instance() { 49 | if (!engine) { 50 | engine = new tX_engine(); 51 | } 52 | 53 | return engine; 54 | } 55 | 56 | int16_t* tX_engine::render_cycle() { 57 | /* Forward the sequencer... */ 58 | sequencer.step(); 59 | 60 | /* Render the next block... */ 61 | int16_t* data = vtt_class::render_all_turntables(); 62 | 63 | /* Record the audio if necessary... */ 64 | if (is_recording()) 65 | tape->eat(data); 66 | 67 | return data; 68 | } 69 | 70 | void tX_engine::loop() { 71 | while (!thread_terminate) { 72 | /* Waiting for the trigger */ 73 | pthread_mutex_lock(&start); 74 | reset_cycles_ctr(); 75 | 76 | #ifdef USE_SCHEDULER 77 | pid_t pid = getpid(); 78 | struct sched_param parm; 79 | 80 | if (globals.use_realtime && (globals.audiodevice_type != JACK)) { 81 | sched_getparam(pid, &parm); 82 | parm.sched_priority = sched_get_priority_max(SCHED_FIFO); 83 | 84 | if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &parm)) { 85 | tX_msg("loop(): failed to set realtime priority."); 86 | } else { 87 | tX_debug("loop(): set SCHED_FIFO."); 88 | } 89 | } else { 90 | sched_getparam(pid, &parm); 91 | parm.sched_priority = sched_get_priority_max(SCHED_OTHER); 92 | 93 | if (pthread_setschedparam(pthread_self(), SCHED_OTHER, &parm)) { 94 | tX_msg("loop(): failed to set non-realtime priority."); 95 | } else { 96 | tX_debug("loop(): set SCHED_OTHER."); 97 | } 98 | } 99 | #endif 100 | loop_is_active = true; 101 | pthread_mutex_unlock(&start); 102 | 103 | if (!stop_flag) 104 | device->start(); // Hand flow control over to the device 105 | 106 | // in case we got kicked out by jack we might have 107 | // to kill the mouse grab 108 | /* if (grab_active) { 109 | mouse->ungrab(); 110 | grab_active=false; 111 | grab_off(); 112 | } */ 113 | 114 | if (!stop_flag) { 115 | runtime_error = true; 116 | usleep(100); 117 | } 118 | /* Stopping engine... */ 119 | loop_is_active = false; 120 | } 121 | } 122 | 123 | void* engine_thread_entry(void* engine_void) { 124 | tX_engine* engine = (tX_engine*)engine_void; 125 | 126 | #ifdef USE_SCHEDULER 127 | pid_t pid = getpid(); 128 | struct sched_param parm; 129 | 130 | if (globals.use_realtime) { 131 | sched_getparam(pid, &parm); 132 | parm.sched_priority = sched_get_priority_max(SCHED_FIFO); 133 | 134 | if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &parm)) { 135 | // we failed to get max prio, let see whether we can get a little less 136 | bool success = false; 137 | 138 | for (int i = parm.__sched_priority; i >= sched_get_priority_min(SCHED_FIFO); i--) { 139 | parm.__sched_priority = i; 140 | 141 | if (!pthread_setschedparam(pthread_self(), SCHED_FIFO, &parm)) { 142 | success = true; 143 | break; 144 | } 145 | } 146 | 147 | if (success) { 148 | tX_msg("engine_thread_entry(): set SCHED_FIFO with priority %i.", parm.__sched_priority); 149 | } else { 150 | tX_warning("engine_thread_entry(): failed to set realtime priority."); 151 | } 152 | } else { 153 | tX_debug("engine_thread_entry(): set SCHED_FIFO with maximum priority."); 154 | } 155 | } 156 | #endif // USE_SCHEDULER 157 | 158 | #ifdef USE_JACK 159 | /* Create the client now, so the user has something to connect to. */ 160 | tX_jack_client::get_instance(); 161 | #endif 162 | 163 | engine->loop(); 164 | tX_debug("engine_thread_entry() engine thread terminating."); 165 | pthread_exit(NULL); 166 | } 167 | 168 | tX_engine ::tX_engine() { 169 | int result; 170 | 171 | pthread_mutex_init(&start, NULL); 172 | pthread_mutex_lock(&start); 173 | thread_terminate = false; 174 | 175 | result = pthread_create(&thread, NULL, engine_thread_entry, (void*)this); 176 | 177 | if (result != 0) { 178 | tX_error("tX_engine() - Failed to create engine thread. Errno is %i.", errno); 179 | exit(1); 180 | } 181 | 182 | #ifdef USE_ALSA_MIDI_IN 183 | midi = new tX_midiin(); 184 | #endif 185 | tape = new tx_tapedeck(); 186 | 187 | device = NULL; 188 | recording = false; 189 | recording_request = false; 190 | loop_is_active = false; 191 | } 192 | 193 | void tX_engine ::set_recording_request(bool recording) { 194 | this->recording_request = recording; 195 | } 196 | 197 | tX_engine_error tX_engine ::run() { 198 | list::iterator vtt; 199 | 200 | runtime_error = false; 201 | overload_error = false; 202 | 203 | if (loop_is_active) 204 | return ERROR_BUSY; 205 | 206 | switch (globals.audiodevice_type) { 207 | #ifdef USE_OSS 208 | case OSS: 209 | device = new tX_audiodevice_oss(); 210 | break; 211 | #endif 212 | 213 | #ifdef USE_ALSA 214 | case ALSA: 215 | device = new tX_audiodevice_alsa(); 216 | break; 217 | #endif 218 | 219 | #ifdef USE_JACK 220 | case JACK: 221 | device = new tX_audiodevice_jack(); 222 | break; 223 | #endif 224 | 225 | #ifdef USE_PULSE 226 | case PULSE: 227 | device = new tX_audiodevice_pulse(); 228 | break; 229 | #endif 230 | 231 | default: 232 | device = NULL; 233 | return ERROR_BACKEND; 234 | } 235 | 236 | if (device->open()) { 237 | if (device->get_is_open()) 238 | device->close(); 239 | delete device; 240 | device = NULL; 241 | return ERROR_AUDIO; 242 | } 243 | 244 | vtt_class::set_sample_rate(device->get_sample_rate()); 245 | 246 | if (recording_request) { 247 | if (tape->start_record(globals.record_filename, vtt_class::get_mix_buffer_size(), device->get_sample_rate())) { 248 | device->close(); 249 | delete device; 250 | device = NULL; 251 | return ERROR_TAPE; 252 | } else { 253 | recording = true; 254 | } 255 | } 256 | 257 | for (vtt = vtt_class::main_list.begin(); vtt != vtt_class::main_list.end(); vtt++) { 258 | (*vtt)->sync_countdown = 0; 259 | if ((*vtt)->autotrigger) 260 | (*vtt)->trigger(); 261 | } 262 | 263 | sequencer.forward_to_start_timestamp(1); 264 | stop_flag = false; 265 | /* Trigger the engine thread... */ 266 | pthread_mutex_unlock(&start); 267 | 268 | return NO_ERROR; 269 | } 270 | 271 | void tX_engine ::stop() { 272 | list::iterator vtt; 273 | 274 | if (!loop_is_active) { 275 | tX_error("tX_engine::stop() - but loop's not running?"); 276 | } 277 | 278 | pthread_mutex_lock(&start); 279 | stop_flag = true; 280 | 281 | tX_debug("tX_engine::stop() - waiting for loop to stop."); 282 | 283 | while (loop_is_active) { 284 | /* Due to gtk+ signal handling this can cause a deadlock 285 | on the seqpars' update list. So we need to handle events 286 | while waiting... 287 | */ 288 | while (gtk_events_pending()) 289 | gtk_main_iteration(); 290 | usleep(50); 291 | } 292 | 293 | tX_debug("tX_engine::stop() - loop has stopped."); 294 | 295 | if (device->get_is_open()) 296 | device->close(); 297 | delete device; 298 | device = NULL; 299 | 300 | for (vtt = vtt_class::main_list.begin(); vtt != vtt_class::main_list.end(); vtt++) { 301 | (*vtt)->stop(); 302 | (*vtt)->ec_clear_buffer(); 303 | } 304 | 305 | if (is_recording()) 306 | tape->stop_record(); 307 | recording = false; 308 | } 309 | 310 | tX_engine ::~tX_engine() { 311 | void* dummy; 312 | 313 | thread_terminate = true; 314 | stop_flag = true; 315 | pthread_mutex_unlock(&start); 316 | tX_debug("~tX_engine() - Waiting for engine thread to terminate."); 317 | pthread_join(thread, &dummy); 318 | 319 | #ifdef USE_ALSA_MIDI_IN 320 | delete midi; 321 | #endif 322 | delete tape; 323 | } 324 | -------------------------------------------------------------------------------- /src/tX_sequencer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | terminatorX - realtime audio scratching software 3 | Copyright (C) 1999-2022 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, see . 17 | 18 | File: tX_sequencer.cc 19 | 20 | Description: Well, implements the sequencer as you might have 21 | guessed. 22 | */ 23 | 24 | #include "tX_sequencer.h" 25 | #include "tX_global.h" 26 | #include "tX_maingui.h" 27 | #include 28 | 29 | tX_sequencer sequencer; 30 | 31 | tX_sequencer ::tX_sequencer() { 32 | current_timestamp = 0; 33 | start_timestamp = 0; 34 | max_timestamp = 0; 35 | next_event = song_list.begin(); 36 | mode = TX_SEQMODE_PLAYONLY; 37 | run = 0; 38 | pthread_mutex_init(&record_lock, NULL); 39 | } 40 | 41 | tX_sequencer ::~tX_sequencer() { 42 | } 43 | 44 | void tX_sequencer ::set_timestamp(guint32 timestamp) { 45 | current_timestamp = 0; 46 | start_timestamp = 0; 47 | next_event = song_list.begin(); 48 | } 49 | 50 | void tX_sequencer ::step() { 51 | if (!run) 52 | return; 53 | 54 | while ((next_event != song_list.end()) && ((*next_event)->get_timestamp() == current_timestamp)) { 55 | (*next_event)->playback(); 56 | next_event++; 57 | } 58 | 59 | current_timestamp++; 60 | } 61 | 62 | tX_event* tX_sequencer ::record_event(tX_seqpar* sp, float value) { 63 | tX_event* new_event; 64 | 65 | new_event = new tX_event(current_timestamp, sp, value); 66 | 67 | pthread_mutex_lock(&record_lock); 68 | record_list.push_back(new_event); 69 | pthread_mutex_unlock(&record_lock); 70 | 71 | return new_event; 72 | } 73 | 74 | int tX_sequencer ::trig_rec() { 75 | record_start_timestamp = start_timestamp; 76 | 77 | mode = TX_SEQMODE_PLAYREC; 78 | return 1; 79 | } 80 | 81 | int tX_sequencer ::trig_play() { 82 | run = 1; 83 | return 1; 84 | } 85 | 86 | // #define SEQ_DEBUG 1 87 | // #define SEQ_DEBUG_MAX 1 88 | 89 | void tX_sequencer ::trig_stop() { 90 | list::iterator song_event; 91 | list::iterator temp_song_event; 92 | list::iterator record_event; 93 | tX_seqpar* sp; 94 | 95 | int oldmode = mode; 96 | 97 | mode = TX_SEQMODE_PLAYONLY; 98 | run = 0; 99 | int confirm = GTK_RESPONSE_YES; 100 | 101 | record_stop_timestamp = current_timestamp; 102 | 103 | if (oldmode == TX_SEQMODE_PLAYREC) { 104 | pthread_mutex_lock(&record_lock); 105 | #ifdef SEQ_DEBUG 106 | printf("Recorded from %i to %i.\n", record_start_timestamp, record_stop_timestamp); 107 | printf("* Song: %i events, Recorded: %i events, sum=%i\n", song_list.size(), record_list.size(), song_list.size() + record_list.size()); 108 | #endif 109 | 110 | if (globals.confirm_events) { 111 | GtkWidget* dialog = gtk_message_dialog_new(GTK_WINDOW(main_window), 112 | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, 113 | "Apply all events recorded with this take?"); 114 | 115 | confirm = gtk_dialog_run(GTK_DIALOG(dialog)); 116 | gtk_widget_destroy(dialog); 117 | } 118 | 119 | if (confirm == GTK_RESPONSE_YES) { 120 | /* The user wants to keep the recorded events... */ 121 | 122 | /* removing all events for touched parameters in song_list */ 123 | 124 | song_event = song_list.begin(); 125 | 126 | while ((song_event != song_list.end()) && ((*song_event)->get_timestamp() < record_start_timestamp)) 127 | song_event++; 128 | 129 | while ((song_event != song_list.end()) && ((*song_event)->get_timestamp() <= record_stop_timestamp)) { 130 | sp = (*song_event)->get_sp(); 131 | #ifdef SEQ_DEBUG_MAX 132 | printf("sp %08x (%i) touched at: %i - timestamp %i.\n", sp, sp->is_touched(), sp->get_touch_timestamp(), (*song_event)->get_timestamp()); 133 | #endif 134 | 135 | if (sp->is_touched() && (sp->get_touch_timestamp() <= (*song_event)->get_timestamp())) { 136 | temp_song_event = song_event; 137 | song_event++; 138 | delete (*temp_song_event); 139 | song_list.erase(temp_song_event); 140 | } else { 141 | song_event++; 142 | } 143 | } 144 | 145 | /* inserting all recorded events into song_list */ 146 | 147 | for (record_event = record_list.begin(), song_event = song_list.begin(); record_event != record_list.end();) { 148 | if (song_event == song_list.end()) { 149 | song_list.insert(song_event, record_event, record_list.end()); 150 | break; 151 | } 152 | 153 | if ((*song_event)->get_timestamp() >= (*record_event)->get_timestamp()) { 154 | song_list.insert(song_event, (*record_event)); 155 | record_event++; 156 | } else { 157 | song_event++; 158 | } 159 | } 160 | } else { 161 | /* The user wants to drop the events from this take */ 162 | for (record_event = record_list.begin(); record_event != record_list.end(); record_event++) { 163 | delete (*record_event); 164 | } 165 | } 166 | 167 | record_list.erase(record_list.begin(), record_list.end()); 168 | 169 | #ifdef SEQ_DEBUG 170 | printf("- Song: %i events, Recorded: %i events, sum=%i\n", song_list.size(), record_list.size(), song_list.size() + record_list.size()); 171 | #endif 172 | 173 | pthread_mutex_unlock(&record_lock); 174 | } 175 | 176 | tX_seqpar::untouch_all(); 177 | 178 | song_event = song_list.end(); 179 | 180 | if (song_event != song_list.begin()) { 181 | song_event--; 182 | max_timestamp = (*song_event)->get_timestamp(); 183 | } 184 | 185 | #ifdef SEQ_DEBUG_MAX 186 | /*dump song_list */ 187 | 188 | for (song_event = song_list.begin(); song_event != song_list.end(); song_event++) { 189 | printf("%-15s| %-27s| %8i | %10f\n", (*song_event)->get_vtt_name(), (*song_event)->get_seqpar_name(), (*song_event)->get_timestamp(), (*song_event)->get_value()); 190 | } 191 | #endif 192 | 193 | current_timestamp = start_timestamp; 194 | seq_update(); 195 | } 196 | 197 | void tX_sequencer ::delete_all_events(del_mode mode) { 198 | list::iterator song_event; 199 | list::iterator temp_song_event; 200 | 201 | for (song_event = song_list.begin(); song_event != song_list.end();) { 202 | if (((mode == DELETE_ALL) || ((mode == DELETE_UPTO_CURRENT) && ((*song_event)->get_timestamp() < current_timestamp)) || ((mode == DELETE_FROM_CURRENT) && ((*song_event)->get_timestamp() >= current_timestamp)))) { 203 | temp_song_event = song_event; 204 | song_event++; 205 | delete (*temp_song_event); 206 | song_list.erase(temp_song_event); 207 | } else { 208 | song_event++; 209 | } 210 | } 211 | 212 | start_timestamp = 0; 213 | current_timestamp = 0; 214 | max_timestamp = 0; 215 | } 216 | 217 | void tX_sequencer ::delete_all_events_for_vtt(vtt_class* vtt, del_mode mode) { 218 | list::iterator sp; 219 | 220 | for (sp = tX_seqpar::all->begin(); sp != tX_seqpar::all->end(); sp++) { 221 | if ((*sp)->vtt == vtt) { 222 | delete_all_events_for_sp((*sp), mode); 223 | } 224 | } 225 | } 226 | 227 | void tX_sequencer ::delete_all_events_for_sp(tX_seqpar* sp, del_mode mode) { 228 | list::iterator song_event; 229 | list::iterator temp_song_event; 230 | 231 | for (song_event = song_list.begin(); song_event != song_list.end();) { 232 | if ((sp == (*song_event)->get_sp()) && ((mode == DELETE_ALL) || ((mode == DELETE_UPTO_CURRENT) && ((*song_event)->get_timestamp() < current_timestamp)) || ((mode == DELETE_FROM_CURRENT) && ((*song_event)->get_timestamp() >= current_timestamp)))) { 233 | temp_song_event = song_event; 234 | song_event++; 235 | delete (*temp_song_event); 236 | song_list.erase(temp_song_event); 237 | } else { 238 | song_event++; 239 | } 240 | } 241 | } 242 | 243 | void tX_sequencer ::save(FILE* rc, gzFile rz, char* indent) { 244 | list::iterator song_event; 245 | 246 | tX_store("%s\n", indent); 247 | strcat(indent, "\t"); 248 | 249 | for (song_event = song_list.begin(); song_event != song_list.end(); song_event++) { 250 | (*song_event)->store(rc, rz, indent); 251 | } 252 | 253 | indent[strlen(indent) - 1] = 0; 254 | tX_store("%s\n", indent); 255 | } 256 | 257 | guint32 tX_sequencer ::set_start_timestamp(float pos) { 258 | guint32 timestamp; 259 | 260 | if (pos > 99.999) 261 | pos = 99.999; 262 | pos /= 100; 263 | 264 | timestamp = (guint32)(((float)max_timestamp) * pos); 265 | start_timestamp = timestamp; 266 | 267 | return start_timestamp; 268 | } 269 | 270 | void tX_sequencer ::forward_to_start_timestamp(int dont_fake) { 271 | int gui_update_max, gui_update; 272 | int run_save = run; 273 | 274 | run = 1; 275 | 276 | gui_update_max = (globals.update_idle * (globals.update_delay + 1) * 1000) >> 1; 277 | gui_update = gui_update_max; 278 | 279 | current_timestamp = 0; 280 | 281 | next_event = song_list.begin(); 282 | 283 | while (current_timestamp < start_timestamp) { 284 | step(); 285 | if (dont_fake) { 286 | vtt_class ::forward_all_turntables(); 287 | 288 | gui_update--; 289 | if (gui_update < 0) { 290 | gui_update = gui_update_max; 291 | seq_update(); 292 | while (gtk_events_pending()) 293 | gtk_main_iteration(); 294 | } 295 | } 296 | } 297 | 298 | run = run_save; 299 | 300 | tX_seqpar ::update_all_graphics(); 301 | while (gtk_events_pending()) 302 | gtk_main_iteration(); 303 | } 304 | 305 | void tX_sequencer ::load(xmlDocPtr doc, xmlNodePtr node) { 306 | tX_event* ev = NULL; 307 | 308 | max_timestamp = 0; 309 | 310 | for (xmlNodePtr cur = node->xmlChildrenNode; cur != NULL; cur = cur->next) { 311 | if (cur->type == XML_ELEMENT_NODE) { 312 | if (xmlStrcmp(cur->name, (xmlChar*)"event") == 0) { 313 | ev = tX_event::load_event(doc, cur); 314 | 315 | if (ev) { 316 | max_timestamp = ev->get_timestamp(); 317 | song_list.push_back(ev); 318 | } 319 | } else { 320 | tX_warning("unhandled sequencer element %s.", cur->name); 321 | } 322 | } 323 | } 324 | 325 | start_timestamp = 0; 326 | current_timestamp = 0; 327 | } 328 | --------------------------------------------------------------------------------