gboolean m4a_can_convert() { gchar *cmd = m4a_get_conversion_cmd(); /* * Return TRUE if * Command exists and fully formed * Target format is NOT set to AAC * convert_m4a preference is set to TRUE */ return cmd && cmd[0] && (prefs_get_int("conversion_target_format") != TARGET_FORMAT_AAC) && prefs_get_int("convert_m4a"); }
/* Logs tracks (@track) that could not be updated with info from mserv database for some reason. Pop up a window with the log by calling with @track = NULL, or remove the log by calling with @track = -1. @txt (if available) is added as an explanation as to why it was impossible to retrieve mserv information */ void display_mserv_problems(Track *track, gchar *txt) { gchar *buf; static gint track_nr = 0; static GString *str = NULL; if ((track == NULL) && str) { if (prefs_get_int("mserv_use") && prefs_get_int("mserv_report_probs") && str->len) { /* Some tracks have had problems. Print a notice */ buf = g_strdup_printf(ngettext("No mserv information could be retrieved for the following track", "No mserv information could be retrieved for the following %d tracks", track_nr), track_nr); gtkpod_confirmation(-1, /* gint id, */ FALSE, /* gboolean modal, */ _("mserv data retrieval problem"), /* title */ buf, /* label */ str->str, /* scrolled text */ NULL, 0, NULL, /* option 1 */ NULL, 0, NULL, /* option 2 */ TRUE, /* gboolean confirm_again, */ "mserv_report_probs",/* confirm_again_key,*/ CONF_NULL_HANDLER, /* ConfHandler ok_handler,*/ NULL, /* don't show "Apply" button */ NULL, /* cancel_handler,*/ NULL, /* gpointer user_data1,*/ NULL); /* gpointer user_data2,*/ g_free(buf); } display_mserv_problems((void *) -1, NULL); } if (track == (void *) -1) { /* clean up */ if (str) g_string_free(str, TRUE); str = NULL; track_nr = 0; gtkpod_tracks_statusbar_update(); } else if (prefs_get_int("mserv_use") && prefs_get_int("mserv_report_probs") && track) { /* add info about it to str */ buf = get_track_info(track, TRUE); if (!str) { track_nr = 0; str = g_string_sized_new(2000); /* used to keep record */ } if (txt) g_string_append_printf(str, "%s (%s)\n", buf, txt); else g_string_append_printf(str, "%s\n", buf); g_free(buf); ++track_nr; /* count tracks */ } }
static gboolean oss_loadsettings (void *dp, prefs_node *f) { oss_driver * const d = dp; prefs_get_string(f, "oss-devdsp", d->p_devdsp); prefs_get_int(f, "oss-resolution", &d->p_resolution); prefs_get_int(f, "oss-channels", &d->p_channels); prefs_get_int(f, "oss-mixfreq", &d->p_mixfreq); prefs_get_int(f, "oss-fragsize", &d->p_fragsize); prefs_init_from_structure(d); return TRUE; }
/* init plugin */ static int http_init(void) { http_buffer_size = prefs_get_int (ap_prefs, "http", "buffer_size", DEFAULT_HTTP_BUFFER_SIZE); /* Be sure http.buffer_size is available in config */ prefs_set_int (ap_prefs, "http", "buffer_size", http_buffer_size); return 1; }
void tips_dialog_load_settings (void) { prefs_node *f; f = prefs_open_read("tips"); if(f) { prefs_get_int(f, "show-tips", &tips_dialog_show_tips); prefs_get_int(f, "last-tip", &tips_dialog_last_tip); prefs_close(f); } if(tips_dialog_last_tip >= TIPS_COUNT || tips_dialog_last_tip < 0) { tips_dialog_last_tip = 0; } return; }
GtkWidget *init_playlist_display_preferences() { GtkBuilder *prefbuilder; GtkWidget *w = NULL; gchar *glade_path = g_build_filename(get_glade_dir(), "playlist_display.xml", NULL); prefbuilder = gtkpod_builder_xml_new(glade_path); w = gtkpod_builder_xml_get_widget(prefbuilder, "prefs_window"); notebook = gtkpod_builder_xml_get_widget(prefbuilder, "playlist_settings_notebook"); g_object_ref(notebook); gtk_container_remove(GTK_CONTAINER(w), notebook); gtk_widget_destroy(w); g_free(glade_path); switch (prefs_get_int("pm_sort")) { case SORT_ASCENDING: w = gtkpod_builder_xml_get_widget(prefbuilder, "pm_ascend"); break; case SORT_DESCENDING: w = gtkpod_builder_xml_get_widget(prefbuilder, "pm_descend"); break; case SORT_NONE: w = gtkpod_builder_xml_get_widget(prefbuilder, "pm_none"); break; } if (w) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), TRUE); if ((w = gtkpod_builder_xml_get_widget(prefbuilder, "pm_cfg_case_sensitive"))) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), prefs_get_int("pm_case_sensitive")); } gtk_builder_connect_signals(prefbuilder, NULL); g_object_unref(prefbuilder); return notebook; }
/** * Sort the given list of tracks based on the clarity_sort preference */ GList *_sort_track_list(GList *tracks) { enum GtkPodSortTypes value = prefs_get_int("clarity_sort"); switch(value) { case SORT_ASCENDING: tracks = g_list_sort(tracks, (GCompareFunc) compare_tracks); break; case SORT_DESCENDING: tracks = g_list_sort(tracks, (GCompareFunc) compare_tracks); tracks = g_list_reverse(tracks); break; default: // Do Nothing break; } return tracks; }
static gboolean alsa_loadsettings (void *dp, prefs_node *f) { alsa_driver * const d = dp; prefs_get_int(f, "alsa-resolution", &d->p_resolution); prefs_get_int(f, "alsa-channels", &d->p_channels); prefs_get_int(f, "alsa-mixfreq", &d->p_mixfreq); prefs_get_int(f, "alsa-fragsize", &d->p_fragsize); prefs_get_int(f, "alsa-card", &d->card_number); prefs_get_int(f, "alsa-device", &d->device_number); prefs_init_from_structure(d); return TRUE; }
static gboolean alsa_loadsettings (void *dp, prefs_node *f) { alsa_driver * const d = dp; guint i; gchar buf[32]; //!!! Port all preferences to gchar, gint, etc... if(prefs_get_string(f, "alsa1x-device", buf)) { g_free(d->device); d->device = g_strdup(buf); } prefs_get_int(f, "alsa1x-resolution", &d->bits); prefs_get_int(f, "alsa1x-stereo", &d->stereo); prefs_get_int(f, "alsa1x-playrate", &d->playrate); prefs_get_int(f, "alsa1x-buffer_size", &d->buffer_size); prefs_get_int(f, "alsa1x-num_periods", &d->num_periods); prefs_get_int(f, "alsa1x-can_8", &d->can8); prefs_get_int(f, "alsa1x-can_16", &d->can16); prefs_get_int(f, "alsa1x-can_mono", &d->canmono); prefs_get_int(f, "alsa1x-can_stereo", &d->canstereo); prefs_get_int(f, "alsa1x-signedness_8", &d->signedness8); prefs_get_int(f, "alsa1x-signedness_16", &d->signedness16); prefs_get_int(f, "alsa1x-period_size_min", (int *)&d->persizemin); prefs_get_int(f, "alsa1x-period_size_max", (int *)&d->persizemax); for(i = 0; i < NUM_FORMATS; i++) { g_sprintf(buf, "alsa1x-devcap[%u].minfreq", i); prefs_get_int(f, buf, &d->devcap[i].minfreq); g_sprintf(buf, "alsa1x-devcap[%u].maxfreq", i); prefs_get_int(f, buf, &d->devcap[i].maxfreq); g_sprintf(buf, "alsa1x-devcap[%u].minbufsize", i); prefs_get_int(f, buf, (int *)&d->devcap[i].minbufsize); g_sprintf(buf, "alsa1x-devcap[%u].maxbufsize", i); prefs_get_int(f, buf, (int *)&d->devcap[i].maxbufsize); } prefs_get_int(f, "alsa1x-verbose", (int *)&d->verbose); prefs_get_str_array(f, "alsa1x-device-list", load_dev_func, d); gtk_combo_box_set_active(GTK_COMBO_BOX(d->alsa_device), 0); prefs_init_from_structure(d); return TRUE; }
void gtkpod_init(int argc, char *argv[]) { AnjutaPluginManager *plugin_manager; AnjutaProfileManager *profile_manager; AnjutaApp *app; AnjutaStatus *status; AnjutaProfile *profile; GFile *session_profile; GError *error = NULL; gchar *default_profile_file = NULL; gchar *user_profile_file = NULL; gchar *ui_file = NULL; gchar *remembered_plugins = NULL; gchar *session_dir = NULL; gchar *splash = NULL; /* Initialise important directories */ init_directories(argv); register_stock_icon(GTKPOD_ICON, GTKPOD_ICON_STOCK_ID); /* Initialise the ui file */ ui_file = g_build_filename(get_ui_dir(), "gtkpod.ui", NULL); anjuta_set_ui_file_path(ui_file); /* Register the application icon */ register_stock_icon("gtkpod", GTKPOD_APP_ICON_STOCK_ID); /* Initialize application class instance*/ app = ANJUTA_APP(anjuta_app_new()); gtkpod_app = GTKPOD_APP(app); /* Initialise the preferences as required for the display of the splash screen */ prefs_init(argc, argv); /* Show some progress as the app is initialised */ status = anjuta_shell_get_status(ANJUTA_SHELL(app), NULL); anjuta_status_progress_add_ticks(status, 1); /* Show the splash screen if user requires */ if (! prefs_get_int(DISABLE_SPLASH_SCREEN)) { splash = g_build_filename(get_icon_dir(), "gtkpod-splash.png", NULL); if (g_file_test(splash, G_FILE_TEST_IS_REGULAR)) anjuta_status_set_splash(status, splash, 100); else { anjuta_status_disable_splash(status, TRUE); } g_free(splash); } /* * initialise gtkpod library items. Needs to be safety threaded due * to splash screen. */ gdk_threads_enter(); gp_init(argc, argv); gdk_threads_leave(); /* Add blocking widgets from the framework */ add_blocked_widget(app->toolbar); add_blocked_widget(app->view_menu); /* Set up shutdown signals */ g_signal_connect(G_OBJECT(app), "delete_event", G_CALLBACK( on_gtkpod_delete_event), NULL); g_signal_connect(G_OBJECT(app), "destroy", G_CALLBACK(on_gtkpod_destroy), NULL); plugin_manager = anjuta_shell_get_plugin_manager(ANJUTA_SHELL(app), NULL); profile_manager = anjuta_shell_get_profile_manager(ANJUTA_SHELL(app), NULL); /* Restore remembered plugins */ remembered_plugins = g_settings_get_string(app->settings, GTKPOD_REMEMBERED_PLUGINS); if (remembered_plugins) anjuta_plugin_manager_set_remembered_plugins(plugin_manager, remembered_plugins); g_free(remembered_plugins); /* Load default profile */ default_profile_file = get_default_profile_path(); profile = anjuta_profile_new(USER_PROFILE_NAME, plugin_manager); session_profile = g_file_new_for_path(default_profile_file); anjuta_profile_add_plugins_from_xml(profile, session_profile, TRUE, &error); if (error) { anjuta_util_dialog_error(GTK_WINDOW(app), "%s", error->message); g_error_free(error); error = NULL; } g_object_unref(session_profile); g_free(default_profile_file); /* Load user session profile */ user_profile_file = get_user_profile_path(); session_profile = g_file_new_for_path(user_profile_file); if (g_file_query_exists(session_profile, NULL)) { anjuta_profile_add_plugins_from_xml(profile, session_profile, FALSE, &error); if (error) { anjuta_util_dialog_error(GTK_WINDOW(app), "%s", error->message); g_error_free(error); error = NULL; } } anjuta_profile_set_sync_file(profile, session_profile); g_object_unref(session_profile); g_free(user_profile_file); /* Load profile */ anjuta_profile_manager_freeze(profile_manager); anjuta_profile_manager_push(profile_manager, profile, &error); if (error) { anjuta_util_dialog_error(GTK_WINDOW(app), "%s", error->message); g_error_free(error); error = NULL; } /* Prepare for session save and load on profile change */ g_signal_connect (profile_manager, "profile-scoped", G_CALLBACK (on_profile_scoped), app); anjuta_profile_manager_thaw(profile_manager, &error); if (error) { anjuta_util_dialog_error(GTK_WINDOW(app), "%s", error->message); g_error_free(error); error = NULL; } g_signal_connect (profile_manager, "profile-descoped", G_CALLBACK (on_profile_descoped), app); gdk_threads_enter(); gp_init_itdbs(); gdk_threads_leave(); /* Load layout.*/ session_dir = get_user_session_dir(); if (!g_file_test(session_dir, G_FILE_TEST_IS_DIR)) session_dir = g_strdup(get_data_dir()); /* Restore session */ anjuta_shell_session_load(ANJUTA_SHELL(app), session_dir, NULL); g_free(session_dir); anjuta_status_progress_tick(status, NULL, _("Loaded Session...")); anjuta_status_disable_splash(status, TRUE); gtk_window_set_default_icon_name("gtkpod"); gtk_window_set_auto_startup_notification(TRUE); gtk_window_set_role(GTK_WINDOW(app), "gtkpod-app"); gtk_widget_show(GTK_WIDGET(app)); }
/* Updates mserv data (rating only) of @track using filename @name to look up mserv information. Return TRUE if successfully updated (or disabled), FALSE if not */ gboolean update_mserv_data_from_file(gchar *name, Track *track) { gboolean success = TRUE; if (!name || !track) return FALSE; if (g_file_test(name, G_FILE_TEST_IS_DIR)) return FALSE; if (!g_file_test(name, G_FILE_TEST_EXISTS)) { gchar *buf = g_strdup_printf(_("Local filename not valid (%s)"), name); display_mserv_problems(track, buf); g_free(buf); return FALSE; } if (prefs_get_int("mserv_use")) { /* try getting the user's rating from the mserv db */ gchar *music_root = prefs_get_string("path_mserv_music_root"); gchar *trackinfo_root = prefs_get_string("path_mserv_trackinfo_root"); /* we expect music_root and trackinfo_root to be initialized */ if (!music_root) music_root = g_strdup(""); if (!trackinfo_root) trackinfo_root = g_strdup(""); success = FALSE; /* printf("mroot %s troot %s fname %s\n", music_root, trackinfo_root, name); */ /* first, check if the file is in the mserv music directory */ if (*music_root == 0 || strstr(name, music_root)) { gchar *infoname = g_strdup_printf("%s%c%s.trk", trackinfo_root, G_DIR_SEPARATOR, &(name[strlen(music_root)])); /* printf("trying %s\n", infoname); */ FILE *fp = fopen(infoname, "r"); if (fp) { /* printf("opened\n");*/ gchar buff[PATH_MAX]; gchar *username = prefs_get_string("mserv_username"); guint usernamelen; g_return_val_if_fail (username, (fclose (fp), FALSE)); usernamelen = strlen(username); while (fgets(buff, PATH_MAX, fp)) { /* printf("username %s (%d) read %s\n", * prefs_get_string("mserv_username"), usernamelen, * buff);*/ if (strncmp(buff, username, usernamelen) == 0 && buff[usernamelen] == (gchar) '=') { /* found it */ track->rating = atoi(&buff[usernamelen + 1]) * ITDB_RATING_STEP; /* printf("found it, = %d\n", orig_track->rating/ITDB_RATING_STEP); */ success = TRUE; break; /* while(fgets(... */ } } fclose(fp); g_free(username); if (!success) { gchar *username = prefs_get_string("mserv_username"); gchar *buf = g_strdup_printf(_("No information found for user '%s' in '%s'"), username, infoname); display_mserv_problems(track, buf); g_free(buf); g_free(username); } } else { gchar *buf = g_strdup_printf(_("mserv data file (%s) not available for track (%s)"), infoname, name); display_mserv_problems(track, buf); g_free(buf); } g_free(infoname); } else { gchar *buf = g_strdup_printf(_("Track (%s) not in mserv music root directory (%s)"), name, music_root); display_mserv_problems(track, buf); g_free(buf); } g_free(music_root); g_free(trackinfo_root); } while (widgets_blocked && gtk_events_pending()) gtk_main_iteration(); return success; }
int main(int argc, char **argv) { const char *device_param = default_pcm_device; char *prefsdir; char thefile[1024]; char str[1024]; float start_vol = 1.0; int ap_result = 0; int use_fragsize = -1; // Initialized int use_fragcount = -1; // later int do_loopsong = 0; int do_looplist = 0; int do_enqueue = 0; int do_replace = 0; int do_realtime = 0; int do_remote_control = 0; int do_shuffle = 0; int do_start = 0; int do_stop = 0; int do_prev = 0; int do_next = 0; int do_pause = 0; int do_jump = -1; int do_clear = 0; int do_seek = -1; int do_relative = 0; int do_setvol = 0; int do_quit = 0; int do_status = 0; int do_speed = 0; float speed_val = 0.0; int do_onebyone = 0; int use_freq = OUTPUT_RATE; float use_vol = 1.0; int use_session = 0; int do_crossfade = 0; int do_save = 1; int bool_val = 0; const char *use_output = NULL; char *use_interface = NULL; char *use_config = NULL; char *use_loopsong = NULL; char *use_onebyone = NULL; char *use_looplist = NULL; int opt; int option_index; const char *options = "Cc:d:eEf:F:g:hi:J:I:l:n:NMp:qrs:vRSQVxo:"; struct option long_options[] = { /* { "long_option", take_argument, 0, 'short_option' }, */ { "config", 1, 0, 'c' }, { "device", 1, 0, 'd' }, { "enqueue", 0, 0, 'e' }, { "replace", 0, 0, 'E' }, { "fragsize", 1, 0, 'f' }, { "frequency", 1, 0, 'F' }, { "fragcount", 1, 0, 'g' }, { "help", 0, 0, 'h' }, { "interface", 1, 0, 'i' }, { "volume", 1, 0, 'Y' }, { "session", 1, 0, 'n' }, { "nosave", 0, 0, 'N' }, { "path", 1, 0, 'p' }, { "quiet", 0, 0, 'q' }, { "realtime", 0, 0, 'r' }, { "script", 1, 0, 'I'}, { "session-name", 1, 0, 's' }, { "version", 0, 0, 'v' }, { "verbose", 0, 0, 'V' }, { "reverb", 0, 0, 'R' }, { "loopsong", 1, 0, 'L' }, { "looplist", 1, 0, 'P' }, { "crossfade", 0, 0, 'x' }, { "output", 1, 0, 'o' }, { "stop", 0, 0, 'U' }, { "pause", 0, 0, 'O' }, { "start", 0, 0, 'T' }, { "shuffle", 0, 0, 'S' }, { "prev", 0, 0, 'Q' }, { "next", 0, 0, 'M' }, { "jump", 1, 0, 'J' }, { "seek", 1, 0, 'X' }, { "relative", 1, 0, 'Z' }, { "speed", 1, 0, 'H' }, { "clear", 0, 0, 'C' }, { "startvolume", 1, 0, 'l' }, { "quit", 0, 0, 'A' }, { "status", 0, 0, 'B' }, { "onebyone", 1, 0, 't' }, // Options that we want to be able to pass on to gtk_init(). See man // gtk-options(7). // Give all of these an option number of 128 because we're going to // ignore them option switch statement anyway. { "gtk-module", 1, 0, 128 }, { "gtk-debug", 1, 0, 128 }, { "gtk-no-debug", 1, 0, 128 }, { "g-fatal-warnings", 0, 0, 128 }, { "display", 1, 0, 128 }, { "screen", 1, 0, 128 }, { "sync", 0, 0, 128 }, { "no-xshm", 0, 0, 128 }, { "name", 1, 0, 128 }, { "class", 1, 0, 128 }, { "gxid_host", 1, 0, 128 }, { "gxid_port", 1, 0, 128 }, { "xim-preedit", 0, 0, 128 }, { "xim-status", 0, 0, 128 }, { "gdk-debug", 1, 0, 128 }, { "gdk-no-debug", 1, 0, 128 }, // End of list marker. { 0, 0, 0, 0 } }; // First setup signal handler signal(SIGPIPE, nonfatal_sighandler); // PIPE (socket control) signal(SIGTERM, exit_sighandler); // kill signal(SIGHUP, exit_sighandler); // kill -HUP / xterm closed signal(SIGINT, exit_sighandler); // Interrupt from keyboard signal(SIGQUIT, exit_sighandler); // Quit from keyboard // fatal errors signal(SIGBUS, exit_sighandler); // bus error //signal(SIGSEGV, exit_sighandler); // segfault signal(SIGILL, exit_sighandler); // illegal instruction signal(SIGFPE, exit_sighandler); // floating point exc. signal(SIGABRT, exit_sighandler); // abort() // Enable locale support #ifdef ENABLE_NLS setlocale (LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); bind_textdomain_codeset (PACKAGE, "UTF-8"); #endif // Init global mutexes pthread_mutex_init(&playlist_sort_seq_mutex, NULL); #if !defined(EMBEDDED) init_effects(); #endif while ((opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { switch(opt) { case 'A': do_remote_control = 1; do_quit = 1; break; case 'B': do_remote_control = 1; do_status = 1; break; case 'c': if (strlen(optarg) < 1023) { use_config = optarg; } else { alsaplayer_error("config file path too long"); return 1; } break; case 'd': device_param = optarg; break; case 'E': do_replace = 1; case 'e': do_enqueue = 1; break; case 'f': use_fragsize = atoi(optarg); if (!use_fragsize) { alsaplayer_error("invalid fragment size"); return 1; } if (use_fragsize > 32768) { alsaplayer_error("fragment size (%d) out of range (0-32768)", use_fragsize); return 1; } break; case 'F': use_freq = atoi(optarg); if (use_freq < 8000 || use_freq > 48000) { alsaplayer_error("frequency (%d) out of range (8000-48000)", use_freq); return 1; } break; case 'g': use_fragcount = atoi(optarg); if (use_fragcount < 2 || use_fragcount > 128) { alsaplayer_error("fragcount (%d) out of range (2-128)", use_fragcount); return 1; } break; case 'h': help(); return 0; case 'H': if ((sscanf(optarg, "%f", &speed_val))) { do_remote_control = 1; do_speed = 1; } break; case 'i': use_interface = optarg; break; case 'l': start_vol = atof(optarg); if (start_vol < 0.0 || start_vol > 1.0) { alsaplayer_error("volume (%.3f) out of range: using 1.0", start_vol); start_vol = 1.0; } break; case 'L': do_remote_control = 1; do_loopsong = 1; use_loopsong = optarg; break; case 'Y': do_remote_control = 1; do_setvol = 1; use_vol = atof(optarg); if (use_vol < 0.0 || use_vol > 1.0) { alsaplayer_error("volume (%.3f) out of range: using 1.0", use_vol); use_vol = 1.0; } break; case 'n': use_session = atoi(optarg); break; case 'N': do_save = 0; break; case 'O': do_remote_control = 1; do_pause = 1; break; case 'p': global_pluginroot = optarg; break; case 'q': global_quiet = 1; break; case 'r': do_realtime = 1; break; case 's': if (strlen(optarg) < 32) { global_session_name = strdup(optarg); } else { alsaplayer_error("max 32 char session name, ignoring"); } break; case 'v': version(); return 0; case 'V': global_verbose = 1; break; case 'R': break; case 'P': do_remote_control = 1; do_looplist = 1; use_looplist = optarg; break; case 'x': do_crossfade = 1; break; case 'o': use_output = optarg; break; case '?': return 1; case 'I': global_interface_script = optarg; break; case 'U': do_remote_control = 1; do_stop = 1; break; case 'T': do_remote_control = 1; do_start = 1; break; case 'S': do_remote_control = 1; do_shuffle = 1; break; case 'Q': do_remote_control = 1; do_prev = 1; break; case 'M': do_remote_control = 1; do_next = 1; break; case 'J': do_remote_control = 1; do_jump = atoi(optarg); break; case 'C': do_remote_control = 1; do_clear = 1; break; case 'X': do_remote_control = 1; do_seek = atoi(optarg); break; case 'Z': do_remote_control = 1; do_relative = 1; do_seek = atoi(optarg); break; case 't': do_remote_control = 1; do_onebyone = 1; use_onebyone = optarg; break; case 128: // Gtk-option which we ignore. break; default: alsaplayer_error("Unknown option '%c'", opt); break; } } prefsdir = get_prefsdir(); mkdir(prefsdir, 0700); /* XXX We don't do any error checking here */ snprintf(thefile, sizeof(thefile)-21, "%s/config", prefsdir); if (use_config) ap_prefs = prefs_load(use_config); else ap_prefs = prefs_load(thefile); if (!ap_prefs) { alsaplayer_error("Invalid config file %s\n", use_config ? use_config : thefile); return 1; } /* Initialize some settings (and populate the prefs system if needed */ if (use_fragsize < 0) use_fragsize = prefs_get_int(ap_prefs, "main", "period_size", 4096); if (use_fragcount < 0) use_fragcount = prefs_get_int(ap_prefs, "main", "period_count", 8); if (global_verbose) puts(copyright_string); if (!global_pluginroot) { global_pluginroot = strdup (ADDON_DIR); } if (use_session == 0) { for (; use_session < MAX_REMOTE_SESSIONS+1; use_session++) { ap_result = ap_session_running(use_session); if (ap_result) break; } if (use_session == (MAX_REMOTE_SESSIONS+1)) { //alsaplayer_error("No remote session found"); if (do_remote_control) { alsaplayer_error("No active sessions"); return 1; } do_enqueue = 0; } else { //alsaplayer_error("Found session %d", use_session); if (prefs_get_bool(ap_prefs, "main", "multiopen", 1) == 0) { // We should not spawn another alsaplayer //alsaplayer_error("Using session %d, not doing multiopen", use_session); do_enqueue = 1; do_replace = 1; } } } // Check if we're in remote control mode if (do_remote_control) { if (do_quit) { ap_quit(use_session); return 0; } else if (do_status) { char res[1024]; float fres; int ires; fprintf(stdout, "---------------- Session ----------------\n"); if (ap_get_session_name(use_session, res) && strlen(res)) fprintf(stdout, "name: %s\n", res); if (ap_get_playlist_length(use_session, &ires)) fprintf(stdout, "playlist_length: %d\n", ires); if (ap_get_volume(use_session, &fres)) fprintf(stdout, "volume: %.2f\n", fres); if (ap_get_speed(use_session, &fres)) fprintf(stdout, "speed: %d%%\n", (int)(fres * 100)); fprintf(stdout, "-------------- Current Track ------------\n"); if (ap_get_artist(use_session, res) && strlen(res)) fprintf(stdout, "artist: %s\n", res); if (ap_get_title(use_session, res) && strlen(res)) fprintf(stdout, "title: %s\n", res); if (ap_get_album(use_session, res) && strlen(res)) fprintf(stdout, "album: %s\n", res); if (ap_get_genre(use_session, res) && strlen(res)) fprintf(stdout, "genre: %s\n", res); if (ap_get_file_path(use_session, res) && strlen(res)) fprintf(stdout, "path: %s\n", res); if (ap_get_blocks(use_session, &ires)) fprintf(stdout, "blocks: %d\n", ires); if (ap_get_length(use_session, &ires)) fprintf(stdout, "length: %d second%s\n", ires, (ires == 1) ? "": "s"); if (ap_get_position(use_session, &ires)) fprintf(stdout, "position: %d\n", ires); fprintf(stdout, "-----------------------------------------\n"); return 0; } else if (do_setvol) { ap_set_volume(use_session, use_vol); return 0; } else if (do_shuffle) { ap_shuffle_playlist(use_session); return 0; } else if (do_start) { ap_play(use_session); return 0; } else if (do_stop) { ap_stop(use_session); return 0; } else if (do_pause) { if (ap_is_paused(use_session, &bool_val)) { if (bool_val) ap_unpause(use_session); else ap_pause(use_session); } return 0; } else if (do_next) { ap_next(use_session); return 0; } else if (do_prev) { ap_prev(use_session); return 0; } else if (do_jump >= 0) { ap_jump_to(use_session, do_jump); return 0; } else if (do_clear) { ap_clear_playlist(use_session); return 0; } else if (do_relative) { if (do_seek != 0) ap_set_position_relative(use_session, do_seek); return 0; } else if (do_speed) { if (speed_val < -10.0 || speed_val > 10.0) { alsaplayer_error("Speed out of range, must be between -10.00 and 10.00"); return 1; } ap_set_speed(use_session, speed_val); return 0; } else if (do_seek >= 0) { ap_set_position(use_session, do_seek); return 0; } else if (do_loopsong) { if (strcasecmp(use_loopsong, "on") != 0) { do_loopsong = false; } ap_set_looping(use_session, do_loopsong); return 0; } else if (do_onebyone) { if (strcasecmp(use_onebyone, "on") != 0) { do_onebyone = false; } ap_set_onebyone(use_session, do_onebyone); return 0; } else if (do_looplist) { if (strcasecmp(use_looplist, "on") != 0) { do_looplist = false; } ap_set_playlist_looping(use_session, do_looplist); return 0; } else alsaplayer_error("No remote control command executed."); } // Check if we need to enqueue the files if (do_enqueue) { char queue_name[2048]; int count = 0; int was_playing = 0; int playlist_length = 0; count = optind; ap_result = 1; if (do_replace && count < argc) { ap_is_playing(use_session, &was_playing); if (was_playing) { ap_stop(use_session); } ap_clear_playlist(use_session); } else { ap_get_playlist_length(use_session, &playlist_length); if (!playlist_length) { // Empty list so fire up after add was_playing = 1; } } while (count < argc && ap_result) { if (is_playlist(argv[count])) { ap_add_playlist(use_session, argv[count]); count++; continue; } if (argv[count][0] != '/' && strncmp(argv[count], "http://", 7) != 0 && strncmp(argv[count], "ftp://", 6) != 0) { // Not absolute so append cwd if (getcwd(queue_name, 1024) == NULL) { alsaplayer_error("error getting cwd"); return 1; } ap_strlcat(queue_name, "/", sizeof(queue_name)); ap_strlcat(queue_name, argv[count], sizeof(queue_name)); } else ap_strlcpy(queue_name, argv[count], sizeof(queue_name)); count++; //alsaplayer_error("Adding %s", queue_name); ap_result = ap_add_path(use_session, queue_name); //alsaplayer_error("ap_result = %d", ap_result); } if (was_playing) ap_jump_to(use_session, 1); if (ap_result) return 0; } AlsaNode *node; // Check if we want jack if (strcmp(argv[0], "jackplayer") == 0) { use_output = "jack"; } // Check the output option if (use_output == NULL) { use_output = prefs_get_string(ap_prefs, "main", "default_output", "alsa"); } // Else do the usual plugin based thing node = new AlsaNode(use_output, device_param, do_realtime); if (!node->RegisterPlugin(use_output)) { alsaplayer_error("Failed to load output plugin \"%s\". Trying defaults.", use_output); if (!node->RegisterPlugin()) return 1; } int output_is_ok = 0; int output_alternate = 0; do { if (!node || !node->ReadyToRun()) { alsaplayer_error ("failed to load output plugin (%s). exitting...", use_output ? use_output: "alsa,etc."); return 1; } if (!node->SetSamplingRate(use_freq) || !node->SetStreamBuffers(use_fragsize, use_fragcount, 2)) { alsaplayer_error ("failed to configure output device...trying OSS"); /* Special case for OSS, since it's easiest to get going, so try it */ if (!output_alternate) { output_alternate = 1; node->RegisterPlugin("oss"); continue; } else { return 1; } } output_is_ok = 1; /* output device initialized */ } while (!output_is_ok); // Initialise reader reader_init (); // Initialise playlist - must be done before things try to register with it playlist = new Playlist(node); if (!prefs_get_bool(ap_prefs, "main", "play_on_start", false)) playlist->Pause(); else playlist->UnPause(); if (!playlist) { alsaplayer_error("Failed to create Playlist object"); return 1; } // Add any command line arguments to the playlist if (optind < argc) { std::vector < std::string > newitems; while (optind < argc) { if (is_playlist(argv[optind])) { if (global_verbose) alsaplayer_error("Loading playlist (%s)", argv[optind]); playlist->Load(std::string(argv[optind++]), playlist->Length(), false); } else { newitems.push_back(std::string(argv[optind++])); } } playlist->Insert(newitems, playlist->Length()); } else { prefsdir = get_prefsdir(); snprintf(thefile, sizeof(thefile)-28, "%s/alsaplayer.m3u", prefsdir); playlist->Load(thefile, playlist->Length(), false); } // Loop song if (do_loopsong) { playlist->LoopSong(); } // Loop Playlist if (do_looplist) { playlist->LoopPlaylist(); } // Play songs one by one if (do_onebyone) { playlist->SetOneByOne(); } // Cross fading if (do_crossfade) { playlist->Crossfade(); } // Set start volume playlist->GetCorePlayer()->SetVolume(start_vol); interface_plugin_info_type interface_plugin_info; interface_plugin *ui; if (get_interface_from_argv0 (argv[0], str)) use_interface = str; if (use_interface && *use_interface) { if (!(interface_plugin_info = load_interface(use_interface))) { alsaplayer_error("Failed to load interface %s\n", use_interface); goto _fatal_err; } } else { const char *interface = prefs_get_string (ap_prefs, "main", "default_interface", "gtk2"); // if we're trying to use the old gtk-1 interface, use gtk-2 instead if (strcmp (interface, "gtk") == 0) interface = "gtk2"; // if we're trying to use the gtk interface, but we have no // $DISPLAY, use the text interface instead if (strcmp (interface, "gtk2") == 0 && !getenv("DISPLAY")) interface = "text"; if (!(interface_plugin_info = load_interface(interface))) { if (!(interface_plugin_info = load_interface(prefs_get_string (ap_prefs, "main", "fallback_interface", "text")))) { alsaplayer_error("Failed to load text interface. This is bad (%s,%s,%s)", interface, interface, global_pluginroot); goto _fatal_err; } } } if (interface_plugin_info) { ui = interface_plugin_info(); if (global_verbose) printf("Interface plugin: %s\n", ui->name); if (!ui->init()) { alsaplayer_error("Failed to load interface plugin. Should fall back to text\n"); } else { control_socket_start(playlist, ui); ui->start(playlist, argc, argv); ui->close(); // Unfortunately gtk+ is a pig when it comes to // cleaning up its resources; it doesn't! // so we can never safely dlclose gtk+ based // user interfaces, bah! //dlclose(ui->handle); control_socket_stop(); } } // Save playlist before exit prefsdir = get_prefsdir(); snprintf(thefile, sizeof(thefile)-25, "%s/alsaplayer", prefsdir); playlist->Save(thefile, PL_FORMAT_M3U); // Save preferences if (ap_prefs && do_save) { if (prefs_save(ap_prefs) < 0) { alsaplayer_error("failed to save preferences."); } } _fatal_err: delete playlist; //delete p; delete node; if (global_session_name) free(global_session_name); return 0; }
gboolean wav_can_convert() { gchar *cmd = wav_get_conversion_cmd(); return cmd && cmd[0] && prefs_get_int("convert_wav"); }
/** * Using the given track, set the metadata of the target * file */ void AP_write_metadata(Track *track, const char *filePath, GError **error) { ExtraTrackData *etr; gchar *atom; gchar *value; g_return_if_fail(track); APar_ScanAtoms(filePath); if (metadata_style != ITUNES_STYLE) { gchar *fbuf = charset_to_utf8(filePath); gtkpod_log_error(error, g_strdup_printf(_("ERROR %s is not itunes style."), fbuf)); g_free(fbuf); return; } // Title set_limited_text_atom_value(TITLE, track->title); // Artist set_limited_text_atom_value(ARTIST, track->artist); // Album Artist set_limited_text_atom_value(ALBUM_ARTIST, track->albumartist); // Album set_limited_text_atom_value(ALBUM, track->album); // Genre APar_MetaData_atomGenre_Set(track->genre); // Track Number and Total atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, TRACK_NUM_AND_TOTAL, DATA); if (track->track_nr == 0) { APar_RemoveAtom(atom, VERSIONED_ATOM, 0); } else { gchar *track_info = g_strdup_printf("%d / %d", track->track_nr, track->tracks); short tracknumData_atom = APar_MetaData_atom_Init(atom, track_info, AtomFlags_Data_Binary); APar_Unified_atom_Put(tracknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16); APar_Unified_atom_Put(tracknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->track_nr, 16); APar_Unified_atom_Put(tracknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->tracks, 16); APar_Unified_atom_Put(tracknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16); g_free(track_info); } g_free(atom); // Disk Number and Total atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, DISK_NUM_AND_TOTAL, DATA); if (track->cd_nr == 0) { APar_RemoveAtom(atom, VERSIONED_ATOM, 0); } else { gchar *disk_info = g_strdup_printf("%d / %d", track->cd_nr, track->cds); short disknumData_atom = APar_MetaData_atom_Init(atom, disk_info, AtomFlags_Data_Binary); APar_Unified_atom_Put(disknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16); APar_Unified_atom_Put(disknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->cd_nr, 16); APar_Unified_atom_Put(disknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->cds, 16); g_free(disk_info); } g_free(atom); // Comment set_limited_text_atom_value(COMMENT, track->comment); // Year gchar *yr = NULL; if (track->year > 0) yr = g_strdup_printf("%d", track->year); set_limited_text_atom_value(YEAR, yr); if (yr) g_free(yr); // Lyrics etr = (ExtraTrackData *) track->userdata; if (etr) write_lyrics_internal(etr->lyrics, filePath, error); // Composer set_limited_text_atom_value(COMPOSER, track->composer); // Grouping set_limited_text_atom_value(GROUPING, track->grouping); // Description set_limited_text_atom_value(DESCRIPTION, track->description); // TV Network set_limited_text_atom_value(TV_NETWORK_NAME, track->tvnetwork); // TV Show Name set_limited_text_atom_value(TV_SHOW, track->tvshow); // TV Episode set_limited_text_atom_value(TV_EPISODE, track->tvepisode); // Compilation atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, COMPILATION, DATA); if (!track->compilation) { APar_RemoveAtom(atom, VERSIONED_ATOM, 0); } else { //compilation: [0, 0, 0, 0, boolean_value]; BUT that first uint32_t is already accounted for in APar_MetaData_atom_Init value = g_strdup_printf("%d", track->compilation); short compilationData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt); APar_Unified_atom_Put(compilationData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 1, 8); //a hard coded uint8_t of: 1 is compilation g_free(value); } g_free(atom); // Tempo / BPM atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, TEMPO, DATA); if (!track->BPM) { APar_RemoveAtom(atom, VERSIONED_ATOM, 0); } else { //bpm is [0, 0, 0, 0, 0, bpm_value]; BUT that first uint32_t is already accounted for in APar_MetaData_atom_Init value = g_strdup_printf("%d", track->BPM); short bpmData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt); APar_Unified_atom_Put(bpmData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->BPM, 16); g_free(value); } g_free(atom); // Media Type atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, MEDIA_TYPE, DATA); guint8 mediaTypeTag = mediaTypeToMediaTypeTag(track->mediatype); value = g_strdup_printf("%d", track->season_nr); short stikData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt); APar_Unified_atom_Put(stikData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, mediaTypeTag, 8); g_free(value); g_free(atom); // TV Season No. atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, TV_SEASON_NO, DATA); if (track->season_nr == 0) { APar_RemoveAtom(atom, VERSIONED_ATOM, 0); } else { value = g_strdup_printf("%d", track->season_nr); short tvseasonData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt); APar_Unified_atom_Put(tvseasonData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16); APar_Unified_atom_Put(tvseasonData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->season_nr, 16); g_free(value); } g_free(atom); // TV Episode No. atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, TV_EPISODE_NO, DATA); if (track->episode_nr == 0) { APar_RemoveAtom(atom, VERSIONED_ATOM, 0); } else { value = g_strdup_printf("%d", track->episode_nr); short tvepisodenumData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt); APar_Unified_atom_Put(tvepisodenumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16); APar_Unified_atom_Put(tvepisodenumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->episode_nr, 16); g_free(value); } g_free(atom); // Keywords set_limited_text_atom_value(KEYWORD, track->keywords); // Podcast Category set_limited_text_atom_value(CATEGORY, track->category); // Podcast URL atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, PODCAST_URL, DATA); if (!track->podcasturl || strlen(track->podcasturl) == 0) { APar_RemoveAtom(atom, VERSIONED_ATOM, 0); } else { short podcasturlData_atom = APar_MetaData_atom_Init(atom, track->podcasturl, AtomFlags_Data_Binary); APar_Unified_atom_Put(podcasturlData_atom, track->podcasturl, UTF8_iTunesStyle_Binary, 0, 0); } g_free(atom); // Gapless Playback atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, GAPLESS_FLAG, DATA); if (!track->gapless_track_flag) { APar_RemoveAtom(atom, VERSIONED_ATOM, 0); } else { value = g_strdup_printf("%d", track->gapless_track_flag); short gaplessData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt); APar_Unified_atom_Put(gaplessData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 1, 8); //a hard coded uint8_t of: 1 is gapl g_free(value); } g_free(atom); // Sort Title set_limited_text_atom_value(SORT_TITLE, track->sort_title); // Sort Artist set_limited_text_atom_value(SORT_ARTIST, track->sort_artist); // Sort Album Artist set_limited_text_atom_value(SORT_ALBUM_ARTIST, track->sort_albumartist); // Sort Composer set_limited_text_atom_value(SORT_COMPOSER, track->sort_composer); // Sort Album set_limited_text_atom_value(SORT_ALBUM, track->sort_album); // Sort TV Show set_limited_text_atom_value(SORT_TV_SHOW, track->sort_tvshow); if (prefs_get_int("coverart_apic")) { GdkPixbuf *pixbuf = (GdkPixbuf*) itdb_artwork_get_pixbuf(track->itdb->device, track->artwork, -1, -1); if (!pixbuf) { // Destroy any existing artwork if any APar_MetaData_atomArtwork_Set("REMOVE_ALL", NULL); } else { gchar *tmp_file = g_build_filename(g_get_tmp_dir(), "ttt.jpg", NULL); GError *pixbuf_err = NULL; gdk_pixbuf_save(pixbuf, tmp_file, "jpeg", &pixbuf_err, "quality", "100", NULL); if (!pixbuf_err) { APar_MetaData_atomArtwork_Set(tmp_file, NULL); g_remove(tmp_file); } else { gtkpod_log_error(error, g_strdup_printf(_("ERROR failed to change track file's artwork.") )); g_error_free(pixbuf_err); return; } g_free(tmp_file); g_object_unref(pixbuf); } } // after all the modifications are enacted on the tree in memory // then write out the changes APar_DetermineAtomLengths(); openSomeFile(filePath, true); APar_WriteFile(filePath, NULL, true); APar_FreeMemory(); }
/** * Open and scan the metadata of the m4a/mp4/... file * and populate the given track. */ void AP_read_metadata(const char *filePath, Track *track) { FILE *mp4File; Trackage *trackage; uint8_t track_cur; uint8_t txttrack_cur; gboolean audio_or_video_found = FALSE; gboolean has_quicktime_chaps = FALSE; uint32_t timescale = 0; APar_ScanAtoms(filePath, true); mp4File = openSomeFile(filePath, true); trackage = APar_ExtractDetails(mp4File, SHOW_TRACK_INFO); for (track_cur = 0; track_cur < trackage->total_tracks; ++track_cur) { TrackInfo *info = trackage->infos[track_cur]; if ((info->type_of_track & AUDIO_TRACK) || (info->type_of_track & VIDEO_TRACK) || (info->type_of_track & DRM_PROTECTED_TRACK)) { /* * the info->duration is in the track's timescale units so must be divided by that * value to get seconds, while track->tracklen in gtkpod is in ms */ float duration = ((float) info->duration / (float) info->parent->movie_info->timescale) * 1000; track->tracklen = (gint32) duration; track->bitrate = APar_calculate_bitrate(info); track->samplerate = info->media_sample_rate; audio_or_video_found = TRUE; break; } } for (txttrack_cur = 0; audio_or_video_found && txttrack_cur < trackage->total_tracks; ++txttrack_cur) { TrackInfo *txtinfo = trackage->infos[txttrack_cur]; char buf[128]; // search for chapter track if (!(txtinfo->type_of_track & TEXT_TRACK)) continue; // see if the AV track's chap refers to this text track // chap: 0: atom size 4: 'chap' 8,12,...,8+(N-1)*4: (0: referenced track ID) snprintf(buf, sizeof(buf), "moov.trak[%u].tref.chap", track_cur + 1); AtomicInfo* chapAtom = APar_FindAtom(buf, false, SIMPLE_ATOM, 0); if (!chapAtom) continue; int entry_count = (chapAtom->AtomicLength - 8) / 4; for (int i = 0; i < entry_count; ++i) { if (APar_read32(buf, mp4File, chapAtom->AtomicStart + 8 + i * 4) == txtinfo->track_id) { has_quicktime_chaps = TRUE; timescale = txtinfo->media_sample_rate; break; } } if (has_quicktime_chaps) break; } if (has_quicktime_chaps) { // found a chapter... now get the chapter data from the text track char buf[128]; // stts: 0: atom size 4: 'stts' 8: version 12: entry count 16,24,...,16+(N-1)*8: (0: frame count 4: duration) snprintf(buf, sizeof(buf), "moov.trak[%u].mdia.minf.stbl.stts", txttrack_cur + 1); AtomicInfo* sampleAtom = APar_FindAtom(buf, false, VERSIONED_ATOM, 0); // stsz: 0: atom size 4: 'stsz' 8: version 12: size of all (or 0) 16: entry count 20,24,...,20+(N-1)*4: (0: sample size) snprintf(buf, sizeof(buf), "moov.trak[%u].mdia.minf.stbl.stsz", txttrack_cur + 1); AtomicInfo* sampleSizeAtom = APar_FindAtom(buf, false, VERSIONED_ATOM, 0); // stco: 0: atom size 4: 'stco' 8: version 12: entry count 16,20,...,16+(N-1)*4: (0: sample byte offset) snprintf(buf, sizeof(buf), "moov.trak[%u].mdia.minf.stbl.stco", txttrack_cur + 1); AtomicInfo* sampleOffsetAtom = APar_FindAtom(buf, false, VERSIONED_ATOM, 0); // We must have a valid sampleAtom to know chapter times. If sampleSizeAtom or sampleOffsetAtom is invalid, // we can do without them (and instead create a default chapter name). if (sampleAtom && sampleAtom->AtomicLength >= 16) { Itdb_Chapterdata *chapterdata = itdb_chapterdata_new(); uint32_t stts_entry_count = APar_read32(buf, mp4File, sampleAtom->AtomicStart + 12); uint32_t stsz_entry_count = !sampleSizeAtom || sampleSizeAtom->AtomicLength < 20 ? 0 : APar_read32(buf, mp4File, sampleSizeAtom->AtomicStart + 16); uint32_t stco_entry_count = !sampleOffsetAtom || sampleOffsetAtom->AtomicLength < 16 ? 0 : APar_read32(buf, mp4File, sampleOffsetAtom->AtomicStart + 12); uint32_t stsz_all_size = !sampleSizeAtom || sampleSizeAtom->AtomicLength < 16 ? 0 : APar_read32(buf, mp4File, sampleSizeAtom->AtomicStart + 12); uint32_t start_time = 0; u_int32_t max_frame_size = stsz_all_size; // if stsz_all_size specified, use only that size for (int i = 0; !stsz_all_size && i < stsz_entry_count; ++i) { uint32_t chap_name_len = APar_read32(buf, mp4File, sampleSizeAtom->AtomicStart + 20 + i * 4); if (chap_name_len > max_frame_size) max_frame_size = chap_name_len; } max_frame_size += 1; // for trailing '\0' (unneeded?), and to make sure that malloc() gets passed at least 1 char * namebuf = (char *)malloc(max_frame_size * sizeof(char)); for (int i = 0; i < stts_entry_count; ++i) { gchar *title = NULL; uint32_t chap_name_len = stsz_all_size; uint32_t chap_offset = 0; if (stsz_all_size == 0 && i < stsz_entry_count) chap_name_len = APar_read32(buf, mp4File, sampleSizeAtom->AtomicStart + 20 + i * 4); if (i < stco_entry_count) chap_offset = APar_read32(buf, mp4File, sampleOffsetAtom->AtomicStart + 16 + i * 4); if (chap_offset != 0) APar_readX(namebuf, mp4File, chap_offset, chap_name_len); else // If the location of the chapter name is unknown, trigger default chapter naming chap_name_len = 0; if (chap_name_len > 2) { int titlelength = (namebuf[0] << 8) + namebuf[1]; // if the stsz atom and the title value disagree, use the smaller one for safety titlelength = (titlelength > chap_name_len) ? chap_name_len : titlelength; // If a title begins with 0xFFFE, it's a UTF-16 title if (titlelength >= 2 && namebuf[2] == 0xff && namebuf[3] == 0xfe) title = g_utf16_to_utf8((const gunichar2 *) &namebuf[4], titlelength - 2, NULL, NULL, NULL); else title = g_strndup(&namebuf[2], titlelength); } else { // chapter title couldn't be found; create our own titles (and some ipods don't display them anyway). // Translators: this string is used to create a chapter title when no chapter title could be found title = g_strdup_printf(_("Chapter %3d"), i); } if (!timescale) // assume 1000, also, don't divide by 0 timescale = 1000; double duration_ms = (double)start_time * 1000.0 / (double)timescale; itdb_chapterdata_add_chapter(chapterdata, duration_ms, title); g_free(title); if (i < (stts_entry_count - 1)) // skip this stage after the last chapter has been added { uint32_t frame_count = APar_read32(buf, mp4File, sampleAtom->AtomicStart + 16 + i * 8); uint32_t duration = APar_read32(buf, mp4File, sampleAtom->AtomicStart + 20 + i * 8); start_time += frame_count * duration; } } if (namebuf) free(namebuf); if (track->chapterdata) // if there was already chapter data, don't leak it itdb_chapterdata_free(track->chapterdata); track->chapterdata = itdb_chapterdata_duplicate(chapterdata); itdb_chapterdata_free(chapterdata); } } // TODO: add support for Nero-style mp4 chapters if (prefs_get_int("readtags")) { char* value = NULL; // MP4 Title value = find_atom_value(TITLE); if (value) { track->title = g_strdup(value); free(value); } // MP4 Artist value = find_atom_value(ARTIST); if (value) { track->artist = g_strdup(value); free(value); } // MP4 Album Artist value = find_atom_value(ALBUM_ARTIST); if (value) { track->albumartist = g_strdup(value); free(value); } // MP4 Composer value = find_atom_value(COMPOSER); if (value) { track->composer = g_strdup(value); free(value); } // MP4 Comment value = find_atom_value(COMMENT); if (value) { track->comment = g_strdup(value); free(value); } // MP4 Description value = find_atom_value(DESCRIPTION); if (value) { track->description = g_strdup(value); free(value); } // MP4 Keywords value = find_atom_value(KEYWORD); if (value) { track->keywords = g_strdup(value); free(value); } // MP4 Year value = find_atom_value(YEAR); if (value) { track->year = atoi(value); free(value); } // MP4 Album value = find_atom_value(ALBUM); if (value) { track->album = g_strdup(value); free(value); } // MP4 Track No. and Total value = find_atom_value(TRACK_NUM_AND_TOTAL); if (value) { const char* delimiter = " of "; char *result = NULL; result = strtok(value, delimiter); if (result) track->track_nr = atoi(result); result = strtok(NULL, delimiter); if (result) track->tracks = atoi(result); free(value); } // MP4 Disk No. and Total value = find_atom_value(DISK_NUM_AND_TOTAL); if (value) { const char* delimiter = " of "; char *result = NULL; result = strtok(value, delimiter); if (result) track->cd_nr = atoi(result); result = strtok(NULL, delimiter); if (result) track->cds = atoi(result); free(value); } // MP4 Grouping value = find_atom_value(GROUPING); if (value) { track->grouping = g_strdup(value); free(value); } // MP4 Genre - note: can be either a standard or custom genre // standard genre value = find_atom_value(STANDARD_GENRE); if (value) { track->genre = charset_to_utf8(value); // Should not free standard genres } else { // custom genre value = find_atom_value(CUSTOM_GENRE); if (value) { track->genre = g_strdup(value); free(value); } } // MP4 Tempo / BPM value = find_atom_value(TEMPO); if (value) { track->BPM = atoi(value); free(value); } // MP4 Lyrics value = find_atom_value(LYRICS); if (value) { track->lyrics_flag = 0x01; free(value); } // MP4 TV Show value = find_atom_value(TV_SHOW); if (value) { track->tvshow = g_strdup(value); free(value); } // MP4 TV Episode value = find_atom_value(TV_EPISODE); if (value) { track->tvepisode = g_strdup(value); free(value); } // MP4 TV Episode No. value = find_atom_value(TV_EPISODE_NO); if (value) { track->episode_nr = atoi(value); free(value); } // MP4 TV Network value = find_atom_value(TV_NETWORK_NAME); if (value) { track->tvnetwork = g_strdup(value); free(value); } // MP4 TV Season No. value = find_atom_value(TV_SEASON_NO); if (value) { track->season_nr = atoi(value); free(value); } // MP4 Media Type value = find_atom_value(MEDIA_TYPE); if (value) { stiks * stik = MatchStikString(value); if (stik) { track->mediatype = mediaTypeTagToMediaType(stik->stik_number); } // Should not free standard media types } // MP4 Compilation flag value = find_atom_value(COMPILATION); if (value) { track->compilation = !g_strcmp0("true", value); free(value); } // MP4 Category value = find_atom_value(CATEGORY); if (value) { track->category = g_strdup(value); free(value); } // MP4 Podcast URL value = find_atom_value(PODCAST_URL); if (value) { track->podcasturl = g_strdup(value); free(value); } value = find_atom_value(GAPLESS_FLAG); if (value) { track->gapless_track_flag = atoi(value); free(value); } // MP4 Sort Title value = find_atom_value(SORT_TITLE); if (value) { track->sort_title = g_strdup(value); free(value); } // MP4 Sort Artist value = find_atom_value(SORT_ARTIST); if (value) { track->sort_artist = g_strdup(value); free(value); } // MP4 Sort Album Artist value = find_atom_value(SORT_ALBUM_ARTIST); if (value) { track->sort_albumartist = g_strdup(value); free(value); } // MP4 Sort Composer value = find_atom_value(SORT_COMPOSER); if (value) { track->sort_composer = g_strdup(value); free(value); } // MP4 Sort Album value = find_atom_value(SORT_ALBUM); if (value) { track->sort_album = g_strdup(value); free(value); } // MP4 Sort TV Show value = find_atom_value(SORT_TV_SHOW); if (value) { track->sort_tvshow = g_strdup(value); free(value); } if (prefs_get_int("coverart_apic")) { gchar *tmp_file_prefix = g_build_filename(g_get_tmp_dir(), "ttt", NULL); gchar *tmp_file; AtomicInfo *info = find_atom("covr"); if (info) { // Extract the data to a temporary file tmp_file = APar_ExtractAAC_Artwork(info->AtomicNumber, tmp_file_prefix, 1); g_free(tmp_file_prefix); if (tmp_file && g_file_test(tmp_file, G_FILE_TEST_EXISTS)) { // Set the thumbnail using the tmp file GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(tmp_file, NULL); if (pixbuf) { itdb_track_set_thumbnails_from_pixbuf(track, pixbuf); g_object_unref(pixbuf); } g_remove(tmp_file); } if (tmp_file) g_free(tmp_file); } } } APar_FreeMemory(); }
static void * draw_thread_func(void * UNUSED (arg)) { Bool configured = FALSE; window_w = prefs_get_int(ap_prefs, "opengl_spectrum", "width", DEFAULT_W); window_h = prefs_get_int(ap_prefs, "opengl_spectrum", "height", DEFAULT_H); if ((window = create_window(window_w, window_h)) == 0) { alsaplayer_error("unable to create window"); pthread_exit(NULL); } XMapWindow(dpy, window); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1, 1, -1, 1, 1.5, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); while(going) { while(XPending(dpy)) { XEvent event; KeySym keysym; char buf[16]; XNextEvent(dpy, &event); switch(event.type) { case ConfigureNotify: glViewport(0,0,event.xconfigure.width, event.xconfigure.height); window_w = event.xconfigure.width; window_h = event.xconfigure.height; prefs_set_int(ap_prefs, "opengl_spectrum", "width", window_w); prefs_set_int(ap_prefs, "opengl_spectrum", "height", window_h); configured = TRUE; break; case KeyPress: XLookupString (&event.xkey, buf, 16, &keysym, NULL); switch(keysym) { case XK_Escape: going = FALSE; break; case XK_z: /*xmms_remote_playlist_prev(oglspectrum_vp.xmms_session); */ break; case XK_x: /*xmms_remote_play(oglspectrum_vp.xmms_session); */ break; case XK_c: /*xmms_remote_pause(oglspectrum_vp.xmms_session); */ break; case XK_v: /*xmms_remote_stop(oglspectrum_vp.xmms_session); */ break; case XK_b: /* xmms_remote_playlist_next(oglspectrum_vp.xmms_session); */ break; case XK_Up: x_speed -= 0.1; if(x_speed < -3.0) x_speed = -3.0; break; case XK_Down: x_speed += 0.1; if(x_speed > 3.0) x_speed = 3.0; break; case XK_Left: y_speed -= 0.1; if(y_speed < -3.0) y_speed = -3.0; break; case XK_Right: y_speed += 0.1; if(y_speed > 3.0) y_speed = 3.0; break; case XK_w: z_speed -= 0.1; if(z_speed < -3.0) z_speed = -3.0; break; case XK_q: z_speed += 0.1; if(z_speed > 3.0) z_speed = 3.0; break; case XK_Return: x_speed = 0.0; y_speed = 0.5; z_speed = 0.0; x_angle = 20.0; y_angle = 45.0; z_angle = 0.0; break; } break; case ClientMessage: if ((Atom)event.xclient.data.l[0] == wm_delete_window_atom) { going = FALSE; } break; } } if(configured) { x_angle += x_speed; if(x_angle >= 360.0) x_angle -= 360.0; y_angle += y_speed; if(y_angle >= 360.0) y_angle -= 360.0; z_angle += z_speed; if(z_angle >= 360.0) z_angle -= 360.0; draw_bars(); } } if (glxcontext) { glXMakeCurrent(dpy, 0, NULL); glXDestroyContext(dpy, glxcontext); glxcontext = NULL; } if (window) { if (grabbed_pointer) { XUngrabPointer(dpy, CurrentTime); grabbed_pointer = FALSE; } XDestroyWindow(dpy, window); window = 0; } pthread_mutex_unlock(&scope_mutex); stop_display(0); /* Close down display */ pthread_exit(NULL); }