/* recorder.c * This demo is a simple GTK human interface combined with a low-level audio interface. The program plays sounds (from a .raw audio file) or records sounds (to a .raw audio file) and displays the sound in a window. Demonstrates menu, toolbar, tooltips, stock icons, and drawing area. Also demonstrates a background thread, and ALSA audio play/record. to do: 1) save file,open 2) hscale and start/stop positions (set, play from) 3) bug, sometimes audio is scratchy. when do a playback right after a record, without exiting first. (audio initialization problem?) Initial user interface machine generated by mkmenu.cpp */ #include #include #include #include #include #include "audio.h" GtkWidget *window1 ; GtkWidget *vbox1 ; GtkWidget *menubar ; GtkWidget *filemenu ; GtkWidget *filemenu_menu ; GtkWidget *fileopen ; GtkWidget *filesave ; GtkWidget *separator_1 ; GtkWidget *fileproperties ; GtkWidget *separator_2 ; GtkWidget *filequit ; GtkWidget *editmenu ; GtkWidget *editmenu_menu ; GtkWidget *editcopy ; GtkWidget *editpaste ; GtkWidget *separator_3 ; GtkWidget *editaudioproperties ; GtkWidget *effectsmenu ; GtkWidget *effectsmenu_menu ; GtkWidget *effectsvolume ; GtkWidget *effectsspeed ; GtkWidget *separator_4 ; GtkWidget *effectsecho ; GtkWidget *helpmenu ; GtkWidget *helpmenu_menu ; GtkWidget *helphelp ; GtkWidget *helpabout ; GtkWidget *toolbar1 ; GtkToolItem *toolmediarewind ; GtkToolItem *toolmediaforward ; GtkToolItem *toolmediaplay ; GtkToolItem *toolmediastop ; GtkToolItem *toolmediarecord ; GtkWidget *frame1 ; GtkWidget *vbox2 ; GtkWidget *hbox2 ; GtkWidget *drawarea1 ; GdkPixmap *pixmap_drawarea1 = NULL; GtkWidget *hscale1 ; GtkAccelGroup *menuGroup; void MessageBox (GtkWindow *parentWindow, char *messageValue) { GtkWidget *dialog; dialog = gtk_message_dialog_new (parentWindow, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, messageValue); gtk_window_set_title (GTK_WINDOW (dialog), "Information"); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } // audio globals AudioGlobal audioGlobals; // common signals between the user interface and the audio routines void AudioInitialize () { audioGlobals.playbackFlag = 0; audioGlobals.audioFilename = "foo.raw"; audioGlobals.stopFlag = 0; audioGlobals.recordFlag = 0; audioGlobals.audioRunningFlag = 0; audioGlobals.audioTimeLimit = 100; audioGlobals.bufferPointer = 0; audioGlobals.bufferSize = 0; } void *AudioMain(void *threadid) { int tid; tid = (int)threadid; ProcessAudio(); fprintf(stderr,"audio exiting\n"); pthread_exit(NULL); } /* .... put initialize stuff here .... */ void InitializeMainSystem () { pthread_t threads[1]; int rc, t; t=0; AudioInitialize(); fprintf(stderr,"In InitializeMainSystem: creating thread %d\n", t); rc = pthread_create(&threads[t], NULL, AudioMain, (void *)t); if (rc){ fprintf(stderr,"ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } } // ======================================================= // user interface callback functions // ======================================================= static void toolmediaplay_clicked (GtkToolItem *toolmediaplay, GtkWindow *parentWindow) { audioGlobals.playbackFlag = 1; // MessageBox(parentWindow, "toolbar toolmediaplay was clicked."); } static void toolmediastop_clicked (GtkToolItem *toolmediastop, GtkWindow *parentWindow) { audioGlobals.stopFlag = 1; // MessageBox(parentWindow, "toolbar toolmediastop was clicked."); } static void toolmediarecord_clicked (GtkToolItem *toolmediarecord, GtkWindow *parentWindow) { audioGlobals.recordFlag = 1; // MessageBox(parentWindow, "toolbar toolmediarecord was clicked."); } /* Stop the GTK+ main loop function. */ static void destroy_window1 (GtkWidget *window, gpointer data) { gtk_main_quit (); } /* Return FALSE to destroy the widget. By returning TRUE, you can cancel a delete-event. This can be used to confirm quitting the application. */ static gboolean delete_event_window1 (GtkWidget *window, GdkEvent *event, gpointer data) { return (FALSE); } static void fileopen_activated (GtkMenuItem *fileopen, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu fileopen was clicked."); } static void filesave_activated (GtkMenuItem *filesave, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu filesave was clicked."); } static void fileproperties_activated (GtkMenuItem *fileproperties, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu fileproperties was clicked."); } static void filequit_activated (GtkMenuItem *filequit, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu filequit was clicked."); } static void editcopy_activated (GtkMenuItem *editcopy, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu editcopy was clicked."); } static void editpaste_activated (GtkMenuItem *editpaste, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu editpaste was clicked."); } static void editaudioproperties_activated (GtkMenuItem *editaudioproperties, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu editaudioproperties was clicked."); } static void effectsvolume_activated (GtkMenuItem *effectsvolume, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu effectsvolume was clicked."); } static void effectsspeed_activated (GtkMenuItem *effectsspeed, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu effectsspeed was clicked."); } static void effectsecho_activated (GtkMenuItem *effectsecho, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu effectsecho was clicked."); } static void helphelp_activated (GtkMenuItem *helphelp, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu helphelp was clicked."); } static void helpabout_activated (GtkMenuItem *helpabout, GtkWindow *parentWindow) { MessageBox(parentWindow, "Menu helpabout was clicked."); } static void toolmediarewind_clicked (GtkToolItem *toolmediarewind, GtkWindow *parentWindow) { MessageBox(parentWindow, "toolbar toolmediarewind was clicked."); } static void toolmediaforward_clicked (GtkToolItem *toolmediaforward, GtkWindow *parentWindow) { MessageBox(parentWindow, "toolbar toolmediaforward was clicked."); } static void hscale1_value_changed (GtkRange *hscale1, GtkWindow *parentWindow) { double value = gtk_range_get_value(hscale1); fprintf(stderr,"hscale value: %g\n",value); } /* On size change: Create a new backing pixmap of the appropriate size */ static gboolean drawarea1_configure_event( GtkWidget *widget, GdkEventConfigure *event ) { if (pixmap_drawarea1) { g_object_unref (pixmap_drawarea1); } pixmap_drawarea1 = gdk_pixmap_new (widget->window, widget->allocation.width, widget->allocation.height, -1); gdk_draw_rectangle (pixmap_drawarea1, widget->style->black_gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height); return (TRUE); } #define NUMBEROFPOINTS (1000) static gboolean drawarea1_timeout (GtkWidget *widget) { static GdkPoint points[NUMBEROFPOINTS+5]; /* test */ static int lastX2 = 0; int i; int16_t *apointer; int x2, value; int x1 = widget->allocation.width; int y1 = widget->allocation.height; int scale = 2; if (pixmap_drawarea1 == NULL){ return(TRUE); } if (lastX2 != 0){ gdk_draw_points(pixmap_drawarea1, widget->style->black_gc, points, lastX2); } x2 = x1; if (x2 >= NUMBEROFPOINTS){ x2 = NUMBEROFPOINTS - 1; } if ((audioGlobals.audioRunningFlag == 0) || (audioGlobals.bufferSize == 0)){ for (i=0; i < x2; i++) { points[i].x = i; points[i].y = y1 / 2; } } else { if (x2 > (audioGlobals.bufferSize/2)){ x2 = (audioGlobals.bufferSize/2); } apointer = (int16_t *)audioGlobals.bufferPointer; for (i=0; i < x2; i++) { points[i].x = i; value = apointer[i]/scale + y1/2; if (value < 0) value = 0; if (value > (y1-1)) value = y1-1; points[i].y = value; } } gdk_draw_points(pixmap_drawarea1, widget->style->white_gc, points, x2); gtk_widget_queue_draw_area (widget, 0, 0, x1, y1); lastX2 = x2; return (TRUE); } /* Redraw the screen from the backing pixmap */ static gboolean drawarea1_expose_event( GtkWidget *widget, GdkEventExpose *event ) { gdk_draw_drawable (widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], pixmap_drawarea1, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); return (FALSE); } void InitializeUserInterface () { menuGroup = gtk_accel_group_new(); /* initialize main window */ window1 = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window1), "Sound Recorder"); gtk_window_set_default_size (GTK_WINDOW (window1), 800, 400); // gtk_window_maximize (GTK_WINDOW (window1)); /* Connect the main window to the destroy and delete-event signals. */ g_signal_connect (G_OBJECT (window1), "destroy", G_CALLBACK (destroy_window1), NULL); g_signal_connect (G_OBJECT (window1), "delete_event", G_CALLBACK (delete_event_window1), NULL); vbox1 = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window1), vbox1); menubar = gtk_menu_bar_new (); gtk_box_pack_start (GTK_BOX (vbox1), menubar, FALSE, FALSE, 2); filemenu = gtk_menu_item_new_with_label ("File"); filemenu_menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (filemenu), filemenu_menu); gtk_menu_shell_append (GTK_MENU_SHELL (menubar), filemenu); fileopen = gtk_image_menu_item_new_from_stock (GTK_STOCK_OPEN, menuGroup); gtk_menu_shell_append (GTK_MENU_SHELL (filemenu_menu), fileopen); g_signal_connect (G_OBJECT (fileopen), "activate", G_CALLBACK (fileopen_activated), (gpointer) window1); filesave = gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE, menuGroup); gtk_menu_shell_append (GTK_MENU_SHELL (filemenu_menu), filesave); g_signal_connect (G_OBJECT (filesave), "activate", G_CALLBACK (filesave_activated), (gpointer) window1); separator_1 = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (filemenu_menu), separator_1); fileproperties = gtk_image_menu_item_new_from_stock (GTK_STOCK_PROPERTIES, menuGroup); gtk_menu_shell_append (GTK_MENU_SHELL (filemenu_menu), fileproperties); g_signal_connect (G_OBJECT (fileproperties), "activate", G_CALLBACK (fileproperties_activated), (gpointer) window1); separator_2 = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (filemenu_menu), separator_2); filequit = gtk_image_menu_item_new_from_stock (GTK_STOCK_QUIT, menuGroup); gtk_menu_shell_append (GTK_MENU_SHELL (filemenu_menu), filequit); g_signal_connect (G_OBJECT (filequit), "activate", G_CALLBACK (filequit_activated), (gpointer) window1); editmenu = gtk_menu_item_new_with_label ("Edit"); editmenu_menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (editmenu), editmenu_menu); gtk_menu_shell_append (GTK_MENU_SHELL (menubar), editmenu); editcopy = gtk_image_menu_item_new_from_stock (GTK_STOCK_COPY, menuGroup); gtk_menu_shell_append (GTK_MENU_SHELL (editmenu_menu), editcopy); g_signal_connect (G_OBJECT (editcopy), "activate", G_CALLBACK (editcopy_activated), (gpointer) window1); editpaste = gtk_image_menu_item_new_from_stock (GTK_STOCK_PASTE, menuGroup); gtk_menu_shell_append (GTK_MENU_SHELL (editmenu_menu), editpaste); g_signal_connect (G_OBJECT (editpaste), "activate", G_CALLBACK (editpaste_activated), (gpointer) window1); separator_3 = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (editmenu_menu), separator_3); editaudioproperties = gtk_menu_item_new_with_label ("Audio Properties"); gtk_menu_shell_append (GTK_MENU_SHELL (editmenu_menu), editaudioproperties); g_signal_connect (G_OBJECT (editaudioproperties), "activate", G_CALLBACK (editaudioproperties_activated), (gpointer) window1); effectsmenu = gtk_menu_item_new_with_label ("Effects"); effectsmenu_menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (effectsmenu), effectsmenu_menu); gtk_menu_shell_append (GTK_MENU_SHELL (menubar), effectsmenu); effectsvolume = gtk_menu_item_new_with_label ("Adjust Volume"); gtk_menu_shell_append (GTK_MENU_SHELL (effectsmenu_menu), effectsvolume); g_signal_connect (G_OBJECT (effectsvolume), "activate", G_CALLBACK (effectsvolume_activated), (gpointer) window1); effectsspeed = gtk_menu_item_new_with_label ("Adjust Speed"); gtk_menu_shell_append (GTK_MENU_SHELL (effectsmenu_menu), effectsspeed); g_signal_connect (G_OBJECT (effectsspeed), "activate", G_CALLBACK (effectsspeed_activated), (gpointer) window1); separator_4 = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (effectsmenu_menu), separator_4); effectsecho = gtk_menu_item_new_with_label ("Add Echo"); gtk_menu_shell_append (GTK_MENU_SHELL (effectsmenu_menu), effectsecho); g_signal_connect (G_OBJECT (effectsecho), "activate", G_CALLBACK (effectsecho_activated), (gpointer) window1); helpmenu = gtk_menu_item_new_with_label ("Help"); helpmenu_menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (helpmenu), helpmenu_menu); gtk_menu_shell_append (GTK_MENU_SHELL (menubar), helpmenu); helphelp = gtk_image_menu_item_new_from_stock (GTK_STOCK_HELP, menuGroup); gtk_menu_shell_append (GTK_MENU_SHELL (helpmenu_menu), helphelp); g_signal_connect (G_OBJECT (helphelp), "activate", G_CALLBACK (helphelp_activated), (gpointer) window1); helpabout = gtk_image_menu_item_new_from_stock (GTK_STOCK_ABOUT, menuGroup); gtk_menu_shell_append (GTK_MENU_SHELL (helpmenu_menu), helpabout); g_signal_connect (G_OBJECT (helpabout), "activate", G_CALLBACK (helpabout_activated), (gpointer) window1); toolbar1 = gtk_toolbar_new (); gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar1), TRUE); gtk_toolbar_set_style (GTK_TOOLBAR (toolbar1), GTK_TOOLBAR_BOTH); gtk_box_pack_start (GTK_BOX (vbox1), toolbar1, FALSE, FALSE, 2); toolmediarewind = gtk_tool_button_new_from_stock (GTK_STOCK_MEDIA_REWIND); gtk_toolbar_insert (GTK_TOOLBAR (toolbar1), toolmediarewind, 0); gtk_widget_set_tooltip_text (GTK_WIDGET(toolmediarewind), "Rewind to Start"); g_signal_connect (G_OBJECT (toolmediarewind), "clicked", G_CALLBACK (toolmediarewind_clicked), (gpointer) window1); toolmediaforward = gtk_tool_button_new_from_stock (GTK_STOCK_MEDIA_FORWARD); gtk_toolbar_insert (GTK_TOOLBAR (toolbar1), toolmediaforward, 1); gtk_widget_set_tooltip_text (GTK_WIDGET(toolmediaforward), "Forward to End"); g_signal_connect (G_OBJECT (toolmediaforward), "clicked", G_CALLBACK (toolmediaforward_clicked), (gpointer) window1); toolmediaplay = gtk_tool_button_new_from_stock (GTK_STOCK_MEDIA_PLAY); gtk_toolbar_insert (GTK_TOOLBAR (toolbar1), toolmediaplay, 2); gtk_widget_set_tooltip_text (GTK_WIDGET(toolmediaplay), "Play Audio"); g_signal_connect (G_OBJECT (toolmediaplay), "clicked", G_CALLBACK (toolmediaplay_clicked), (gpointer) window1); toolmediastop = gtk_tool_button_new_from_stock (GTK_STOCK_MEDIA_STOP); gtk_toolbar_insert (GTK_TOOLBAR (toolbar1), toolmediastop, 3); gtk_widget_set_tooltip_text (GTK_WIDGET(toolmediastop), "Stop Audio"); g_signal_connect (G_OBJECT (toolmediastop), "clicked", G_CALLBACK (toolmediastop_clicked), (gpointer) window1); toolmediarecord = gtk_tool_button_new_from_stock (GTK_STOCK_MEDIA_RECORD); gtk_toolbar_insert (GTK_TOOLBAR (toolbar1), toolmediarecord, 4); gtk_widget_set_tooltip_text (GTK_WIDGET(toolmediarecord), "Record Audio"); g_signal_connect (G_OBJECT (toolmediarecord), "clicked", G_CALLBACK (toolmediarecord_clicked), (gpointer) window1); frame1 = gtk_frame_new ("Waveform"); gtk_box_pack_start (GTK_BOX (vbox1), frame1, TRUE, TRUE, 2); vbox2 = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (frame1), vbox2); hbox2 = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox2), hbox2, TRUE, TRUE, 5); /* Create the drawing area */ drawarea1 = gtk_drawing_area_new(); gtk_box_pack_start (GTK_BOX (hbox2), drawarea1, TRUE, TRUE, 2); g_signal_connect (G_OBJECT (drawarea1), "expose_event", G_CALLBACK (drawarea1_expose_event), (gpointer) window1); g_timeout_add (100, (GSourceFunc) drawarea1_timeout, (gpointer) drawarea1); g_signal_connect (G_OBJECT (drawarea1), "configure_event", G_CALLBACK (drawarea1_configure_event), (gpointer) window1); hscale1 = gtk_hscale_new_with_range(0.0,100.0,1.0); gtk_scale_set_digits (GTK_SCALE (hscale1), 0); gtk_scale_set_value_pos (GTK_SCALE (hscale1), GTK_POS_RIGHT); gtk_box_pack_start (GTK_BOX (vbox1), hscale1, FALSE, FALSE, 2); gtk_widget_set_tooltip_text( hscale1, "Slide to Starting Position"); g_signal_connect (G_OBJECT (hscale1), "value_changed", G_CALLBACK (hscale1_value_changed), (gpointer) window1); gtk_window_add_accel_group( GTK_WINDOW(window1), menuGroup); } int main (int argc, char *argv[]) { gtk_init (&argc, &argv); InitializeMainSystem(); InitializeUserInterface(); gtk_widget_show_all (window1); gtk_main (); return (0); }