/* This is gonna be my second "mod player" to date (previous one was in Turbo pascal + asm some 20years ago...) This one is intended to be a preview for underpowered platforms with lots of degrade functions (lower frequency, low bit count...) */ #include #include #include #include #include "player_module.h" #include "alsa_playback.h" GtkWidget *window; GtkWidget *sample_drawing_area; #define MY_MAX_PATH 4096 int cur_sample=1; int cur_pattern=0; void update_sample(void); static gboolean delete_event( GtkWidget *widget, GdkEvent *event, gpointer data ) { g_print ("delete event occurred May autosave in release...\n"); gtk_main_quit (); } static void destroy( GtkWidget *widget, gpointer data ) { gtk_main_quit (); } /* open_file: * Charge une nouvelle disquette (callback). */ static void open_mod_file ( GtkWidget *widget, gpointer data ) { GtkFileFilter *filter; static GtkWidget *dialog; char *folderName; static char folderNameLast[MY_MAX_PATH+1]=""; char *fileName; g_print ("Open mod file...\n"); dialog = gtk_file_chooser_dialog_new ( "Open a module file", (GtkWindow *) window, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter,"Plain old amiga files"); gtk_file_filter_add_pattern (filter, "*.MOD"); gtk_file_filter_add_pattern (filter, "*.mod"); gtk_file_filter_add_pattern (filter, "mod.*"); gtk_file_filter_add_pattern (filter, "MOD.*"); gtk_file_chooser_add_filter ((GtkFileChooser *)dialog, filter); /* voids any pending message */ while (gtk_events_pending ()) gtk_main_iteration (); if (folderNameLast[0]=='\0') { strncpy(folderNameLast,g_get_current_dir(),MY_MAX_PATH); } (void)gtk_file_chooser_set_current_folder((GtkFileChooser *)dialog,folderNameLast); if (gtk_dialog_run ((GtkDialog *)dialog) == GTK_RESPONSE_ACCEPT) { fileName = gtk_file_chooser_get_filename((GtkFileChooser *)dialog); folderName = gtk_file_chooser_get_current_folder ((GtkFileChooser *)dialog); strncpy(folderNameLast,folderName,MY_MAX_PATH); load_module(fileName); update_song(); update_pattern(0); update_sample(); } gtk_widget_hide(dialog); } static void play_mod ( GtkWidget *widget, gpointer data ) { stop_playback(); play_start(); start_playback(); } static void stop_mod ( GtkWidget *widget, gpointer data ) { stop_playback(); } static void play_atstart ( GtkWidget *widget, gpointer data ) { stop_playback(); play_start(); start_playback(); } static void play_rewind ( GtkWidget *widget, gpointer data ) { stop_playback(); play_prev_pattern(); start_playback(); } static void play_forward ( GtkWidget *widget, gpointer data ) { stop_playback(); play_next_pattern(); start_playback(); } void get_main_menu( GtkWidget *window, GtkWidget **menuBar ) { GtkWidget *menu; GtkWidget *filemenu; GtkWidget *file; GtkWidget *new; GtkWidget *open; GtkWidget *export; GtkWidget *quit; GtkWidget *sep; GtkAccelGroup *accel_group = NULL; menu = gtk_menu_new (); *menuBar = gtk_menu_bar_new(); filemenu = gtk_menu_new(); accel_group = gtk_accel_group_new(); gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); file = gtk_menu_item_new_with_mnemonic("_File"); // new = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL); open = gtk_image_menu_item_new_from_stock("Open module", NULL); export = gtk_image_menu_item_new_from_stock("Export", NULL); sep = gtk_separator_menu_item_new(); quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel_group); gtk_widget_add_accelerator(quit, "activate", accel_group, GDK_KEY_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu); // gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), new); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), open); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), export); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit); gtk_menu_shell_append(GTK_MENU_SHELL(*menuBar), file); g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(G_OBJECT(quit), "activate", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(G_OBJECT(open), "activate", G_CALLBACK(open_mod_file),"from_menu"); } void get_main_toolbar( GtkWidget *window, GtkWidget **toolBar ) { GtkWidget *open; GtkWidget *export; GtkWidget *sep; GtkWidget *mediaStart; GtkWidget *mediaRewind; GtkWidget *mediaPlay; GtkWidget *mediaStop; GtkWidget *mediaForward; *toolBar = gtk_toolbar_new(); gtk_toolbar_set_style(GTK_TOOLBAR(*toolBar), GTK_TOOLBAR_ICONS); gtk_container_set_border_width(GTK_CONTAINER(*toolBar), 2); open = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN); gtk_toolbar_insert(GTK_TOOLBAR(*toolBar), GTK_TOOL_ITEM(open), -1); export = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE); gtk_toolbar_insert(GTK_TOOLBAR(*toolBar), GTK_TOOL_ITEM(export), -1); sep = gtk_separator_tool_item_new(); gtk_toolbar_insert(GTK_TOOLBAR(*toolBar), GTK_TOOL_ITEM(sep), -1); mediaStart = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PREVIOUS); gtk_toolbar_insert(GTK_TOOLBAR(*toolBar), GTK_TOOL_ITEM(mediaStart), -1); mediaRewind = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_REWIND); gtk_toolbar_insert(GTK_TOOLBAR(*toolBar), GTK_TOOL_ITEM(mediaRewind), -1); mediaPlay = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PLAY); gtk_toolbar_insert(GTK_TOOLBAR(*toolBar), GTK_TOOL_ITEM(mediaPlay), -1); mediaStop = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_STOP); gtk_toolbar_insert(GTK_TOOLBAR(*toolBar), GTK_TOOL_ITEM(mediaStop), -1); mediaForward = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_FORWARD); gtk_toolbar_insert(GTK_TOOLBAR(*toolBar), GTK_TOOL_ITEM(mediaForward), -1); g_signal_connect(G_OBJECT(open), "clicked", G_CALLBACK(open_mod_file),"from_toolbar"); g_signal_connect(G_OBJECT(mediaPlay), "clicked", G_CALLBACK(play_mod),"from_toolbar"); g_signal_connect(G_OBJECT(mediaStop), "clicked", G_CALLBACK(stop_mod),"from_toolbar"); g_signal_connect(G_OBJECT(mediaRewind), "clicked", G_CALLBACK(play_rewind),"from_toolbar"); g_signal_connect(G_OBJECT(mediaForward), "clicked", G_CALLBACK(play_forward),"from_toolbar"); g_signal_connect(G_OBJECT(mediaStart), "clicked", G_CALLBACK(play_atstart),"from_toolbar"); } static GtkWidget *song_view; static GtkListStore *list_store_song; enum { SONG_INDEX=0, SONG_PATTERN, NB_COL }; volatile int song_updating=FALSE; gboolean select_pattern (GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer userdata) { GtkTreeIter iter; if (gtk_tree_model_get_iter(model, &iter, path)) { int song_pattern; gtk_tree_model_get(model, &iter, SONG_PATTERN, &song_pattern, -1); if (!path_currently_selected) { // g_print ("%d is going to be selected.\n", sample_index); cur_pattern=song_pattern; update_pattern(cur_pattern); } else { // g_print ("%s is going to be unselected.\n", name); } } return TRUE; /* allow selection state to change */ } void update_song_pos(int i) { GtkTreeSelection *selection; GtkTreePath *path; if (song_updating) return; selection=gtk_tree_view_get_selection(song_view); path=gtk_tree_path_new_from_indices(i,-1); gtk_tree_view_scroll_to_cell(song_view,path,NULL,FALSE,1.0,1.0); gtk_tree_selection_select_path(selection,path); gtk_tree_path_free(path); } void update_song(void) { int loop; GtkTreeIter iter; static GtkListStore *list_store_song_new; song_updating=TRUE; list_store_song_new = gtk_list_store_new (2, G_TYPE_UINT, G_TYPE_UINT); for (loop=0;loop<128;loop++) { gtk_list_store_append(list_store_song_new, &iter); gtk_list_store_set (list_store_song_new, &iter, SONG_INDEX, (guint)loop, SONG_PATTERN, (guint)get_song_pattern(loop), -1); } gtk_tree_view_set_model(GTK_TREE_VIEW(song_view), GTK_TREE_MODEL(list_store_song_new)); g_object_unref(list_store_song); list_store_song=list_store_song_new; song_updating=FALSE; } void get_song ( GtkWidget *box ) { GtkWidget *widget; GtkTreeViewColumn *col; GtkCellRenderer *renderer; GtkTreeIter iter; GtkTreeSelection *selection; int loop; list_store_song = gtk_list_store_new (2, G_TYPE_UINT, G_TYPE_UINT); for (loop=0;loop<128;loop++) { gtk_list_store_append(list_store_song, &iter); gtk_list_store_set (list_store_song, &iter, SONG_INDEX, (guint)loop, SONG_PATTERN, (guint)0, -1); } song_view = gtk_tree_view_new(); /* --- Column #1 --- */ col = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(col, "Num"); gtk_tree_view_append_column(GTK_TREE_VIEW(song_view), col); renderer = gtk_cell_renderer_text_new(); /* pack cell renderer into tree view column */ gtk_tree_view_column_pack_start(col, renderer, TRUE); gtk_tree_view_column_add_attribute(col, renderer, "text", SONG_INDEX); /* --- Column #2 --- */ col = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(col, "Pattern"); gtk_tree_view_append_column(GTK_TREE_VIEW(song_view), col); renderer = gtk_cell_renderer_text_new(); /* pack cell renderer into tree view column */ gtk_tree_view_column_pack_start(col, renderer, TRUE); gtk_tree_view_column_add_attribute(col, renderer, "text", SONG_PATTERN); gtk_tree_view_set_model(GTK_TREE_VIEW(song_view), GTK_TREE_MODEL(list_store_song)); gtk_widget_show(song_view); widget=gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_min_content_height((GtkScrolledWindow*)widget,150); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_container_add(GTK_CONTAINER(widget), song_view); gtk_box_pack_start( GTK_BOX(box), widget, TRUE, TRUE, 0); selection=gtk_tree_view_get_selection(song_view); gtk_tree_selection_set_select_function(selection, select_pattern, NULL, NULL); } static GtkWidget *sample_view; static GtkListStore *list_store_sample; enum { SAMPLE_INDEX=0, SAMPLE_NAME, SAMPLE_LEN, SAMPLE_HIT, SAMPLE_NOTES, NB_COL_SAMPLE }; volatile int sample_updating=FALSE; gboolean select_sample (GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer userdata) { GtkTreeIter iter; if (gtk_tree_model_get_iter(model, &iter, path)) { int sample_index; gtk_tree_model_get(model, &iter, SAMPLE_INDEX, &sample_index, -1); if (!path_currently_selected) { // g_print ("%d is going to be selected.\n", sample_index); cur_sample=sample_index; gtk_widget_queue_draw(sample_drawing_area); } else { // g_print ("%s is going to be unselected.\n", name); } } return TRUE; /* allow selection state to change */ } void update_sample(void) { int loop; GtkTreeIter iter; static GtkListStore *list_store_sample_new; sample_updating=TRUE; list_store_sample_new = gtk_list_store_new (5, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT); for (loop=1;loop