2 #include <glade/glade.h>
3 #include <libxml/parser.h>
4 #include <libxml/tree.h>
12 #define MAX_SAMPLES 10
15 #include "rateit_glade.h"
26 typedef struct Trial
{
40 char *experiment_name
;
47 Session
*session
= NULL
;
49 GladeXML
*main_window
;
51 GtkWidget
*vscales
[MAX_SAMPLES
];
52 GtkWidget
*commentButtons
[MAX_SAMPLES
];
53 GtkWidget
*playButtons
[MAX_SAMPLES
];
57 void chld_handler(int sig
)
60 fprintf(stderr
, "Got SIGCHLD\n");
61 while ((pid
=waitpid(-1, NULL
, WNOHANG
))>0)
69 int xmlGetInt(xmlNode
*node
, const char *prop
, int def
)
73 tmpStr
= xmlGetProp(node
, (const xmlChar
*)prop
);
76 val
= atoi((char*)tmpStr
);
82 char *xmlGetString(xmlNode
*node
, const char *prop
, char *def
)
86 tmpStr
= xmlGetProp(node
, (const xmlChar
*)prop
);
89 val
= strdup((char*)tmpStr
);
97 /* FIXME: LEAK HERE -- Must delete a few here if we don't want to leak */
100 void destroy_session()
102 /* FIXME: BIG LEAK HERE -- Must delete lots of stuff here if we don't want to leak */
106 /*int pos2ID(int pos)
109 Trial *tr = &session->trials[session->curr_trial];
110 for (i=0;i<session->nbSamples;i++)
112 if (tr->samp[i].pos == ID)
113 return tr->samp[i].id;
121 xmlDocPtr doc
= NULL
; /* document pointer */
122 xmlNodePtr root_node
= NULL
, trial_node
= NULL
, sample_node
= NULL
; /* node pointers */
123 /*xmlDtdPtr dtd = NULL;*/ /* DTD pointer */
125 printf ("Saving to %s\n", session
->savepath
);
126 doc
= xmlNewDoc(BAD_CAST
"1.0");
127 root_node
= xmlNewNode(NULL
, BAD_CAST
"MUSHRAEval");
128 xmlDocSetRootElement(doc
, root_node
);
130 snprintf(buf
, 256, "%d", session
->curr_trial
);
131 xmlNewProp(root_node
, BAD_CAST
"currTrial", BAD_CAST buf
);
132 xmlNewProp(root_node
, BAD_CAST
"expName", BAD_CAST session
->experiment_name
);
134 for (i
=0;i
<session
->nbTrials
;i
++)
136 trial_node
= xmlNewChild(root_node
, NULL
, BAD_CAST
"SessionTrial", NULL
);
137 snprintf(buf
, 256, "%d", i
);
138 xmlNewProp(trial_node
, BAD_CAST
"id", BAD_CAST buf
);
139 for (j
=0;j
<session
->nbSamples
;j
++)
141 sample_node
= xmlNewChild(trial_node
, NULL
, BAD_CAST
"PlayedSample", BAD_CAST session
->trials
[i
].samp
[j
].comment
);
142 snprintf(buf
, 256, "%d", session
->trials
[i
].samp
[j
].id
);
143 xmlNewProp(sample_node
, BAD_CAST
"id", BAD_CAST buf
);
144 snprintf(buf
, 256, "%d", session
->trials
[i
].samp
[j
].pos
);
145 xmlNewProp(sample_node
, BAD_CAST
"pos", BAD_CAST buf
);
146 snprintf(buf
, 256, "%d", session
->trials
[i
].samp
[j
].score
);
147 xmlNewProp(sample_node
, BAD_CAST
"score", BAD_CAST buf
);
150 xmlSaveFormatFileEnc(session
->savepath
, doc
, "UTF-8", 1);
152 /*free the document */
156 void on_save_as_activate (GtkWidget
*widget
, gpointer user_data
)
158 GtkWidget
*saveasDialog
= glade_xml_get_widget (main_window
, "SaveAsDialog");
160 if (!session->savepath)
162 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (saveasDialog), ".");
163 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (saveasDialog), "Untitled session");
166 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (saveasDialog), session->savepath);
168 if (gtk_dialog_run (GTK_DIALOG (saveasDialog
)) == GTK_RESPONSE_OK
)
171 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (saveasDialog
));
172 session
->savepath
= strdup(filename
);
176 printf ("Cancel open\n");
178 gtk_widget_hide(saveasDialog
);
185 const char *expStr
, *trialStr
="";
188 for (i
=0;i
<session
->nbSamples
;i
++)
190 gtk_range_set_value (GTK_RANGE(vscales
[session
->trials
[session
->curr_trial
].samp
[i
].pos
]),
191 session
->trials
[session
->curr_trial
].samp
[i
].score
);
192 /*gtk_widget_set_sensitive(vscales[session->trials[session->curr_trial].samp[i].pos],session->active);
193 gtk_widget_set_sensitive(commentButtons[session->trials[session->curr_trial].samp[i].pos],session->active);
194 gtk_widget_set_sensitive(playButtons[session->trials[session->curr_trial].samp[i].pos],session->active);*/
195 gtk_widget_set_sensitive(vscales
[session
->trials
[session
->curr_trial
].samp
[i
].pos
],session
->last_played
==session
->trials
[session
->curr_trial
].samp
[i
].id
);
196 gtk_widget_set_sensitive(commentButtons
[session
->trials
[session
->curr_trial
].samp
[i
].pos
],session
->last_played
==session
->trials
[session
->curr_trial
].samp
[i
].id
);
198 expStr
= session
->experiment_name
;
200 trialStr
=session
->trials
[session
->curr_trial
].name
;
202 expStr
= "No experiment loaded";
205 w
= glade_xml_get_widget (main_window
, "labelExperiment");
206 gtk_label_set_text(GTK_LABEL(w
), expStr
);
207 w
= glade_xml_get_widget (main_window
, "labelTrial");
208 gtk_label_set_text(GTK_LABEL(w
), trialStr
);
210 w
= glade_xml_get_widget (main_window
, "new1");
211 gtk_widget_set_sensitive(w
, session
!=NULL
);
212 w
= glade_xml_get_widget (main_window
, "open1");
213 gtk_widget_set_sensitive(w
, session
!=NULL
);
214 w
= glade_xml_get_widget (main_window
, "save1");
215 gtk_widget_set_sensitive(w
, session
!=NULL
&& session
->active
);
216 w
= glade_xml_get_widget (main_window
, "save_as1");
217 gtk_widget_set_sensitive(w
, session
!=NULL
&& session
->active
);
219 w
= glade_xml_get_widget (main_window
, "table1");
220 gtk_widget_set_sensitive(w
, session
!=NULL
&& session
->active
);
221 w
= glade_xml_get_widget (main_window
, "buttonNext");
222 gtk_widget_set_sensitive(w
, session
!=NULL
&& session
->active
);
223 if (session
!=NULL
&& session
->active
)
225 if (session
->curr_trial
== session
->nbTrials
-1)
227 w
= glade_xml_get_widget (main_window
, "labelNext");
228 gtk_label_set_markup(GTK_LABEL(w
), "<b>Finish</b>");
230 w
= glade_xml_get_widget (main_window
, "labelNext");
231 gtk_label_set_markup(GTK_LABEL(w
), "<b>Next trial</b>");
234 w
= glade_xml_get_widget (main_window
, "buttonPrev");
235 gtk_widget_set_sensitive(w
, session
!=NULL
&& session
->active
&& session
->curr_trial
!= 0);
236 w
= glade_xml_get_widget (main_window
, "buttonPlayRef");
237 gtk_widget_set_sensitive(w
, session
!=NULL
&& session
->active
);
238 w
= glade_xml_get_widget (main_window
, "buttonPause");
239 gtk_widget_set_sensitive(w
, session
!=NULL
&& session
->active
&& play_pid
);
240 w
= glade_xml_get_widget (main_window
, "buttonStop");
241 gtk_widget_set_sensitive(w
, session
!=NULL
&& session
->active
&& play_pid
);
244 void on_save_activate (GtkWidget
*widget
, gpointer user_data
)
246 if (session
->savepath
)
249 on_save_as_activate(NULL
, NULL
);
255 GtkWidget
*dialog
= glade_xml_get_widget (main_window
, "CloseConfirm");
256 gint response
= gtk_dialog_run (GTK_DIALOG (dialog
));
257 gtk_widget_hide(dialog
);
258 if (response
== GTK_RESPONSE_YES
)
260 on_save_activate(NULL
, NULL
);
262 } else if (response
== GTK_RESPONSE_NO
)
278 /* Close current session */
279 if (!close_request())
284 session
->curr_trial
= 0;
285 for (i
=0;i
<session
->nbTrials
;i
++)
287 for (j
=0;j
<session
->nbSamples
;j
++)
290 session
->trials
[i
].samp
[j
].score
= 100;
295 /* FIXME: Must randomize properly */
296 session
->trials
[i
].samp
[j
].pos
= rand()%session
->nbSamples
;
299 if (session
->trials
[i
].samp
[k
].pos
== session
->trials
[i
].samp
[j
].pos
)
308 printf ("New session\n");
312 int create_session(xmlDocPtr current_experiment
)
316 xmlNode
*sample_node
;
321 session
= malloc(sizeof(Session
));
323 root
= xmlDocGetRootElement(current_experiment
);
325 tmpStr
= xmlGetProp(root
, (const xmlChar
*)"nbSamples");
329 session
->nbSamples
= atoi((char*)tmpStr
);
332 session
->nbSamples
= 0;
335 tmpStr
= xmlGetProp(root
, (const xmlChar
*)"nbTrials");
338 session
->nbTrials
= atoi((char*)tmpStr
);
341 session
->nbTrials
= 0;
343 if (session
->nbTrials
< 1 || session
->nbTrials
>= MAX_TRIALS
|| session
->nbSamples
<1 || session
->nbSamples
>=MAX_SAMPLES
)
345 fprintf (stderr
, "Attempted to create a session with %d trials and %d samples\n", session
->nbTrials
, session
->nbSamples
);
350 for (i
=0;i
<session
->nbSamples
;i
++)
352 gtk_widget_show(vscales
[i
]);
353 gtk_widget_show(commentButtons
[i
]);
354 gtk_widget_show(playButtons
[i
]);
356 for (i
=session
->nbSamples
;i
<MAX_SAMPLES
;i
++)
358 gtk_widget_hide(vscales
[i
]);
359 gtk_widget_hide(commentButtons
[i
]);
360 gtk_widget_hide(playButtons
[i
]);
363 session
->last_played
= -1;
364 session
->experiment_name
= xmlGetString(root
, "name", "unknown experiment");
365 session
->trials
= malloc(sizeof(Trial
)*session
->nbTrials
);
366 session
->participant
= NULL
;
367 session
->savepath
= NULL
;
368 session
->curr_trial
= 0;
369 session
->basepath
= xmlGetString(root
, "samplePath", "");
370 for (i
=0;i
<session
->nbTrials
;i
++)
372 session
->trials
[i
].samp
= malloc(sizeof(Session
)*session
->nbSamples
);
373 session
->trials
[i
].id
= i
;
374 session
->trials
[i
].refID
= 0;
375 session
->trials
[i
].name
= NULL
;
376 session
->trials
[i
].nbSamples
= session
->nbSamples
;
377 for (j
=0;j
<session
->nbSamples
;j
++)
379 session
->trials
[i
].samp
[j
].score
= 100;
380 session
->trials
[i
].samp
[j
].id
= j
;
381 session
->trials
[i
].samp
[j
].pos
= j
;
382 session
->trials
[i
].samp
[j
].comment
= NULL
;
383 session
->trials
[i
].samp
[j
].name
= NULL
;
384 session
->trials
[i
].samp
[j
].path
= NULL
;
388 trial_node
= root
->children
;
391 if (trial_node
->type
== XML_ELEMENT_NODE
)
394 tid
= xmlGetInt(trial_node
, "id", 0);
395 if (tid
>= session
->nbTrials
|| tid
<0)
397 fprintf (stderr
, "Attempted to load trial %d of %d\n", tid
, session
->nbTrials
);
398 trial_node
= trial_node
->next
;
402 /*fprintf (stderr, "tid = %d of %d\n", tid, session->nbTrials);*/
403 session
->trials
[tid
].name
= xmlGetString(trial_node
, "name", NULL
);
404 sample_node
= trial_node
->children
;
407 if (trial_node
->type
== XML_ELEMENT_NODE
&& strcmp((char*)sample_node
->name
, "Sample")==0)
410 int sid
= xmlGetInt(sample_node
, "id", 0);
411 if (sid
>= session
->nbSamples
|| sid
<0)
413 fprintf (stderr
, "Attempted to load sample %d of %d\n", sid
, session
->nbSamples
);
414 sample_node
= sample_node
->next
;
418 session
->trials
[tid
].samp
[sid
].name
= xmlGetString(sample_node
, "name", NULL
);
419 /*session->trials[tid].samp[sid].path = xmlGetString(sample_node, "file", NULL);*/
420 tmpStr
= (char*)xmlGetProp(sample_node
, (xmlChar
*)"file");
423 session
->trials
[tid
].samp
[sid
].path
= malloc(strlen(tmpStr
)+strlen(session
->basepath
)+2);
424 strcpy(session
->trials
[tid
].samp
[sid
].path
, session
->basepath
);
425 strcat(session
->trials
[tid
].samp
[sid
].path
, "/");
426 strcat(session
->trials
[tid
].samp
[sid
].path
, tmpStr
);
428 tmpStr
= xmlGetString(sample_node
, "ref", NULL
);
429 if (tmpStr
&& strcmp(tmpStr
, "true")==0)
430 session
->trials
[tid
].refID
= sid
;
432 session
->trials
[tid
].samp
[sid
].id
= sid
;
434 sample_node
= sample_node
->next
;
437 trial_node
= trial_node
->next
;
439 for (i
=0;i
<session
->nbTrials
;i
++)
441 for (j
=0;j
<session
->nbSamples
;j
++)
443 if (!session
->trials
[i
].samp
[j
].path
)
445 fprintf (stderr
, "Sample has no path\n");
453 for (i
=0;i
<session
->nbTrials
;i
++)
454 free(session
->trials
[i
].samp
);
455 fprintf (stderr
, "Loading of experiment failed (bad file)\n");
464 void loadSession(const char *filename
)
466 xmlDocPtr current_session
;
467 xmlNode
*session_root
;
474 /* Close current session */
475 if (!close_request())
479 session
->savepath
= strdup(filename
);
480 current_session
= xmlReadFile(filename
, NULL
, 0);
481 if (current_session
== NULL
) {
482 fprintf(stderr
, "Failed to parse %s\n", filename
);
485 fprintf(stderr
, "Successfully loaded %s\n", filename
);
487 session_root
= xmlDocGetRootElement(current_session
);
488 sname
= xmlGetProp(session_root
, (const xmlChar
*)"expName");
489 if (!sname
|| strcmp((char*)sname
, session
->experiment_name
) != 0)
491 fprintf(stderr
, "Session name doesn't match: %s\n", filename
);
494 xmlFreeDoc(current_session
);
498 session
->curr_trial
= xmlGetInt(session_root
, "currTrial", 0);
499 trial_node
= session_root
->children
;
502 if (trial_node
->type
== XML_ELEMENT_NODE
)
505 xmlNode
*sample_node
;
506 tid
= xmlGetInt(trial_node
, "id", 0);
507 sample_node
= trial_node
->children
;
510 if (sample_node
->type
== XML_ELEMENT_NODE
)
513 sid
= xmlGetInt(sample_node
, "id", 0);
514 session
->trials
[tid
].samp
[sid
].pos
= xmlGetInt(sample_node
, "pos", 0);
515 session
->trials
[tid
].samp
[sid
].score
= xmlGetInt(sample_node
, "score", 0);
516 /*fprintf(stderr, "name: %s at %s\n", session->trials[tid].name, session->trials[tid].samp[sid].path);*/
518 sample_node
= sample_node
->next
;
521 trial_node
= trial_node
->next
;
523 xmlFreeDoc(current_session
);
529 void loadExperiment(const char *filename
)
531 xmlDocPtr current_experiment
;
535 if (!close_request())
537 /* Close current session */
540 current_experiment
= xmlReadFile(filename
, NULL
, 0);
541 if (current_experiment
== NULL
) {
542 fprintf(stderr
, "Failed to parse %s\n", filename
);
545 fprintf(stderr
, "Successfully loaded %s\n", filename
);
547 root
= xmlDocGetRootElement(current_experiment
);
548 if (strcmp((char*)root
->name
, "MUSHRA") != 0)
550 fprintf(stderr
, "Failed validate %s\n", filename
);
551 xmlFreeDoc(current_experiment
);
552 current_experiment
= NULL
;
555 create_session(current_experiment
);
557 xmlFreeDoc(current_experiment
);
560 int getIDFromLabel(GtkWidget
*label
)
562 const char *name
= gtk_label_get_text(GTK_LABEL(label
));
563 if (strcmp(name
, "Ref")==0)
570 Sample
*getSampleFromLabel(GtkWidget
*label
, int update_last_played
)
574 int ID
= getIDFromLabel(label
);
575 /*printf ("pos = %d\n", ID);*/
576 tr
= &session
->trials
[session
->curr_trial
];
577 for (i
=0;i
<session
->nbSamples
;i
++)
579 if (tr
->samp
[i
].pos
== ID
)
581 if (update_last_played
)
582 session
->last_played
= i
;
586 return &tr
->samp
[tr
->refID
];
589 void on_new_activate (GtkWidget
*widget
, gpointer user_data
)
594 void on_open_activate (GtkWidget
*widget
, gpointer user_data
)
596 GtkWidget
*openDialog
= glade_xml_get_widget (main_window
, "OpenDialog");
597 gtk_widget_show(openDialog
);
598 if (gtk_dialog_run (GTK_DIALOG (openDialog
)) == GTK_RESPONSE_OK
)
601 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (openDialog
));
602 /*open_file (filename);*/
603 /*printf ("Opening %s\n", filename);*/
604 loadSession(filename
);
607 gtk_widget_hide(openDialog
);
610 void on_open_experiment (GtkWidget
*widget
, gpointer user_data
)
612 GtkWidget
*openDialog
= glade_xml_get_widget (main_window
, "OpenDialog");
613 gtk_widget_show(openDialog
);
614 if (gtk_dialog_run (GTK_DIALOG (openDialog
)) == GTK_RESPONSE_OK
)
617 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (openDialog
));
618 /*printf ("Opening %s\n", filename);*/
619 loadExperiment(filename
);
622 gtk_widget_hide(openDialog
);
627 void on_vscale_value_changed (GtkWidget
*widget
, gpointer user_data
)
629 Sample
*s
= getSampleFromLabel(widget
, 0);
630 s
->score
= gtk_range_get_value(GTK_RANGE(vscales
[s
->pos
]));
631 /*printf ("%d -> %d\n", s->id, s->score);*/
634 void on_buttonPlay_clicked (GtkWidget
*widget
, gpointer user_data
)
636 Sample
*s
= getSampleFromLabel(widget
, 1);
637 /*snprintf(command, 256, "play \"%s\" >& /dev/null &", s->path);*/
638 /*printf ("%s\n", command);*/
639 /*system("killall play >& /dev/null; killall sox >& /dev/null");*/
643 kill(play_pid
, SIGINT
);
644 waitpid(play_pid
, NULL
, 0);
646 if ((play_pid
=fork())==0)
651 execlp("sox", "sox", s
->path
, "-t", "ossdsp", "/dev/dsp", NULL
);
658 void on_buttonPause_clicked (GtkWidget
*widget
, gpointer user_data
)
660 /*system("killall play >& /dev/null; killall sox >& /dev/null");*/
663 kill(play_pid
, SIGINT
);
664 waitpid(play_pid
, NULL
, 0);
670 void on_buttonStop_clicked (GtkWidget
*widget
, gpointer user_data
)
672 /*system("killall play >& /dev/null; killall sox >& /dev/null");*/
675 kill(play_pid
, SIGINT
);
676 waitpid(play_pid
, NULL
, 0);
682 void on_buttonNext_clicked (GtkWidget
*widget
, gpointer user_data
)
684 if (session
->curr_trial
< session
->nbTrials
-1)
686 session
->curr_trial
++;
687 session
->last_played
=-1;
689 on_buttonStop_clicked(NULL
, NULL
);
692 on_save_activate(NULL
, NULL
);
693 printf ("Completed!\n");
697 void on_buttonPrev_clicked (GtkWidget
*widget
, gpointer user_data
)
699 if (session
->curr_trial
> 0)
701 session
->curr_trial
--;
702 session
->last_played
=-1;
706 printf ("Already at the beginning!\n");
710 void on_buttonComment_clicked (GtkWidget
*widget
, gpointer user_data
)
712 GtkWidget
*commentDialog
;
713 GtkTextIter startIter
, endIter
;
714 GtkTextBuffer
*buffer
;
716 Sample
*s
= getSampleFromLabel(widget
, 0);
718 commentDialog
= glade_xml_get_widget (main_window
, "CommentDialog");
719 GtkWidget
*textview
= glade_xml_get_widget (main_window
, "textviewComments");
720 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview
));
721 gtk_text_buffer_set_text(buffer
, s
->comment
? s
->comment
: "", -1);
723 if (gtk_dialog_run (GTK_DIALOG (commentDialog
)) == GTK_RESPONSE_CLOSE
)
726 gtk_text_buffer_get_start_iter(buffer
, &startIter
);
727 gtk_text_buffer_get_end_iter(buffer
, &endIter
);
728 commentStr
= gtk_text_buffer_get_text(buffer
, &startIter
, &endIter
, FALSE
);
730 s
->comment
= strdup(commentStr
);
733 printf ("Cancel open\n");
735 gtk_widget_hide(commentDialog
);
738 void on_instructions_activate (GtkWidget
*widget
, gpointer user_data
)
741 dialog
= glade_xml_get_widget (main_window
, "InstructionsDialog");
742 gtk_dialog_run (GTK_DIALOG (dialog
));
743 gtk_widget_hide(dialog
);
746 void on_hscale_value_changed (GtkWidget
*widget
, gpointer user_data
)
750 void quit_request (GtkWidget
*widget
, gpointer user_data
)
752 if (session
&& session
->active
)
754 if (!close_request())
757 on_buttonStop_clicked(NULL
, NULL
);
763 on_about_activate (GtkWidget
*widget
, gpointer user_data
)
765 GtkWidget
*about
= glade_xml_get_widget (main_window
, "AboutDialog");
766 gtk_widget_show(about
);
770 main (int argc
, char *argv
[])
774 gtk_init (&argc
, &argv
);
777 signal (SIGCHLD
, chld_handler
);
778 /* load the interface */
779 /*main_window = glade_xml_new ("rateit.glade", NULL, NULL);*/
780 main_window
= glade_xml_new_from_memory((char*)rateit_glade
, 1+strlen((char*)rateit_glade
), NULL
, NULL
);
782 /* connect the signals in the interface */
783 glade_xml_signal_autoconnect (main_window
);
785 /* Extract widgets to a table */
786 for (i
=0;i
<MAX_SAMPLES
;i
++)
788 char widget_name
[100];
789 snprintf(widget_name
, 100, "vscale%c", 'A'+i
);
790 vscales
[i
] = glade_xml_get_widget (main_window
, widget_name
);
791 snprintf(widget_name
, 100, "buttonComment%c", 'A'+i
);
792 commentButtons
[i
] = glade_xml_get_widget (main_window
, widget_name
);
793 snprintf(widget_name
, 100, "buttonPlay%c", 'A'+i
);
794 playButtons
[i
] = glade_xml_get_widget (main_window
, widget_name
);
798 loadExperiment(argv
[1]);
800 loadSession(argv
[2]);
802 /* start the event loop */