#include #include #include // Largest file we want to read #define BUF_SIZE 200000 GtkWidget *window; /* Called when a file is chosen by the open menu. */ static void set_file (GFile *file, gpointer data) { char *name; unsigned char buf[BUF_SIZE]; const char *output; if (!file) { return; } name = g_file_get_path (file); puts(name); // Porting Note: By Default verovio installs this to "/usr/local/share/verovio" void *pointer = vrvToolkit_constructorResourcePath("/usr/share/verovio"); FILE *cfile = fopen(name, "r"); size_t read = fread(buf, 1, BUF_SIZE-1, cfile); // If the file is longer than the buffer, truncate it (which may be okay for some formats...) buf[read] = '\0'; fclose(cfile); if (read == 0) return; // Try to put all of the content on the first page. //--page-height 50000 //--adjust-page-height //--breaks smart vrvToolkit_setOptions(pointer, "{\"pageHeight\": 50000, \"adjustPageHeight\": true, \"breaks\": \"smart\"}"); vrvToolkit_loadData(pointer, buf); output = vrvToolkit_renderToSVG(pointer, 1, TRUE); if(output[0] == '\0') return; // https://stackoverflow.com/a/14123191/1861686 GdkPixbufLoader *loader = gdk_pixbuf_loader_new (); gdk_pixbuf_loader_write (loader, output, strlen(output), NULL); gdk_pixbuf_loader_close(loader, NULL); GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf); gtk_window_set_child (GTK_WINDOW (window), image); // TODO: keep this around free(pointer); g_free (name); } static void file_opened (GObject *source, GAsyncResult *result, void *data) { GFile *file; GError *error = NULL; file = gtk_file_dialog_open_finish (GTK_FILE_DIALOG (source), result, &error); if (!file) { g_print ("%s\n", error->message); g_error_free (error); } set_file (file, data); } /* Called when the "Open" button is clicked */ static void open_file (GtkButton *picker, GtkLabel *label) { GtkWindow *parent = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (picker))); GtkFileDialog *dialog; dialog = gtk_file_dialog_new (); gtk_file_dialog_set_title (dialog, "Select Sheet Music File"); // Filters for the different types that are supported. GListStore *filters; filters = g_list_store_new (GTK_TYPE_FILE_FILTER); // Note: Files are usually recognized by extension (not mime type). GtkFileFilter *filter; // abc notation https://abcnotation.com/ filter = gtk_file_filter_new(); gtk_file_filter_set_name (filter, "ABC"); gtk_file_filter_add_mime_type(filter, "text/vnd.abc"); gtk_file_filter_add_suffix(filter, "abc"); g_list_store_append (filters, filter); g_object_unref (filter); // TODO: do DARMS and PAE have common extension or mimetype? // DARMS https://wiki.ccarh.org/wiki/DARMS // PAE https://www.iaml.info/plaine-easie-code // Humdrum https://www.humdrum.org/ filter = gtk_file_filter_new(); gtk_file_filter_set_name (filter, "Humdrum"); gtk_file_filter_add_suffix(filter, "krn"); g_list_store_append (filters, filter); g_object_unref (filter); // MEI https://music-encoding.org/ // MusicXML https://www.musicxml.com/ filter = gtk_file_filter_new(); gtk_file_filter_set_name (filter, "MEI, MusicXML"); // Generic XML? //gtk_file_filter_add_mime_type (filter, "application/xml"); //gtk_file_filter_add_mime_type (filter, "text/xml"); gtk_file_filter_add_suffix(filter, "xml"); // MusicXML gtk_file_filter_add_mime_type(filter, "application/vnd.recordare.musicxml+xml"); gtk_file_filter_add_suffix(filter, "musicxml"); // Compressed MusicXML gtk_file_filter_add_mime_type(filter, "application/vnd.recordare.musicxml"); gtk_file_filter_add_suffix(filter, "mxl"); // MEI gtk_file_filter_add_suffix(filter, "mei"); g_list_store_append (filters, filter); gtk_file_dialog_set_default_filter (dialog, filter); g_object_unref (filter); gtk_file_dialog_set_filters (dialog, G_LIST_MODEL (filters)); g_object_unref (filters); gtk_file_dialog_open (dialog, parent, NULL, file_opened, label); g_object_unref (dialog); } static void activate (GtkApplication* app, gpointer user_data) { GtkWidget *header; GtkWidget *image; GtkWidget *button; // Window window = gtk_application_window_new (app); gtk_window_set_title (GTK_WINDOW (window), "SheMuVi"); gtk_window_set_default_size (GTK_WINDOW (window), 400, 600); gtk_widget_set_visible (window, TRUE); // Header header = gtk_header_bar_new(); button = gtk_button_new_from_icon_name ("document-open-symbolic"); gtk_widget_set_tooltip_text (button, "Load file"); g_signal_connect (button, "clicked", G_CALLBACK (open_file), NULL); gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button); gtk_window_set_titlebar (GTK_WINDOW (window), header); // Image will be added by "open" GtkWidget* label = gtk_label_new_with_mnemonic("Please open a file."); gtk_window_set_child (GTK_WINDOW (window), label); } void app_open (GtkApplication* app, GFile** files, gint n_files, const gchar* hint) { activate(app,NULL); // TODO: do we actually want to handle opening multiple in one application? set_file(files[0], NULL); } int main (int argc, char **argv) { GtkApplication *app; int status; app = gtk_application_new ("com.zachdecook.shemuvi", G_APPLICATION_DEFAULT_FLAGS|G_APPLICATION_HANDLES_OPEN); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); g_signal_connect (app, "open", G_CALLBACK(app_open), NULL); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); return status; }