Highlight recently played audio samples (configurable).
authorAlexander Koenig <alex@lisas.de>
Tue, 21 Jun 2016 20:47:56 +0000 (22:47 +0200)
committerAlexander Koenig <alex@lisas.de>
Tue, 21 Jun 2016 20:47:56 +0000 (22:47 +0200)
src/tX_audiodevice.cc
src/tX_audiofile.cc
src/tX_dialog.cc
src/tX_global.c
src/tX_global.h
src/tX_ui_interface.cc
src/tX_widget.c
src/tX_widget.h

index 95473aa..b3726a0 100644 (file)
@@ -491,8 +491,6 @@ void tX_audiodevice_pulse::stream_drain_complete_callback(pa_stream *stream, int
        }
 }
 
-#define min(a,b) ((a) < (b) ? (a) : (b))
-
 void tX_audiodevice_pulse::stream_write_callback(pa_stream *stream, size_t length) {
        size_t sample_length = length/2;
 
@@ -520,7 +518,7 @@ void tX_audiodevice_pulse::stream_write_callback(pa_stream *stream, size_t lengt
                while (outbuffer_pos<sample_length) {
                        int16_t *data=engine->render_cycle();
 
-                       sample = min(vtt_class::samples_in_mix_buffer, (sample_length - outbuffer_pos));
+                       sample = tX_min(vtt_class::samples_in_mix_buffer, (sample_length - outbuffer_pos));
 
                        memcpy(&outbuffer[outbuffer_pos], data, sizeof(int16_t) * sample);
                        outbuffer_pos+=sample;
index 3e2420b..ca23155 100644 (file)
@@ -64,8 +64,6 @@
 #      include <audiofile.h>
 #endif
 
-#define min(a,b) ((a) < (b) ? (a) : (b))
-
 tx_audiofile :: tx_audiofile()
 {
        mem_type=TX_AUDIO_UNDEFINED;
@@ -309,7 +307,7 @@ tX_audio_error tx_audiofile :: load_wav() {
 #endif 
        while (wav_in.len>allbytes)
        {       
-               bytes = fread(p, 1, min(1024, wav_in.len-allbytes), wav_in.handle);
+               bytes = fread(p, 1, tX_min(1024, wav_in.len-allbytes), wav_in.handle);
 
 #ifdef ENABLE_DEBUG_OUTPUT
                if (output) { tX_debug("tX_audiofile::load_wav() read %zu Bytes [%04x %04x %04x %04x %04x %04x ..]", bytes, (unsigned int) p[0],  (unsigned int) p[1], (unsigned int) p[2], (unsigned int) p[3], (unsigned int) p[4], (unsigned int) p[5]); }
@@ -409,7 +407,7 @@ static enum mad_flow tX_mad_input(void *data, struct mad_stream *stream) {
        unsigned int pos;
 
        if (buffer->first_call) {
-               bs=min(TX_MAD_BLOCKSIZE, buffer->size);
+               bs=tX_min(TX_MAD_BLOCKSIZE, buffer->size);
                mad_stream_buffer(stream, buffer->start, bs);
                buffer->first_call=false;
                return MAD_FLOW_CONTINUE;
@@ -417,7 +415,7 @@ static enum mad_flow tX_mad_input(void *data, struct mad_stream *stream) {
                if (!stream->next_frame) return MAD_FLOW_STOP;
                
                pos=stream->next_frame-buffer->start;
-               bs=min(TX_MAD_BLOCKSIZE, buffer->size-pos);
+               bs=tX_min(TX_MAD_BLOCKSIZE, buffer->size-pos);
                //tX_debug("last: %08x, new %08x, bs: %i, pos: %i",  buffer->last_frame, stream->next_frame, bs, pos);
                
                mad_stream_buffer(stream, stream->next_frame, bs);
index b5b0b1d..94e1173 100644 (file)
@@ -126,7 +126,9 @@ void apply_options(GtkWidget *dialog) {
        } else {
                globals.knob_size_override = 0;
        }
-       
+
+       globals.wav_display_history=(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "wav_display_history")))==TRUE);
+
        /* Audio Colors */
        
        strcpy(globals.wav_display_bg_focus, (char *) g_object_get_data(G_OBJECT(lookup_widget(dialog, "wav_display_bg_focus")), "Color"));
@@ -425,6 +427,9 @@ void init_tx_options(GtkWidget *dialog) {
        } else {
                gtk_range_set_value(GTK_RANGE(lookup_widget(dialog, "knob_size")), 48);
        }
+       
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "wav_display_history")), globals.wav_display_history);
+
        /* Audio Colors */
        int ctr=0;
        
index ccb4dba..4dd20fc 100644 (file)
@@ -138,7 +138,9 @@ void set_global_defaults() {
        globals.alsa_free_hwstats=0;
        globals.filename_length=20;
        globals.restore_midi_connections=1;
-       
+
+       globals.wav_display_history=1;
+
        strcpy(globals.wav_display_bg_focus, "#00004C");
        strcpy(globals.wav_display_bg_no_focus, "#000000");
 
@@ -244,7 +246,8 @@ int load_globals_xml() {
                        restore_int("confirm_events", globals.confirm_events);
                        restore_float("vtt_inertia", globals.vtt_inertia);
                        restore_int("restore_midi_connections", globals.restore_midi_connections);
-                       
+
+                       restore_int("wav_display_history", globals.wav_display_history);
                        restore_string("wav_display_bg_focus", globals.wav_display_bg_focus);
                        restore_string("wav_display_bg_no_focus", globals.wav_display_bg_no_focus);
                        restore_string("wav_display_fg_focus", globals.wav_display_fg_focus);
@@ -372,6 +375,7 @@ void store_globals() {
                store_string("last_path", globals.current_path);
                store_int("restore_midi_connections", globals.restore_midi_connections);
 
+               store_int("wav_display_history", globals.wav_display_history);
                store_string("wav_display_bg_focus", globals.wav_display_bg_focus);
                store_string("wav_display_bg_no_focus", globals.wav_display_bg_no_focus);
                store_string("wav_display_fg_focus", globals.wav_display_fg_focus);
index bfa1652..e7c655c 100644 (file)
@@ -61,6 +61,9 @@ extern "C" {
 #define tX_msg(fmt, args...); { fprintf(stderr, "- tX_msg: "); fprintf(stderr, fmt , ## args); fprintf(stderr, "\n"); }
 #define tX_plugin_warning(fmt, args...); { if (globals.verbose_plugin_loading) { fprintf(stderr, "+ tX_warning: "); fprintf(stderr, fmt , ## args); fprintf(stderr, "\n"); }}
 
+#define tX_min(a,b) ((a) < (b) ? (a) : (b))
+#define tX_max(a,b) ((a) > (b) ? (a) : (b))
+       
 #ifdef MEM_DEBUG
 #define tX_freemem(ptr, varname, comment); fprintf(stderr, "** free() [%s] at %08x. %s.\n", varname, ptr, comment); free(ptr);
 #define tX_malloc(ptr, varname, comment, size, type); fprintf(stderr, "**[1/2] malloc() [%s]. Size: %i. %s.\n", varname, size, comment); ptr=type malloc(size); fprintf(stderr, "**[2/2] malloc() [%s]. ptr: %08x.\n", varname, ptr);
@@ -161,6 +164,7 @@ typedef struct {
        int filename_length;
        
        int restore_midi_connections;
+       int wav_display_history;
        
        char wav_display_bg_focus[8];
        char wav_display_bg_no_focus[8];
index 0872992..02b2f34 100644 (file)
@@ -200,6 +200,7 @@ create_tx_options (GtkWindow* parent)
   GtkWidget *label45;
   GtkWidget *label46;
   GtkWidget *label47;
+  GtkWidget *wav_display_history;
   GtkWidget *wav_display_bg_focus;
   GtkWidget *wav_display_bg_no_focus;
   GtkWidget *wav_display_fg_focus;
@@ -581,6 +582,16 @@ create_tx_options (GtkWindow* parent)
   gtk_scale_set_value_pos (GTK_SCALE (knob_size), GTK_POS_LEFT);
   gtk_scale_set_digits (GTK_SCALE (knob_size), 0);
 
+  label38 = gtk_label_new("Highlight:");
+  gtk_widget_show (label38);
+  gtk_grid_attach (GTK_GRID (grid2), label38, 0, 9, 1, 1);
+  gtk_widget_set_halign(label38, GTK_ALIGN_START);
+
+  wav_display_history = gtk_check_button_new_with_mnemonic ("Highlight recently played back samples");
+  gtk_widget_show (wav_display_history);
+  gtk_grid_attach (GTK_GRID (grid2), wav_display_history, 1, 9, 1, 1);
+  gtk_widget_set_tooltip_text(wav_display_history, "Adds visual history to the turntable cursor or needles.");
+
   label2 = gtk_label_new ("User Interface");
   gtk_widget_show (label2);
   gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 2), label2);
@@ -969,6 +980,7 @@ create_tx_options (GtkWindow* parent)
   TX_UI_HOOKUP_OBJECT (tx_options, label_knob_size, "label_knob_size");
   TX_UI_HOOKUP_OBJECT (tx_options, knob_size, "knob_size");
   TX_UI_HOOKUP_OBJECT (tx_options, override_knob_size, "override_knob_size");
+  TX_UI_HOOKUP_OBJECT (tx_options, wav_display_history, "wav_display_history");
 
   return tx_options;
 }
index 74344c7..1e51c35 100644 (file)
@@ -95,6 +95,9 @@ static void gtk_tx_class_init(GtkTxClass * gclass) {
        widget_class->size_allocate = gtk_tx_size_allocate;
 }
 
+#define COL_FOCUS 0 
+#define COL_NO_FOCUS 1
+
 #define COL_BG_FOCUS     0
 #define COL_BG_NO_FOCUS  1
 #define COL_FG_FOCUS     2
@@ -103,6 +106,8 @@ static void gtk_tx_class_init(GtkTxClass * gclass) {
 #define COL_CURSOR_MUTE  5
 
 void gtk_tx_update_colors(GtkTx *tx) {
+       int step;
+
        gdk_rgba_parse(&tx->colors[COL_BG_FOCUS], globals.wav_display_bg_focus);
        tx->colors[COL_BG_FOCUS].alpha=1.0;
        gdk_rgba_parse(&tx->colors[COL_BG_NO_FOCUS], globals.wav_display_bg_no_focus);
@@ -117,6 +122,17 @@ void gtk_tx_update_colors(GtkTx *tx) {
        tx->colors[COL_CURSOR].alpha=1.0;
        gdk_rgba_parse(&tx->colors[COL_CURSOR_MUTE], globals.wav_display_cursor_mute);
        tx->colors[COL_CURSOR_MUTE].alpha=1.0;
+
+       for (step = 0; step < GTK_TX_HISTORY_LENGTH; step++) {
+               double frac = (1.0 / ((double) GTK_TX_HISTORY_LENGTH + 2.0)) * ((double) step + 1.0);
+
+               GdkRGBA *color = &tx->history_colors[step];
+               color->red = tx->colors[COL_CURSOR].red;
+               color->green = tx->colors[COL_CURSOR].green;
+               color->blue = tx->colors[COL_CURSOR].blue;
+               color->alpha = frac*frac/2;
+//             printf("%i, %lf\n", step, frac);
+       }
 }
 
 
@@ -129,7 +145,8 @@ static void gtk_tx_init(GtkTx * tx) {
 #endif
        
        memset(tx->colors, 0, sizeof(tx->colors));
-       
+       memset(tx->history_colors, 0, sizeof(tx->history_colors));
+
        gtk_tx_update_colors(tx);
        
        tx->current_fg=tx->audio_colors_focus;
@@ -231,7 +248,7 @@ static void gtk_tx_get_preferred_width (GtkWidget *widget, gint *minimal_width,
 }
 
 static void gtk_tx_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height) {
-    *minimal_height = *natural_height = TX_DEFAULT_SIZE_Y;
+       *minimal_height = *natural_height = TX_DEFAULT_SIZE_Y;
 }
 
 static void gtk_tx_reallocate_disp_data(GtkWidget *widget) {
@@ -433,9 +450,9 @@ static gboolean gtk_tx_draw(GtkWidget * widget, cairo_t *cr) {
        cairo_set_line_width(cr, 1);
 
        if (tx->disp_data) {
-               int src_x;
-
+               int src_x, step;
                int x_offset;
+
                if (tx->zoom > 0.0) {
                    x_offset= tx->cursor_pos > tx->xc ? tx->cursor_pos-tx->xc : 0;
                        if (x_offset+tx->xmax > tx->display_width) {
@@ -456,6 +473,58 @@ static gboolean gtk_tx_draw(GtkWidget * widget, cairo_t *cr) {
                        }
                }
 
+               tx->cursor_history[tx->cursor_history_offset] = tx->cursor_pos;
+               tx->cursor_history_offset++;
+               if (tx->cursor_history_offset >= GTK_TX_HISTORY_LENGTH) {
+                       tx->cursor_history_offset -= GTK_TX_HISTORY_LENGTH;
+               }
+
+               if (globals.wav_display_history && !tx->mute) {
+                       int prev_sample_pos = -1;
+                       /* draw history */
+
+                       for (step = 0; step < GTK_TX_HISTORY_LENGTH; step++) {
+                               int history_pos = tx->cursor_history_offset - step;
+
+                               if (history_pos < 0) {
+                                       history_pos += GTK_TX_HISTORY_LENGTH;
+                               }
+
+                               int sample_pos = tx->cursor_history[history_pos];
+
+                               if ((sample_pos >= 0) && (prev_sample_pos >= 0)) {
+                                       int sample_x_pos = sample_pos - tx->display_x_offset;
+                                       int prev_sample_x_pos = prev_sample_pos - tx->display_x_offset;
+                                       int min, max;
+
+                                       if (prev_sample_x_pos > sample_x_pos) {
+                                               min = sample_x_pos;
+                                               max = prev_sample_x_pos;
+                                       } else {
+                                               min = prev_sample_x_pos;
+                                               max = sample_x_pos;
+                                       }
+                                       
+                                       if ((max - min) <= tx->xc) {
+                                               for (x=min; x < max; x++) {
+                                                       int value = tx->disp_data[x+tx->display_x_offset];
+                                                       draw_sample(x, tx->yc-value, tx->yc+value+1, &tx->history_colors[GTK_TX_HISTORY_LENGTH-step]);
+                                               }
+                                       } else {
+                                               for (x = 0; x < min; x++) {
+                                                       int value = tx->disp_data[x+tx->display_x_offset];
+                                                       draw_sample(x, tx->yc-value, tx->yc+value+1, &tx->history_colors[GTK_TX_HISTORY_LENGTH-step]);
+                                               }
+                                               for (x= max; x < tx->xmax; x++) {
+                                                       int value = tx->disp_data[x+tx->display_x_offset];
+                                                       draw_sample(x, tx->yc-value, tx->yc+value+1, &tx->history_colors[GTK_TX_HISTORY_LENGTH-step]);
+                                               }
+                                       }
+                               }
+
+                               prev_sample_pos = sample_pos;
+                       }
+               }
                /* draw cursor */
                draw_sample(tx->cursor_x_pos, 0, tx->ymax, tx->mute ? &tx->colors[COL_CURSOR_MUTE] : &tx->colors[COL_CURSOR]);
        } else {
@@ -478,6 +547,7 @@ void gtk_tx_update_pos_display(GtkTx * tx, int sample, int mute) {
 void gtk_tx_cleanup_pos_display(GtkTx * tx) {
        GtkWidget *widget;
        GtkAllocation allocation;
+       int step;
 
        widget = GTK_WIDGET(tx);
        gtk_widget_get_allocation(widget, &allocation);
@@ -485,6 +555,10 @@ void gtk_tx_cleanup_pos_display(GtkTx * tx) {
        tx->display_x_offset=0;
        tx->cursor_pos=-1;
        tx->cursor_x_pos=-1;
+
+       for (step = 0; step < GTK_TX_HISTORY_LENGTH; step++) {
+               tx->cursor_history[step] = -1;
+       }
        
        gtk_widget_queue_draw(widget);
 }
index 21a6097..80bc44b 100644 (file)
@@ -32,7 +32,6 @@
 extern "C" {
 #endif /* __cplusplus */
 
-
 #define GTK_TX(obj)          G_TYPE_CHECK_INSTANCE_CAST (obj, gtk_tx_get_type (), GtkTx)
 #define GTK_TX_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_tx_get_type (), GtkTxClass)
 #define GTK_IS_TX(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, gtk_tx_get_type ())
@@ -46,6 +45,8 @@ typedef enum tx_widget_motion {
        MOTION_RIGHT
 } tx_widget_motion;
 
+#define GTK_TX_HISTORY_LENGTH 4 
+
 struct _GtkTx {
        GtkWidget widget;
 
@@ -54,6 +55,7 @@ struct _GtkTx {
        int samples;
        
        GdkRGBA colors[6];
+       GdkRGBA history_colors[GTK_TX_HISTORY_LENGTH];
        
        GdkRGBA *current_fg;
        GdkRGBA *current_bg;
@@ -72,6 +74,8 @@ struct _GtkTx {
        int cursor_pos;
        int cursor_x_pos;
        int mute;
+       int cursor_history[GTK_TX_HISTORY_LENGTH];
+       int cursor_history_offset;
 
        int display_width;
        int display_x_offset;