fprintf(stderr, "%s - Copyright (C) 1999-2003 by Alexander König\n", VERSIONSTRING);
fprintf(stderr, "terminatorX comes with ABSOLUTELY NO WARRANTY - for details read the license.\n");
- engine=new tX_engine();
+ tX_engine *engine=tX_engine::get_instance();
#ifdef USE_3DNOW
if (tx_mm_support()!=5) {
#define ALSA_PCM_NEW_HW_PARAMS_API
#include "tX_audiodevice.h"
+#include "tX_vtt.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
+#include "tX_engine.h"
-void tX_audiodevice :: init()
+tX_audiodevice :: tX_audiodevice() : samples_per_buffer(0),
+current_buffer(0), buffer_pos(0)
{
- samples_per_buffer=0;
- //set_buffersize_near(globals.audiodevice_buffersize);
+ sample_buffer[0]=NULL;
+ sample_buffer[1]=NULL;
+ engine=tX_engine::get_instance();
}
+void tX_audiodevice :: start() {
+ sample_buffer[0]=new int16_t[samples_per_buffer*2];
+ sample_buffer[1]=new int16_t[samples_per_buffer*2];
+ int current=0;
+
+ while (!engine->is_stopped()) {
+ current=current ? 0 : 1;
+
+ int16_t *current_buffer=sample_buffer[current];
+ int16_t *next_buffer=sample_buffer[current ? 0 : 1];
+
+ fill_buffer(current_buffer, next_buffer);
+ play(current_buffer);
+ }
+
+ delete [] sample_buffer[0];
+ delete [] sample_buffer[1];
+}
+
+void tX_audiodevice :: fill_buffer(int16_t *target_buffer, int16_t *next_target_buffer) {
+ int vtt_buffer_size=vtt_class::get_mix_buffer_size()<<1;
+ int prefill;
+
+ while (buffer_pos < samples_per_buffer) {
+ int16_t *data=engine->render_cycle();
+
+ int rest=samples_per_buffer-(buffer_pos+vtt_buffer_size);
+
+ if (rest>0) {
+ memcpy(&target_buffer[buffer_pos], data, samples_per_buffer << 1);
+ } else {
+ rest*=-1;
+
+ memcpy(&target_buffer[buffer_pos], data, (vtt_buffer_size-rest) << 1);
+ memcpy(next_target_buffer, &data[vtt_buffer_size-rest], rest << 1);
+ prefill=rest;
+ }
+
+ buffer_pos+=vtt_buffer_size;
+ }
+
+ buffer_pos=prefill;
+}
+
+/* Driver Specific Code follows.. */
+
#ifdef USE_OSS
int tX_audiodevice_oss :: open()
return 0;
}
-tX_audiodevice_oss :: tX_audiodevice_oss()
-{
- fd=0;
- blocksize=0;
- init();
-}
+tX_audiodevice_oss :: tX_audiodevice_oss() : tX_audiodevice(),
+fd(0), blocksize(0) {}
double tX_audiodevice_oss :: get_latency()
{
}
-tX_audiodevice_alsa :: tX_audiodevice_alsa()
-{
- pcm_handle=NULL;
- init();
-}
+tX_audiodevice_alsa :: tX_audiodevice_alsa() : tX_audiodevice(),
+pcm_handle(NULL) {}
void tX_audiodevice_alsa :: play(int16_t *buffer)
{
#include <alsa/asoundlib.h>
#endif
+class tX_engine;
+
class tX_audiodevice
{
protected:
int samples_per_buffer;
+ int16_t *sample_buffer[2];
+ int current_buffer;
+ int buffer_pos;
+ tX_engine *engine;
+
int sample_rate;
- void init();
+ tX_audiodevice();
public:
virtual double get_latency()=0; /* call only valid *after* open() */
virtual int open()=0;
virtual int close()=0;
-
+
+ void fill_buffer(int16_t *target_buffer, int16_t *next_target_buffer);
+
+ virtual void start();
virtual void play(int16_t*)=0; /* play blocked */
};
/* Misc */
strcpy(globals.file_editor, gtk_entry_get_text(GTK_ENTRY(lookup_widget(dialog, "soundfile_editor"))));
+ strcpy(globals.lrdf_path, gtk_entry_get_text(GTK_ENTRY(lookup_widget(dialog, "ladspa_rdf_path"))));
globals.prelis=(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "prelisten_enabled")))==TRUE);
}
/* Misc */
gtk_entry_set_text(GTK_ENTRY(lookup_widget(dialog, "soundfile_editor")), globals.file_editor);
+ gtk_entry_set_text(GTK_ENTRY(lookup_widget(dialog, "ladspa_rdf_path")), globals.lrdf_path);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "prelisten_enabled")), globals.prelis);
}
#include <sys/time.h>
#include <sys/resource.h>
-tX_engine *engine=NULL;
+tX_engine *tX_engine :: engine=NULL;
+
+tX_engine *tX_engine :: get_instance() {
+ if (!engine) {
+ engine=new tX_engine();
+ }
+
+ return engine;
+}
void tX_engine :: set_grab_request() {
grab_request=true;
}
-void tX_engine :: loop() {
+void tX_engine :: loop_og() {
int16_t *temp=NULL;
int result;
}
}
+int16_t* tX_engine :: render_cycle() {
+ /* Checking whether to grab or not */
+ if (grab_request!=grab_active) {
+ if (grab_request) {
+ /* Activating grab... */
+ int result=mouse->grab();
+ if (result!=0) {
+ tX_error("tX_engine::loop(): failed to grab mouse - error %i", result);
+ grab_active=false;
+ /* Reseting grab_request, too - doesn't help keeping it, does it ? ;) */
+ grab_request=false;
+ mouse->ungrab();
+ grab_off();
+ } else {
+ grab_active=true;
+ }
+ } else {
+ /* Deactivating grab... */
+ mouse->ungrab();
+ grab_active=false;
+ grab_off(); // for the mastergui this is...
+ }
+ }
+
+ /* Handling input events... */
+ if (grab_active) {
+ if (mouse->check_event()) {
+ /* If we're here the user pressed ESC */
+ grab_request=false;
+ }
+ }
+
+#ifdef USE_ALSA_MIDI_IN
+ if (midi->get_is_open()) midi->check_event();
+#endif
+ /* Forward the sequencer... */
+ sequencer.step();
+
+ /* Render the next block... */
+ int16_t *data=vtt_class::render_all_turntables();
+
+ /* Record the audio if necessary... */
+ if (is_recording()) tape->eat(data);
+
+ return data;
+}
+
+void tX_engine :: loop() {
+ int16_t *temp=NULL;
+ int result;
+
+ while (!thread_terminate) {
+ /* Waiting for the trigger */
+ pthread_mutex_lock(&start);
+ loop_is_active=true;
+ pthread_mutex_unlock(&start);
+
+ device->start(); // Hand flow control over to the device
+
+ /* Stopping engine... */
+ loop_is_active=false;
+ }
+}
+
+
void *engine_thread_entry(void *engine_void) {
tX_engine *engine=(tX_engine*) engine_void;
int result;
}
vtt_class::set_sample_rate(device->get_sample_rate());
- vtt_class::set_mix_buffer_size(device->get_buffersize()/2); //mixbuffer is mono
if (recording_request) {
if (tape->start_record(globals.record_filename, device->get_buffersize()*sizeof(int16_t), device->get_sample_rate())) {
class tX_engine {
private:
+ static tX_engine *engine;
+
pthread_t thread;
pthread_mutex_t start;
bool thread_terminate;
tX_midiin *get_midi() { return midi; }
#endif
+ static tX_engine *get_instance();
tX_engine();
~tX_engine();
tX_engine_error run();
void stop();
void loop();
+ void loop_og();
+
void set_recording_request(bool recording);
bool get_recording_request() { return recording_request; }
bool is_recording() { return recording; }
+ int16_t* render_cycle();
void set_grab_request();
+ bool is_stopped() { return stop_flag; }
};
-
-extern tX_engine *engine;
#endif
GtkWidget *soundfile_editor;
GtkWidget *label26;
GtkWidget *prelisten_enabled;
+ GtkWidget *label31;
+ GtkWidget *ladspa_rdf_path;
GtkWidget *label3;
GtkWidget *dialog_action_area1;
GtkWidget *pref_cancel;
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 5), label2);
gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT);
- table3 = gtk_table_new (2, 2, FALSE);
+ table3 = gtk_table_new (3, 2, FALSE);
gtk_widget_show (table3);
gtk_container_add (GTK_CONTAINER (notebook1), table3);
gtk_container_set_border_width (GTK_CONTAINER (table3), 4);
label26 = gtk_label_new ("\"Pre-Listen\" to soundfiles:");
gtk_widget_show (label26);
- gtk_table_attach (GTK_TABLE (table3), label26, 0, 1, 1, 2,
+ gtk_table_attach (GTK_TABLE (table3), label26, 0, 1, 2, 3,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_label_set_justify (GTK_LABEL (label26), GTK_JUSTIFY_LEFT);
prelisten_enabled = gtk_check_button_new_with_mnemonic ("Enabled");
gtk_widget_show (prelisten_enabled);
- gtk_table_attach (GTK_TABLE (table3), prelisten_enabled, 1, 2, 1, 2,
+ gtk_table_attach (GTK_TABLE (table3), prelisten_enabled, 1, 2, 2, 3,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_tooltips_set_tip (tooltips, prelisten_enabled, "When enabled soundfiles will be playedback when selected in a file dialog (before loading them).", NULL);
+ label31 = gtk_label_new ("LADSPA RDF Path:");
+ gtk_widget_show (label31);
+ gtk_table_attach (GTK_TABLE (table3), label31, 0, 1, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_label_set_justify (GTK_LABEL (label31), GTK_JUSTIFY_LEFT);
+ gtk_misc_set_alignment (GTK_MISC (label31), 0, 0.5);
+
+ ladspa_rdf_path = gtk_entry_new ();
+ gtk_widget_show (ladspa_rdf_path);
+ gtk_table_attach (GTK_TABLE (table3), ladspa_rdf_path, 1, 2, 1, 2,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
label3 = gtk_label_new ("Misc");
gtk_widget_show (label3);
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 6), label3);
GLADE_HOOKUP_OBJECT (tx_options, soundfile_editor, "soundfile_editor");
GLADE_HOOKUP_OBJECT (tx_options, label26, "label26");
GLADE_HOOKUP_OBJECT (tx_options, prelisten_enabled, "prelisten_enabled");
+ GLADE_HOOKUP_OBJECT (tx_options, label31, "label31");
+ GLADE_HOOKUP_OBJECT (tx_options, ladspa_rdf_path, "ladspa_rdf_path");
GLADE_HOOKUP_OBJECT (tx_options, label3, "label3");
GLADE_HOOKUP_OBJECT_NO_REF (tx_options, dialog_action_area1, "dialog_action_area1");
GLADE_HOOKUP_OBJECT (tx_options, pref_cancel, "pref_cancel");
{
sequencer_ready=0;
mg_enable_critical_buttons(0);
- res=engine->run();
+ res=tX_engine::get_instance()->run();
sequencer_ready=1;
if (res!=NO_ERROR)
{
if (!sequencer_ready) return NULL;
gtk_widget_set_sensitive(grab_button, 0);
- engine->stop();
+ tX_engine::get_instance()->stop();
stop_update=1;
audioon=0;
- if (engine->get_recording_request()) {
- engine->set_recording_request(false);
+ if (tX_engine::get_instance()->get_recording_request()) {
+ tX_engine::get_instance()->set_recording_request(false);
rec_dont_care=1;
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(rec_menu_item), 0);
rec_dont_care=0;
if (strlen(buffer))
{
strcpy(globals.record_filename, buffer);
- engine->set_recording_request(true);
+ tX_engine::get_instance()->set_recording_request(true);
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(rec_menu_item), 1);
}
}
else
{
- engine->set_recording_request(false);
+ tX_engine::get_instance()->set_recording_request(false);
}
return NULL;
void grab_on(GtkWidget *w, void *d)
{
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
- engine->set_grab_request();
+ tX_engine::get_instance()->set_grab_request();
}
grab_status=1;
}
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Configure MIDI Bindings");
- gtk_window_set_default_size(GTK_WINDOW(window), 400, 260);
+ gtk_window_set_default_size(GTK_WINDOW(window), 600, 260);
- hbox1 = gtk_hbox_new (FALSE, 0);
+ hbox1 = gtk_hbox_new (FALSE, 2);
gtk_widget_show (hbox1);
gtk_container_add (GTK_CONTAINER (window), hbox1);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_show (scrolledwindow1);
frame1 = gtk_frame_new (NULL);
gtk_widget_show (frame1);
gtk_box_pack_start (GTK_BOX (vbox1), frame1, TRUE, TRUE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (frame1), 1);
+ gtk_container_set_border_width (GTK_CONTAINER (frame1), 2);
gtk_frame_set_label_align (GTK_FRAME (frame1), 0, 0);
gtk_frame_set_shadow_type (GTK_FRAME (frame1), GTK_SHADOW_IN);
f_prec vtt_class::mix_max_l=0;
f_prec vtt_class::mix_max_r=0;
f_prec vtt_class::vol_channel_adjust=1.0;
+int vtt_class::mix_buffer_size=0;
#define GAIN_AUTO_ADJUST 0.8
}
if ((!mix_buffer) || (!mix_out_buffer) || res) return(1);
+
+ mix_buffer_size=no_samples;
+
return(0);
}
}
(*vtt)->recalc_pitch();
}
+
+ int no_samples=(int) (sr*0.001); // Forcing 1 ms blocksize
+
+ set_mix_buffer_size(no_samples);
}
static int master_triggered_at;
static vtt_class * focused_vtt;
static int solo_ctr;
+ static int mix_buffer_size;
/* the gui */
vtt_gui gui;
vtt_class(int);
~vtt_class();
+ static int get_mix_buffer_size() { return mix_buffer_size; }
+
/* Parameter setup methods */
void set_name(char *);
int set_output_buffer_size(int);
#ifdef USE_ALSA_MIDI_IN
void midi_mapping_clicked(GtkWidget *wid, vtt_class *vtt)
{
- engine->midi->configure_bindings(vtt);
+ tX_engine::get_instance()->midi->configure_bindings(vtt);
}
#endif
gui_set_tooltip(g->midi_mapping, "Determines what parameters should be bound to what MIDI events.");
gtk_box_pack_start(GTK_BOX(tempbox), g->midi_mapping, WID_DYN);
- if (!engine->get_midi()->get_is_open()) {
+ if (!tX_engine::get_instance()->get_midi()->get_is_open()) {
gtk_widget_set_sensitive(g->midi_mapping, FALSE);
}
#endif
<widget class="GtkTable" id="table3">
<property name="border_width">4</property>
<property name="visible">True</property>
- <property name="n_rows">2</property>
+ <property name="n_rows">3</property>
<property name="n_columns">2</property>
<property name="homogeneous">False</property>
<property name="row_spacing">2</property>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label31">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">LADSPA RDF Path:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
+
+ <child>
+ <widget class="GtkEntry" id="ladspa_rdf_path">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char" translatable="yes">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="tab_expand">False</property>