ant-phone/src/llcheck.c

388 lines
11 KiB
C

/*
* line level checker functions
*
* This file is part of ANT (Ant is Not a Telephone)
*
* Copyright 2002, 2003 Roland Stigge
* Copyright 2007 Ivan Schreter
*
* ANT 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 of the License, or
* (at your option) any later version.
*
* ANT 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 ANT; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "config.h"
/* regular GNU system includes */
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
/* GTK */
#include <gtk/gtk.h>
/* own header files */
#include "globals.h"
#include "llcheck.h"
#include "session.h"
#include "gtk.h"
/* constants */
/* number of milliseconds for history */
#define HISTORY_TIME 1500
/*
* the chain link type for the maximum history
*/
struct history_t {
double value;
struct history_t *next;
};
/*
* return an empty (all zero) history of fixed size (10)
*/
struct history_t *history_new(void) {
struct history_t *root = NULL;
struct history_t *temp;
int i;
for (i = 0; i < 10; i++) {
temp = root;
root = (struct history_t *)malloc(sizeof(struct history_t));
root->value = 0.0;
root->next = temp;
}
return root;
}
/*
* free memory allocated for history
*/
void history_free(struct history_t *history) {
while (history != NULL) {
struct history_t *next = history->next;
free(history);
history = next;
}
}
/*
* appends x to history (rotating) and returns maximum value in whole history
*
* NOTE: history is assumed to be non-empty
*/
double history_append(struct history_t **history, double x) {
double result = x;
struct history_t **hist = &(*history)->next;
/* get new maximum */
while (*hist != NULL) {
if ((*hist)->value > result)
result = (*hist)->value;
hist = &(*hist)->next;
}
/* append */
*hist = *history; /* hist is ** to last element -> append old first one */
*history = (*history)->next;
(*hist)->next = NULL;
(*hist)->value = x;
return result;
}
/*
* sets history to all zero
*/
void history_reset(struct history_t *history) {
while (history) {
history->value = 0.0;
history = history->next;
}
}
/*
* called when OK button is clicked
*/
static void llcheck_quit(GtkObject *window) {
session_t *session = gtk_object_get_data(window, "session");
GtkWidget *bar = gtk_object_get_data(GTK_OBJECT(window), "bar");
/* reset i/o handlers */
session_io_handlers_start(session);
/* stop effect */
session_effect_stop(session);
llcheck_bar_deinit(bar);
gtk_object_set_data(GTK_OBJECT(session->llcheck_out), "bar", NULL);
gtk_widget_destroy(GTK_WIDGET(window));
session_set_state(session, STATE_READY);
}
/*
* called when sound is requested in level check window
*
* input: widget: (play) button
* data: session pointer
*/
static void llcheck_play(GtkWidget *widget _U_, gpointer data) {
session_t *session = (session_t *)data;
/* start playing effect */
session_effect_start(session, EFFECT_TEST);
}
/*
* Returns a line level check bar
* input: width, height: size of the whole widget
* r, g, b: color of bright bar, dark bar will be some derivative
* of it
*
*/
GtkWidget *llcheck_bar_new(gint width, gint height,
unsigned char r, unsigned char g, unsigned char b) {
GtkWidget *progress_bar;
GtkWidget *bar;
GtkRcStyle *style;
GdkColor color;
/* the result to prepare */
bar = gtk_hbox_new(FALSE, 0);
gtk_widget_set_size_request(bar, width, height);
gtk_object_set_data(GTK_OBJECT(bar), "width", GINT_TO_POINTER(width));
/* progress bar: fast/slow relation progressbar */
progress_bar = gtk_progress_bar_new();
style = gtk_rc_style_new();
style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_BG;
color.red = r * 257; color.green = g * 257; color.blue = b * 257;
gdk_colormap_alloc_color(gtk_widget_get_colormap(bar), &color,
TRUE, TRUE);
style->bg[GTK_STATE_PRELIGHT] = color;
style->color_flags[GTK_STATE_NORMAL] = GTK_RC_BG;
color.red = r * 257 * 2 / 3;
color.green = g * 257 * 2 / 3;
color.blue = b * 257 * 2 / 3;
gdk_colormap_alloc_color(gtk_widget_get_colormap(bar), &color,
TRUE, TRUE);
style->bg[GTK_STATE_NORMAL] = color;
gtk_widget_modify_style(progress_bar, style);
gtk_rc_style_unref(style);
gtk_progress_set_percentage(GTK_PROGRESS(progress_bar), 0.0); /* 0..1 */
gtk_object_set_data(GTK_OBJECT(bar), "pbar1", (gpointer) progress_bar);
gtk_widget_set_size_request(progress_bar, 1, -1); /* 1..width-1 */
gtk_box_pack_start(GTK_BOX(bar), progress_bar, TRUE, TRUE, 0);
gtk_widget_show(progress_bar);
/* progress bar: rest */
progress_bar = gtk_progress_bar_new();
style = gtk_rc_style_new();
style->color_flags[GTK_STATE_NORMAL] = GTK_RC_BG;
color.red = r * 257 / 3;
color.green = g * 257 / 3;
color.blue = b * 257 / 3;
gdk_colormap_alloc_color(gtk_widget_get_colormap(bar), &color,
TRUE, TRUE);
style->bg[GTK_STATE_NORMAL] = color;
gtk_widget_modify_style(progress_bar, style);
gtk_rc_style_unref(style);
gtk_progress_set_percentage(GTK_PROGRESS(progress_bar), 0.0);
gtk_widget_set_size_request(progress_bar, width - 1, -1); /* 1..width-1 */
gtk_object_set_data(GTK_OBJECT(bar), "pbar2", (gpointer) progress_bar);
gtk_object_set_data(GTK_OBJECT(bar), "history", (gpointer) history_new());
gtk_box_pack_start(GTK_BOX(bar), progress_bar, TRUE, TRUE, 0);
gtk_widget_show(progress_bar);
return bar;
}
/*
* set state of line level check bar and update maximum history
*
* input: bar: llcheck_bar
* max: the current maximum (0.0 <= max <= 1.0)
*/
void llcheck_bar_set(GtkWidget *bar, double max) {
/* the maximum area */
GtkWidget *pbar1 =
(GtkWidget *)gtk_object_get_data(GTK_OBJECT(bar), "pbar1");
/* the dark area */
GtkWidget *pbar2 =
(GtkWidget *)gtk_object_get_data(GTK_OBJECT(bar), "pbar2");
/* related bar (for llcheck dialog box) */
GtkWidget *related =
(GtkWidget*) gtk_object_get_data(GTK_OBJECT(bar), "bar");
struct history_t *history =
(struct history_t *)gtk_object_get_data(GTK_OBJECT(bar), "history");
double maxmax = history ? history_append(&history, max) : max;
int width = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(bar), "width"));
/* saving additional width
(bar->allocation.width is valid only with shown widgets) */
int pbar1size;
double percentage;
gtk_object_set_data(GTK_OBJECT(bar), "history", history);
pbar1size = maxmax * (width - 2) + 1;
gtk_widget_set_size_request(pbar1, pbar1size, -1);
gtk_widget_set_size_request(pbar2, width - pbar1size, -1);
percentage = maxmax > 0.0 ? max / maxmax : 0.0;
gtk_progress_set_percentage(GTK_PROGRESS(pbar1), percentage);
if (related)
llcheck_bar_set(related, max);
}
/*
* set line level check bar to all zero (history included);
*/
void llcheck_bar_reset(GtkWidget *bar) {
struct history_t *history =
(struct history_t *)gtk_object_get_data(GTK_OBJECT(bar), "history");
history_reset(history);
llcheck_bar_set(bar, 0.0);
}
/*
* deinit bar (free history mem ...)
*/
void llcheck_bar_deinit(GtkWidget *bar) {
struct history_t *history = gtk_object_get_data(GTK_OBJECT(bar), "history");
history_free(history);
}
/*
* The Line level check callback
* -> displays dialog window with level check bar and play button
* -> modal
*/
void llcheck(GtkWidget *widget _U_, gpointer data, guint action _U_) {
session_t *session = (session_t *) data;
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *button_box;
GtkWidget *button;
GtkWidget *label;
GtkWidget *bar;
/* set to service state -> open audio device */
if (!session_set_state(session, STATE_SERVICE)) {
/* the window itself */
window = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(window), _("Line Level Check"));
gtk_object_set(GTK_OBJECT(window), "allow_shrink", FALSE, NULL);
gtk_object_set(GTK_OBJECT(window), "allow_grow", FALSE, NULL);
/* new big vbox */
vbox = gtk_vbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->vbox), vbox);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
gtk_widget_show(vbox);
/* message label */
label = gtk_label_new(_("Please check the line input level\n"
"and adjust it using your favorite\n"
"mixer application.\n"
"You can also play a sound\n"
"to test the sound output."));
gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
gtk_box_pack_start(GTK_BOX(vbox), label,
FALSE, FALSE, 0);
gtk_widget_show(label);
/* the line level check bar */
bar = llcheck_bar_new(300, 20, 200, 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), bar, FALSE, FALSE, 0);
gtk_widget_show(bar);
/* action area */
button_box = gtk_hbutton_box_new();
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->action_area),
button_box);
gtk_widget_show(button_box);
/* the play button */
button = gtk_button_new_with_label(_("Play sound"));
gtk_box_pack_start_defaults(GTK_BOX(button_box), button);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
GTK_SIGNAL_FUNC(llcheck_play),
(gpointer) session );
gtk_widget_show(button);
/* save session in window (quit(): audio handling) */
gtk_object_set_data(GTK_OBJECT(window), "session", (gpointer) session);
/* save bar in window (quit(): destroy) */
gtk_object_set_data(GTK_OBJECT(window), "bar", (gpointer) bar);
/* save session in bar widget (input handling) */
gtk_object_set_data(GTK_OBJECT(bar), "session", (gpointer) session);
/* save bar as related in llcheck_out */
gtk_object_set_data(GTK_OBJECT(session->llcheck_out), "bar", (gpointer) bar);
/* the OK button */
button = gtk_button_new_with_label(_("OK"));
gtk_box_pack_start_defaults(GTK_BOX(button_box), button);
gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
GTK_SIGNAL_FUNC(llcheck_quit), GTK_OBJECT(window));
/* handler for kill function of window */
gtk_signal_connect_object(GTK_OBJECT(window), "delete_event",
GTK_SIGNAL_FUNC(llcheck_quit), GTK_OBJECT(window));
gtk_widget_show(button);
gtk_window_set_modal(GTK_WINDOW(window), TRUE);
/* start empty effect */
session_effect_start(session, EFFECT_EMPTY);
/* show everything */
gtk_widget_show(window);
} else {
show_audio_error_dialog();
}
}
/* called when line levels view check button is toggled */
void llcheck_toggle_cb(GtkWidget *widget _U_, gpointer data, guint action _U_) {
session_t *session = (session_t *) data;
if (GTK_CHECK_MENU_ITEM (session->llcheck_check_menu_item)->active) {
gtk_widget_show(session->llcheck);
session->option_show_llcheck = 1;
} else {
gtk_widget_hide(session->llcheck);
session->option_show_llcheck = 0;
/* shrink if no growing callerid monitor present */
if (!session->option_show_callerid)
gtk_window_resize(GTK_WINDOW(session->main_window), 1, 1);
}
}