Example #1
0
static gboolean tone_play(const gchar *filename, VFSFile *file)
{
    GArray *frequencies;
    gfloat data[BUF_SAMPLES];
    gsize i;
    gboolean error = FALSE;
    struct
    {
        gdouble wd;
        guint period, t;
    } *tone = NULL;

    frequencies = tone_filename_parse(filename);
    if (frequencies == NULL)
        return FALSE;

    if (aud_input_open_audio(FMT_FLOAT, OUTPUT_FREQ, 1) == 0)
    {
        error = TRUE;
        goto error_exit;
    }

    aud_input_set_bitrate(16 * OUTPUT_FREQ);

    tone = g_malloc(frequencies->len * sizeof(*tone));
    for (i = 0; i < frequencies->len; i++)
    {
        gdouble f = g_array_index(frequencies, gdouble, i);
        tone[i].wd = 2 * PI * f / OUTPUT_FREQ;
        tone[i].period = (G_MAXINT * 2U / OUTPUT_FREQ) * (OUTPUT_FREQ / f);
        tone[i].t = 0;
    }

    while (!aud_input_check_stop())
    {
        for (i = 0; i < BUF_SAMPLES; i++)
        {
            gsize j;
            double sum_sines;

            for (sum_sines = 0, j = 0; j < frequencies->len; j++)
            {
                sum_sines += sin(tone[j].wd * tone[j].t);
                if (tone[j].t > tone[j].period)
                    tone[j].t -= tone[j].period;
                tone[j].t++;
            }
            /* dithering can cause a little bit of clipping */
            data[i] = (sum_sines * 0.999 / (gdouble) frequencies->len);
        }

        aud_input_write_audio(data, BUF_BYTES);
    }

error_exit:
    g_array_free(frequencies, TRUE);
    g_free(tone);

    return !error;
}
Example #2
0
static bool_t psf2_play(const char * filename, VFSFile * file)
{
	void *buffer;
	int64_t size;
	PSFEngine eng;
	bool_t error = FALSE;

	const char * slash = strrchr (filename, '/');
	if (! slash)
		return FALSE;

	SNCOPY (dirbuf, filename, slash + 1 - filename);
	dirpath = dirbuf;

	vfs_file_get_contents (filename, & buffer, & size);

	eng = psf_probe(buffer);
	if (eng == ENG_NONE || eng == ENG_COUNT)
	{
		free(buffer);
		return FALSE;
	}

	f = &psf_functor_map[eng];
	if (f->start(buffer, size) != AO_SUCCESS)
	{
		free(buffer);
		return FALSE;
	}

	aud_input_open_audio(FMT_S16_NE, 44100, 2);

	aud_input_set_bitrate(44100*2*2*8);

	stop_flag = FALSE;

	f->execute();
	f->stop();

	f = NULL;
	dirpath = NULL;
	free(buffer);

	return ! error;
}
Example #3
0
static gboolean vorbis_play (const gchar * filename, VFSFile * file)
{
    if (file == NULL)
        return FALSE;

    vorbis_info *vi;
    OggVorbis_File vf;
    gint last_section = -1;
    ReplayGainInfo rg_info;
    gfloat pcmout[PCM_BUFSIZE*sizeof(float)], **pcm;
    gint bytes, channels, samplerate, br;
    gchar * title = NULL;

    memset(&vf, 0, sizeof(vf));

    gboolean error = FALSE;

    if (ov_open_callbacks (file, & vf, NULL, 0, vfs_is_streaming (file) ?
     vorbis_callbacks_stream : vorbis_callbacks) < 0)
    {
        error = TRUE;
        goto play_cleanup;
    }

    vi = ov_info(&vf, -1);

    if (vi->channels > 2)
        goto play_cleanup;

    br = vi->bitrate_nominal;
    channels = vi->channels;
    samplerate = vi->rate;

    aud_input_set_bitrate (br);

    if (!aud_input_open_audio(FMT_FLOAT, samplerate, channels)) {
        error = TRUE;
        goto play_cleanup;
    }

    vorbis_update_replaygain(&vf, &rg_info);
    aud_input_set_gain (& rg_info);

    /*
     * Note that chaining changes things here; A vorbis file may
     * be a mix of different channels, bitrates and sample rates.
     * You can fetch the information for any section of the file
     * using the ov_ interface.
     */

    while (! aud_input_check_stop ())
    {
        int seek_value = aud_input_check_seek();

        if (seek_value >= 0 && ov_time_seek (& vf, (double) seek_value / 1000) < 0)
        {
            fprintf (stderr, "vorbis: seek failed\n");
            error = TRUE;
            break;
        }

        gint current_section = last_section;
        bytes = ov_read_float(&vf, &pcm, PCM_FRAMES, &current_section);
        if (bytes == OV_HOLE)
            continue;

        if (bytes <= 0)
            break;

        bytes = vorbis_interleave_buffer (pcm, bytes, channels, pcmout);

        { /* try to detect when metadata has changed */
            vorbis_comment * comment = ov_comment (& vf, -1);
            const gchar * new_title = (comment == NULL) ? NULL :
             vorbis_comment_query (comment, "title", 0);

            if (new_title != NULL && (title == NULL || strcmp (title, new_title)))
            {
                g_free (title);
                title = g_strdup (new_title);

                aud_input_set_tuple (get_tuple_for_vorbisfile (& vf,
                 filename));
            }
        }

        if (current_section != last_section)
        {
            /*
             * The info struct is different in each section.  vf
             * holds them all for the given bitstream.  This
             * requests the current one
             */
            vi = ov_info(&vf, -1);

            if (vi->channels > 2)
                goto stop_processing;

            if (vi->rate != samplerate || vi->channels != channels)
            {
                samplerate = vi->rate;
                channels = vi->channels;

                if (!aud_input_open_audio(FMT_FLOAT, vi->rate, vi->channels)) {
                    error = TRUE;
                    goto stop_processing;
                }

                vorbis_update_replaygain(&vf, &rg_info);
                aud_input_set_gain (& rg_info); /* audio reopened */
            }
        }

        aud_input_write_audio (pcmout, bytes);

stop_processing:

        if (current_section != last_section)
        {
            aud_input_set_bitrate (br);
            last_section = current_section;
        }
    } /* main loop */

play_cleanup:

    ov_clear(&vf);
    g_free (title);
    return ! error;
}
Example #4
0
static bool_t metronom_play (const char * filename, VFSFile * file)
{
    metronom_t pmetronom;
    int16_t data[BUF_SAMPLES];
    int t = 0, tact, num;
    int datagoal = 0;
    int datamiddle = 0;
    int datacurrent = datamiddle;
    int datalast = datamiddle;
    int data_form[TACT_FORM_MAX];

    if (aud_input_open_audio(FMT_S16_NE, AUDIO_FREQ, 1) == 0)
        return FALSE;

    if (!metronom_get_cp(filename, &pmetronom, NULL))
    {
        fprintf (stderr, "Invalid metronom tact parameters in URI %s", filename);
        return FALSE;
    }

    aud_input_set_bitrate(sizeof(data[0]) * 8 * AUDIO_FREQ);

    tact = 60 * AUDIO_FREQ / pmetronom.bpm;

    /* prepare weighted amplitudes */
    for (num = 0; num < pmetronom.num; num++)
    {
        data_form[num] = MAX_AMPL * tact_form[pmetronom.id][num];
    }

    num = 0;
    while (!aud_input_check_stop())
    {
        int i;

        for (i = 0; i < BUF_SAMPLES; i++)
        {
            if (t == tact)
            {
                t = 0;
                datagoal = data_form[num];
            }
            else if (t == 10)
            {
                datagoal = -data_form[num];
            }
            else if (t == 25)
            {
                datagoal = data_form[num];
                /* circle through weighted amplitudes */
                num++;
                if (num >= pmetronom.num)
                    num = 0;
            }
            /* makes curve a little bit smoother  */
            data[i] = (datalast + datacurrent + datagoal) / 3;
            datalast = datacurrent;
            datacurrent = data[i];
            if (t > 35)
                datagoal = (datamiddle + 7 * datagoal) / 8;
            t++;
        }

        aud_input_write_audio(data, BUF_BYTES);
    }

    return TRUE;
}
Example #5
0
static gboolean vtx_play(const gchar * filename, VFSFile * file)
{
    gboolean eof = FALSE;
    void *stream;               /* pointer to current position in sound buffer */
    guchar regs[14];
    gint need;
    gint left;                   /* how many sound frames can play with current AY register frame */
    gint donow;
    gint rate;

    left = 0;
    rate = chans * (bits / 8);

    memset(&ay, 0, sizeof(ay));

    if (!ayemu_vtx_open(&vtx, filename))
    {
        g_print("libvtx: Error read vtx header from %s\n", filename);
        return FALSE;
    }
    else if (!ayemu_vtx_load_data(&vtx))
    {
        g_print("libvtx: Error read vtx data from %s\n", filename);
        return FALSE;
    }

    ayemu_init(&ay);
    ayemu_set_chip_type(&ay, vtx.hdr.chiptype, NULL);
    ayemu_set_chip_freq(&ay, vtx.hdr.chipFreq);
    ayemu_set_stereo(&ay, vtx.hdr.stereo, NULL);

    if (aud_input_open_audio(FMT_S16_NE, freq, chans) == 0)
    {
        g_print("libvtx: output audio error!\n");
        return FALSE;
    }

    aud_input_set_bitrate(14 * 50 * 8);

    while (!aud_input_check_stop() && !eof)
    {
        /* (time in sec) * 50 = offset in AY register data frames */
        int seek_value = aud_input_check_seek();
        if (seek_value >= 0)
            vtx.pos = seek_value / 20;

        /* fill sound buffer */
        stream = sndbuf;

        for (need = SNDBUFSIZE / rate; need > 0; need -= donow)
        {
            if (left > 0)
            {                   /* use current AY register frame */
                donow = (need > left) ? left : need;
                left -= donow;
                stream = ayemu_gen_sound(&ay, (char *)stream, donow * rate);
            }
            else
            {                   /* get next AY register frame */
                if (ayemu_vtx_get_next_frame(&vtx, (char *)regs) == 0)
                {
                    donow = need;
                    memset(stream, 0, donow * rate);
                    eof = TRUE;
                }
                else
                {
                    left = freq / vtx.hdr.playerFreq;
                    ayemu_set_regs(&ay, regs);
                    donow = 0;
                }
            }
        }

        aud_input_write_audio(sndbuf, SNDBUFSIZE);
    }

    ayemu_vtx_free(&vtx);

    return TRUE;
}
static gboolean ffaudio_play (const gchar * filename, VFSFile * file)
{
    AUDDBG ("Playing %s.\n", filename);
    if (! file)
        return FALSE;

    AVPacket pkt = {.data = NULL};
    gint errcount;
    gboolean codec_opened = FALSE;
    gint out_fmt;
    gboolean planar;
    gboolean seekable;
    gboolean error = FALSE;

    void *buf = NULL;
    gint bufsize = 0;

    AVFormatContext * ic = open_input_file (filename, file);
    if (! ic)
        return FALSE;

    CodecInfo cinfo;

    if (! find_codec (ic, & cinfo))
    {
        fprintf (stderr, "ffaudio: No codec found for %s.\n", filename);
        goto error_exit;
    }

    AUDDBG("got codec %s for stream index %d, opening\n", cinfo.codec->name, cinfo.stream_idx);

    if (avcodec_open2 (cinfo.context, cinfo.codec, NULL) < 0)
        goto error_exit;

    codec_opened = TRUE;

    switch (cinfo.context->sample_fmt)
    {
        case AV_SAMPLE_FMT_U8: out_fmt = FMT_U8; planar = FALSE; break;
        case AV_SAMPLE_FMT_S16: out_fmt = FMT_S16_NE; planar = FALSE; break;
        case AV_SAMPLE_FMT_S32: out_fmt = FMT_S32_NE; planar = FALSE; break;
        case AV_SAMPLE_FMT_FLT: out_fmt = FMT_FLOAT; planar = FALSE; break;

        case AV_SAMPLE_FMT_U8P: out_fmt = FMT_U8; planar = TRUE; break;
        case AV_SAMPLE_FMT_S16P: out_fmt = FMT_S16_NE; planar = TRUE; break;
        case AV_SAMPLE_FMT_S32P: out_fmt = FMT_S32_NE; planar = TRUE; break;
        case AV_SAMPLE_FMT_FLTP: out_fmt = FMT_FLOAT; planar = TRUE; break;

    default:
        fprintf (stderr, "ffaudio: Unsupported audio format %d\n", (int) cinfo.context->sample_fmt);
        goto error_exit;
    }

    /* Open audio output */
    AUDDBG("opening audio output\n");

    if (aud_input_open_audio(out_fmt, cinfo.context->sample_rate, cinfo.context->channels) <= 0)
    {
        error = TRUE;
        goto error_exit;
    }

    AUDDBG("setting parameters\n");

    aud_input_set_bitrate(ic->bit_rate);

    errcount = 0;
    seekable = ffaudio_codec_is_seekable(cinfo.codec);

    while (! aud_input_check_stop ())
    {
        int seek_value = aud_input_check_seek ();

        if (seek_value >= 0 && seekable)
        {
            if (av_seek_frame (ic, -1, (gint64) seek_value * AV_TIME_BASE /
             1000, AVSEEK_FLAG_ANY) < 0)
            {
                _ERROR("error while seeking\n");
            } else
                errcount = 0;

            seek_value = -1;
        }

        AVPacket tmp;
        gint ret;

        /* Read next frame (or more) of data */
        if ((ret = av_read_frame(ic, &pkt)) < 0)
        {
            if (ret == AVERROR_EOF)
            {
                AUDDBG("eof reached\n");
                break;
            }
            else
            {
                if (++errcount > 4)
                {
                    _ERROR("av_read_frame error %d, giving up.\n", ret);
                    break;
                } else
                    continue;
            }
        } else
            errcount = 0;

        /* Ignore any other substreams */
        if (pkt.stream_index != cinfo.stream_idx)
        {
            av_free_packet(&pkt);
            continue;
        }

        /* Decode and play packet/frame */
        memcpy(&tmp, &pkt, sizeof(tmp));
        while (tmp.size > 0 && ! aud_input_check_stop ())
        {
            /* Check for seek request and bail out if we have one */
            if (seek_value < 0)
                seek_value = aud_input_check_seek ();

            if (seek_value >= 0)
                break;

#if CHECK_LIBAVCODEC_VERSION (55, 28, 1)
            AVFrame * frame = av_frame_alloc ();
#else
            AVFrame * frame = avcodec_alloc_frame ();
#endif
            int decoded = 0;
            int len = avcodec_decode_audio4 (cinfo.context, frame, & decoded, & tmp);

            if (len < 0)
            {
                fprintf (stderr, "ffaudio: decode_audio() failed, code %d\n", len);
                break;
            }

            tmp.size -= len;
            tmp.data += len;

            if (! decoded)
                continue;

            gint size = FMT_SIZEOF (out_fmt) * cinfo.context->channels * frame->nb_samples;

            if (planar)
            {
                if (bufsize < size)
                {
                    buf = g_realloc (buf, size);
                    bufsize = size;
                }

                audio_interlace ((const void * *) frame->data, out_fmt,
                 cinfo.context->channels, buf, frame->nb_samples);
                aud_input_write_audio (buf, size);
            }
            else
                aud_input_write_audio (frame->data[0], size);

#if CHECK_LIBAVCODEC_VERSION (55, 28, 1)
            av_frame_free (& frame);
#else
            avcodec_free_frame (& frame);
#endif
        }

        if (pkt.data)
            av_free_packet(&pkt);
    }

error_exit:
    if (pkt.data)
        av_free_packet(&pkt);
    if (codec_opened)
        avcodec_close(cinfo.context);
    if (ic != NULL)
        close_input_file(ic);

    g_free (buf);

    return ! error;
}
Example #7
0
static bool_t flac_play (const char * filename, VFSFile * file)
{
    if (!file)
        return FALSE;

    void * play_buffer = NULL;
    bool_t error = FALSE;

    info->fd = file;

    if (read_metadata(decoder, info) == FALSE)
    {
        FLACNG_ERROR("Could not prepare file for playing!\n");
        error = TRUE;
        goto ERR_NO_CLOSE;
    }

    play_buffer = g_malloc (BUFFER_SIZE_BYTE);

    if (! aud_input_open_audio (SAMPLE_FMT (info->bits_per_sample),
        info->sample_rate, info->channels))
    {
        error = TRUE;
        goto ERR_NO_CLOSE;
    }

    aud_input_set_bitrate(info->bitrate);

    while (FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM)
    {
        if (aud_input_check_stop ())
            break;

        int seek_value = aud_input_check_seek ();
        if (seek_value >= 0)
            FLAC__stream_decoder_seek_absolute (decoder, (int64_t)
             seek_value * info->sample_rate / 1000);

        /* Try to decode a single frame of audio */
        if (FLAC__stream_decoder_process_single(decoder) == FALSE)
        {
            FLACNG_ERROR("Error while decoding!\n");
            error = TRUE;
            break;
        }

        squeeze_audio(info->output_buffer, play_buffer, info->buffer_used, info->bits_per_sample);
        aud_input_write_audio(play_buffer, info->buffer_used * SAMPLE_SIZE(info->bits_per_sample));

        reset_info(info);
    }

ERR_NO_CLOSE:
    g_free (play_buffer);
    reset_info(info);

    if (FLAC__stream_decoder_flush(decoder) == FALSE)
        FLACNG_ERROR("Could not flush decoder state!\n");

    return ! error;
}
Example #8
0
/*
 * Start playing the given file
 */
bool_t xs_play_file(const char *filename, VFSFile *file)
{
    xs_tuneinfo_t *tmpTune;
    int audioBufSize, bufRemaining, tmpLength, subTune = -1;
    char *audioBuffer = NULL, *oversampleBuffer = NULL;
    Tuple *tmpTuple;

    uri_parse (filename, NULL, NULL, NULL, & subTune);

    /* Get tune information */
    pthread_mutex_lock(&xs_status_mutex);

    if (! (xs_status.tuneInfo = xs_sidplayfp_getinfo (filename)))
    {
        pthread_mutex_unlock(&xs_status_mutex);
        return FALSE;
    }

    /* Initialize the tune */
    if (! xs_sidplayfp_load (& xs_status, filename))
    {
        pthread_mutex_unlock(&xs_status_mutex);
        xs_tuneinfo_free(xs_status.tuneInfo);
        xs_status.tuneInfo = NULL;
        return FALSE;
    }

    bool_t error = FALSE;

    /* Set general status information */
    tmpTune = xs_status.tuneInfo;

    if (subTune < 1 || subTune > xs_status.tuneInfo->nsubTunes)
        xs_status.currSong = xs_status.tuneInfo->startTune;
    else
        xs_status.currSong = subTune;

    int channels = xs_status.audioChannels;

    /* Allocate audio buffer */
    audioBufSize = xs_status.audioFrequency * channels * FMT_SIZEOF (FMT_S16_NE);
    if (audioBufSize < 512) audioBufSize = 512;

    audioBuffer = (char *) malloc(audioBufSize);
    if (audioBuffer == NULL) {
        xs_error("Couldn't allocate memory for audio data buffer!\n");
        pthread_mutex_unlock(&xs_status_mutex);
        goto xs_err_exit;
    }

    /* Check minimum playtime */
    tmpLength = tmpTune->subTunes[xs_status.currSong - 1].tuneLength;
    if (xs_cfg.playMinTimeEnable && (tmpLength >= 0)) {
        if (tmpLength < xs_cfg.playMinTime)
            tmpLength = xs_cfg.playMinTime;
    }

    /* Initialize song */
    if (!xs_sidplayfp_initsong(&xs_status)) {
        xs_error("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n",
            tmpTune->sidFilename, xs_status.currSong);
        pthread_mutex_unlock(&xs_status_mutex);
        goto xs_err_exit;
    }

    /* Open the audio output */
    if (!aud_input_open_audio(FMT_S16_NE, xs_status.audioFrequency, channels))
    {
        xs_error("Couldn't open audio output (fmt=%x, freq=%i, nchan=%i)!\n",
            FMT_S16_NE,
            xs_status.audioFrequency,
            channels);

        pthread_mutex_unlock(&xs_status_mutex);
        goto xs_err_exit;
    }

    /* Set song information for current subtune */
    xs_sidplayfp_updateinfo(&xs_status);
    tmpTuple = tuple_new_from_filename(tmpTune->sidFilename);
    xs_get_song_tuple_info(tmpTuple, tmpTune, xs_status.currSong);

    pthread_mutex_unlock(&xs_status_mutex);

    aud_input_set_tuple(tmpTuple);

    while (! aud_input_check_stop ())
    {
        bufRemaining = xs_sidplayfp_fillbuffer(&xs_status, audioBuffer, audioBufSize);

        aud_input_write_audio (audioBuffer, bufRemaining);

        /* Check if we have played enough */
        if (xs_cfg.playMaxTimeEnable) {
            if (xs_cfg.playMaxTimeUnknown) {
                if (tmpLength < 0 &&
                    aud_input_written_time() >= xs_cfg.playMaxTime * 1000)
                    break;
            } else {
                if (aud_input_written_time() >= xs_cfg.playMaxTime * 1000)
                    break;
            }
        }

        if (tmpLength >= 0) {
            if (aud_input_written_time() >= tmpLength * 1000)
                break;
        }
    }

DONE:
    free(audioBuffer);
    free(oversampleBuffer);

    /* Set playing status to false (stopped), thus when
     * XMMS next calls xs_get_time(), it can return appropriate
     * value "not playing" status and XMMS knows to move to
     * next entry in the playlist .. or whatever it wishes.
     */
    pthread_mutex_lock(&xs_status_mutex);

    /* Free tune information */
    xs_sidplayfp_delete(&xs_status);
    xs_tuneinfo_free(xs_status.tuneInfo);
    xs_status.tuneInfo = NULL;
    pthread_mutex_unlock(&xs_status_mutex);

    /* Exit the playing thread */
    return ! error;

xs_err_exit:
    error = TRUE;
    goto DONE;
}