/* * Copyright (C) 2004-2005 Vadim Berezniker * http://www.kryptolus.com * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * http://www.gnu.org/copyleft/gpl.html * */ #include "stdafx.h" #include "common.h" #include "pavl.h" #include "kry_marker.h" #include "kry_region.h" #include "kry_region_fixed_list.h" #include "kry_waveform.h" #include "kry_waveform_group_item.h" #include "sound.h" static void kry_waveform_class_init (KryWaveformClass *klass); static void kry_waveform_init (KryWaveform *waveform); static void kry_waveform_destroy (GtkObject *object); static void kry_waveform_realize (GtkWidget *widget); static void kry_waveform_find_first_region(KryWaveform *waveform, gboolean backward); static void kry_waveform_size_request (GtkWidget *widget, GtkRequisition *requisition); void kry_waveform_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gboolean kry_waveform_button_press( GtkWidget *widget, GdkEventButton *event ); static gboolean kry_waveform_button_release( GtkWidget *widget, GdkEventButton *event ); static gboolean kry_waveform_motion_notify( GtkWidget *widget, GdkEventMotion *event ); static void kry_waveform_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data); void kry_waveform_set_data(KryWaveform *waveform, struct sound_info *sound_info); static gboolean kry_waveform_key_press( GtkWidget *widget, GdkEventKey *event ); static void kry_waveform_redraw(KryWaveform *waveform); static GtkWidgetClass *parent_class = NULL; static double kry_waveform_get_zoom_internal(KryWaveform *waveform); static void kry_waveform_update_zoom(KryWaveform *waveform); struct waveform_state { int width; int height; }; enum { ZOOM_CHANGED_SIGNAL, SCALE_CHANGED_SIGNAL, MIN_ZOOM_CHANGED_SIGNAL, LAST_SIGNAL }; static guint kry_waveform_signals[LAST_SIGNAL] = { 0 }; GtkType kry_waveform_get_type () { static GtkType waveform_type = 0; if (!waveform_type) { static const GtkTypeInfo waveform_info = { "KryWaveform", sizeof (KryWaveform), sizeof (KryWaveformClass), (GtkClassInitFunc) kry_waveform_class_init, (GtkObjectInitFunc) kry_waveform_init, /* reserved_1 */ NULL, /* reserved_1 */ NULL, (GtkClassInitFunc) NULL }; waveform_type = gtk_type_unique (GTK_TYPE_WIDGET, &waveform_info); } return waveform_type; } static void kry_waveform_class_init (KryWaveformClass *klass) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; object_class = (GtkObjectClass*) klass; widget_class = (GtkWidgetClass*) klass; parent_class = GTK_WIDGET_CLASS(gtk_type_class (gtk_widget_get_type ())); object_class->destroy = kry_waveform_destroy; widget_class->realize = kry_waveform_realize; widget_class->expose_event = kry_waveform_expose; widget_class->size_request = kry_waveform_size_request; widget_class->size_allocate = kry_waveform_size_allocate; widget_class->button_press_event = kry_waveform_button_press; widget_class->button_release_event = kry_waveform_button_release; widget_class->motion_notify_event = kry_waveform_motion_notify; widget_class->key_press_event = kry_waveform_key_press; kry_waveform_signals[ZOOM_CHANGED_SIGNAL] = g_signal_new ("zoom_changed", G_OBJECT_CLASS_TYPE (klass), (GSignalFlags) (G_SIGNAL_RUN_FIRST), G_STRUCT_OFFSET (KryWaveformClass, zoom_changed), NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); kry_waveform_signals[SCALE_CHANGED_SIGNAL] = g_signal_new ("scale_changed", G_OBJECT_CLASS_TYPE (klass), (GSignalFlags) (G_SIGNAL_RUN_FIRST), G_STRUCT_OFFSET (KryWaveformClass, scale_changed), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); kry_waveform_signals[MIN_ZOOM_CHANGED_SIGNAL] = g_signal_new ("min_zoom_changed", G_OBJECT_CLASS_TYPE (klass), (GSignalFlags) (G_SIGNAL_RUN_FIRST), G_STRUCT_OFFSET (KryWaveformClass, min_zoom_changed), NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); } static void kry_waveform_init (KryWaveform *waveform) { waveform->button_press = FALSE; waveform->data_per_pixel = 1; waveform->scale = 1; waveform->show_scrub_bar = TRUE; waveform->show_time_bar = TRUE; waveform->show_time_markers = TRUE; waveform->show_keyframe = TRUE; waveform->scrub_bar_height = 15; waveform->scrub_bar_height_real = 15; waveform->drag_selection_enabled = TRUE; waveform->zoom = 3.0; waveform->marker_width = 2; waveform->corner_width = 8; waveform->data_thread_mutex = g_mutex_new(); waveform->data_thread_mutex_global = g_mutex_new(); waveform->region_fixed_list = NULL; } void kry_waveform_disable_draw(KryWaveform *widget) { KryWaveform *waveform; g_return_if_fail (widget != NULL); g_return_if_fail (KRY_IS_WAVEFORM (widget)); waveform = KRY_WAVEFORM(widget); waveform->draw_disabled = TRUE; } void kry_waveform_enable_draw(KryWaveform *widget) { KryWaveform *waveform; g_return_if_fail (widget != NULL); g_return_if_fail (KRY_IS_WAVEFORM (widget)); waveform = KRY_WAVEFORM(widget); waveform->draw_disabled = FALSE; kry_waveform_redraw(waveform); } void kry_waveform_marker_draw_erase_real(KryWaveform *waveform, int pos_rel_pixel, gboolean erase) { GList *list = NULL; struct KryWaveformMarkerInfo *info = NULL; int width = waveform->marker_width; if(!erase) { info = kry_new(struct KryWaveformMarkerInfo, 1); info->marker = NULL; info->pos_rel_pixel = pos_rel_pixel; list = g_list_append(NULL, info); waveform->markers = g_list_concat(waveform->markers, list); } kry_waveform_backbuffer_draw_final(GTK_WIDGET(waveform), pos_rel_pixel, width, TRUE, FALSE); if(!erase) { waveform->markers = g_list_delete_link(waveform->markers, list); kry_free(info); } } /*void kry_waveform_marker_draw_erase(GtkWidget *widget, int mili, int mili_prev) { KryWaveform *waveform; g_return_if_fail (widget != NULL); g_return_if_fail (KRY_IS_WAVEFORM (widget)); waveform = KRY_WAVEFORM(widget); int pos_rel_pixel = kry_waveform_rel_pixel_from_mili(waveform, mili); int pos_rel_pixel_prev = kry_waveform_rel_pixel_from_mili(waveform, mili_prev); if(mili_prev != -1) kry_waveform_marker_draw_erase_real(waveform, pos_rel_pixel_prev, TRUE); if(mili != -1) kry_waveform_marker_draw_erase_real(waveform, pos_rel_pixel, FALSE); if(mili == -1) kry_waveform_update_front_buffer(waveform, pos_rel_pixel_prev, waveform->marker_width); else if(mili_prev == -1) kry_waveform_update_front_buffer(waveform, pos_rel_pixel, waveform->marker_width); else kry_waveform_update_front_buffer(waveform, pos_rel_pixel_prev, pos_rel_pixel - pos_rel_pixel_prev + waveform->marker_width); } void kry_waveform_marker_erase(GtkWidget *widget, int mili) { kry_waveform_marker_draw_erase(widget, mili, TRUE); }*/ static void kry_waveform_redraw_partial(KryWaveform *waveform, int start, int width, gboolean redraw_time_bar, gboolean do_draw) { if(!GTK_WIDGET_REALIZED(waveform)) return; kry_waveform_backbuffer_draw_final(GTK_WIDGET(waveform), start, width, TRUE, redraw_time_bar); if(do_draw) kry_waveform_update_front_buffer(waveform, start, width); } // redraws the entire wave. must be used only when necessary static void kry_waveform_redraw(KryWaveform *waveform) { if(!GTK_WIDGET_REALIZED(waveform) || waveform->draw_disabled) return; if(!waveform->data_pixel) return; waveform->last_draw_rect.x = kry_waveform_abs_pixel_from_rel(waveform, 0); waveform->last_draw_rect.width = GTK_WIDGET(waveform)->allocation.width; kry_waveform_backbuffer_draw_final(GTK_WIDGET(waveform), 0, GTK_WIDGET(waveform)->allocation.width, TRUE, TRUE); kry_waveform_update_front_buffer(waveform, 0, GTK_WIDGET(waveform)->allocation.width); } int kry_waveform_abs_pixel_from_mili(KryWaveform *waveform, long time) { return (int) ((((time / 1000.0) * waveform->data_info->vals_per_sec) / waveform->data_per_pixel)); } // gets a relative pixel position for the given time // (relative to the left side of the waveform) int kry_waveform_rel_pixel_from_mili(KryWaveform *waveform, long time) { return (int) ((((time / 1000.0) * waveform->data_info->vals_per_sec) / waveform->data_per_pixel) - ((waveform->left - fmod(waveform->left, waveform->data_per_pixel)) / waveform->data_per_pixel)); } int kry_waveform_abs_pixel_from_rel(KryWaveform *waveform, int pixel) { double abs = (pixel + waveform->left / waveform->data_per_pixel); return (int) abs + 1; } int kry_waveform_mili_from_rel_pixel(KryWaveform *waveform, int pixel) { return (int) (((pixel + (waveform->left - fmod(waveform->left, waveform->data_per_pixel)) / waveform->data_per_pixel) * 1000.0 * waveform->data_per_pixel) / waveform->data_info->vals_per_sec); } /* * Invoked when a color in the color table used by the wave widget changes. * This forces a redraw of the wave. */ void kry_waveform_color_changed(kryObject *obj, kryColor *color, KryWaveform *waveform) { //kryColorTable *table = (kryColorTable *) obj; #ifdef _WINDOWS if(color->GetID() == WAVEFORM_COLOR_BACKGROUND) { DeleteObject(waveform->black_brush); waveform->black_brush = CreateSolidBrush(RGB(color->GetRed(), color->GetGreen(), color->GetBlue())); } HPEN pen = (HPEN) color->GetUserData(); LOGPEN pen_info; GetObject(pen, sizeof(LOGPEN), &pen_info); if( GetRValue(pen_info.lopnColor) != color->GetRed() || GetGValue(pen_info.lopnColor) != color->GetGreen() || GetBValue(pen_info.lopnColor) != color->GetBlue()) { DeleteObject(color->GetUserData()); color->SetUserData(CreatePen(PS_SOLID, 1, RGB(color->GetRed(), color->GetGreen(), color->GetBlue()))); } #else GdkColor *gdkcolor = (GdkColor *) color->GetUserData(); gdkcolor->red = color->GetRed() * 255; gdkcolor->green = color->GetGreen() * 255; gdkcolor->blue = color->GetBlue() * 255; #endif kry_waveform_redraw(waveform); } GtkWidget *kry_waveform_new(KryWaveformDataInfo *info, GtkAdjustment *adjustment, kryColorTable *color_table) { KryWaveform *waveform; waveform = KRY_WAVEFORM(gtk_type_new (kry_waveform_get_type ())); if(color_table) { waveform->color_table = color_table; color_table->Ref(); waveform->signal_color_change = color_table->ConnectSignal(kryColorTable::SIGNAL_COLOR_CHANGED, (krySignalFunc1) kry_waveform_color_changed, waveform); } else { waveform->color_table = new kryColorTable(WAVEFORM_COLOR_COUNT); waveform->color_table->Set(WAVEFORM_COLOR_LINE, "WaveformLine", __("Color|Line"), 0, 0xAA, 0); waveform->color_table->Set(WAVEFORM_COLOR_SELECTION_HIGHLIGHT, "WaveformSelectionHighlight", __("Color|Selection Highlight"), 0xC0, 0xFF, 0); waveform->color_table->Set(WAVEFORM_COLOR_SILENCE_HIGHLIGHT, "WaveformSilenceHighlight", __("Color|Silence Highlight"), 0, 0x66, 0); waveform->color_table->Set(WAVEFORM_COLOR_MARKER_START, "WaveformMarkerStart", __("Color|Start Marker"), 0xAA, 0xAA, 0); waveform->color_table->Set(WAVEFORM_COLOR_MARKER_END, "WaveformMarkerEnd", __("Color|End Marker"), 0xAA, 0, 0); waveform->color_table->Set(WAVEFORM_COLOR_MARKER_KEYFRAME, "WaveformMarkerKeyframe", __("Color|Keyframe Marker"), 0xAA, 0xAA, 0xAA); waveform->color_table->Set(WAVEFORM_COLOR_BACKGROUND, "WaveformBackground", __("Color|Background"), 0, 0, 0); waveform->color_table->Set(WAVEFORM_COLOR_MARKER_TIME, "WaveformMarkerTime", __("Color|Time Marker"), 0, 0, 0x66); waveform->color_table->Set(WAVEFORM_COLOR_MARKER_CURRENT, "WaveformMarkerCurrent", __("Color|Play Marker"), 0x33, 0xFF, 0x33); waveform->color_table->Set(WAVEFORM_COLOR_TEXT, "WaveformText", __("Color|Text"), 0x55, 0xBB, 0xBB); waveform->color_table->Set(WAVEFORM_COLOR_MARKER_KARAOKE, "WaveformMarkerKaraoke", __("Color|Karaoke Marker"), 0x66, 0x30, 0x66); waveform->color_table->Set(WAVEFORM_COLOR_SCRUB_BAR_SEPARATOR, "WaveformScrubBarSeparator", __("Color|Scrub Bar Separator"), 0xFF, 0xFF, 0xFF); waveform->color_table->Set(WAVEFORM_COLOR_SCRUB_BAR_SLIDER, "WaveformScrubBarSlider", __("Color|Scrub Bar Slider"), 0x00, 0x44, 0xFF); waveform->color_table->Set(WAVEFORM_COLOR_SCRUB_BAR_EXTENSION, "WaveformScrubBarExtension", __("Color|Scrub Bar Extension"), 0x00, 0x88, 0x00); waveform->signal_color_change = waveform->color_table->ConnectSignal(kryColorTable::SIGNAL_COLOR_CHANGED, (krySignalFunc1) kry_waveform_color_changed, waveform); #ifdef _WINDOWS for(int i = 0; i < WAVEFORM_COLOR_COUNT; i++) { kryColor *color = waveform->color_table->Get(i); if(color->IsInitialized()) { HPEN pen = CreatePen(PS_SOLID, 1, RGB(color->GetRed(), color->GetGreen(), color->GetBlue())); color->SetUserData(pen); } } #else for(int i = 0; i < WAVEFORM_COLOR_COUNT; i++) { kryColor *color = waveform->color_table->Get(i); if(color->IsInitialized()) { GdkColor *color_gdk = kry_new0(GdkColor); color_gdk->red = color->GetRed() * 257; color_gdk->green = color->GetGreen() * 257; color_gdk->blue = color->GetBlue() * 257; gdk_rgb_find_color(gtk_widget_get_colormap(GTK_WIDGET(waveform)), color_gdk); color->SetUserData(color_gdk); } } #endif } #ifdef _WINDOWS kryColor *background = waveform->color_table->Get(WAVEFORM_COLOR_BACKGROUND); waveform->black_brush = CreateSolidBrush(RGB(background->GetRed(), background->GetGreen(), background->GetBlue())); waveform->cursor_normal = LoadCursor(NULL, IDC_ARROW); waveform->cursor_drag = LoadCursor(NULL, IDC_SIZEWE); #else waveform->cursor_drag = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW); waveform->layout = PANGO_LAYOUT(gtk_widget_create_pango_layout(GTK_WIDGET(waveform), NULL)); PangoFontDescription *desc = pango_font_description_from_string("Arial 10"); pango_layout_set_font_description(waveform->layout, desc); #endif waveform->data_info = info; if(adjustment) kry_waveform_set_adjustment(waveform, adjustment); g_object_set(waveform, "can-focus", TRUE, NULL); gtk_widget_set_double_buffered(GTK_WIDGET(waveform), FALSE); return GTK_WIDGET (waveform); } static void kry_waveform_destroy_graphics(KryWaveform *waveform) { #ifdef _WINDOWS if(waveform->bitmap_backbuffer_waveonly) { if(!DeleteObject(waveform->bitmap_backbuffer_waveonly)) g_warning("failed to delete backbuffer bitmap"); waveform->bitmap_backbuffer_waveonly = NULL; } if(waveform->backbuffer_waveonly) { if(!DeleteDC(waveform->backbuffer_waveonly)) g_warning("failed to delete backbuffer"); waveform->backbuffer_waveonly = NULL; } if(waveform->bitmap_backbuffer_final) { if(!DeleteObject(waveform->bitmap_backbuffer_final)) g_warning("failed to delete backbuffer copy bitmap"); waveform->bitmap_backbuffer_final = NULL; } if(waveform->backbuffer_final) { if(!DeleteDC(waveform->backbuffer_final)) g_warning("failed to delete backbuffer copy"); waveform->backbuffer_final = NULL; } if(waveform->dc) { ReleaseDC(HWND(GDK_WINDOW_HWND(GTK_WIDGET(waveform)->window)), waveform->dc); waveform->dc = NULL; } if(waveform->font) { if(!DeleteObject(waveform->font)) g_warning("failed to delete font"); waveform->font = NULL; } #else if(waveform->backbuffer_waveonly) { g_object_unref(waveform->backbuffer_waveonly); waveform->backbuffer_waveonly = NULL; } if(waveform->backbuffer_final) { g_object_unref(waveform->backbuffer_final); waveform->backbuffer_final = NULL; } if(waveform->gc) { g_object_unref(waveform->gc); waveform->gc = NULL; } #endif } static void kry_waveform_destroy(GtkObject *object) { KryWaveform *waveform; g_return_if_fail (object != NULL); g_return_if_fail (KRY_IS_WAVEFORM (object)); waveform = KRY_WAVEFORM (object); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); if(waveform->adjustment) { g_signal_handlers_disconnect_by_func(waveform->adjustment, (void *) kry_waveform_adjustment_value_changed, waveform); g_object_unref(waveform->adjustment); waveform->adjustment = NULL; } //if(waveform->mutex_markers) //{ kry_waveform_marker_remove_all(waveform); if(waveform->region_list) { kry_waveform_region_remove_all(waveform); waveform->region_list = NULL; } // g_mutex_free(waveform->mutex_markers); // waveform->mutex_markers = NULL; //} kry_waveform_destroy_graphics(waveform); #ifdef _WINDOWS int i; if(waveform->color_table) { waveform->color_table->DisconnectSignal(kryColorTable::SIGNAL_COLOR_CHANGED, waveform->signal_color_change); if(waveform->color_table->GetRefCount() == 1) { for(i = 0; i < WAVEFORM_COLOR_COUNT; i++) { if(waveform->color_table->GetUserData(i) != NULL) { DeleteObject(waveform->color_table->GetUserData(i)); waveform->color_table->SetUserData(i, NULL); } } delete waveform->color_table; } else { waveform->color_table->Unref(); } waveform->color_table = NULL; } if(waveform->black_brush) { DeleteObject(waveform->black_brush); waveform->black_brush = NULL; } #else if(waveform->layout) { g_object_unref(waveform->layout); waveform->layout = NULL; } #endif kry_waveform_data_thread_end(waveform); if(waveform->data_pixel) { kry_free(waveform->data_pixel); waveform->data_pixel = NULL; } if(waveform->data_time) { kry_free(waveform->data_time); waveform->data_time = NULL; } kry_waveform_region_fixed_list_set(waveform, NULL); } GtkAdjustment* kry_waveform_get_adjustment (KryWaveform *waveform) { g_return_val_if_fail (waveform != NULL, NULL); g_return_val_if_fail (KRY_IS_WAVEFORM (waveform), NULL); return waveform->adjustment; } void kry_waveform_marker_redraw_at_time(KryWaveform *waveform, long time_mili, gboolean no_update = FALSE) { if(time_mili == -1 || waveform->data_info == NULL) return; int start = kry_waveform_rel_pixel_from_mili(waveform, time_mili); int width = waveform->marker_width + waveform->corner_width; kry_waveform_redraw_partial(waveform, start, width, FALSE, !no_update); } void kry_waveform_marker_changed_cb(KryMarker *marker, int old_position, KryWaveform *waveform) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); if(!waveform->data_info) return; if(g_object_get_data(G_OBJECT(marker), "highlight")) return; int pos1 = kry_waveform_rel_pixel_from_mili(waveform, kry_marker_get_value(marker)); int pos2 = kry_waveform_rel_pixel_from_mili(waveform, old_position); int width = waveform->marker_width + 10; kry_waveform_redraw_partial(waveform, pos1, width, FALSE, FALSE); kry_waveform_redraw_partial(waveform, pos2, width, FALSE, FALSE); kry_waveform_update_front_buffer_fast(waveform, pos1, width); kry_waveform_update_front_buffer_fast(waveform, pos2, width); if(waveform->marker_autoscroll == marker) { if((pos1 * 100) / GTK_WIDGET(waveform)->allocation.width > 90) { int page_increment = (int) waveform->adjustment->page_increment; int val = (int) (gtk_adjustment_get_value(waveform->adjustment) + page_increment); gtk_adjustment_set_value(waveform->adjustment, val); } } } void kry_waveform_highlight_marker_changed(KryMarker *marker, long old_position, KryWaveform *waveform) { GtkWidget *widget; int start_pixel, end_pixel; g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); if(waveform->data_info == NULL) return; if(old_position == -1) { kry_waveform_redraw(waveform); return; } if(kry_marker_get_value(marker) == -1) start_pixel = 0; else start_pixel = kry_waveform_rel_pixel_from_mili(waveform, kry_marker_get_value(marker)); if(old_position == -1) end_pixel = 0; else end_pixel = kry_waveform_rel_pixel_from_mili(waveform, old_position); if(start_pixel > end_pixel) { int tmp = start_pixel; start_pixel = end_pixel; end_pixel = tmp; } widget = GTK_WIDGET(waveform); if(start_pixel + waveform->marker_width + waveform->corner_width < 0 && end_pixel + waveform->marker_width + waveform->corner_width < 0 || start_pixel > widget->allocation.width && end_pixel > widget->allocation.width) { return; } if(start_pixel < 0) start_pixel = 0; if(end_pixel >= widget->allocation.width) end_pixel = widget->allocation.width - 1; kry_waveform_redraw_partial(waveform, start_pixel - waveform->corner_width, end_pixel + waveform->marker_width + waveform->corner_width * 2 - start_pixel, FALSE, TRUE); } void kry_waveform_region_add_new(KryWaveform *waveform, KryMarker *marker_left, KryMarker *marker_right, int color_id) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); KryRegion *region = KRY_REGION(kry_region_new(marker_left, marker_right, color_id)); kry_waveform_region_add(waveform, region); } void kry_waveform_region_add(KryWaveform *waveform, KryRegion *region) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); g_object_ref(region); int color_id = kry_region_get_colorid(region); if(color_id != -1) { g_object_set_data(G_OBJECT(kry_region_get_marker_start(region)), "highlight", (gpointer) TRUE); g_object_set_data(G_OBJECT(kry_region_get_marker_end(region)), "highlight", (gpointer) TRUE); g_signal_connect(kry_region_get_marker_start(region), "value-changed", G_CALLBACK(kry_waveform_highlight_marker_changed), waveform); g_signal_connect(kry_region_get_marker_end(region), "value-changed", G_CALLBACK(kry_waveform_highlight_marker_changed), waveform); } waveform->region_list = g_list_append(waveform->region_list, region); if(color_id != -1 && waveform->data_info) { KryMarker *m1 = kry_region_get_marker_start(region); KryMarker *m2 = kry_region_get_marker_end(region); int px1 = kry_waveform_rel_pixel_from_mili(waveform, kry_marker_get_value(m1)); int px2 = kry_waveform_rel_pixel_from_mili(waveform, kry_marker_get_value(m2)); if(px1 <= GTK_WIDGET(waveform)->allocation.width - 1 && px2 >= 0 && px1 <= px2) kry_waveform_redraw_partial(waveform, px1, px2 + waveform->marker_width - 1, FALSE, TRUE); } } static void kry_waveform_region_fixed_added_cb(KryRegionFixedList *list, KryRegionFixed *region, KryWaveform *waveform) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); if(!waveform->data_info) return; if(pavl_count(waveform->region_fixed_list->tree) == 1) pavl_t_first(&waveform->region_fixed_list_iter, waveform->region_fixed_list->tree); int px1 = kry_waveform_rel_pixel_from_mili(waveform, region->start); int px2 = kry_waveform_rel_pixel_from_mili(waveform, region->end); if(px1 <= GTK_WIDGET(waveform)->allocation.width - 1 && px2 >= 0 && px1 <= px2) { struct KryRegionFixedInfo *info = (struct KryRegionFixedInfo *) pavl_t_cur(&waveform->region_fixed_list_iter); if(info) { struct KryRegionFixed *region_cur = (struct KryRegionFixed *) info->regions->data; if(region_cur->start > region->start) pavl_t_prev(&waveform->region_fixed_list_iter); }; kry_waveform_redraw_partial(waveform, px1, px2 + waveform->marker_width - 1, FALSE, TRUE); } } static void kry_waveform_region_fixed_removed_cb(KryRegionFixedList *list, KryRegionFixed *region, KryWaveform *waveform) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); if(!waveform->data_info) return; pavl_t_first(&waveform->region_fixed_list_iter, waveform->region_fixed_list->tree); kry_waveform_find_first_region(waveform, FALSE); int px1 = kry_waveform_rel_pixel_from_mili(waveform, region->start); int px2 = kry_waveform_rel_pixel_from_mili(waveform, region->end); if(px1 <= GTK_WIDGET(waveform)->allocation.width - 1 && px2 >= 0 && px1 <= px2) kry_waveform_redraw_partial(waveform, px1, px2 + waveform->marker_width - 1, FALSE, TRUE); } void kry_waveform_region_fixed_list_set(KryWaveform *waveform, KryRegionFixedList *list) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); if(waveform->region_fixed_list) { g_signal_handlers_disconnect_by_func(waveform->region_fixed_list, (void *) kry_waveform_region_fixed_added_cb, waveform); g_signal_handlers_disconnect_by_func(waveform->region_fixed_list, (void *) kry_waveform_region_fixed_removed_cb, waveform); waveform->region_fixed_list = NULL; } if(list) { waveform->region_fixed_list = list; pavl_t_first(&waveform->region_fixed_list_iter, waveform->region_fixed_list->tree); g_signal_connect(list, "region-added", (GCallback) kry_waveform_region_fixed_added_cb, waveform); g_signal_connect(list, "region-removed", (GCallback) kry_waveform_region_fixed_removed_cb, waveform); } kry_waveform_redraw(waveform); } void kry_waveform_region_remove_by_type(KryWaveform *waveform, int color_id) { GList *ptr_next; g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); for(GList *ptr = waveform->region_list; ptr; ptr = ptr_next) { ptr_next = ptr->next; KryRegion *region = (KryRegion *) ptr->data; if(color_id != -1 && kry_region_get_colorid(region) != color_id) continue; g_signal_handlers_disconnect_by_func(kry_region_get_marker_start(region), (void *) kry_waveform_highlight_marker_changed, waveform); g_signal_handlers_disconnect_by_func(kry_region_get_marker_end(region), (void *) kry_waveform_highlight_marker_changed, waveform); g_object_set_data(G_OBJECT(kry_region_get_marker_start(region)), "highlight", (gpointer) FALSE); g_object_set_data(G_OBJECT(kry_region_get_marker_end(region)), "highlight", (gpointer) FALSE); waveform->region_list = g_list_remove(waveform->region_list, region); g_object_unref(G_OBJECT(region)); } } void kry_waveform_region_remove_all(KryWaveform *waveform) { kry_waveform_region_remove_by_type(waveform, -1); } void kry_waveform_marker_add(KryWaveform *waveform, KryMarker *marker) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); struct KryWaveformMarkerInfo *marker_info = kry_new(struct KryWaveformMarkerInfo, 1); marker_info->marker = marker; //g_mutex_lock(waveform->mutex_markers); waveform->markers = g_list_append(waveform->markers, marker_info); g_signal_connect(marker, "value-changed", G_CALLBACK(kry_waveform_marker_changed_cb), waveform); // this forces the marker area to be redrawn kry_waveform_marker_redraw_at_time(waveform, kry_marker_get_value(marker)); //g_mutex_unlock(waveform->mutex_markers); } void kry_waveform_marker_hide(KryWaveform *waveform, KryMarker *marker) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); g_object_set_data(G_OBJECT(marker), "hidden", (gpointer) 1); kry_waveform_marker_redraw_at_time(waveform, kry_marker_get_value(marker)); } void kry_waveform_marker_show(KryWaveform *waveform, KryMarker *marker) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); g_object_set_data(G_OBJECT(marker), "hidden", 0); kry_waveform_marker_redraw_at_time(waveform, kry_marker_get_value(marker)); } static void kry_waveform_marker_remove_internal(KryWaveform *waveform, KryMarker *marker_match, enum marker_type type, gboolean remove_all) { GList *ptr; GList *next = NULL; g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); //g_mutex_lock(waveform->mutex_markers); for(ptr = waveform->markers; ptr; ptr = next) { struct KryWaveformMarkerInfo *info = (struct KryWaveformMarkerInfo *) ptr->data; KryMarker *marker = info->marker; next = ptr->next; if(marker_match && marker == marker_match || kry_marker_get_marker_type(marker) == type || remove_all) { if(waveform->marker_active_start == marker) kry_waveform_marker_set_active_start(waveform, NULL); if(waveform->marker_active_end == marker) kry_waveform_marker_set_active_end(waveform, NULL); g_signal_handlers_disconnect_by_func(marker, (void *) kry_waveform_marker_changed_cb, waveform); waveform->markers = g_list_delete_link(waveform->markers, ptr); kry_waveform_marker_redraw_at_time(waveform, kry_marker_get_value(marker)); } } //g_mutex_unlock(waveform->mutex_markers); } void kry_waveform_marker_remove_by_type(KryWaveform *waveform, enum marker_type type) { kry_waveform_marker_remove_internal(waveform, NULL, type, FALSE); } void kry_waveform_marker_remove(KryWaveform *waveform, KryMarker *marker) { kry_waveform_marker_remove_internal(waveform, marker, (enum marker_type) 0, FALSE); } void kry_waveform_marker_remove_all(KryWaveform *waveform) { kry_waveform_marker_remove_internal(waveform, NULL, (enum marker_type) 0, TRUE); } void kry_waveform_marker_set_autoscroll(KryWaveform *waveform, KryMarker *marker) { g_return_if_fail (KRY_IS_WAVEFORM (waveform)); waveform->marker_autoscroll = marker; } gboolean kry_waveform_get_show_time_bar(KryWaveform *waveform) { g_return_val_if_fail (waveform != NULL, FALSE); g_return_val_if_fail (KRY_IS_WAVEFORM (waveform), FALSE); return waveform->show_time_bar; } gboolean kry_waveform_get_show_keyframes(KryWaveform *waveform) { g_return_val_if_fail (waveform != NULL, FALSE); g_return_val_if_fail (KRY_IS_WAVEFORM (waveform), FALSE); return waveform->show_keyframe; } void kry_waveform_set_show_scrub_bar(KryWaveform *waveform, gboolean val) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); if(waveform->show_scrub_bar == val) return; if(val) waveform->scrub_bar_height = waveform->scrub_bar_height_real; else waveform->scrub_bar_height = 0; waveform->wave_height = GTK_WIDGET(waveform)->allocation.height - waveform->time_bar_height - waveform->scrub_bar_height; waveform->show_scrub_bar = val; kry_waveform_redraw(waveform); } void kry_waveform_set_show_time_bar(KryWaveform *waveform, gboolean val) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); if(waveform->show_time_bar == val) return; if(val) waveform->time_bar_height = waveform->time_bar_height_real; else waveform->time_bar_height = 0; waveform->wave_height = GTK_WIDGET(waveform)->allocation.height - waveform->time_bar_height - waveform->scrub_bar_height; waveform->show_time_bar = val; kry_waveform_redraw(waveform); } void kry_waveform_set_show_time_markers(KryWaveform *waveform, gboolean val) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); if(waveform->show_time_markers == val) return; waveform->show_time_markers = val; kry_waveform_redraw(waveform); } void kry_waveform_set_show_keyframes(KryWaveform *waveform, gboolean val) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); waveform->show_keyframe = val; kry_waveform_redraw(waveform); } void kry_waveform_set_adjustment (KryWaveform *waveform, GtkAdjustment *adjustment) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); if(waveform->adjustment) { g_signal_handlers_disconnect_by_func(waveform->adjustment, (void *) kry_waveform_adjustment_value_changed, waveform); g_object_unref (GTK_OBJECT (waveform->adjustment)); } waveform->adjustment = adjustment; g_object_ref(adjustment); gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", (GtkSignalFunc) kry_waveform_adjustment_value_changed, (gpointer) waveform); kry_waveform_adjustment_value_changed(adjustment, waveform); } static void kry_waveform_realize (GtkWidget *widget) { KryWaveform *waveform; GdkWindowAttr attributes; gint attributes_mask; g_return_if_fail (widget != NULL); g_return_if_fail (KRY_IS_WAVEFORM (widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); waveform = KRY_WAVEFORM (widget); attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); #ifdef _WINDOWS waveform->dc = GetDC(HWND(GDK_WINDOW_HWND(widget->window))); #else waveform->gc = gdk_gc_new(widget->window); #endif widget->style = gtk_style_attach (widget->style, widget->window); gdk_window_set_user_data (widget->window, widget); gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE); if(!waveform->backbuffer_waveonly) kry_waveform_size_allocate(widget, &widget->allocation); } static void kry_waveform_size_request (GtkWidget *widget, GtkRequisition *requisition) { requisition->width = 200; requisition->height = 80; } void kry_waveform_update_adjustment(KryWaveform *waveform) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); waveform->adjustment->step_increment = ((GTK_WIDGET(waveform)->allocation.width - 100) * waveform->data_per_pixel) / 10; waveform->adjustment->page_increment = ((GTK_WIDGET(waveform)->allocation.width - 100) * waveform->data_per_pixel); waveform->adjustment->upper = waveform->data_info->length_seconds * waveform->data_info->vals_per_sec; waveform->adjustment->page_size = (double) waveform->adjustment->upper * waveform->data_per_pixel * GTK_WIDGET(waveform)->allocation.width / (double) (waveform->data_info->length_seconds * waveform->data_info->vals_per_sec); g_signal_emit_by_name(G_OBJECT(waveform->adjustment), "changed"); } void kry_waveform_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { KryWaveform *waveform; g_return_if_fail (widget != NULL); g_return_if_fail (KRY_IS_WAVEFORM (widget)); g_return_if_fail (allocation != NULL); widget->allocation = *allocation; if (GTK_WIDGET_REALIZED (widget)) { #ifdef _WINDOWS LOGFONT lfont; #endif waveform = KRY_WAVEFORM (widget); gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); if(waveform->adjustment && waveform->data_info) kry_waveform_update_adjustment(waveform); kry_waveform_destroy_graphics(waveform); #ifdef _WINDOWS lfont.lfHeight = 14; lfont.lfWidth = 0; lfont.lfEscapement = 0; lfont.lfOrientation = 0; lfont.lfWeight = FW_NORMAL; lfont.lfItalic = 0; lfont.lfUnderline = 0; lfont.lfStrikeOut = 0; lfont.lfCharSet = ANSI_CHARSET; lfont.lfOutPrecision = OUT_DEFAULT_PRECIS; lfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; // lfQuality Specifies the output quality. Use ANTIALIASED_QUALITY! lfont.lfQuality = ANTIALIASED_QUALITY; lfont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN; lstrcpy(lfont.lfFaceName,"Arial"); waveform->font = CreateFontIndirect(&lfont); if(!waveform->font) g_warning("failed to create font"); waveform->dc = GetDC(HWND(GDK_WINDOW_HWND(GTK_WIDGET(waveform)->window))); if(!waveform->dc) g_warning("failed to obtain waveform db"); waveform->backbuffer_waveonly = CreateCompatibleDC(waveform->dc); if(!waveform->backbuffer_waveonly) g_warning("failed to create backbuffer"); waveform->backbuffer_final = CreateCompatibleDC(waveform->dc); if(!waveform->backbuffer_final) g_warning("failed to create backbuffer copy"); waveform->bitmap_backbuffer_waveonly = CreateCompatibleBitmap (waveform->dc, allocation->width, allocation->height); if(!waveform->bitmap_backbuffer_waveonly) g_warning("failed to create backbuffer bitmap"); if(!SelectObject (waveform->backbuffer_waveonly, waveform->bitmap_backbuffer_waveonly)) g_warning("failed to select backbuffer bitmap"); waveform->bitmap_backbuffer_final = CreateCompatibleBitmap (waveform->dc, allocation->width, allocation->height); if(!waveform->bitmap_backbuffer_final) g_warning("failed to create backbuffer copy bitmap"); if(!SelectObject (waveform->backbuffer_final, waveform->bitmap_backbuffer_final)) g_warning("failed to select backbuffer bitmap copy"); if(!SelectObject(waveform->backbuffer_waveonly, waveform->font)) g_warning("failed to select font"); if(!SetBkMode(waveform->backbuffer_waveonly, TRANSPARENT)) g_warning("failed to set background mode"); TEXTMETRIC metric; GetTextMetrics(waveform->backbuffer_final, &metric); waveform->time_bar_height_real = metric.tmHeight; #else PangoContext *context = pango_layout_get_context(waveform->layout); PangoFontDescription *desc = (PangoFontDescription *) pango_layout_get_font_description(waveform->layout); PangoFontMetrics *metrics = pango_context_get_metrics(context, desc, NULL); waveform->backbuffer_waveonly = gdk_pixmap_new(widget->window, allocation->width, allocation->height, -1); waveform->backbuffer_final = gdk_pixmap_new(waveform->backbuffer_waveonly, allocation->width, allocation->height, -1); waveform->gc = gdk_gc_new(widget->window); waveform->time_bar_height_real = (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) / PANGO_SCALE; #endif if(waveform->show_time_bar) waveform->time_bar_height = waveform->time_bar_height_real; waveform->wave_height = allocation->height - waveform->time_bar_height - waveform->scrub_bar_height; kry_waveform_update_zoom(waveform); double min_zoom = kry_waveform_get_zoom_min(waveform); if(fabs(min_zoom - waveform->min_zoom) > 0.0001) { waveform->min_zoom = min_zoom; g_signal_emit(waveform, kry_waveform_signals[MIN_ZOOM_CHANGED_SIGNAL], 0, min_zoom); } kry_waveform_redraw(waveform); } } static gboolean kry_waveform_key_press( GtkWidget *widget, GdkEventKey *event ) { KryWaveform *waveform; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (KRY_IS_WAVEFORM (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); waveform = KRY_WAVEFORM (widget); return TRUE; } static gboolean kry_waveform_is_over_marker(KryWaveform *waveform, KryMarker *marker, int x) { int marker_pos = kry_waveform_rel_pixel_from_mili(waveform, kry_marker_get_value(marker)); if(x >= marker_pos - 3 && x <= marker_pos + 4) return TRUE; else return FALSE; } static gboolean kry_waveform_button_press( GtkWidget *widget, GdkEventButton *event ) { KryWaveform *waveform; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (KRY_IS_WAVEFORM (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); waveform = KRY_WAVEFORM (widget); if(!waveform->data_info) return FALSE; waveform->button_press = TRUE; if(event->button == 2) return FALSE; if(!GTK_WIDGET_HAS_FOCUS(widget)) gtk_widget_grab_focus(widget); if(event->y < waveform->scrub_bar_height) { if(event->x >= waveform->scrub_bar_left_ext && event->x <= waveform->scrub_bar_right_ext) { waveform->is_scrub_bar_dragging = TRUE; waveform->scrub_bar_drag_offset = (int) event->x - waveform->scrub_bar_left; } return FALSE; } // user clicked on the start marker if(waveform->drag_markers_enabled && waveform->marker_active_start && kry_waveform_is_over_marker(waveform, waveform->marker_active_start, (int) event->x)) { waveform->marker_dragging = waveform->marker_active_start; } // user clicked on the end marker if(waveform->drag_markers_enabled && !waveform->marker_dragging && waveform->marker_active_end && kry_waveform_is_over_marker(waveform, waveform->marker_active_end, (int) event->x)) { waveform->marker_dragging = waveform->marker_active_end; } // user didn't click on a marker (he either wants to put the start marker there, or he wants to create a selection by dragging) if(!waveform->marker_dragging && event->button == 1 && waveform->marker_active_start) { int mili = kry_waveform_mili_from_rel_pixel(waveform, (int) event->x); kry_marker_set_value(waveform->marker_active_start, mili); if(waveform->drag_selection_enabled && waveform->drag_markers_enabled) { waveform->marker_dragging = waveform->marker_active_end; waveform->drag_select = TRUE; } else { waveform->marker_dragging = waveform->marker_active_start; } } if(waveform->drag_markers_enabled && waveform->marker_dragging) { #ifdef _WINDOWS SetCursor(waveform->cursor_drag); #endif return FALSE; } if(event->button == 3 && waveform->marker_active_end) { int mili = kry_waveform_mili_from_rel_pixel(waveform, (int) event->x); kry_marker_set_value(waveform->marker_active_end, mili); if(!waveform->drag_selection_enabled || !waveform->drag_markers_enabled) waveform->marker_dragging = waveform->marker_active_end; } return FALSE; } static gboolean kry_waveform_motion_notify( GtkWidget *widget, GdkEventMotion *event ) { KryWaveform *waveform; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (KRY_IS_WAVEFORM (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); waveform = KRY_WAVEFORM (widget); if(!waveform->data_info) return FALSE; if(waveform->is_scrub_bar_dragging) { int left = (int) waveform->left; if(event->x < 0) event->x = 0; if(event->x >= GTK_WIDGET(waveform)->allocation.width) event->x = GTK_WIDGET(waveform)->allocation.width - 1; left = (int) ((event->x - waveform->scrub_bar_drag_offset) * (((double) waveform->data_info->length_seconds * waveform->data_info->vals_per_sec) / GTK_WIDGET(waveform)->allocation.width)); if(left < 0) waveform->scrub_bar_drag_offset = (int) event->x; if(left >= waveform->adjustment->upper - waveform->adjustment->page_size) { left = (int) (waveform->adjustment->upper - waveform->adjustment->page_size); waveform->scrub_bar_drag_offset = waveform->scrub_bar_width - (GTK_WIDGET(waveform)->allocation.width - (int) event->x); } gtk_adjustment_set_value(waveform->adjustment, left); return FALSE; } // in the middle of a drag operation if(waveform->marker_dragging) { // if in the middle of a "drag to create a selection" operation if(waveform->drag_select) { // don't do anything unless the pointer has moved at least 10 pixels from the original location" int oldpx = kry_waveform_rel_pixel_from_mili(waveform, kry_marker_get_value(waveform->marker_active_start)); if(abs((int) event->x - oldpx) < 10) return FALSE; waveform->drag_select = FALSE; } int marker_pixel = (int) event->x; int marker_mili = kry_waveform_mili_from_rel_pixel(waveform, marker_pixel); // if keyframes are on, see if there are any keyframes nearby if(waveform->show_keyframe) { for(int i = 0; i < waveform->keyframes_rel_count; i++) { int val = kry_waveform_rel_pixel_from_mili(waveform, waveform->keyframes_rel[i]); if(val - marker_pixel > 20) break; if(abs(val - marker_pixel) <= 20) { int mili = waveform->keyframes_rel[i]; if(mili % 10 != 0) mili -= (mili % 10); mili -= 10; marker_mili = mili; break; } } } //g_warning("set value"); kry_marker_set_value(waveform->marker_dragging, marker_mili); return FALSE; } if(event->y < waveform->scrub_bar_height) return FALSE; if(waveform->drag_markers_enabled && (waveform->marker_active_start && kry_waveform_is_over_marker(waveform, waveform->marker_active_start, (int) event->x) ||waveform->marker_active_end && kry_waveform_is_over_marker(waveform, waveform->marker_active_end, (int) event->x))) { #ifdef _WINDOWS SetCursor(waveform->cursor_drag); #else gdk_window_set_cursor(widget->window, waveform->cursor_drag); #endif } else { #ifdef _WINDOWS SetCursor(waveform->cursor_normal); #else gdk_window_set_cursor(widget->window, NULL); #endif } return FALSE; } /*KryMarker *kry_waveform_get_marker(KryWaveform *waveform, enum marker_type type) { GList *ptr; g_return_val_if_fail (waveform != NULL, NULL); g_return_val_if_fail (KRY_IS_WAVEFORM (waveform), NULL); for(ptr = waveform->markers; ptr; ptr = ptr->next) { KryMarker *marker = KRY_MARKER(ptr->data); if(marker->type == type) return marker; } return NULL; }*/ static gboolean kry_waveform_button_release(GtkWidget *widget, GdkEventButton *event) { KryWaveform *waveform; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (KRY_IS_WAVEFORM (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); waveform = KRY_WAVEFORM (widget); if(waveform->button_press == FALSE) return FALSE; waveform->button_press = FALSE; if(!waveform->data_info) return FALSE; if(waveform->is_scrub_bar_dragging) waveform->is_scrub_bar_dragging = FALSE; if(waveform->marker_dragging) { waveform->marker_dragging = NULL; waveform->drag_select = FALSE; return FALSE; } if(event->button != 2) return FALSE; struct pavl_traverser iter; kry_region_fixed_list_get_iter(waveform->region_fixed_list, &iter); while(struct KryRegionFixedInfo *info = (struct KryRegionFixedInfo *) pavl_t_next(&iter)) { for(GList *ptr = info->regions; ptr; ptr = ptr->next) { KryRegion *region = (KryRegion *) ptr->data; int mili = kry_waveform_mili_from_rel_pixel(waveform, (int) event->x); int start_mili = kry_marker_get_value(kry_region_get_marker_start(region)); int end_mili = kry_marker_get_value(kry_region_get_marker_end(region)); if(mili >= start_mili && mili <= end_mili) { kry_region_selected(region); break; } } } return FALSE; } void kry_waveform_setup_rel_keyframe_list(KryWaveform *waveform) { waveform->keyframes_rel = NULL; waveform->keyframes_rel_count = 0; if(!waveform->keyframe_list || !waveform->data_info) return; long left_mili = (long) (((double) waveform->left / waveform->data_info->vals_per_sec) * 1000); for(int i = 0; i < waveform->keyframe_list->count; i++) { if(waveform->keyframe_list->list[i] >= left_mili) { waveform->keyframes_rel = waveform->keyframe_list->list + i; waveform->keyframes_rel_count = waveform->keyframe_list->count - i; break; } } } struct KryWaveformKeyframeList *kry_waveform_get_keyframe_list(KryWaveform *waveform) { g_return_val_if_fail (waveform != NULL, NULL); g_return_val_if_fail (KRY_IS_WAVEFORM (waveform), NULL); return waveform->keyframe_list; } void kry_waveform_set_keyframe_list(KryWaveform *waveform, KryWaveformKeyframeList *list) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); waveform->keyframe_list = list; kry_waveform_setup_rel_keyframe_list(waveform); kry_waveform_redraw(waveform); } double kry_waveform_get_zoom_internal(KryWaveform *waveform) { double data_per_pixel = (waveform->data_info->vals_per_sec * waveform->zoom) / GTK_WIDGET(waveform)->allocation.width; return data_per_pixel; } void kry_waveform_data_process_range(KryWaveform *waveform, int sec_start, int sec_end) { int j; unsigned char *wave = (unsigned char *) waveform->data_info->waveform_data; int num_data = (int) waveform->data_per_pixel; if(waveform->data_per_pixel - (int) waveform->data_per_pixel > 0.01) num_data++; int pixel_start = kry_waveform_abs_pixel_from_mili(waveform, sec_start * 1000); int pixel_end = kry_waveform_abs_pixel_from_mili(waveform, sec_end * 1000); //g_warning("px %d - %d", pixel_start, pixel_end); int max_index = waveform->data_info->vals_per_sec * waveform->data_info->length_seconds * 2; int last_index = 0; for(int pixel = pixel_start; pixel < pixel_end; pixel++) { unsigned char vpos = 0, vneg = 0; int index = kry_waveform_get_index_at_abs_pixel(waveform, pixel); /*if(pixel > 0 && waveform->data_per_pixel - (int) waveform->data_per_pixel > 0.01) { int prev_end_index = kry_waveform_get_index_at_rel_pixel(waveform, pixel - 1) + (num_data - 1) * 2; if(index != prev_end_index) { num_data += (index - prev_end_index) / 2; index = prev_end_index; } }*/ if(index + num_data * 2 >= max_index) { vpos = 0; vneg = 0; //int length_mili = waveform->data_info->length_seconds * 1000; //int pixels = kry_waveform_abs_pixel_from_mili(waveform, length_mili); //memset(waveform->data_per_pixel } else { // we find the maximum positive value of the points that represent the current pixel for(j = 0; j < num_data; j++) if(wave[index + j*2] > vpos) vpos = wave[index + j*2]; // we find the maximum negative value of the points that represent the current pixel for(j = 0; j < num_data; j++) if(wave[index + j*2 + 1] > vneg) vneg = wave[index + j*2 + 1]; } int px = pixel * 2; if(px + 1 < waveform->data_pixel_length) { waveform->data_pixel[px] = vpos; waveform->data_pixel[px + 1] = vneg; } last_index = px; } //g_warning("last index: %d", last_index); for(int i = sec_start; i < sec_end; i++) waveform->data_time[i] = 1; } void kry_waveform_data_thread(KryWaveform *waveform) { g_mutex_lock(waveform->data_thread_mutex_global); for(int i = 0; i < waveform->data_info->length_seconds; i++) { g_mutex_lock(waveform->data_thread_mutex); if(waveform->data_time[i]) { g_mutex_unlock(waveform->data_thread_mutex); continue; } if(waveform->data_thread_quit) { g_mutex_unlock(waveform->data_thread_mutex); break; } kry_waveform_data_process_range(waveform, i, i + 1); g_mutex_unlock(waveform->data_thread_mutex); } g_mutex_lock(waveform->data_thread_mutex); waveform->data_thread = NULL; g_mutex_unlock(waveform->data_thread_mutex); g_mutex_unlock(waveform->data_thread_mutex_global); } void kry_waveform_data_ensure_available(KryWaveform *waveform, int sec_start, int sec_end) { g_mutex_lock(waveform->data_thread_mutex); if(sec_start >= waveform->data_info->length_seconds) return; for(int i = sec_start; i < sec_end; i++) { if(waveform->data_time[i]) continue; kry_waveform_data_process_range(waveform, i, i + 1); } g_mutex_unlock(waveform->data_thread_mutex); } void kry_waveform_data_thread_end(KryWaveform *waveform) { g_mutex_lock(waveform->data_thread_mutex); if(waveform->data_thread) { waveform->data_thread_quit = TRUE; g_mutex_unlock(waveform->data_thread_mutex); g_mutex_lock(waveform->data_thread_mutex_global); g_mutex_unlock(waveform->data_thread_mutex_global); waveform->data_thread_quit = FALSE; } else { g_mutex_unlock(waveform->data_thread_mutex); } } void kry_waveform_update_zoom(KryWaveform *waveform) { if(!waveform->data_info) return; kry_waveform_data_thread_end(waveform); if(waveform->data_pixel) kry_free(waveform->data_pixel); if(waveform->data_time) kry_free(waveform->data_time); waveform->data_per_pixel = kry_waveform_get_zoom_internal(waveform); if(waveform->data_per_pixel < 1) waveform->data_per_pixel = 1; int length_mili = waveform->data_info->length_seconds * 1000; int pixels = kry_waveform_abs_pixel_from_mili(waveform, length_mili); //g_warning("allocated: %d", pixels * 2); waveform->data_pixel = kry_new(char, pixels * 2); waveform->data_pixel_length = pixels * 2; waveform->data_time = kry_new0_n(char, waveform->data_info->length_seconds); waveform->data_thread = g_thread_create((GThreadFunc) kry_waveform_data_thread, waveform, TRUE, NULL); if(waveform->adjustment) { kry_waveform_update_adjustment(waveform); if(waveform->adjustment->value > waveform->adjustment->upper - waveform->adjustment->page_size) { waveform->adjustment->value = waveform->adjustment->upper - waveform->adjustment->page_size; if(waveform->adjustment->value < 0) waveform->adjustment->value = 0; g_signal_emit_by_name(G_OBJECT(waveform->adjustment), "value-changed"); } } } void kry_waveform_set_zoom(KryWaveform *waveform, double factor) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); if(fabs(factor - kry_waveform_get_zoom(waveform)) < 0.0001) return; waveform->zoom = factor; g_signal_emit (waveform, kry_waveform_signals[ZOOM_CHANGED_SIGNAL], 0, factor); kry_waveform_update_zoom(waveform); kry_waveform_redraw(waveform); } double kry_waveform_get_zoom_min(KryWaveform *waveform) { g_return_val_if_fail (waveform != NULL, 1); g_return_val_if_fail (KRY_IS_WAVEFORM (waveform), 1); if(!waveform->data_info) return 1; double width = GTK_WIDGET(waveform)->allocation.width; return (width / waveform->data_info->vals_per_sec); } double kry_waveform_get_zoom_max(KryWaveform *waveform) { g_return_val_if_fail (waveform != NULL, 1); g_return_val_if_fail (KRY_IS_WAVEFORM (waveform), 1); if(!waveform->data_info) return 1; return waveform->data_info->length_seconds; } double kry_waveform_get_zoom(KryWaveform *waveform) { g_return_val_if_fail (waveform != NULL, 1); g_return_val_if_fail (KRY_IS_WAVEFORM (waveform), 1); if(!waveform->data_info) return 1; return waveform->zoom; } void kry_waveform_focus_selected(KryWaveform *waveform) { double selection_length = 0, window_length = 0; long start = 0, end = 0; long start_val = 0; long end_val = 0; g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); if(!waveform->data_info) return; KryMarker *marker_start = waveform->marker_active_start; KryMarker *marker_end = waveform->marker_active_end; if(marker_start) start_val = kry_marker_get_value(marker_start); if(marker_end) end_val = kry_marker_get_value(marker_end); if(!marker_start || !marker_end || (start_val == -1 && end_val == -1)) return; if(start_val != -1) start = (long) ((kry_marker_get_value(marker_start) / 1000.0) * waveform->data_info->vals_per_sec); if(end_val != -1) end = (long) ((kry_marker_get_value(marker_end) / 1000.0) * waveform->data_info->vals_per_sec); if(start_val != -1 && end_val != -1) { selection_length = ((double) end - start) / waveform->data_info->vals_per_sec; window_length = (double) (GTK_WIDGET(waveform)->allocation.width * waveform->data_per_pixel) / (waveform->data_info->vals_per_sec); } // can the selected region fit in weveform? if(selection_length < window_length && start_val != -1 && end_val != -1) { double left = (GTK_WIDGET(waveform)->allocation.width - ((end - start) / (double) waveform->data_per_pixel)) / 2.0; if(left < 250) left = 250; left *= waveform->data_per_pixel; waveform->adjustment->value = start - left; } else { if(start_val == -1) waveform->adjustment->value = end - (250 * waveform->data_per_pixel); else waveform->adjustment->value = start - (250 * waveform->data_per_pixel); } if(waveform->adjustment->value < 0) waveform->adjustment->value = 0; if(waveform->adjustment->value > waveform->adjustment->upper - waveform->adjustment->page_size) waveform->adjustment->value = waveform->adjustment->upper - waveform->adjustment->page_size; g_signal_emit_by_name(G_OBJECT(waveform->adjustment), "value-changed"); } /*struct sound_info *kry_waveform_get_sound_info(KryWaveform *widget) { KryWaveform *waveform; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (KRY_IS_WAVEFORM (widget), FALSE); waveform = KRY_WAVEFORM (widget); return waveform->data_info; }*/ /*void kry_waveform_set_data(KryWaveform *waveform, struct sound_info *sound_info) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); waveform->sound_info = sound_info; }*/ /*void kry_waveform_set_channel(KryWaveform *waveform, int channel) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); waveform->channel = channel; }*/ double kry_waveform_get_scale(KryWaveform *waveform) { g_return_val_if_fail (waveform != NULL, 1); g_return_val_if_fail (KRY_IS_WAVEFORM (waveform), 1); return waveform->scale; } void kry_waveform_set_scale(KryWaveform *waveform, int value) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); double scale_val = value / 100.0; if(fabs(scale_val - waveform->scale) < 0.0001) return; waveform->scale = scale_val; g_signal_emit (waveform, kry_waveform_signals[SCALE_CHANGED_SIGNAL], 0, value); kry_waveform_redraw(waveform); } static void kry_waveform_find_first_region(KryWaveform *waveform, gboolean backward) { int counter = 0; gboolean found = FALSE; while(!found) { struct KryRegionFixedInfo *info = (struct KryRegionFixedInfo *) pavl_t_cur(&waveform->region_fixed_list_iter); if(!info) break; for(GList *ptr_h = info->regions; ptr_h; ptr_h = ptr_h->next) { struct KryRegionFixed *region = (struct KryRegionFixed *) ptr_h->data; long m1val = region->start; long m2val = region->end; long m1pos = kry_waveform_rel_pixel_from_mili(waveform, m1val); long m2pos = kry_waveform_rel_pixel_from_mili(waveform, m2val); counter++; if(m1val == -1 || m2val == -1 || m1val >= m2val) continue; gboolean region_match = (m1pos < 0 && m2pos > 0 || m1pos >= 0); if(!backward && region_match) { found = TRUE; break; } else if(backward && !region_match) { struct pavl_traverser iter = waveform->region_fixed_list_iter; pavl_t_next(&waveform->region_fixed_list_iter); if(!waveform->region_fixed_list_iter.pavl_node) waveform->region_fixed_list_iter = iter; found = TRUE; break; } } if(!found) { struct pavl_traverser iter = waveform->region_fixed_list_iter; if(!backward) { pavl_t_next(&waveform->region_fixed_list_iter); } else { pavl_t_prev(&waveform->region_fixed_list_iter); } if(pavl_t_cur(&waveform->region_fixed_list_iter) == NULL) { waveform->region_fixed_list_iter = iter; found = TRUE; } } } } static void kry_waveform_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data) { KryWaveform *waveform; g_return_if_fail (adjustment != NULL); g_return_if_fail (data != NULL); waveform = KRY_WAVEFORM (data); waveform->left = (long) adjustment->value; kry_waveform_setup_rel_keyframe_list(waveform); if(waveform->left != waveform->left_previous) { int curx = kry_waveform_abs_pixel_from_rel(waveform, 0); GdkRectangle *rect = &waveform->last_draw_rect; kry_waveform_find_first_region(waveform, curx < rect->x); // scroll to the right (image scrolls left) if(curx > rect->x && curx < rect->x + rect->width) { #ifdef _WINDOWS RECT scroll, clip; scroll.left = curx - rect->x; scroll.right = rect->width; scroll.top = waveform->scrub_bar_height + waveform->time_bar_height; scroll.bottom = waveform->wave_height + scroll.top; clip.left = 0; clip.right = rect->width; clip.top = scroll.top; clip.bottom = scroll.bottom; if(!ScrollDC(waveform->backbuffer_final, rect->x - curx, 0, &scroll, &clip, NULL, NULL)) g_warning("scroll failed"); #else gdk_draw_drawable(waveform->backbuffer_final, waveform->gc, waveform->backbuffer_final, curx - rect->x, waveform->time_bar_height + waveform->scrub_bar_height, 0, waveform->time_bar_height + waveform->scrub_bar_height, rect->width - (curx - rect->x), waveform->wave_height); #endif kry_waveform_redraw_partial(waveform, rect->width - (curx - rect->x), curx - rect->x, TRUE, FALSE); kry_waveform_update_front_buffer(waveform, 0, GTK_WIDGET(waveform)->allocation.width); rect->x = curx; } // scroll left (image moves right) else if(curx < rect->x && curx + rect->width > rect->x) { #ifdef _WINDOWS RECT scroll, clip; scroll.left = 0; scroll.right = rect->width - (rect->x - curx); scroll.top = waveform->scrub_bar_height + waveform->time_bar_height; scroll.bottom = waveform->wave_height + scroll.top; clip.left = 0; clip.right = rect->width; clip.top = scroll.top; clip.bottom = scroll.bottom; if(!ScrollDC(waveform->backbuffer_final, rect->x - curx, 0, &scroll, &clip, NULL, NULL)) g_warning("scroll failed"); #else gdk_draw_drawable(waveform->backbuffer_final, waveform->gc, waveform->backbuffer_final, 0, waveform->time_bar_height + waveform->scrub_bar_height, rect->x - curx, waveform->time_bar_height + waveform->scrub_bar_height, rect->width - (rect->x - curx), waveform->wave_height); #endif kry_waveform_redraw_partial(waveform, 0, rect->x - curx, TRUE, FALSE); kry_waveform_update_front_buffer(waveform, 0, GTK_WIDGET(waveform)->allocation.width); rect->x = curx; } else { kry_waveform_redraw(waveform); } waveform->left_previous = waveform->left; } } void kry_waveform_marker_set_active_start(KryWaveform *waveform, KryMarker *marker) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); KryMarker *old_marker = waveform->marker_active_start; waveform->marker_active_start = marker; if(!GTK_WIDGET_REALIZED(waveform)) return; if(old_marker) kry_waveform_marker_redraw_at_time(waveform, kry_marker_get_value(old_marker)); if(marker) kry_waveform_marker_redraw_at_time(waveform, kry_marker_get_value(marker)); } void kry_waveform_marker_set_active_end(KryWaveform *waveform, KryMarker *marker) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); KryMarker *old_marker = waveform->marker_active_end; waveform->marker_active_end = marker; if(!GTK_WIDGET_REALIZED(waveform)) return; if(old_marker) kry_waveform_marker_redraw_at_time(waveform, kry_marker_get_value(old_marker)); if(marker) kry_waveform_marker_redraw_at_time(waveform, kry_marker_get_value(marker)); } kryColorTable *kry_waveform_get_color_table(KryWaveform *waveform) { g_return_val_if_fail (waveform != NULL, NULL); g_return_val_if_fail (KRY_IS_WAVEFORM (waveform), NULL); return waveform->color_table; } void kry_waveform_set_drag_selection(KryWaveform *waveform, gboolean drag) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); waveform->drag_selection_enabled = drag; } void kry_waveform_set_marker_dragging(KryWaveform *waveform, gboolean drag) { g_return_if_fail (waveform != NULL); g_return_if_fail (KRY_IS_WAVEFORM (waveform)); waveform->drag_markers_enabled = drag; }