1 /* gtkui.c - GTK+ GUI implementation
2  *
3  * Copyright 2010 Petteri Hintsanen <petterih@iki.fi>
4  *
5  * This file is part of abx.
6  *
7  * abx is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * abx is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15  * License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with abx.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "gtkui.h"
22 #include "test.h"
23 #include <stdlib.h>
24 
25 int current_trial;              /* Current test trial, or -1 if there
26                                  * is no test in progress. */
27 Metadata metadata_a;            /* Metadata for sample A. */
28 Metadata metadata_b;            /* Metadata for sample B. */
29 gchar *basename_a;              /* Basename for file A. */
30 gchar *basename_b;              /* Basename for file B. */
31 
32 static gint ntrials = 10;
33 static gint outdev = -1;
34 
35 
36 /*
37  * Parse command line options.
38  */
39 static void
parse_options(int * argc,char ** argv[])40 parse_options(int *argc, char **argv[])
41 {
42     GError *error = NULL;
43     GOptionContext *context;
44 
45     GOptionEntry entries[] = {
46         { "num-trials", 'i', 0, G_OPTION_ARG_INT, &ntrials,
47           "Do N trials.", "N" },
48         { "audio-device", 'd', 0, G_OPTION_ARG_INT, &outdev,
49           "Use PortAudio audio device ID", "ID" },
50         { NULL }
51     };
52 
53     context = g_option_context_new("[SAMPLE-A SAMPLE-B]");
54     g_option_context_set_summary
55         (context, "Test for audible differences in fidelity between "
56          "two audio samples\nwith ABX test.");
57     g_option_context_set_description
58         (context, "Report bugs to <petterih@iki.fi>.");
59     g_option_context_add_main_entries(context, entries, NULL);
60     g_option_context_add_group(context, gtk_get_option_group(TRUE));
61     if (!g_option_context_parse(context, argc, argv, &error))
62     {
63         g_error("option parsing failed: %s\n", error->message);
64     }
65 
66     /* ntrials must be positive */
67     if (ntrials < 0) ntrials = 0;
68 }
69 
70 /*
71  * Initialize GTK+, init a new test with command-line arguments (if
72  * needed), and pass control for GTK+.
73  */
74 void
ui_main(int argc,char * argv[])75 ui_main(int argc, char *argv[])
76 {
77     parse_options(&argc, &argv);
78     gtk_init(&argc, &argv);
79 
80     if (argc >= 3) {
81         switch (init_test(argv[1], argv[2], ntrials, outdev)) {
82         case 0:
83             /* test init successful */
84             show_main_window();
85             reset_test();
86             break;
87         case 1:
88             error_dialog(main_window,
89                          "An error occurred while setting up playback "
90                          "for the first sample.");
91             return;
92         case 2:
93             error_dialog(main_window,
94                          "An error occurred while setting up playback "
95                          "for the second sample.");
96             return;
97         case 3:
98             error_dialog
99                 (main_window, "The given samples have "
100                  "different durations.  Both samples must have "
101                  "exactly the same duration.");
102             return;
103         case 4:
104             error_dialog
105                 (main_window, "Invalid number of trials given in "
106                  "the command line.");
107             return;
108         }
109     } else {
110         /* no current test available */
111         current_trial = -1;
112         show_main_window();
113     }
114 
115     gtk_main();
116 }
117 
118 /*
119  * Display a simple error dialog with the given parent window and
120  * error message.
121  */
122 void
error_dialog(GtkWidget * parent_win,char * msg)123 error_dialog(GtkWidget *parent_win, char *msg)
124 {
125     GtkWidget *errdialog;
126     errdialog = gtk_message_dialog_new
127         (GTK_WINDOW(parent_win), GTK_DIALOG_DESTROY_WITH_PARENT,
128          GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", msg);
129     gtk_window_set_title(GTK_WINDOW(errdialog), "Error");
130     gtk_dialog_run(GTK_DIALOG(errdialog));
131     gtk_widget_destroy(errdialog);
132 }
133 
134 /*
135  * Reset test parameters (current trial and metadata).  Close and
136  * destroy possibly open windows, and update the main window.  This
137  * function is usually called after a new test has been successfully
138  * initialized.
139  */
140 void
reset_test(void)141 reset_test(void)
142 {
143     if (basename_a) g_free(basename_a);
144     if (basename_b) g_free(basename_b);
145     current_trial = 0;
146     get_metadatas(&metadata_a, &metadata_b);
147     basename_a = g_path_get_basename(metadata_a.filename);
148     basename_b = g_path_get_basename(metadata_b.filename);
149     hide_decide_dialog();
150     hide_result_window();
151     update_main_window();
152 }
153