Пример #1
0
static int oglspectrum_init(void * UNUSED (arg))
{
	pthread_mutex_init(&scope_mutex, NULL);

	if (prefs_get_bool(ap_prefs, "opengl_spectrum", "active", 0)) {
		oglspectrum_start();
	}
	return 1;
}
Пример #2
0
/* Init function */
static int init_fftscope()
{
	int i;

	memset(act_fft, 0, sizeof(act_fft));

	if (prefs_get_bool(ap_prefs, "fftscope", "active", 0))
		start_fftscope();
	
	return 1;
}
Пример #3
0
static int init_fftscope(void *arg)
{
	int i;
	
	for (i = 0; i < BARS; i++) {
		maxbar[ i ] = 0;
	}	
	
	if (prefs_get_bool(ap_prefs, "logbarfft", "active", 0))
		start_fftscope();
	
	return 1;
}
Пример #4
0
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;
}
Пример #5
0
static int mad_open(input_object *obj, const char *path)
{
	struct mad_local_data *data;
	char *p;
	int mode;

	if (!obj)
		return 0;

	obj->local_data = malloc(sizeof(struct mad_local_data));
	if (!obj->local_data) {
		puts("failed to allocate local data");
		return 0;
	}
	data = (struct mad_local_data *)obj->local_data;
	memset(data, 0, sizeof(struct mad_local_data));

	if ((data->mad_fd = reader_open(path, &reader_status, obj)) == NULL) {
		fprintf(stderr, "mad_open(obj, %s) failed\n", path);
		free(obj->local_data);
		obj->local_data = NULL;
		return 0;
	}
	obj->flags = 0;

	if (strncasecmp(path, "http://", 7) == 0) {
		obj->flags |= P_STREAMBASED;
		strcpy(data->sinfo.status, "Prebuffering");
	} else {
		obj->flags |= P_FILEBASED;
	}
	if (!reader_seekable(data->mad_fd)) {
		data->seekable = 0;
	} else {
		obj->flags |= P_SEEK;
		obj->flags |= P_PERFECTSEEK;
		data->seekable = 1;
	}
	obj->flags |= P_REENTRANT;

	mad_init_decoder(data);
	memset(&data->xing, 0, sizeof(struct xing));
	xing_init (&data->xing);
	data->mad_init = 1;
	fill_buffer(data, -1);
	//alsaplayer_error("initial bytes_avail = %d", data->bytes_avail);
	if (obj->flags & P_PERFECTSEEK) {
		data->offset = find_initial_frame(data->mad_map, 
				data->bytes_avail < STREAM_BUFFER_SIZE ? data->bytes_avail :
				STREAM_BUFFER_SIZE);
	} else {
		data->offset = 0;
	}	
	data->highest_frame = 0;
	if (data->offset < 0) {
		//fprintf(stderr, "mad_open() couldn't find valid MPEG header\n");
		data->offset = 0;
	}
	//alsaplayer_error("data->offset = %d", data->offset);
	if (data->offset > data->bytes_avail) {
		data->seekable = 1;
		//alsaplayer_error("Need to refill buffer (data->offset = %d)", data->offset);
		fill_buffer(data, 0);
		mad_stream_buffer(&data->stream, data->mad_map, data->bytes_avail);
	} else {
		mad_stream_buffer(&data->stream, data->mad_map + data->offset,
				data->bytes_avail - data->offset);
		data->bytes_avail -= data->offset;
	}	
first_frame:

	if ((mad_header_decode(&data->frame.header, &data->stream) == -1)) {
		switch (data->stream.error) {
			case MAD_ERROR_BUFLEN:
				return 0;
			case MAD_ERROR_LOSTSYNC:
			case MAD_ERROR_BADEMPHASIS:
			case MAD_ERROR_BADBITRATE:
			case MAD_ERROR_BADLAYER:	
			case MAD_ERROR_BADSAMPLERATE:	
				//alsaplayer_error("Error %x (frame %d)", data->stream.error, data->current_frame);
				data->bytes_avail-=(data->stream.next_frame - data->stream.this_frame);
				goto first_frame;
				break;
			case MAD_ERROR_BADBITALLOC:
				return 0;
			case MAD_ERROR_BADCRC:
				alsaplayer_error("MAD_ERROR_BADCRC: %s", error_str(data->stream.error, data->str));
			case MAD_ERROR_BADBIGVALUES:
			case MAD_ERROR_BADDATAPTR:
				break;
			default:
				alsaplayer_error("ERROR: %s", error_str(data->stream.error, data->str));
				alsaplayer_error("No valid frame found at start (pos: %d, error: 0x%x --> %x %x %x %x) (%s)", data->offset, data->stream.error, 
						data->stream.this_frame[0],
						data->stream.this_frame[1],
						data->stream.this_frame[2],
						data->stream.this_frame[3],path);
				return 0;
		}
	}

	mad_frame_decode(&data->frame, &data->stream);
	/*	
		alsaplayer_error("xing parsing...%x %x %x %x (%x %d)", 
		data->stream.this_frame[0], data->stream.this_frame[1],
		data->stream.this_frame[2], data->stream.this_frame[3],
		data->stream.anc_ptr, data->stream.anc_bitlen);
		*/		
	if (xing_parse(&data->xing, data->stream.anc_ptr, data->stream.anc_bitlen) == 0) {
		// We use the xing data later on
	}

	mode = (data->frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ?
		1 : 2;
	data->samplerate = data->frame.header.samplerate;
	data->bitrate	= data->frame.header.bitrate;
	mad_synth_frame (&data->synth, &data->frame);
	{
		struct mad_pcm *pcm = &data->synth.pcm;			

		obj->nr_channels = pcm->channels;
		//alsaplayer_error("nr_channels = %d", obj->nr_channels);
	}
	//alsaplayer_error("Initial: %d, %d, %d", data->samplerate, data->bitrate, obj->nr_channels);
	/* Calculate some values */
	data->bytes_avail = data->stream.bufend - data->stream.next_frame;
	{
		int64_t time;
		int64_t samples;
		int64_t frames;

		long oldpos = reader_tell(data->mad_fd);
		reader_seek(data->mad_fd, 0, SEEK_END);

		data->filesize = reader_tell(data->mad_fd);
		data->filesize -= data->offset;

		reader_seek(data->mad_fd, oldpos, SEEK_SET);
		if (data->bitrate)
			time = (data->filesize * 8) / (data->bitrate);
		else
			time = 0;

		samples = 32 * MAD_NSBSAMPLES(&data->frame.header);

		obj->frame_size = (int) samples << 2; /* Assume 16-bit stereo */
		frames = data->samplerate * (time+1) / samples;
		if (data->xing.flags & XING_FRAMES) {
			obj->nr_frames = data->xing.frames;
		} else {	
			obj->nr_frames = (int) frames;
		}	
		obj->nr_tracks = 1;
	}
	/* Determine if nr_frames makes sense */
	if (!(obj->flags & P_SEEK) && (obj->flags & P_STREAMBASED)) {
		obj->nr_frames = -1;
	}	

	/* Allocate frame index */
	if (!data->seekable  || obj->nr_frames > 1000000 ||
			(data->frames = (ssize_t *)malloc((obj->nr_frames + FRAME_RESERVE) * sizeof(ssize_t))) == NULL) {
		data->seekable = 0; // Given really
	}	else {
		data->seekable = 1;
		data->frames[0] = 0;
	}	
	data->mad_init = 1;

	p = strrchr(path, '/');
	if (p) {
		strcpy(data->filename, ++p);
	} else {
		strcpy(data->filename, path);
	}
	strcpy(data->path, path);

	data->parse_id3 = prefs_get_bool(ap_prefs, "mad", "parse_id3", 1);

	return 1;
}