Пример #1
0
static int
_rg_write_meta (DB_playItem_t *track) {
    const char *path = NULL;
    const char *decoder_id = NULL;

    deadbeef->pl_lock ();
    path = strdupa (deadbeef->pl_find_meta_raw (track, ":URI"));
    int is_subtrack = deadbeef->pl_get_item_flags (track) & DDB_IS_SUBTRACK;
    if (is_subtrack) {
        trace ("rg_scanner: Can't write to subtrack of file: %s\n", path);
        deadbeef->pl_unlock ();
        return -1;
    }
    decoder_id = deadbeef->pl_find_meta_raw (track, ":DECODER");
    if (!decoder_id) {
        trace ("rg_scanner: Invalid decoder in track %s\n", path);
        deadbeef->pl_unlock ();
        return -1;
    }
    decoder_id = strdupa (decoder_id);

    int match = track && decoder_id;
    deadbeef->pl_unlock ();

    if (match) {
        int is_subtrack = deadbeef->pl_get_item_flags (track) & DDB_IS_SUBTRACK;
        if (is_subtrack) {
            return 0; // only write tags for actual tracks
        }
        // find decoder
        DB_decoder_t *dec = NULL;
        DB_decoder_t **decoders = deadbeef->plug_get_decoder_list ();
        for (int i = 0; decoders[i]; i++) {
            if (!strcmp (decoders[i]->plugin.id, decoder_id)) {
                dec = decoders[i];
                if (dec->write_metadata) {
                    if (dec->write_metadata (track)) {
                        trace ("rg_scanner: Failed to write tag to %s\n", path);
                        return -1;
                    }
                }
                else {
                    trace ("rg_scanner: Writing tags is not supported for the file %s\n", path);
                }
                break;
            }
        }
    }
    else {
        trace ("rg_scanner: Could not find matching decoder for %s\n", path);
        return -1;
    }
    return 0;
}
Пример #2
0
// prepare to decode the track, fill in mandatory plugin fields
// return -1 on failure
static int
example_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
    example_info_t *info = (example_info_t *)_info;

    // take this parameters from your input file
    // we set constants for clarity sake
    _info->fmt.bps = 16;
    _info->fmt.channels = 2;
    _info->fmt.samplerate  = 44100;
    for (int i = 0; i < _info->fmt.channels; i++) {
        _info->fmt.channelmask |= 1 << i;
    }
    _info->readpos = 0;
    _info->plugin = &plugin;

    if (it->endsample > 0) {
        info->startsample = it->startsample;
        info->endsample = it->endsample;
        plugin.seek_sample (_info, 0);
    }
    else {
        info->startsample = 0;
        int TOTALSAMPLES = 1000; // calculate from file
        info->endsample = TOTALSAMPLES-1;
    }
    return 0;
}
Пример #3
0
static void
write_meta_worker (void *ctx) {
    for (int t = 0; t < numtracks; t++) {
        if (progress_aborted) {
            break;
        }
        DB_playItem_t *track = tracks[t];
        deadbeef->pl_lock ();
        const char *dec = deadbeef->pl_find_meta_raw (track, ":DECODER");
        char decoder_id[100];
        if (dec) {
            strncpy (decoder_id, dec, sizeof (decoder_id));
        }
        int match = track && dec;
        deadbeef->pl_unlock ();
        if (match) {
            int is_subtrack = deadbeef->pl_get_item_flags (track) & DDB_IS_SUBTRACK;
            if (is_subtrack) {
                continue;
            }
            deadbeef->pl_item_ref (track);
            g_idle_add (set_progress_cb, track);
            // find decoder
            DB_decoder_t *dec = NULL;
            DB_decoder_t **decoders = deadbeef->plug_get_decoder_list ();
            for (int i = 0; decoders[i]; i++) {
                if (!strcmp (decoders[i]->plugin.id, decoder_id)) {
                    dec = decoders[i];
                    if (dec->write_metadata) {
                        dec->write_metadata (track);
                    }
                    break;
                }
            }
        }
    }
    g_idle_add (write_finished_cb, ctx);
}
Пример #4
0
static int
tta_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
    tta_info_t *info = (tta_info_t *)_info;

    deadbeef->pl_lock ();
    const char *fname = deadbeef->pl_find_meta (it, ":URI")
    trace ("open_tta_file %s\n", fname);
    if (open_tta_file (fname, &info->tta, 0) != 0) {
        deadbeef->pl_unlock ();
        fprintf (stderr, "tta: failed to open %s\n", fname);
        return -1;
    }

    if (player_init (&info->tta) != 0) {
        deadbeef->pl_unlock ();
        fprintf (stderr, "tta: failed to init player for %s\n", fname);
        return -1;
    }
    deadbeef->pl_unlock ();

    _info->fmt.bps = info->tta.BPS;
    _info->fmt.channels = info->tta.NCH;
    _info->fmt.samplerate = info->tta.SAMPLERATE;
    for (int i = 0; i < _info->fmt.channels; i++) {
        _info->fmt.channelmask |= 1 << i;
    }
    _info->readpos = 0;
    _info->plugin = &plugin;

    int64_t endsample = deadbeef->pl_item_get_endsample (it);
    if (endsample > 0) {
        info->startsample = deadbeef->pl_item_get_startsample (it);
        info->endsample = endsample;
        plugin.seek_sample (_info, 0);
    }
    else {
        info->startsample = 0;
        info->endsample = (info->tta.DATALENGTH)-1;
    }
    trace ("open_tta_file %s success!\n", deadbeef->pl_find_meta (it, ":URI"));
    return 0;
}
Пример #5
0
static int
aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
    aac_info_t *info = (aac_info_t *)_info;

    info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
    if (!info->file) {
        return -1;
    }

    // probe
    float duration = -1;
    int samplerate = -1;
    int channels = -1;
    int totalsamples = -1;

    info->junk = deadbeef->junk_get_leading_size (info->file);
    if (!info->file->vfs->is_streaming ()) {
        if (info->junk >= 0) {
            deadbeef->fseek (info->file, info->junk, SEEK_SET);
        }
        else {
            info->junk = 0;
        }
    }
    else {
        deadbeef->fset_track (info->file, it);
    }

    info->mp4track = -1;
#if USE_MP4FF
    info->mp4reader.read = aac_fs_read;
    info->mp4reader.write = NULL;
    info->mp4reader.seek = aac_fs_seek;
    info->mp4reader.truncate = NULL;
    info->mp4reader.user_data = info;
#else
    info->mp4reader.open = aac_fs_open;
    info->mp4reader.seek = aac_fs_seek;
    info->mp4reader.read = aac_fs_read;
    info->mp4reader.write = NULL;
    info->mp4reader.close = aac_fs_close;
#endif

    if (!info->file->vfs->is_streaming ()) {
#ifdef USE_MP4FF
        trace ("aac_init: mp4ff_open_read %s\n", deadbeef->pl_find_meta (it, ":URI"));
        info->mp4file = mp4ff_open_read (&info->mp4reader);
        if (info->mp4file) {
            int ntracks = mp4ff_total_tracks (info->mp4file);
            if (ntracks > 0) {
                trace ("m4a container detected, ntracks=%d\n", ntracks);
                int i = -1;
                unsigned char*  buff = 0;
                unsigned int    buff_size = 0;
                for (i = 0; i < ntracks; i++) {
                    mp4AudioSpecificConfig mp4ASC;
                    mp4ff_get_decoder_config (info->mp4file, i, &buff, &buff_size);
                    if(buff){
                        int rc = AudioSpecificConfig(buff, buff_size, &mp4ASC);
                        if(rc < 0)
                            continue;
                        break;
                    }
                }
                trace ("mp4 probe-buffer size: %d\n", buff_size);

                if (i != ntracks && buff) 
                {
                    trace ("mp4 track: %d\n", i);
                    int samples = mp4ff_num_samples(info->mp4file, i);
                    info->mp4samples = samples;
                    info->mp4track = i;

                    // init mp4 decoding
                    info->dec = NeAACDecOpen ();
                    unsigned long srate;
                    unsigned char ch;
                    if (NeAACDecInit2(info->dec, buff, buff_size, &srate, &ch) < 0) {
                        trace ("NeAACDecInit2 returned error\n");
                        free (buff);
                        return -1;
                    }
                    samplerate = srate;
                    channels = ch;
                    samples = (int64_t)samples * srate / mp4ff_time_scale (info->mp4file, i);
                    totalsamples = samples;
                    NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec);
                    conf->dontUpSampleImplicitSBR = 1;
                    NeAACDecSetConfiguration (info->dec, conf);
                    mp4AudioSpecificConfig mp4ASC;
                    if (NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC) >= 0)
                    {
                        info->mp4framesize = 1024;
                        if (mp4ASC.frameLengthFlag == 1) {
                            info->mp4framesize = 960;
                        }
//                        if (mp4ASC.sbr_present_flag == 1) {
//                            info->mp4framesize *= 2;
//                        }
                    }
                    totalsamples *= info->mp4framesize;
                    duration = (float)totalsamples  / samplerate;
                }
                else {
                    mp4ff_close (info->mp4file);
                    info->mp4file = NULL;
                }
                if (buff) {
                    free (buff);
                }
            }
            else {
                mp4ff_close (info->mp4file);
                info->mp4file = NULL;
            }
        }
// {{{ libmp4v2 code
#else
        trace ("aac_init: MP4ReadProvider %s\n", deadbeef->pl_find_meta (it, ":URI"));
        info->mp4file = MP4ReadProvider (deadbeef->pl_find_meta (it, ":URI"), 0, &info->mp4reader);
        info->mp4track = MP4FindTrackId(info->mp4file, 0, "audio", 0);
        trace ("aac_init: MP4FindTrackId returned %d\n", info->mp4track);
        if (info->mp4track >= 0) {
            info->timescale = MP4GetTrackTimeScale(info->mp4file, info->mp4track);

            u_int8_t* pConfig;
            uint32_t configSize = 0;
            bool res = MP4GetTrackESConfiguration(info->mp4file, info->mp4track, &pConfig, &configSize);

            mp4AudioSpecificConfig mp4ASC;
            int rc = AudioSpecificConfig(pConfig, configSize, &mp4ASC);
            if (rc >= 0) {
                _info->samplerate = mp4ASC.samplingFrequency;
                _info->channels = MP4GetTrackAudioChannels (info->mp4file, info->mp4track);
                totalsamples = MP4GetTrackNumberOfSamples (info->mp4file, info->mp4track) * 1024 * _info->channels;

                // init mp4 decoding
                info->dec = NeAACDecOpen ();
                unsigned long srate;
                unsigned char ch;
                if (NeAACDecInit2(info->dec, pConfig, configSize, &srate, &ch) < 0) {
                    trace ("NeAACDecInit2 returned error\n");
                    return -1;
                }
                samplerate = srate;
                channels = ch;
                NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec);
                conf->dontUpSampleImplicitSBR = 1;
                NeAACDecSetConfiguration (info->dec, conf);
                mp4AudioSpecificConfig mp4ASC;
                if (NeAACDecAudioSpecificConfig(pConfig, configSize, &mp4ASC) >= 0)
                {
                    info->mp4framesize = 1024;
                    if (mp4ASC.frameLengthFlag == 1) {
                        info->mp4framesize = 960;
                    }
//                    if (mp4ASC.sbr_present_flag == 1) {
//                        info->mp4framesize *= 2;
//                    }
                }
                //totalsamples *= info->mp4framesize;
                free (pConfig);
                info->maxSampleSize = MP4GetTrackMaxSampleSize(info->mp4file, info->mp4track);
                info->samplebuffer = malloc (info->maxSampleSize);
                info->mp4sample = 1;
            }
            else {
                MP4Close (info->mp4file);
                info->mp4file = NULL;
            }
        }
        else {
            MP4Close (info->mp4file);
            info->mp4file = NULL;
        }
#endif
// }}}
        if (!info->mp4file) {
            trace ("mp4 track not found, looking for aac stream...\n");

            if (info->junk >= 0) {
                deadbeef->fseek (info->file, info->junk, SEEK_SET);
            }
            else {
                deadbeef->rewind (info->file);
            }
            int offs = parse_aac_stream (info->file, &samplerate, &channels, &duration, &totalsamples);
            if (offs == -1) {
                trace ("aac stream not found\n");
                return -1;
            }
            if (offs > info->junk) {
                info->junk = offs;
            }
            if (info->junk >= 0) {
                deadbeef->fseek (info->file, info->junk, SEEK_SET);
            }
            else {
                deadbeef->rewind (info->file);
            }
            trace ("found aac stream (junk: %d, offs: %d)\n", info->junk, offs);
        }

        _info->fmt.channels = channels;
        _info->fmt.samplerate = samplerate;
    }
    else {
        // sync before attempting to init
        int samplerate, channels;
        float duration;
        int offs = parse_aac_stream (info->file, &samplerate, &channels, &duration, NULL);
        if (offs < 0) {
            trace ("aac: parse_aac_stream failed\n");
            return -1;
        }
        if (offs > info->junk) {
            info->junk = offs;
        }
        trace("parse_aac_stream returned %x\n", offs);
        deadbeef->pl_replace_meta (it, "!FILETYPE", "AAC");
    }

//    duration = (float)totalsamples / samplerate;
//    deadbeef->pl_set_item_duration (it, duration);

    _info->fmt.bps = 16;
    _info->plugin = &plugin;

    if (!info->mp4file) {
        //trace ("NeAACDecGetCapabilities\n");
        //unsigned long caps = NeAACDecGetCapabilities();

        trace ("NeAACDecOpen\n");
        info->dec = NeAACDecOpen ();

        trace ("prepare for NeAACDecInit: fread %d from offs %lld\n", AAC_BUFFER_SIZE, deadbeef->ftell (info->file));
        info->remaining = deadbeef->fread (info->buffer, 1, AAC_BUFFER_SIZE, info->file);

        NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec);
//        conf->dontUpSampleImplicitSBR = 1;
        NeAACDecSetConfiguration (info->dec, conf);
        unsigned long srate;
        unsigned char ch;
        trace ("NeAACDecInit (%d bytes)\n", info->remaining);
        int consumed = NeAACDecInit (info->dec, info->buffer, info->remaining, &srate, &ch);
        trace ("NeAACDecInit returned samplerate=%d, channels=%d, consumed: %d\n", (int)srate, (int)ch, consumed);
        if (consumed < 0) {
            trace ("NeAACDecInit returned %d\n", consumed);
            return -1;
        }
        if (consumed > info->remaining) {
            trace ("NeAACDecInit consumed more than available! wtf?\n");
            return -1;
        }
        if (consumed == info->remaining) {
            info->remaining = 0;
        }
        else if (consumed > 0) {
            memmove (info->buffer, info->buffer + consumed, info->remaining - consumed);
            info->remaining -= consumed;
        }
        _info->fmt.channels = ch;
        _info->fmt.samplerate = srate;
    }

    if (!info->file->vfs->is_streaming ()) {
        if (it->endsample > 0) {
            info->startsample = it->startsample;
            info->endsample = it->endsample;
            plugin.seek_sample (_info, 0);
        }
        else {
            info->startsample = 0;
            info->endsample = totalsamples-1;
        }
    }
    trace ("totalsamples: %d, endsample: %d, samples-from-duration: %d\n", totalsamples-1, info->endsample, (int)deadbeef->pl_get_item_duration (it)*44100);

    for (int i = 0; i < _info->fmt.channels; i++) {
        _info->fmt.channelmask |= 1 << i;
    }
    info->noremap = 0;
    info->remap[0] = -1;
    trace ("init success\n");

    return 0;
}
Пример #6
0
static int
wv_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
    wvctx_t *info = (wvctx_t *)_info;
    deadbeef->pl_lock ();
    info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
    deadbeef->pl_unlock ();
    if (!info->file) {
        return -1;
    }

#ifndef TINYWV
    deadbeef->pl_lock ();
    const char *uri = deadbeef->pl_find_meta (it, ":URI");
    char *c_fname = alloca (strlen (uri) + 2);
    if (c_fname) {
        strcpy (c_fname, uri);
        strcat (c_fname, "c");
        info->c_file = deadbeef->fopen (c_fname);
    }
    else {
        fprintf (stderr, "wavpack warning: failed to alloc memory for correction file name\n");
    }
    deadbeef->pl_unlock ();
#endif

    char error[80];
#ifdef TINYWV
    info->ctx = WavpackOpenFileInput (wv_read_stream, info->file, error);
#else
    info->ctx = WavpackOpenFileInputEx (&wsr, info->file, info->c_file, error, OPEN_NORMALIZE, 0);
#endif
    if (!info->ctx) {
        fprintf (stderr, "wavpack error: %s\n", error);
        return -1;
    }
    _info->plugin = &plugin;
    _info->fmt.bps = WavpackGetBytesPerSample (info->ctx) * 8;
    _info->fmt.channels = WavpackGetNumChannels (info->ctx);
    _info->fmt.samplerate = WavpackGetSampleRate (info->ctx);
    _info->fmt.is_float = (WavpackGetMode (info->ctx) & MODE_FLOAT) ? 1 : 0;

    // FIXME: streamer and maybe output plugins need to be fixed to support
    // arbitrary channelmask

    // _info->fmt.channelmask = WavpackGetChannelMask (info->ctx);

    for (int i = 0; i < _info->fmt.channels; i++) {
        _info->fmt.channelmask |= 1 << i;
    }
    _info->readpos = 0;
    if (it->endsample > 0) {
        info->startsample = it->startsample;
        info->endsample = it->endsample;
        if (plugin.seek_sample (_info, 0) < 0) {
            return -1;
        }
    }
    else {
        info->startsample = 0;
        info->endsample = WavpackGetNumSamples (info->ctx)-1;
    }
    return 0;
}
Пример #7
0
static int
aac_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
    aac_info_t *info = (aac_info_t *)_info;

    deadbeef->pl_lock ();
    info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
    deadbeef->pl_unlock ();
    if (!info->file) {
        return -1;
    }

    // probe
    float duration = -1;
    int samplerate = -1;
    int channels = -1;
    int totalsamples = -1;

    info->junk = deadbeef->junk_get_leading_size (info->file);
    if (!info->file->vfs->is_streaming ()) {
        if (info->junk >= 0) {
            deadbeef->fseek (info->file, info->junk, SEEK_SET);
        }
        else {
            info->junk = 0;
        }
    }
    else {
        deadbeef->fset_track (info->file, it);
    }

    info->mp4track = -1;
    info->mp4reader.read = aac_fs_read;
    info->mp4reader.write = NULL;
    info->mp4reader.seek = aac_fs_seek;
    info->mp4reader.truncate = NULL;
    info->mp4reader.user_data = info;

    if (!info->file->vfs->is_streaming ()) {
        trace ("aac_init: mp4ff_open_read %s\n", deadbeef->pl_find_meta (it, ":URI"));
        info->mp4 = mp4ff_open_read (&info->mp4reader);
        if (info->mp4) {
            int ntracks = mp4ff_total_tracks (info->mp4);
            for (int i = 0; i < ntracks; i++) {
                if (mp4ff_get_track_type (info->mp4, i) != TRACK_AUDIO) {
                    continue;
                }
                int res = mp4_track_get_info (info->mp4, i, &duration, &samplerate, &channels, &totalsamples, &info->mp4framesize);
                if (res >= 0 && duration > 0) {
                    info->mp4track = i;
                    break;
                }
            }
            trace ("track: %d\n", info->mp4track);
            if (info->mp4track >= 0) {
                // prepare decoder
                int res = mp4_track_get_info (info->mp4, info->mp4track, &duration, &samplerate, &channels, &totalsamples, &info->mp4framesize);
                if (res != 0) {
                    trace ("aac: mp4_track_get_info(%d) returned error\n", info->mp4track);
                    return -1;
                }

                // init mp4 decoding
                info->mp4samples = mp4ff_num_samples(info->mp4, info->mp4track);
                info->dec = NeAACDecOpen ();
                unsigned long srate;
                unsigned char ch;
                unsigned char*  buff = 0;
                unsigned int    buff_size = 0;
                mp4AudioSpecificConfig mp4ASC;
                mp4ff_get_decoder_config (info->mp4, info->mp4track, &buff, &buff_size);
                if (NeAACDecInit2(info->dec, buff, buff_size, &srate, &ch) < 0) {
                    trace ("NeAACDecInit2 returned error\n");
                    free (buff);
                    return -1;
                }

                if (buff) {
                    free (buff);
                }
                trace ("aac: successfully initialized track %d\n", info->mp4track);
                _info->fmt.samplerate = samplerate;
                _info->fmt.channels = channels;
            }
            else {
                trace ("aac: track not found in mp4 container\n");
                mp4ff_close (info->mp4);
                info->mp4 = NULL;
            }
        }

        if (!info->mp4) {
            trace ("aac: looking for raw stream...\n");

            if (info->junk >= 0) {
                deadbeef->fseek (info->file, info->junk, SEEK_SET);
            }
            else {
                deadbeef->rewind (info->file);
            }
            int offs = parse_aac_stream (info->file, &samplerate, &channels, &duration, &totalsamples);
            if (offs == -1) {
                trace ("aac stream not found\n");
                return -1;
            }
            if (offs > info->junk) {
                info->junk = offs;
            }
            if (info->junk >= 0) {
                deadbeef->fseek (info->file, info->junk, SEEK_SET);
            }
            else {
                deadbeef->rewind (info->file);
            }
            trace ("found aac stream (junk: %d, offs: %d)\n", info->junk, offs);

            _info->fmt.channels = channels;
            _info->fmt.samplerate = samplerate;
        }
    }
    else {
        // sync before attempting to init
        int samplerate, channels;
        float duration;
        int offs = parse_aac_stream (info->file, &samplerate, &channels, &duration, NULL);
        if (offs < 0) {
            trace ("aac: parse_aac_stream failed\n");
            return -1;
        }
        if (offs > info->junk) {
            info->junk = offs;
        }
        trace("parse_aac_stream returned %x\n", offs);
        deadbeef->pl_replace_meta (it, "!FILETYPE", "AAC");
    }

//    duration = (float)totalsamples / samplerate;
//    deadbeef->pl_set_item_duration (it, duration);

    _info->fmt.bps = 16;
    _info->plugin = &plugin;

    if (!info->mp4) {
        trace ("NeAACDecOpen for raw stream\n");
        info->dec = NeAACDecOpen ();

        trace ("prepare for NeAACDecInit: fread %d from offs %lld\n", AAC_BUFFER_SIZE, deadbeef->ftell (info->file));
        info->remaining = deadbeef->fread (info->buffer, 1, AAC_BUFFER_SIZE, info->file);

        NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration (info->dec);
//        conf->dontUpSampleImplicitSBR = 1;
        NeAACDecSetConfiguration (info->dec, conf);
        unsigned long srate;
        unsigned char ch;
        trace ("NeAACDecInit (%d bytes)\n", info->remaining);
        int consumed = NeAACDecInit (info->dec, info->buffer, info->remaining, &srate, &ch);
        trace ("NeAACDecInit returned samplerate=%d, channels=%d, consumed: %d\n", (int)srate, (int)ch, consumed);
        if (consumed < 0) {
            trace ("NeAACDecInit returned %d\n", consumed);
            return -1;
        }
        if (consumed > info->remaining) {
            trace ("NeAACDecInit consumed more than available! wtf?\n");
            return -1;
        }
        if (consumed == info->remaining) {
            info->remaining = 0;
        }
        else if (consumed > 0) {
            memmove (info->buffer, info->buffer + consumed, info->remaining - consumed);
            info->remaining -= consumed;
        }
        _info->fmt.channels = ch;
        _info->fmt.samplerate = srate;
    }

    if (!info->file->vfs->is_streaming ()) {
        if (it->endsample > 0) {
            info->startsample = it->startsample;
            info->endsample = it->endsample;
            plugin.seek_sample (_info, 0);
        }
        else {
            info->startsample = 0;
            info->endsample = totalsamples-1;
        }
    }
    if (_info->fmt.channels == 7) {
        _info->fmt.channels = 8;
    }

    trace ("totalsamples: %d, endsample: %d, samples-from-duration: %d, samplerate %d, channels %d\n", totalsamples-1, info->endsample, (int)deadbeef->pl_get_item_duration (it)*44100, _info->fmt.samplerate, _info->fmt.channels);

    for (int i = 0; i < _info->fmt.channels; i++) {
        _info->fmt.channelmask |= 1 << i;
    }
    info->noremap = 0;
    info->remap[0] = -1;
    trace ("init success\n");

    return 0;
}
Пример #8
0
static int
sndfile_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
    sndfile_info_t *info = (sndfile_info_t*)_info;

    SF_INFO inf;
    DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
    if (!fp) {
        trace ("sndfile: failed to open %s\n", deadbeef->pl_find_meta (it, ":URI"));
        return -1;
    }
    int fsize = deadbeef->fgetlength (fp);

    info->file = fp;
    info->ctx = sf_open_virtual (&vfs, SFM_READ, &inf, info);
    if (!info->ctx) {
        trace ("sndfile: %s: unsupported file format\n");
        return -1;
    }
    _info->plugin = &plugin;
    info->sf_format = inf.format&0x000f;

    switch (inf.format&0x000f) {
    case SF_FORMAT_PCM_S8:
    case SF_FORMAT_PCM_U8:
        _info->fmt.bps = 8;
        break;
    case SF_FORMAT_PCM_16:
        _info->fmt.bps = 16;
        break;
    case SF_FORMAT_PCM_24:
        _info->fmt.bps = 24;
        break;
    case SF_FORMAT_FLOAT:
        _info->fmt.is_float = 1;
    case SF_FORMAT_PCM_32:
        _info->fmt.bps = 32;
        break;
    default:
        info->read_as_short = 1;
        _info->fmt.bps = 16;
        trace ("[sndfile] unidentified input format: 0x%X\n", inf.format&0x000f);
        break;
    }

    _info->fmt.channels = inf.channels;
    _info->fmt.samplerate = inf.samplerate;

    int channel_map [inf.channels];
    int cmdres = sf_command (info->ctx, SFC_GET_CHANNEL_MAP_INFO, channel_map, sizeof (channel_map)) ;
    if (cmdres != SF_FALSE) {
        // channel map found, convert to channel mask
        _info->fmt.channelmask = wavex_gen_channel_mask (channel_map, inf.channels);
    }
    else {
        // channel map not found, generate from channel number
        for (int i = 0; i < inf.channels; i++) {
            _info->fmt.channelmask |= 1 << i;
        }
    }

    _info->readpos = 0;
    if (it->endsample > 0) {
        info->startsample = it->startsample;
        info->endsample = it->endsample;
        if (plugin.seek_sample (_info, 0) < 0) {
            return -1;
        }
    }
    else {
        info->startsample = 0;
        info->endsample = inf.frames-1;
    }
    // hack bitrate

    int totalsamples = inf.frames;
    float sec = (float)totalsamples / inf.samplerate;
    if (sec > 0) {
        info->bitrate = fsize / sec * 8 / 1000;
    }
    else {
        info->bitrate = -1;
    }

    return 0;
}
Пример #9
0
int
convert (DB_playItem_t *it, const char *out, int output_bps, int output_is_float, ddb_encoder_preset_t *encoder_preset, ddb_dsp_preset_t *dsp_preset, int *abort) {
    char *buffer = NULL;
    char *dspbuffer = NULL;
    if (deadbeef->pl_get_item_duration (it) <= 0) {
        deadbeef->pl_lock ();
        fprintf (stderr, "converter: stream %s doesn't have finite length, skipped\n", deadbeef->pl_find_meta (it, ":URI"));
        deadbeef->pl_unlock ();
        return -1;
    }

    int err = -1;
    FILE *enc_pipe = NULL;
    int temp_file = -1;
    DB_decoder_t *dec = NULL;
    DB_fileinfo_t *fileinfo = NULL;
    char input_file_name[PATH_MAX] = "";
    deadbeef->pl_lock ();
    dec = (DB_decoder_t *)deadbeef->plug_get_for_id (deadbeef->pl_find_meta (it, ":DECODER"));
    deadbeef->pl_unlock ();

    if (dec) {
        fileinfo = dec->open (0);
        if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (it)) != 0) {
            deadbeef->pl_lock ();
            fprintf (stderr, "converter: failed to decode file %s\n", deadbeef->pl_find_meta (it, ":URI"));
            deadbeef->pl_unlock ();
            goto error;
        }
        if (fileinfo) {
            if (output_bps == -1) {
                output_bps = fileinfo->fmt.bps;
                output_is_float = fileinfo->fmt.is_float;
            }

            char *final_path = strdupa (out);
            char *sep = strrchr (final_path, '/');
            if (sep) {
                *sep = 0;
                if (!check_dir (final_path, 0755)) {
                    fprintf (stderr, "converter: failed to create output folder: %s\n", final_path);
                    goto error;
                }
            }

            if (encoder_preset->method == DDB_ENCODER_METHOD_FILE) {
                const char *tmp = getenv ("TMPDIR");
                if (!tmp) {
                    tmp = "/tmp";
                }
                snprintf (input_file_name, sizeof (input_file_name), "%s/ddbconvXXXXXX", tmp);
                char *res = mktemp (input_file_name);
                strcat (input_file_name, ".wav");
            }
            else {
                strcpy (input_file_name, "-");
            }

            char enc[2000];
            memset (enc, 0, sizeof (enc));

            char escaped_out[PATH_MAX];
            escape_filepath (out, escaped_out, sizeof (escaped_out));

            // formatting: %o = outfile, %i = infile
            char *e = encoder_preset->encoder;
            char *o = enc;
            *o = 0;
            int len = sizeof (enc);
            while (e && *e) {
                if (len <= 0) {
                    fprintf (stderr, "converter: failed to assemble encoder command line - buffer is not big enough, try to shorten your parameters. max allowed length is %u characters\n", (unsigned)sizeof (enc));
                    goto error;
                }
                if (e[0] == '%' && e[1]) {
                    if (e[1] == 'o') {
                        int l = snprintf (o, len, "\"%s\"", escaped_out);
                        o += l;
                        len -= l;
                    }
                    else if (e[1] == 'i') {
                        int l = snprintf (o, len, "\"%s\"", input_file_name);
                        o += l;
                        len -= l;
                    }
                    else {
                        strncpy (o, e, 2);
                        o += 2;
                        len -= 2;
                    }
                    e += 2;
                }
                else {
                    *o++ = *e++;
                    *o = 0;
                    len--;
                }
            }

            fprintf (stderr, "converter: will encode using: %s\n", enc[0] ? enc : "internal RIFF WAVE writer");

            mode_t wrmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;

            if (!encoder_preset->encoder[0]) {
                // write to wave file
                trace ("opening %s\n", out);
                temp_file = open (out, O_LARGEFILE | O_WRONLY | O_CREAT | O_TRUNC, wrmode);
                if (temp_file == -1) {
                    fprintf (stderr, "converter: failed to open output wave file %s\n", out);
                    goto error;
                }
            }
            else if (encoder_preset->method == DDB_ENCODER_METHOD_FILE) {
                temp_file = open (input_file_name, O_LARGEFILE | O_WRONLY | O_CREAT | O_TRUNC, wrmode);
                if (temp_file == -1) {
                    fprintf (stderr, "converter: failed to open temp file %s\n", input_file_name);
                    goto error;
                }
            }
            else {
                enc_pipe = popen (enc, "w");
                if (!enc_pipe) {
                    fprintf (stderr, "converter: failed to open encoder\n");
                    goto error;
                }
            }

            if (temp_file == -1 && enc_pipe) {
                temp_file = fileno (enc_pipe);
            }

            // write wave header
            char wavehdr_int[] = {
                0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61
            };
            char wavehdr_float[] = {
                0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x28, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x02, 0x00, 0x40, 0x1f, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x16, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71, 0x66, 0x61, 0x63, 0x74, 0x04, 0x00, 0x00, 0x00, 0xc5, 0x5b, 0x00, 0x00, 0x64, 0x61, 0x74, 0x61
            };
            char *wavehdr = output_is_float ? wavehdr_float : wavehdr_int;
            int wavehdr_size = output_is_float ? sizeof (wavehdr_float) : sizeof (wavehdr_int);
            int header_written = 0;
            uint32_t outsize = 0;
            uint32_t outsr = fileinfo->fmt.samplerate;
            uint16_t outch = fileinfo->fmt.channels;

            int samplesize = fileinfo->fmt.channels * fileinfo->fmt.bps / 8;

            // block size
            int bs = 2000 * samplesize;
            // expected buffer size after worst-case dsp
            int dspsize = bs/samplesize*sizeof(float)*8*48;
            buffer = malloc (dspsize);
            // account for up to float32 7.1 resampled to 48x ratio
            dspbuffer = malloc (dspsize);
            int eof = 0;
            for (;;) {
                if (eof) {
                    break;
                }
                if (abort && *abort) {
                    break;
                }
                int sz = dec->read (fileinfo, buffer, bs);

                if (sz != bs) {
                    eof = 1;
                }
                if (dsp_preset) {
                    ddb_waveformat_t fmt;
                    ddb_waveformat_t outfmt;
                    memcpy (&fmt, &fileinfo->fmt, sizeof (fmt));
                    memcpy (&outfmt, &fileinfo->fmt, sizeof (fmt));
                    fmt.bps = 32;
                    fmt.is_float = 1;
                    deadbeef->pcm_convert (&fileinfo->fmt, buffer, &fmt, dspbuffer, sz);

                    ddb_dsp_context_t *dsp = dsp_preset->chain;
                    int frames = sz / samplesize;
                    while (dsp) {
                        frames = dsp->plugin->process (dsp, (float *)dspbuffer, frames, dspsize / (fmt.channels * 4), &fmt, NULL);
                        if (frames <= 0) {
                            break;
                        }
                        dsp = dsp->next;
                    }
                    if (frames <= 0) {
                        fprintf (stderr, "converter: dsp error, please check you dsp preset\n");
                        goto error;
                    }

                    outsr = fmt.samplerate;
                    outch = fmt.channels;

                    outfmt.bps = output_bps;
                    outfmt.is_float = output_is_float;
                    outfmt.channels = outch;
                    outfmt.samplerate = outsr;

                    int n = deadbeef->pcm_convert (&fmt, dspbuffer, &outfmt, buffer, frames * sizeof (float) * fmt.channels);
                    sz = n;
                }
                else if (fileinfo->fmt.bps != output_bps || fileinfo->fmt.is_float != output_is_float) {
                    ddb_waveformat_t outfmt;
                    memcpy (&outfmt, &fileinfo->fmt, sizeof (outfmt));
                    outfmt.bps = output_bps;
                    outfmt.is_float = output_is_float;
                    outfmt.channels = outch;
                    outfmt.samplerate = outsr;

                    int frames = sz / samplesize;
                    int n = deadbeef->pcm_convert (&fileinfo->fmt, buffer, &outfmt, dspbuffer, frames * samplesize);
                    memcpy (buffer, dspbuffer, n);
                    sz = n;
                }
                outsize += sz;

                if (!header_written) {
                    uint64_t size = (int64_t)(it->endsample-it->startsample) * outch * output_bps / 8;
                    if (!size) {
                        size = (double)deadbeef->pl_get_item_duration (it) * fileinfo->fmt.samplerate * outch * output_bps / 8;

                    }

                    if (outsr != fileinfo->fmt.samplerate) {
                        uint64_t temp = size;
                        temp *= outsr;
                        temp /= fileinfo->fmt.samplerate;
                        size  = temp;
                    }

                    uint64_t chunksize;
                    chunksize = size + 40;

                    // for float, add 36 more
                    if (output_is_float) {
                        chunksize += 36;
                    }

                    uint32_t size32 = 0xffffffff;
                    if (chunksize <= 0xffffffff) {
                        size32 = chunksize;
                    }
                    memcpy (&wavehdr[4], &size32, 4);
                    memcpy (&wavehdr[22], &outch, 2);
                    memcpy (&wavehdr[24], &outsr, 4);
                    uint16_t blockalign = outch * output_bps / 8;
                    memcpy (&wavehdr[32], &blockalign, 2);
                    memcpy (&wavehdr[34], &output_bps, 2);

                    size32 = 0xffffffff;
                    if (size <= 0xffffffff) {
                        size32 = size;
                    }

                    if (wavehdr_size != write (temp_file, wavehdr, wavehdr_size)) {
                        fprintf (stderr, "converter: wave header write error\n");
                        goto error;
                    }
                    if (encoder_preset->method == DDB_ENCODER_METHOD_PIPE) {
                        size32 = 0;
                    }
                    if (write (temp_file, &size32, sizeof (size32)) != sizeof (size32)) {
                        fprintf (stderr, "converter: wave header size write error\n");
                        goto error;
                    }
                    header_written = 1;
                }

                int64_t res = write (temp_file, buffer, sz);
                if (sz != res) {
                    fprintf (stderr, "converter: write error (%"PRId64" bytes written out of %d)\n", res, sz);
                    goto error;
                }
            }
            if (abort && *abort) {
                goto error;
            }
            if (temp_file != -1 && (!enc_pipe || temp_file != fileno (enc_pipe))) {
                lseek (temp_file, wavehdr_size, SEEK_SET);
                if (4 != write (temp_file, &outsize, 4)) {
                    fprintf (stderr, "converter: data size write error\n");
                    goto error;
                }

                if (temp_file != -1 && (!enc_pipe || temp_file != fileno (enc_pipe))) {
                    close (temp_file);
                    temp_file = -1;
                }
            }

            if (encoder_preset->encoder[0] && encoder_preset->method == DDB_ENCODER_METHOD_FILE) {
                enc_pipe = popen (enc, "w");
            }
        }
    }
    err = 0;
error:
    if (buffer) {
        free (buffer);
        buffer = NULL;
    }
    if (dspbuffer) {
        free (dspbuffer);
        dspbuffer = NULL;
    }
    if (temp_file != -1 && (!enc_pipe || temp_file != fileno (enc_pipe))) {
        close (temp_file);
        temp_file = -1;
    }
    if (enc_pipe) {
        pclose (enc_pipe);
        enc_pipe = NULL;
    }
    if (dec && fileinfo) {
        dec->free (fileinfo);
        fileinfo = NULL;
    }
    if (abort && *abort && out[0]) {
        unlink (out);
    }
    if (input_file_name[0] && strcmp (input_file_name, "-")) {
        unlink (input_file_name);
    }
    if (err != 0) {
        return err;
    }

    // write junklib tags

    DB_playItem_t *out_it = NULL;

    if (encoder_preset->tag_id3v2 || encoder_preset->tag_id3v1 || encoder_preset->tag_apev2 || encoder_preset->tag_flac || encoder_preset->tag_oggvorbis) {
        out_it = deadbeef->pl_item_alloc ();
        deadbeef->pl_item_copy (out_it, it);
        deadbeef->pl_set_item_flags (out_it, 0);
        DB_metaInfo_t *m = deadbeef->pl_get_metadata_head (out_it);
        while (m) {
            DB_metaInfo_t *next = m->next;
            if (m->key[0] == ':' || m->key[0] == '!' || !strcasecmp (m->key, "cuesheet")) {
                deadbeef->pl_delete_metadata (out_it, m);
            }
            m = next;
        }
        deadbeef->pl_replace_meta (out_it, ":URI", out);
    }

    uint32_t tagflags = 0;
    if (encoder_preset->tag_id3v2) {
        tagflags |= JUNK_WRITE_ID3V2;
    }
    if (encoder_preset->tag_id3v1) {
        tagflags |= JUNK_WRITE_ID3V1;
    }
    if (encoder_preset->tag_apev2) {
        tagflags |= JUNK_WRITE_APEV2;
    }

    if (tagflags) {
        tagflags |= JUNK_STRIP_ID3V2 | JUNK_STRIP_APEV2 | JUNK_STRIP_ID3V1;
        deadbeef->junk_rewrite_tags (out_it, tagflags, encoder_preset->id3v2_version + 3, "iso8859-1");
    }

    // write flac tags
    if (encoder_preset->tag_flac) {
        // find flac decoder plugin
        DB_decoder_t **plugs = deadbeef->plug_get_decoder_list ();
        DB_decoder_t *flac = NULL;
        for (int i = 0; plugs[i]; i++) {
            if (!strcmp (plugs[i]->plugin.id, "stdflac")) {
                flac = plugs[i];
                break;
            }
        }
        if (!flac) {
            fprintf (stderr, "converter: flac plugin not found, cannot write flac metadata\n");
        }
        else {
            if (0 != flac->write_metadata (out_it)) {
                fprintf (stderr, "converter: failed to write flac metadata, not a flac file?\n");
            }
        }
    }

    // write vorbis tags
    if (encoder_preset->tag_oggvorbis) {
        // find flac decoder plugin
        DB_decoder_t **plugs = deadbeef->plug_get_decoder_list ();
        int res = -1;
        for (int i = 0; plugs[i]; i++) {
            if (!strcmp (plugs[i]->plugin.id, "stdogg")
                    || !strcmp (plugs[i]->plugin.id, "stdopus")) {
                res = plugs[i]->write_metadata (out_it);
                if (!res) {
                    break;
                }
            }
        }
        if (res) {
            fprintf (stderr, "converter: failed to write ogg metadata, not an ogg file?\n");
        }
    }
    if (out_it) {
        deadbeef->pl_item_unref (out_it);
    }

    return err;
}
Пример #10
0
int
convert (DB_playItem_t *it, const char *outfolder, const char *outfile, int output_bps, int output_is_float, int preserve_folder_structure, const char *root_folder, ddb_encoder_preset_t *encoder_preset, ddb_dsp_preset_t *dsp_preset, int *abort) {
    if (deadbeef->pl_get_item_duration (it) <= 0) {
        deadbeef->pl_lock ();
        const char *fname = deadbeef->pl_find_meta (it, ":URI");
        fprintf (stderr, "converter: stream %s doesn't have finite length, skipped\n", fname);
        deadbeef->pl_unlock ();
        return -1;
    }

    char *path = outfolder[0] ? strdupa (outfolder) : strdupa (getenv("HOME"));
    if (!check_dir (path, 0755)) {
        fprintf (stderr, "converter: failed to create output folder: %s\n", outfolder);
        return -1;
    }

    int err = -1;
    FILE *enc_pipe = NULL;
    FILE *temp_file = NULL;
    DB_decoder_t *dec = NULL;
    DB_fileinfo_t *fileinfo = NULL;
    char out[PATH_MAX] = ""; // full path to output file
    char input_file_name[PATH_MAX] = "";
    dec = (DB_decoder_t *)deadbeef->plug_get_for_id (deadbeef->pl_find_meta (it, ":DECODER"));

    if (dec) {
        fileinfo = dec->open (0);
        if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (it)) != 0) {
            deadbeef->pl_lock ();
            fprintf (stderr, "converter: failed to decode file %s\n", deadbeef->pl_find_meta (it, ":URI"));
            deadbeef->pl_unlock ();
            goto error;
        }
        if (fileinfo) {
            if (output_bps == -1) {
                output_bps = fileinfo->fmt.bps;
                output_is_float = fileinfo->fmt.is_float;
            }

            get_output_path (it, outfolder, outfile, encoder_preset, out, sizeof (out));
            if (encoder_preset->method == DDB_ENCODER_METHOD_FILE) {
                const char *tmp = getenv ("TMPDIR");
                if (!tmp) {
                    tmp = "/tmp";
                }
                snprintf (input_file_name, sizeof (input_file_name), "%s/ddbconvXXXXXX", tmp);
                mktemp (input_file_name);
                strcat (input_file_name, ".wav");
            }
            else {
                strcpy (input_file_name, "-");
            }

            char enc[2000];
            memset (enc, 0, sizeof (enc));

            // formatting: %o = outfile, %i = infile
            char *e = encoder_preset->encoder;
            char *o = enc;
            *o = 0;
            int len = sizeof (enc);
            while (e && *e) {
                if (len <= 0) {
                    fprintf (stderr, "converter: failed to assemble encoder command line - buffer is not big enough, try to shorten your parameters. max allowed length is %u characters\n", (unsigned)sizeof (enc));
                    goto error;
                }
                if (e[0] == '%' && e[1]) {
                    if (e[1] == 'o') {
                        int l = snprintf (o, len, "\"%s\"", out);
                        o += l;
                        len -= l;
                    }
                    else if (e[1] == 'i') {
                        int l = snprintf (o, len, "\"%s\"", input_file_name);
                        o += l;
                        len -= l;
                    }
                    else {
                        strncpy (o, e, 2);
                        o += 2;
                        len -= 2;
                    }
                    e += 2;
                }
                else {
                    *o++ = *e++;
                    *o = 0;
                    len--;
                }
            }

            fprintf (stderr, "converter: will encode using: %s\n", enc[0] ? enc : "internal RIFF WAVE writer");

            if (!encoder_preset->encoder[0]) {
                // write to wave file
                temp_file = fopen (out, "w+b");
                if (!temp_file) {
                    fprintf (stderr, "converter: failed to open output wave file %s\n", out);
                    goto error;
                }
            }
            else if (encoder_preset->method == DDB_ENCODER_METHOD_FILE) {
                temp_file = fopen (input_file_name, "w+b");
                if (!temp_file) {
                    fprintf (stderr, "converter: failed to open temp file %s\n", input_file_name);
                    goto error;
                }
            }
            else {
                enc_pipe = popen (enc, "w");
                if (!enc_pipe) {
                    fprintf (stderr, "converter: failed to open encoder\n");
                    goto error;
                }
            }

            if (!temp_file) {
                temp_file = enc_pipe;
            }

            // write wave header
            char wavehdr_int[] = {
                0x52, 0x49, 0x46, 0x46, 0x24, 0x70, 0x0d, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61
            };
            char wavehdr_float[] = {
                0x52, 0x49, 0x46, 0x46, 0x2a, 0xdf, 0x02, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x28, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x02, 0x00, 0x40, 0x1f, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x16, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71, 0x66, 0x61, 0x63, 0x74, 0x04, 0x00, 0x00, 0x00, 0xc5, 0x5b, 0x00, 0x00, 0x64, 0x61, 0x74, 0x61
            };
            char *wavehdr = output_is_float ? wavehdr_float : wavehdr_int;
            int wavehdr_size = output_is_float ? sizeof (wavehdr_float) : sizeof (wavehdr_int);
            int header_written = 0;
            uint32_t outsize = 0;
            uint32_t outsr = fileinfo->fmt.samplerate;
            uint16_t outch = fileinfo->fmt.channels;

            int samplesize = fileinfo->fmt.channels * fileinfo->fmt.bps / 8;
            int bs = 10250 * samplesize;
            char buffer[bs * 4];
            int dspsize = bs / samplesize * sizeof (float) * fileinfo->fmt.channels;
            char dspbuffer[dspsize * 4];
            int eof = 0;
            for (;;) {
                if (eof) {
                    break;
                }
                if (abort && *abort) {
                    break;
                }
                int sz = dec->read (fileinfo, buffer, bs);

                if (sz != bs) {
                    eof = 1;
                }
                if (dsp_preset) {
                    ddb_waveformat_t fmt;
                    ddb_waveformat_t outfmt;
                    memcpy (&fmt, &fileinfo->fmt, sizeof (fmt));
                    memcpy (&outfmt, &fileinfo->fmt, sizeof (fmt));
                    fmt.bps = 32;
                    fmt.is_float = 1;
                    deadbeef->pcm_convert (&fileinfo->fmt, buffer, &fmt, dspbuffer, sz);

                    ddb_dsp_context_t *dsp = dsp_preset->chain;
                    int frames = sz / samplesize;
                    while (dsp) {
                        frames = dsp->plugin->process (dsp, (float *)dspbuffer, frames, sizeof (dspbuffer) / (fmt.channels * 4), &fmt, NULL);
                        dsp = dsp->next;
                    }

                    outsr = fmt.samplerate;
                    outch = fmt.channels;

                    outfmt.bps = output_bps;
                    outfmt.is_float = output_is_float;
                    outfmt.channels = outch;
                    outfmt.samplerate = outsr;

                    int n = deadbeef->pcm_convert (&fmt, dspbuffer, &outfmt, buffer, frames * sizeof (float) * fmt.channels);
                    sz = n;
                }
                else if (fileinfo->fmt.bps != output_bps || fileinfo->fmt.is_float != output_is_float) {
                    ddb_waveformat_t outfmt;
                    memcpy (&outfmt, &fileinfo->fmt, sizeof (outfmt));
                    outfmt.bps = output_bps;
                    outfmt.is_float = output_is_float;
                    outfmt.channels = outch;
                    outfmt.samplerate = outsr;

                    int frames = sz / samplesize;
                    int n = deadbeef->pcm_convert (&fileinfo->fmt, buffer, &outfmt, dspbuffer, frames * samplesize);
                    memcpy (buffer, dspbuffer, n);
                    sz = n;
                }
                outsize += sz;

                if (!header_written) {
                    uint32_t size = (it->endsample-it->startsample) * outch * output_bps / 8;
                    if (!size) {
                        size = deadbeef->pl_get_item_duration (it) * fileinfo->fmt.samplerate * outch * output_bps / 8;

                    }

                    if (outsr != fileinfo->fmt.samplerate) {
                        uint64_t temp = size;
                        temp *= outsr;
                        temp /= fileinfo->fmt.samplerate;
                        size  = temp;
                    }

                    memcpy (&wavehdr[22], &outch, 2);
                    memcpy (&wavehdr[24], &outsr, 4);
                    uint16_t blockalign = outch * output_bps / 8;
                    memcpy (&wavehdr[32], &blockalign, 2);
                    memcpy (&wavehdr[34], &output_bps, 2);

                    fwrite (wavehdr, 1, wavehdr_size, temp_file);
                    if (encoder_preset->method == DDB_ENCODER_METHOD_PIPE) {
                        size = 0;
                    }
                    fwrite (&size, 1, sizeof (size), temp_file);
                    header_written = 1;
                }

                int64_t res = fwrite (buffer, 1, sz, temp_file);
                if (sz != res) {
                    fprintf (stderr, "converter: write error (%lld bytes written out of %d)\n", res, sz);
                    goto error;
                }
            }
            if (abort && *abort) {
                goto error;
            }
            if (temp_file && temp_file != enc_pipe) {
                fseek (temp_file, wavehdr_size, SEEK_SET);
                fwrite (&outsize, 1, 4, temp_file);

                fclose (temp_file);
                temp_file = NULL;
            }

            if (encoder_preset->encoder[0] && encoder_preset->method == DDB_ENCODER_METHOD_FILE) {
                enc_pipe = popen (enc, "w");
            }
        }
    }
    err = 0;
error:
    if (temp_file && temp_file != enc_pipe) {
        fclose (temp_file);
        temp_file = NULL;
    }
    if (enc_pipe) {
        pclose (enc_pipe);
        enc_pipe = NULL;
    }
    if (dec && fileinfo) {
        dec->free (fileinfo);
        fileinfo = NULL;
    }
    if (abort && *abort && out[0]) {
        unlink (out);
    }
    if (input_file_name[0] && strcmp (input_file_name, "-")) {
        unlink (input_file_name);
    }

    // write junklib tags
    uint32_t tagflags = JUNK_STRIP_ID3V2 | JUNK_STRIP_APEV2 | JUNK_STRIP_ID3V1;
    if (encoder_preset->tag_id3v2) {
        tagflags |= JUNK_WRITE_ID3V2;
    }
    if (encoder_preset->tag_id3v1) {
        tagflags |= JUNK_WRITE_ID3V1;
    }
    if (encoder_preset->tag_apev2) {
        tagflags |= JUNK_WRITE_APEV2;
    }
    DB_playItem_t *out_it = deadbeef->pl_item_alloc ();
    deadbeef->pl_item_copy (out_it, it);
    deadbeef->pl_replace_meta (out_it, ":URI", out);
    deadbeef->pl_delete_meta (out_it, "cuesheet");

    deadbeef->junk_rewrite_tags (out_it, tagflags, encoder_preset->id3v2_version + 3, "iso8859-1");

    // write flac tags
    if (encoder_preset->tag_flac) {
        // find flac decoder plugin
        DB_decoder_t **plugs = deadbeef->plug_get_decoder_list ();
        DB_decoder_t *flac = NULL;
        for (int i = 0; plugs[i]; i++) {
            if (!strcmp (plugs[i]->plugin.id, "stdflac")) {
                flac = plugs[i];
                break;
            }
        }
        if (!flac) {
            fprintf (stderr, "converter: flac plugin not found, cannot write flac metadata\n");
        }
        else {
            if (0 != flac->write_metadata (out_it)) {
                fprintf (stderr, "converter: failed to write flac metadata, not a flac file?\n");
            }
        }
    }

    // write vorbis tags
    if (encoder_preset->tag_oggvorbis) {
        // find flac decoder plugin
        DB_decoder_t **plugs = deadbeef->plug_get_decoder_list ();
        DB_decoder_t *ogg = NULL;
        for (int i = 0; plugs[i]; i++) {
            if (!strcmp (plugs[i]->plugin.id, "stdogg")) {
                ogg = plugs[i];
                break;
            }
        }
        if (!ogg) {
            fprintf (stderr, "converter: ogg plugin not found, cannot write ogg metadata\n");
        }
        else {
            if (0 != ogg->write_metadata (out_it)) {
                fprintf (stderr, "converter: failed to write ogg metadata, not an ogg file?\n");
            }
        }
    }

    deadbeef->pl_item_unref (out_it);


    return err;
}
Пример #11
0
void
rg_calc_thread(void *ctx) {
    DB_decoder_t *dec = NULL;
    DB_fileinfo_t *fileinfo = NULL;

    char *buffer = NULL;
    char *bufferf = NULL;

    track_state_t *st = (track_state_t *)ctx;
    if (st->settings->pabort && *(st->settings->pabort)) {
        return;
    }
    if (deadbeef->pl_get_item_duration (st->settings->tracks[st->track_index]) <= 0) {
        st->settings->results[st->track_index].scan_result = DDB_RG_SCAN_RESULT_INVALID_FILE;
        return;
    }


    deadbeef->pl_lock ();
    dec = (DB_decoder_t *)deadbeef->plug_get_for_id (deadbeef->pl_find_meta (st->settings->tracks[st->track_index], ":DECODER"));
    deadbeef->pl_unlock ();

    if (dec) {
        fileinfo = dec->open (DDB_DECODER_HINT_RAW_SIGNAL);

        if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (st->settings->tracks[st->track_index])) != 0) {
            st->settings->results[st->track_index].scan_result = DDB_RG_SCAN_RESULT_FILE_NOT_FOUND;
            goto error;
        }

        if (fileinfo) {
            st->gain_state[st->track_index] = ebur128_init(fileinfo->fmt.channels, fileinfo->fmt.samplerate, EBUR128_MODE_I);
            st->peak_state[st->track_index] = ebur128_init(fileinfo->fmt.channels, fileinfo->fmt.samplerate, EBUR128_MODE_SAMPLE_PEAK);

            // speaker mask mapping from WAV to EBUR128
            static const int chmap[18] = {
                EBUR128_LEFT,
                EBUR128_RIGHT,
                EBUR128_CENTER,
                EBUR128_UNUSED,
                EBUR128_LEFT_SURROUND,
                EBUR128_RIGHT_SURROUND,
                EBUR128_LEFT_SURROUND,
                EBUR128_RIGHT_SURROUND,
                EBUR128_CENTER,
                EBUR128_LEFT_SURROUND,
                EBUR128_RIGHT_SURROUND,
                EBUR128_CENTER,
                EBUR128_LEFT_SURROUND,
                EBUR128_CENTER,
                EBUR128_RIGHT_SURROUND,
                EBUR128_LEFT_SURROUND,
                EBUR128_CENTER,
                EBUR128_RIGHT_SURROUND,
            };

            uint32_t channelmask = fileinfo->fmt.channelmask;

            // first 18 speaker positions are known, the rest will be marked as UNUSED
            int ch = 0;
            for (int i = 0; i < 32 && ch < fileinfo->fmt.channels; i++) {
                if (i < 18) {
                    if (channelmask & (1<<i))
                    {
                        ebur128_set_channel (st->gain_state[st->track_index], ch, chmap[i]);
                        ebur128_set_channel (st->peak_state[st->track_index], ch, chmap[i]);
                        ch++;
                    }
                }
                else {
                    ebur128_set_channel (st->gain_state[st->track_index], ch, EBUR128_UNUSED);
                    ebur128_set_channel (st->peak_state[st->track_index], ch, EBUR128_UNUSED);
                    ch++;
                }
            }

            int samplesize = fileinfo->fmt.channels * fileinfo->fmt.bps / 8;

            int bs = 2000 * samplesize;
            ddb_waveformat_t fmt;

            buffer = malloc (bs);

            if (!fileinfo->fmt.is_float) {
                bufferf = malloc (2000 * sizeof (float) * fileinfo->fmt.channels);
                memcpy (&fmt, &fileinfo->fmt, sizeof (fmt));
                fmt.bps = 32;
                fmt.is_float = 1;
            }
            else {
                bufferf = buffer;
            }

            int eof = 0;
            for (;;) {
                if (eof) {
                    break;
                }
                if (st->settings->pabort && *(st->settings->pabort)) {
                    break;
                }

                int sz = dec->read (fileinfo, buffer, bs); // read one block

                deadbeef->mutex_lock (st->settings->sync_mutex);
                int samplesize = fileinfo->fmt.channels * (fileinfo->fmt.bps >> 3);
                int numsamples = sz / samplesize;
                st->settings->cd_samples_processed += numsamples * 44100 / fileinfo->fmt.samplerate;
                deadbeef->mutex_unlock (st->settings->sync_mutex);

                if (sz != bs) {
                    eof = 1;
                }

                // convert from native output to float,
                // only if the input is not float already
                if (!fileinfo->fmt.is_float) {
                    deadbeef->pcm_convert (&fileinfo->fmt, buffer, &fmt, bufferf, sz);
                }

                int frames = sz / samplesize;

                ebur128_add_frames_float (st->gain_state[st->track_index], (float*) bufferf, frames); // collect data
                ebur128_add_frames_float (st->peak_state[st->track_index], (float*) bufferf, frames); // collect data
            }
        }

        if (!st->settings->pabort || !(*(st->settings->pabort))) {
            // calculating track peak
            // libEBUR128 calculates peak per channel, so we have to pick the highest value
            double tr_peak = 0;
            double ch_peak = 0;
            int res;
            for (int ch = 0; ch < fileinfo->fmt.channels; ++ch) {
                res = ebur128_sample_peak (st->peak_state[st->track_index], ch, &ch_peak);
                //trace ("rg_scanner: peak for ch %d: %f\n", ch, ch_peak);
                if (ch_peak > tr_peak) {
                    //trace ("rg_scanner: %f > %f\n", ch_peak, tr_peak);
                    tr_peak = ch_peak;
                }
            }

            st->settings->results[st->track_index].track_peak = (float) tr_peak;

            // calculate track loudness
            double loudness = st->settings->ref_loudness;
            ebur128_loudness_global (st->gain_state[st->track_index], &loudness);

            /*
             * EBUR128 sets the target level to -23 LUFS = 84dB
             * -> -23 - loudness = track gain to get to 84dB
             *
             * The old implementation of RG used 89dB, most people still use that
             * -> the above + (loudness - 84) = track gain to get to 89dB (or user specified)
             */
            st->settings->results[st->track_index].track_gain = -23 - loudness + st->settings->ref_loudness - 84;
        }
    }

error:
    // clean up
    if (fileinfo) {
        dec->free (fileinfo);
    }

    if (buffer && buffer != bufferf) {
        free (buffer);
        buffer = NULL;
    }

    if (bufferf) {
        free (bufferf);
        bufferf = NULL;
    }
}