/* * 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" #ifdef _WINDOWS static void kry_waveform_backbuffer_color(KryWaveform *waveform, int id, HDC dc) { HPEN color = (HPEN) waveform->color_table->GetUserData(id); if(!SelectObject(dc, color)) g_warning("failed to set color on backbuffer"); } #else static void kry_waveform_backbuffer_color(KryWaveform *waveform, int id, void *dummy) { GdkColor *color = (GdkColor *) waveform->color_table->GetUserData(id); gdk_gc_set_foreground(waveform->gc, color); } #endif static void kry_waveform_backbuffer_line(KryWaveform *waveform, int x1, int y1, int x2, int y2, void *data) { #ifdef _WINDOWS if(!MoveToEx(HDC(data), x1, y1, NULL)) g_warning("moveto failed"); if(!LineTo(HDC(data), x2, y2)) g_warning("lineto failed"); #else gdk_draw_line(GDK_DRAWABLE(data), waveform->gc, x1, y1, x2, y2); #endif } void kry_waveform_backbuffer_draw_scrub_bar(KryWaveform *waveform) { if(!waveform->show_scrub_bar) return; #ifdef _WINDOWS kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_BACKGROUND, waveform->backbuffer_waveonly); if(!SelectObject(waveform->backbuffer_waveonly, waveform->black_brush)) g_warning("error selecting color for background"); if(!Rectangle(waveform->backbuffer_waveonly, 0, 0, GTK_WIDGET(waveform)->allocation.width, waveform->scrub_bar_height)) g_warning("error drawing backbuffer background"); #else kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_BACKGROUND, waveform->backbuffer_waveonly); gdk_draw_rectangle(waveform->backbuffer_waveonly, waveform->gc, TRUE, 0, 0, GTK_WIDGET(waveform)->allocation.width, waveform->scrub_bar_height); #endif kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_SCRUB_BAR_SEPARATOR, waveform->backbuffer_waveonly); kry_waveform_backbuffer_line(waveform, 0, waveform->scrub_bar_height - 1, GTK_WIDGET(waveform)->allocation.width, waveform->scrub_bar_height - 1, waveform->backbuffer_waveonly); kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_SCRUB_BAR_SLIDER, waveform->backbuffer_waveonly); int left = (int) ((((double) waveform->left * GTK_WIDGET(waveform)->allocation.width)) / (waveform->data_info->length_seconds * waveform->data_info->vals_per_sec)); int width = (int) ((GTK_WIDGET(waveform)->allocation.width * GTK_WIDGET(waveform)->allocation.width) / (waveform->data_info->length_seconds * waveform->data_info->vals_per_sec / waveform->data_per_pixel)); kry_waveform_backbuffer_line(waveform, left, 0, left, waveform->scrub_bar_height - 1, waveform->backbuffer_waveonly); kry_waveform_backbuffer_line(waveform, left + width - 1, 0, left + width - 1, waveform->scrub_bar_height - 1, waveform->backbuffer_waveonly); kry_waveform_backbuffer_line(waveform, left, (2 * waveform->scrub_bar_height / 7), left + width - 1, (2 * waveform->scrub_bar_height / 7), waveform->backbuffer_waveonly); kry_waveform_backbuffer_line(waveform, left, (5 * waveform->scrub_bar_height / 7), left + width - 1, (5 * waveform->scrub_bar_height / 7), waveform->backbuffer_waveonly); if(width < 20) { int left_ext = left - (25 - width) / 2; int right_ext = left + width + (25 - width) / 2; kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_SCRUB_BAR_EXTENSION, waveform->backbuffer_waveonly); kry_waveform_backbuffer_line(waveform, left_ext, 0, left_ext, waveform->scrub_bar_height - 1, waveform->backbuffer_waveonly); kry_waveform_backbuffer_line(waveform, left_ext, (waveform->scrub_bar_height / 2), left, (waveform->scrub_bar_height / 2), waveform->backbuffer_waveonly); kry_waveform_backbuffer_line(waveform, right_ext, 0, right_ext, waveform->scrub_bar_height - 1, waveform->backbuffer_waveonly); kry_waveform_backbuffer_line(waveform, right_ext, (waveform->scrub_bar_height / 2), left + width - 1, (waveform->scrub_bar_height / 2), waveform->backbuffer_waveonly); waveform->scrub_bar_left_ext = left_ext; waveform->scrub_bar_right_ext = right_ext; } else { waveform->scrub_bar_left_ext = left; waveform->scrub_bar_right_ext = left + width - 1; } waveform->scrub_bar_left = left; waveform->scrub_bar_width = width; } #ifdef _WINDOWS void kry_waveform_backbuffer_draw_time_bar(KryWaveform *waveform) { GtkWidget *widget = GTK_WIDGET(waveform); if(!waveform->show_time_bar || waveform->draw_disabled) return; kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_BACKGROUND, waveform->backbuffer_waveonly); if(!SelectObject(waveform->backbuffer_waveonly, waveform->black_brush)) g_warning("error selecting color for background"); if(!Rectangle(waveform->backbuffer_waveonly, 0, 0, widget->allocation.width, waveform->time_bar_height + waveform->scrub_bar_height)) g_warning("error drawing backbuffer background"); char *text = NULL; int ref = kry_waveform_abs_pixel_from_rel(waveform, 0); int start_px = 0; if(ref % 70 != 0) start_px += (70 - ref % 70); while(TRUE) { text = time_mili_to_string_compact(kry_waveform_mili_from_rel_pixel(waveform, start_px)); RECT extents = {0, 0, 0, 0}; if(!DrawText(waveform->backbuffer_waveonly, text, strlen(text), &extents, DT_CALCRECT)) g_warning("failed to calculate text extents"); if(start_px - extents.right / 2.0 < 0) { kry_free(text); start_px += 70; continue; } if(start_px + extents.right / 2.0 > widget->allocation.width) { kry_free(text); break; } kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_TEXT, waveform->backbuffer_waveonly); int width; kryColor *color = waveform->color_table->Get(WAVEFORM_COLOR_TEXT); SetTextColor(waveform->backbuffer_waveonly, RGB(color->GetRed(), color->GetGreen(), color->GetBlue())); width = (extents.right - extents.left); extents.left += (long) (start_px - (width / 2.0)); extents.right += (long) (start_px - (width / 2.0)); extents.top += (waveform->scrub_bar_height + 3); extents.bottom += (waveform->scrub_bar_height + 3); if(!DrawText(waveform->backbuffer_waveonly, text, strlen(text), &extents, 0)) g_warning("failed to draw text"); start_px += 70; kry_free(text); } kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_LINE, waveform->backbuffer_waveonly); } #else void kry_waveform_backbuffer_draw_time_bar(KryWaveform *waveform) { GtkWidget *widget = GTK_WIDGET(waveform); if(!waveform->show_time_bar || waveform->draw_disabled) return; kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_BACKGROUND, waveform->backbuffer_waveonly); gdk_draw_rectangle(waveform->backbuffer_waveonly, waveform->gc, TRUE, 0, waveform->scrub_bar_height, widget->allocation.width, waveform->time_bar_height); char *text = NULL; int ref = kry_waveform_abs_pixel_from_rel(waveform, 0); int start_px = 0; if(ref % 70 != 0) start_px += (70 - ref % 70); while(TRUE) { text = time_mili_to_string_compact(kry_waveform_mili_from_rel_pixel(waveform, start_px)); PangoRectangle extents; pango_layout_set_text(waveform->layout, text, -1); pango_layout_get_pixel_extents(waveform->layout, NULL, &extents); if(start_px - extents.width / 2.0 < 0) { kry_free(text); start_px += 70; continue; } if(start_px + extents.width / 2.0 > widget->allocation.width) { kry_free(text); break; } kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_TEXT, waveform->backbuffer_waveonly); gdk_draw_layout(waveform->backbuffer_waveonly, waveform->gc, start_px - extents.width / 2, waveform->scrub_bar_height, waveform->layout); start_px += 70; kry_free(text); } kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_LINE, waveform->backbuffer_waveonly); } #endif void kry_waveform_backbuffer_draw_wave_time_marker(KryWaveform *waveform, int pos) { GtkWidget *widget = GTK_WIDGET(waveform); kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_MARKER_TIME, waveform->backbuffer_waveonly); kry_waveform_backbuffer_line(waveform, pos, waveform->time_bar_height + waveform->scrub_bar_height, pos, widget->allocation.height, waveform->backbuffer_waveonly); kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_LINE, waveform->backbuffer_waveonly); } int kry_waveform_region_compare(const void *r1, const void *r2) { int r1s = kry_marker_get_value(kry_region_get_marker_start(*((KryRegion**) r1))); int r2s = kry_marker_get_value(kry_region_get_marker_start(*((KryRegion**) r2))); if(r1s < r2s) return -1; else if(r1s == r2s) return 0; else return 1; } GList *kry_waveform_build_highlight_list_fixed(KryWaveform *waveform, int start, int width) { GList *highlights = NULL; int counter = 0; 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_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; // check for a highlight that starts before this region but the end is inside/after the region if((m1pos < start && m2pos > start)) highlights = g_list_append(highlights, region); // check if the highlight starts within the current region else if(m1pos >= start && m1pos < start + width) highlights = g_list_append(highlights, region); } } g_warning("%d regions examined", counter); return highlights; } GList *kry_waveform_build_highlight_list(KryWaveform *waveform, int start, int width) { GList *highlights = NULL; for(GList *ptr_h = waveform->region_list; ptr_h; ptr_h = ptr_h->next) { KryRegion *region = (KryRegion *) ptr_h->data; long m1val = kry_marker_get_value(kry_region_get_marker_start(region)); long m2val = kry_marker_get_value(kry_region_get_marker_end(region)); long m1pos = kry_waveform_rel_pixel_from_mili(waveform, m1val); long m2pos = kry_waveform_rel_pixel_from_mili(waveform, m2val); if(m1val == -1 || m2val == -1 || m1val >= m2val) continue; // check for a highlight that starts before this region but the end is inside/after the region if((m1pos < start && m2pos > start)) highlights = g_list_append(highlights, region); // check if the highlight starts within the current region else if(m1pos >= start && m1pos < start + width) highlights = g_list_append(highlights, region); } int highlight_count = g_list_length(highlights); KryRegion **highlights_arr = new KryRegion *[highlight_count]; int i = 0; for(GList *ptr = highlights; ptr; ptr = ptr->next, i++) highlights_arr[i] = (KryRegion *) ptr->data; qsort(highlights_arr, g_list_length(highlights), sizeof(KryRegion*), kry_waveform_region_compare); g_list_free(highlights); highlights = NULL; for(i = 0; i < highlight_count; i++) highlights = g_list_append(highlights, highlights_arr[i]); delete [] highlights_arr; return highlights; } int kry_waveform_get_index_at_abs_pixel(KryWaveform *waveform, int pixel) { return 2 * ((int) (pixel * waveform->data_per_pixel)); } /*int kry_waveform_get_index_at_rel_pixel(KryWaveform *waveform, int pixel) { //return 2 * ((int) (((int) (waveform->left - (fmod(waveform->left, waveform->data_per_pixel)))) + pixel * waveform->data_per_pixel)); return 2 * ((int) ((waveform->left - (fmod(waveform->left, waveform->data_per_pixel))) + pixel * waveform->data_per_pixel)); }*/ double kry_waveform_get_mfactor(KryWaveform *waveform) { double mfactor_pos = (waveform->scale * waveform->wave_height / 2) / (double) waveform->data_info->max_pos; double mfactor_neg = (waveform->scale * waveform->wave_height / 2) / (double) waveform->data_info->max_neg; if(mfactor_neg < mfactor_pos) return mfactor_neg; else return mfactor_pos; } static KryRegionFixed *kry_waveform_region_list_fixed_closest(KryWaveform *waveform, pavl_traverser *iter, int px) { if(!waveform->region_fixed_list || iter->pavl_node == NULL) return NULL; while(struct KryRegionFixedInfo *info = (struct KryRegionFixedInfo *) pavl_t_cur(iter)) { for(GList *ptr = info->regions; ptr; ptr = ptr->next) { struct KryRegionFixed *region = (struct KryRegionFixed *) ptr->data; int rstart_mili = region->start; int rend_mili = region->end; int rstart_px = kry_waveform_rel_pixel_from_mili(waveform, rstart_mili); int rend_px = kry_waveform_rel_pixel_from_mili(waveform, rend_mili); //g_warning("%d %d", region->start, region->end); if(rend_px < px) { if(ptr == g_list_last(info->regions)) pavl_t_next(iter); continue; } if(rstart_px >= GTK_WIDGET(waveform)->allocation.width) iter->pavl_node = NULL; if(rstart_px <= px) return region; else return NULL; } } return NULL; } void kry_waveform_backbuffer_draw_wave(GtkWidget *widget, int start, int width) { KryWaveform *waveform; double mfactor; gint yc, xc; double data_per_pixel; int i; g_return_if_fail (widget != NULL); g_return_if_fail (KRY_IS_WAVEFORM (widget)); waveform = KRY_WAVEFORM(widget); #ifdef _WINDOWS if(waveform->dc == NULL || waveform->backbuffer_waveonly == NULL) return; #endif if(waveform->draw_disabled) return; // draw the background kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_BACKGROUND, waveform->backbuffer_waveonly); #ifdef _WINDOWS if(!SelectObject(waveform->backbuffer_waveonly, waveform->black_brush)) g_warning("error selecting color for background"); if(!Rectangle(waveform->backbuffer_waveonly, start, waveform->time_bar_height + waveform->scrub_bar_height, start + width, widget->allocation.height)) g_warning("error drawing backbuffer background"); #else gdk_draw_rectangle(waveform->backbuffer_waveonly, waveform->gc, TRUE, start, waveform->time_bar_height + waveform->scrub_bar_height, width, widget->allocation.height); #endif if(!waveform->data_info) return; data_per_pixel = waveform->data_per_pixel; xc = widget->allocation.width/2; yc = waveform->wave_height / 2 + waveform->time_bar_height + waveform->scrub_bar_height; mfactor = kry_waveform_get_mfactor(waveform); // draws a horizontal line going through the entire wave kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_LINE, waveform->backbuffer_waveonly); kry_waveform_backbuffer_line(waveform, start, yc, start + width, yc, waveform->backbuffer_waveonly); int mili_start = kry_waveform_mili_from_rel_pixel(waveform, start); int mili_end = kry_waveform_mili_from_rel_pixel(waveform, start + width); kry_waveform_data_ensure_available(waveform, mili_start / 1000, (mili_end / 1000) + 1); struct KryRegionFixed *highlight_fixed_current = NULL; pavl_traverser highlights_fixed_iter = waveform->region_fixed_list_iter; GList *highlights = kry_waveform_build_highlight_list(waveform, start, width - 1); KryRegion *highlight_current = NULL; //int max_index = waveform->data_info->vals_per_sec * waveform->data_info->length_seconds * 2; //g_warning("max index: %d", max_index); for(i = start; i < start + width; i++) { unsigned char val_pos = 0; unsigned char val_neg = 0; /* check if we should draw vertical time guide at this point */ if(waveform->show_time_markers && kry_waveform_abs_pixel_from_rel(waveform, i) % 70 == 0) kry_waveform_backbuffer_draw_wave_time_marker(waveform, i); // check if we are at the end of the available data long mili_cur = kry_waveform_mili_from_rel_pixel(waveform, i); if(mili_cur >= waveform->data_info->length_seconds * 1000) break; int px = kry_waveform_abs_pixel_from_rel(waveform, i); if(px * 2 + 1 >= waveform->data_pixel_length) break; val_pos = waveform->data_pixel[px * 2]; val_neg = waveform->data_pixel[px * 2 + 1]; /*if(px * 2 > 830) { g_warning("%d / %d | %d / %d | %d", val_pos, val_neg, mili_cur, waveform->data_info->length_seconds * 1000, px * 2); }*/ //g_warning("offset: %d", px * 2); highlight_fixed_current = kry_waveform_region_list_fixed_closest(waveform, &highlights_fixed_iter, i); GList *ptr_next; highlight_current = NULL; for(GList *ptr = highlights; ptr; ptr = ptr_next) { ptr_next = ptr->next; KryRegion *region = (KryRegion *) ptr->data; int rstart_mili = kry_marker_get_value(kry_region_get_marker_start(region)); int rend_mili = kry_marker_get_value(kry_region_get_marker_end(region)); int rstart_px = kry_waveform_rel_pixel_from_mili(waveform, rstart_mili); int rend_px = kry_waveform_rel_pixel_from_mili(waveform, rend_mili); if(rend_px < i) { highlights = g_list_delete_link(highlights, ptr); continue; } if(rstart_px > i) break; highlight_current = region; } if(highlight_current) kry_waveform_backbuffer_color(waveform, highlight_current->color_id, waveform->backbuffer_waveonly); else if(highlight_fixed_current) kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_SILENCE_HIGHLIGHT, waveform->backbuffer_waveonly); else kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_LINE, waveform->backbuffer_waveonly); // upper half px = (int) (yc - val_pos * mfactor); if(px < waveform->time_bar_height + waveform->scrub_bar_height) px = waveform->time_bar_height + waveform->scrub_bar_height; kry_waveform_backbuffer_line(waveform, i, yc, i, px, waveform->backbuffer_waveonly); // lower half kry_waveform_backbuffer_line(waveform, i, yc, i, (int) (yc + val_neg * mfactor), waveform->backbuffer_waveonly); } } /* * the markers_mutex must be locked before calling this function */ void kry_waveform_backbuffer_draw_final_real(GtkWidget *widget, int start, int width, gboolean force_draw_wave, gboolean draw_time_bar) { gint xc, yc; int i; double mfactor; GList *ptr; KryWaveform *waveform; g_return_if_fail (widget != NULL); g_return_if_fail (KRY_IS_WAVEFORM (widget)); waveform = KRY_WAVEFORM (widget); if(waveform->backbuffer_final == NULL) return; //g_warning("draw real: %d - %d", start, start + width); xc = widget->allocation.width/2; yc = waveform->wave_height / 2 + waveform->time_bar_height + waveform->scrub_bar_height; if(waveform->draw_disabled || !waveform->data_info) { #ifdef _WINDOWS if(!SelectObject(waveform->backbuffer_final, waveform->color_table->GetUserData(WAVEFORM_COLOR_BACKGROUND))) g_warning("failed to select color pen"); if(!SelectObject(waveform->backbuffer_final, waveform->black_brush)) g_warning("failed to select color brush"); if(!Rectangle(waveform->backbuffer_final, 0, 0, widget->allocation.width, widget->allocation.height)) g_warning("failed to draw rectangle background"); #else gdk_draw_rectangle(waveform->backbuffer_final, waveform->gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height); #endif return; } if(force_draw_wave) kry_waveform_backbuffer_draw_wave(GTK_WIDGET(waveform), start, width); if(draw_time_bar) { //g_warning("draw.."); kry_waveform_backbuffer_draw_time_bar(waveform); kry_waveform_backbuffer_draw_scrub_bar(waveform); } #ifdef _WINDOWS if(!BitBlt(waveform->backbuffer_final, start, 0, width, widget->allocation.height, waveform->backbuffer_waveonly, start, 0, SRCCOPY)) g_warning("failed"); #else gdk_draw_drawable(waveform->backbuffer_final, waveform->gc, waveform->backbuffer_waveonly, start, 0, start, 0, width, widget->allocation.height); #endif if(draw_time_bar && start != 0 || width != widget->allocation.width) { #ifdef _WINDOWS if(!BitBlt(waveform->backbuffer_final, 0, 0, widget->allocation.width, waveform->time_bar_height + waveform->scrub_bar_height, waveform->backbuffer_waveonly, 0, 0, SRCCOPY)) g_warning("failed"); #else gdk_draw_drawable(waveform->backbuffer_final, waveform->gc, waveform->backbuffer_waveonly, 0, 0, 0, 0, widget->allocation.width, waveform->time_bar_height + waveform->scrub_bar_height); #endif } kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_LINE, waveform->backbuffer_final); int widget_width = widget->allocation.width; int *keyframe_present = kry_new0_n(int, widget_width); // draw keyframes if(waveform->show_keyframe) { kry_waveform_backbuffer_color(waveform, WAVEFORM_COLOR_MARKER_KEYFRAME, waveform->backbuffer_final); for(i = 0; i < waveform->keyframes_rel_count; i++) { int px = kry_waveform_rel_pixel_from_mili(waveform, waveform->keyframes_rel[i]); if(px >= start + width) break; keyframe_present[px] = 1; keyframe_present[px + 1] = 1; kry_waveform_backbuffer_line(waveform, px, waveform->time_bar_height + waveform->scrub_bar_height, px, widget->allocation.height, waveform->backbuffer_final); kry_waveform_backbuffer_line(waveform, px + 1, waveform->time_bar_height + waveform->scrub_bar_height, px + 1, widget->allocation.height, waveform->backbuffer_final); } } mfactor = kry_waveform_get_mfactor(waveform); for(ptr = waveform->markers; ptr; ptr = ptr->next) { struct KryWaveformMarkerInfo *info = (struct KryWaveformMarkerInfo *) ptr->data; if(!info->draw) continue; int pos = info->pos_rel_pixel; kry_waveform_backbuffer_color(waveform, info->colorid, waveform->backbuffer_final); if(info->marker == waveform->marker_active_start || info->marker == waveform->marker_active_end) { unsigned char val_pos_max = 0, val_neg_max = 0, val_pos, val_neg; for(int i = (pos > 0 ? -1 : 0); i < 3; i++) { if(kry_waveform_mili_from_rel_pixel(waveform, pos + i) >= waveform->data_info->length_seconds * 1000) break; val_pos = waveform->data_pixel[kry_waveform_abs_pixel_from_rel(waveform, pos + i) * 2]; if(val_pos > val_pos_max) val_pos_max = val_pos; val_neg = waveform->data_pixel[kry_waveform_abs_pixel_from_rel(waveform, pos + i) * 2 + 1]; if(val_neg > val_neg_max) val_neg_max = val_neg; } for(int i = 0; i < waveform->marker_width; i++) { kry_waveform_backbuffer_line(waveform, pos + i, waveform->time_bar_height + waveform->scrub_bar_height, pos + i, (int) (yc - val_pos_max * mfactor) - 5, waveform->backbuffer_final); kry_waveform_backbuffer_line(waveform, pos + i, widget->allocation.height, pos + i, (int) (yc + val_neg_max * mfactor) + 5, waveform->backbuffer_final); } } else { for(int i = 0; i < waveform->marker_width; i++) { if(pos + i >= 0 && pos + i < widget_width && !keyframe_present[pos + i]) { kry_waveform_backbuffer_line(waveform, pos + i, waveform->time_bar_height + waveform->scrub_bar_height, pos + i, widget->allocation.height, waveform->backbuffer_final); } } } if(info->corner_type != MARKER_CORNER_NONE) { int step; int offset; if(info->corner_type == MARKER_CORNER_START) { step = 1; offset = 0; } else { step = -1; offset = -waveform->corner_width; } int counter = waveform->corner_width * step; // while(counter != 0) // { for(counter = 0; counter < waveform->corner_width; counter++) { int height = info->corner_type == MARKER_CORNER_START ? waveform->corner_width - counter : counter; if(pos + offset + counter >= 0 && pos + offset + counter < widget_width && !keyframe_present[pos + offset + counter]) { kry_waveform_backbuffer_line(waveform, pos + offset + counter, waveform->time_bar_height + waveform->scrub_bar_height - 0, pos + offset + counter, waveform->time_bar_height + waveform->scrub_bar_height + height, waveform->backbuffer_final); kry_waveform_backbuffer_line(waveform, pos + offset + counter, GTK_WIDGET(waveform)->allocation.height - 0, pos + offset + counter, GTK_WIDGET(waveform)->allocation.height - height, waveform->backbuffer_final); } //counter -= step; } } } kry_free(keyframe_present); } void kry_waveform_backbuffer_draw_final(GtkWidget *widget, int start, int width, gboolean force_draw_wave, gboolean draw_time_bar) { GList *ptr; KryWaveform *waveform; GList *markers_region = NULL; g_return_if_fail (widget != NULL); g_return_if_fail (KRY_IS_WAVEFORM (widget)); waveform = KRY_WAVEFORM (widget); if(waveform->data_info) { for(ptr = waveform->markers; ptr; ptr = ptr->next) { long position, pos; struct KryWaveformMarkerInfo *info = (struct KryWaveformMarkerInfo *) ptr->data; KryMarker *marker = info->marker; if(marker) { position = kry_marker_get_value(marker); pos = kry_waveform_rel_pixel_from_mili(waveform, position); } else { position = -1; pos = info->pos_rel_pixel; } info->pos_rel_pixel = pos; info->draw = FALSE; info->corner_type = MARKER_CORNER_NONE; if(marker && (position == -1 || g_object_get_data(G_OBJECT(marker), "hidden"))) continue; if(marker) { if(kry_marker_get_marker_type(marker) == MARKER_START || marker == waveform->marker_active_start) { info->colorid = WAVEFORM_COLOR_MARKER_START; info->corner_type = MARKER_CORNER_START; } else if(kry_marker_get_marker_type(marker) == MARKER_END || marker == waveform->marker_active_end) { info->colorid = WAVEFORM_COLOR_MARKER_END; info->corner_type = MARKER_CORNER_END; } else if(kry_marker_get_marker_type(marker) == MARKER_CURRENT) { info->colorid = WAVEFORM_COLOR_MARKER_CURRENT; } else if(kry_marker_get_marker_type(marker) == MARKER_KARAOKE) { info->colorid = WAVEFORM_COLOR_MARKER_KARAOKE; } } else { info->colorid = WAVEFORM_COLOR_MARKER_CURRENT; } if(pos + waveform->marker_width + waveform->corner_width >= start && pos - waveform->corner_width <= start + width) info->draw = TRUE; } if(waveform->region_fixed_list) { gboolean breakout = FALSE; struct pavl_traverser iter = waveform->region_fixed_list_iter; while(struct KryRegionFixedInfo *info = (struct KryRegionFixedInfo *) pavl_t_cur(&iter)) { for(GList *ptr = info->regions; ptr; ptr = ptr->next) { struct KryRegionFixed *region = (struct KryRegionFixed *) ptr->data; int start_px = kry_waveform_rel_pixel_from_mili(waveform, region->start); int end_px = kry_waveform_rel_pixel_from_mili(waveform, region->end); if(start_px >= GTK_WIDGET(waveform)->allocation.width) { breakout = TRUE; break; } if(start_px + waveform->marker_width + waveform->corner_width >= start && start_px <= start + width) { struct KryWaveformMarkerInfo *info = kry_new(struct KryWaveformMarkerInfo, 1); info->pos_rel_pixel = start_px; info->colorid = WAVEFORM_COLOR_MARKER_KARAOKE; info->marker = NULL; info->draw = TRUE; info->corner_type = MARKER_CORNER_START; markers_region = g_list_append(markers_region, info); } if(end_px + waveform->marker_width + waveform->corner_width >= start && end_px <= start + width) { struct KryWaveformMarkerInfo *info = kry_new(struct KryWaveformMarkerInfo, 1); info->pos_rel_pixel = end_px; info->colorid = WAVEFORM_COLOR_MARKER_KARAOKE; info->marker = NULL; info->draw = TRUE; info->corner_type = MARKER_CORNER_END; markers_region = g_list_append(markers_region, info); } } if(breakout) break; pavl_t_next(&iter); } } } GList *orig_markers = waveform->markers; waveform->markers = g_list_concat(markers_region, waveform->markers); kry_waveform_backbuffer_draw_final_real(widget, start, width, force_draw_wave, draw_time_bar); if(markers_region) { waveform->markers = orig_markers; waveform->markers->prev->next = NULL; waveform->markers->prev = NULL; } g_list_foreach(markers_region, (GFunc) kry_free_minimal, NULL); g_list_free(markers_region); } void kry_waveform_update_front_buffer_rect(KryWaveform *waveform, GdkRectangle *area) { if(!GTK_WIDGET_REALIZED(waveform)) return; #ifdef _WINDOWS if(!BitBlt(waveform->dc, area->x, area->y, area->width, area->height, waveform->backbuffer_final, area->x, area->y, SRCCOPY)) { g_warning("backbuffer copy -> window failed"); } #else if(!waveform->backbuffer_final) g_warning("backbuffer is NULL!"); GtkWidget *widget = GTK_WIDGET(waveform); gdk_draw_drawable(widget->window, waveform->gc, waveform->backbuffer_final, area->x, area->y, area->x, area->y, area->width, area->height); #endif } void kry_waveform_update_front_buffer_fast(KryWaveform *waveform, int x, int width) { #ifndef _WINDOWS gtk_widget_queue_draw_area(GTK_WIDGET(waveform), x, 0, width, GTK_WIDGET(waveform)->allocation.height); #else GdkRectangle rect; rect.x = x; rect.width = width; rect.y = 0; rect.height = GTK_WIDGET(waveform)->allocation.height; kry_waveform_update_front_buffer_rect(waveform, &rect); #endif } void kry_waveform_update_front_buffer(KryWaveform *waveform, int x, int width) { GdkRectangle rect; rect.x = x; rect.width = width; rect.y = 0; rect.height = GTK_WIDGET(waveform)->allocation.height; kry_waveform_update_front_buffer_rect(waveform, &rect); } gboolean kry_waveform_expose( GtkWidget *widget, GdkEventExpose *event ) { KryWaveform *waveform; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (KRY_IS_WAVEFORM (widget), FALSE); waveform = KRY_WAVEFORM (widget); if (event && event->count > 0 || waveform->draw_disabled) return FALSE; kry_waveform_update_front_buffer_rect(waveform, &event->area); return FALSE; }