Beispiel #1
0
static void analyze_audio( mlt_filter filter, void* buffer, int samples )
{
	mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
	private_data* pdata = (private_data*)filter->child;
	int result = -1;
	double loudness = 0.0;

	ebur128_add_frames_float( pdata->r128, buffer, samples );

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_program" ) )
	{
		result = ebur128_loudness_global( pdata->r128, &loudness );
		if( result == EBUR128_SUCCESS && loudness != HUGE_VAL && loudness != -HUGE_VAL )
		{
			mlt_properties_set_double( properties, "program", loudness );
		}
	}

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_shortterm" ) )
	{
		result = ebur128_loudness_shortterm( pdata->r128, &loudness );
		if( result == EBUR128_SUCCESS && loudness != HUGE_VAL && loudness != -HUGE_VAL )
		{
			mlt_properties_set_double( properties, "shortterm", loudness );
		}
	}

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_momentary" ) )
	{
		result = ebur128_loudness_momentary( pdata->r128, &loudness );
		if( result == EBUR128_SUCCESS && loudness != HUGE_VAL && loudness != -HUGE_VAL )
		{
			mlt_properties_set_double( properties, "momentary", loudness );
		}
	}

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_range" ) )
	{
		double range = 0;
		result = ebur128_loudness_range( pdata->r128, &range );
		if( result == EBUR128_SUCCESS && range != HUGE_VAL && range != -HUGE_VAL )
		{
			mlt_properties_set_double( properties, "range", range );
		}
	}

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_peak" ) )
	{
		double prev_peak = 0.0;
		double max_peak = 0.0;
		int c = 0;
		for( c = 0; c < pdata->r128->channels; c++ )
		{
			double peak;
			result = ebur128_sample_peak( pdata->r128, c, &peak );
			if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > max_peak )
			{
				max_peak = peak;
			}
			result = ebur128_prev_sample_peak( pdata->r128, c, &peak );
			if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > prev_peak )
			{
				prev_peak = peak;
			}
		}
		mlt_properties_set_double( properties, "max_peak", 20 * log10(max_peak) );
		mlt_properties_set_double( properties, "peak", 20 * log10(prev_peak) );
	}

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_true_peak" ) )
	{
		double prev_peak = 0.0;
		double max_peak = 0.0;
		int c = 0;
		for( c = 0; c < pdata->r128->channels; c++ )
		{
			double peak;
			result = ebur128_true_peak( pdata->r128, c, &peak );
			if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > max_peak )
			{
				max_peak = peak;
			}
			result = ebur128_prev_true_peak( pdata->r128, c, &peak );
			if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > prev_peak )
			{
				prev_peak = peak;
			}
		}
		mlt_properties_set_double( properties, "max_true_peak", 20 * log10(max_peak) );
		mlt_properties_set_double( properties, "true_peak", 20 * log10(prev_peak) );
	}

	mlt_properties_set_position( properties, "frames_processed", mlt_properties_get_position( properties, "frames_processed" ) + 1 );
}
Beispiel #2
0
void TrackScanner::run()
{
    bool ffmpegIsFloat=false;
    #ifdef FFMPEG_FOUND
    FfmpegInput *ffmpeg=new FfmpegInput(file);
    if (*ffmpeg) {
        input=ffmpeg;
        ffmpegIsFloat=ffmpeg->isFloatCodec();
    } else {
        delete ffmpeg;
        ffmpeg=0;
    }
    #endif

    #if MPG123_FOUND
    if (file.endsWith(".mp3", Qt::CaseInsensitive) && (!input || !ffmpegIsFloat)) {
        Mpg123Input *mpg123=new Mpg123Input(file);
        if (*mpg123) {
            input=mpg123;
            #ifdef FFMPEG_FOUND
            if (ffmpeg) {
                delete ffmpeg;
            }
            #endif
        } else {
            delete mpg123;
        }
    }
    #endif

    if (!input) {
        setFinishedStatus(false);
        return;
    }

    state=ebur128_init(input->channels(), input->sampleRate(), EBUR128_MODE_M|EBUR128_MODE_I|EBUR128_MODE_SAMPLE_PEAK);

    int *channelMap=new int [state->channels];
    if (input->setChannelMap(channelMap)) {
        for (unsigned int i = 0; i < state->channels; ++i) {
            ebur128_set_channel(state, i, channelMap[i]);
        }
    }

    delete [] channelMap;

    //if (1==state->channels && opts->force_dual_mono) {
    //    ebur128_set_channel(state, 0, EBUR128_DUAL_MONO);
    //}

    size_t numFramesRead=0;
    size_t totalRead=0;
    input->allocateBuffer();
    while ((numFramesRead = input->readFrames())) {
        if (abortRequested) {
            setFinishedStatus(false);
            return;
        }
        totalRead+=numFramesRead;
        emit progress((int)((totalRead*100.0/input->totalFrames())+0.5));
        if (ebur128_add_frames_float(state, input->buffer(), numFramesRead)) {
            setFinishedStatus(false);
            return;
        }
    }

    if (abortRequested) {
        setFinishedStatus(false);
        return;
    }

    ebur128_loudness_global(state, &data.loudness);
//     if (opts->lra) {
//         result = ebur128_loudness_range(ebur, &lra);
//         if (result) abort();
//     }

    if (EBUR128_MODE_SAMPLE_PEAK==(state->mode & EBUR128_MODE_SAMPLE_PEAK)) {
        for (unsigned i = 0; i < state->channels; ++i) {
            double sp;
            ebur128_sample_peak(state, i, &sp);
            if (sp > data.peak) {
                data.peak = sp;
            }
        }
    }
    if (EBUR128_MODE_TRUE_PEAK==(state->mode & EBUR128_MODE_TRUE_PEAK)) {
        for (unsigned i = 0; i < state->channels; ++i) {
            double tp;
            ebur128_true_peak(state, i, &tp);
            if (tp > data.truePeak) {
                data.truePeak = tp;
            }
        }
    }
    setFinishedStatus(true);
}
Beispiel #3
0
void init_state_and_scan_work_item(struct filename_list_node *fln, struct scan_opts *opts)
{
    struct file_data *fd = (struct file_data *) fln->d;

    struct input_ops* ops = NULL;
    struct input_handle* ih = NULL;
    int r128_mode = EBUR128_MODE_I;
    unsigned int i;
    int *channel_map;

    int result;
    float *buffer = NULL;
    size_t nr_frames_read;

#ifdef USE_SNDFILE
    SNDFILE *outfile = NULL;
#endif

    result = open_plugin(fln->fr->raw, fln->fr->display, &ops, &ih);
    if (result) {
        g_mutex_lock(progress_mutex);
        elapsed_frames += fd->number_of_frames;
        g_cond_broadcast(progress_cond);
        g_mutex_unlock(progress_mutex);
        goto free;
    }

    if (opts->lra)
        r128_mode |= EBUR128_MODE_LRA;
    if (opts->peak) {
        if (!strcmp(opts->peak, "sample") || !strcmp(opts->peak, "all"))
            r128_mode |= EBUR128_MODE_SAMPLE_PEAK;
#ifdef USE_SPEEX_RESAMPLER
        if (!strcmp(opts->peak, "true") || !strcmp(opts->peak, "dbtp") ||
            !strcmp(opts->peak, "all"))
            r128_mode |= EBUR128_MODE_TRUE_PEAK;
#endif
    }
    if (opts->histogram)
        r128_mode |= EBUR128_MODE_HISTOGRAM;

    fd->st = ebur128_init(ops->get_channels(ih),
                          ops->get_samplerate(ih),
                          r128_mode);

    channel_map = g_malloc(fd->st->channels * sizeof(int));
    if (!ops->set_channel_map(ih, channel_map)) {
        for (i = 0; i < fd->st->channels; ++i) {
            ebur128_set_channel(fd->st, i, channel_map[i]);
        }
    }
    free(channel_map);

    if (fd->st->channels == 1 && opts->force_dual_mono) {
        ebur128_set_channel(fd->st, 0, EBUR128_DUAL_MONO);
    }

    result = ops->allocate_buffer(ih);
    if (result) abort();
    buffer = ops->get_buffer(ih);

#ifdef USE_SNDFILE
    if (opts->decode_file) {
        SF_INFO sf_info;
        memset(&sf_info, '\0', sizeof sf_info);
        sf_info.samplerate = (int) fd->st->samplerate;
        sf_info.channels = (int) fd->st->channels;
        sf_info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
        outfile = sf_open(opts->decode_file, SFM_WRITE, &sf_info);
        if (!outfile) {
            fprintf(stderr, "output file could not be opened\n");
            exit(EXIT_FAILURE);
        }
    }
#endif

    while ((nr_frames_read = ops->read_frames(ih))) {
        g_mutex_lock(progress_mutex);
        elapsed_frames += nr_frames_read;
        g_cond_broadcast(progress_cond);
        g_mutex_unlock(progress_mutex);
        fd->number_of_elapsed_frames += nr_frames_read;
        result = ebur128_add_frames_float(fd->st, buffer, nr_frames_read);
#ifdef USE_SNDFILE
        if (opts->decode_file) {
            if (sf_writef_float(outfile, buffer, (sf_count_t) nr_frames_read) != (sf_count_t) nr_frames_read)
                sf_perror(outfile);
        }
#endif
        if (result) abort();
    }

#ifdef USE_SNDFILE
    if (opts->decode_file) {
        sf_close(outfile);
    }
#endif

    if (fd->number_of_elapsed_frames != fd->number_of_frames) {
        if (verbose) {
            fprintf(stderr, "Warning: Could not read full file"
                            " or determine right length: "
                            "Expected: %lu Got: %lu",
                            fd->number_of_frames, fd->number_of_elapsed_frames);
        }
        g_mutex_lock(progress_mutex);
        total_frames = total_frames + fd->number_of_elapsed_frames - fd->number_of_frames;
        g_cond_broadcast(progress_cond);
        g_mutex_unlock(progress_mutex);
    }
    ebur128_loudness_global(fd->st, &fd->loudness);
    if (opts->lra) {
        result = ebur128_loudness_range(fd->st, &fd->lra);
        if (result) abort();
    }

    if ((fd->st->mode & EBUR128_MODE_SAMPLE_PEAK) == EBUR128_MODE_SAMPLE_PEAK) {
        for (i = 0; i < fd->st->channels; ++i) {
            double sp;
            ebur128_sample_peak(fd->st, i, &sp);
            if (sp > fd->peak) {
                fd->peak = sp;
            }
        }
    }
#ifdef USE_SPEEX_RESAMPLER
    if ((fd->st->mode & EBUR128_MODE_TRUE_PEAK) == EBUR128_MODE_TRUE_PEAK) {
        for (i = 0; i < fd->st->channels; ++i) {
            double tp;
            ebur128_true_peak(fd->st, i, &tp);
            if (tp > fd->true_peak) {
                fd->true_peak = tp;
            }
        }
    }
#endif
    fd->scanned = TRUE;

    if (ih) ops->free_buffer(ih);
  free:
    if (!result) ops->close_file(ih);
    if (ih) ops->handle_destroy(&ih);
}
Beispiel #4
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;
    }
}