int audio_init(context_t *context) { int rc = 0; static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 1 }; int error; daemon_log(LOG_INFO, "Opening %s for input", context->input_device ?: "default source"); context->pa_input = pa_simple_new(NULL, "shusherd", PA_STREAM_RECORD, context->input_device, "record", &ss, NULL, NULL, &error); if (!context->pa_input) { daemon_log(LOG_ERR, "pa_simple_new failed: %s", pa_strerror(error)); assert(context->pa_input); } context->ebur128_state = ebur128_init(ss.channels, ss.rate, EBUR128_MODE_S); assert(context->ebur128_state); context->enable_processing = 1; rc = pthread_create(&context->audio_thread, NULL, audio_loop, (void *)context); if (rc) { daemon_log(LOG_ERR, "Unable to create audio thread: %d", rc); goto cleanup_ebur128_state; } return 0; cleanup_ebur128_state: ebur128_destroy(&context->ebur128_state); return rc; } void audio_destroy(context_t *context) { context->enable_processing = 0; pthread_join(context->audio_thread, NULL); ebur128_destroy(&context->ebur128_state); pa_simple_free(context->pa_input); }
static void check_for_reset( mlt_filter filter, int channels, int frequency ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); private_data* pdata = (private_data*)filter->child; if( pdata->reset ) { if( pdata->r128 ) { ebur128_destroy( &pdata->r128 ); } pdata->r128 = 0; pdata->target_gain = 0.0; pdata->start_gain = 0.0; pdata->end_gain = 0.0; pdata->reset = 0; pdata->time_elapsed_ms = 0; pdata->prev_o_pos = -1; mlt_properties_set_double( properties, "out_gain", 0.0 ); mlt_properties_set_double( properties, "in_loudness", -100.0 ); mlt_properties_set_int( properties, "reset_count", mlt_properties_get_int( properties, "reset_count") + 1 ); } if( !pdata->r128 ) { pdata->r128 = ebur128_init( channels, frequency, EBUR128_MODE_I ); ebur128_set_max_window( pdata->r128, 400 ); ebur128_set_max_history( pdata->r128, mlt_properties_get_int( properties, "window" ) * 1000.0 ); } }
TrackScanner::~TrackScanner() { delete input; if (state) { ebur128_destroy(&state); state=0; } }
void destroy_state(struct filename_list_node *fln, gpointer unused) { struct file_data *fd = (struct file_data *) fln->d; (void) unused; if (fd->st) { ebur128_destroy(&fd->st); } }
/** @This frees a upipe. * * @param upipe description structure of the pipe */ static void upipe_filter_ebur128_free(struct upipe *upipe) { struct upipe_filter_ebur128 *upipe_filter_ebur128 = upipe_filter_ebur128_from_upipe(upipe); if (likely(upipe_filter_ebur128->st)) { ebur128_destroy(&upipe_filter_ebur128->st); } upipe_throw_dead(upipe); upipe_filter_ebur128_clean_output(upipe); upipe_filter_ebur128_clean_urefcount(upipe); upipe_filter_ebur128_free_void(upipe); }
double test_true_peak(const char* filename) { SF_INFO file_info; SNDFILE* file; sf_count_t nr_frames_read; int i; ebur128_state* st = NULL; double true_peak; double max_true_peak = -HUGE_VAL; double* buffer; memset(&file_info, '\0', sizeof(file_info)); file = sf_open(filename, SFM_READ, &file_info); if (!file) { fprintf(stderr, "Could not open file %s!\n", filename); return 0.0; } st = ebur128_init((unsigned) file_info.channels, (unsigned) file_info.samplerate, EBUR128_MODE_TRUE_PEAK); if (file_info.channels == 5) { ebur128_set_channel(st, 0, EBUR128_LEFT); ebur128_set_channel(st, 1, EBUR128_RIGHT); ebur128_set_channel(st, 2, EBUR128_CENTER); ebur128_set_channel(st, 3, EBUR128_LEFT_SURROUND); ebur128_set_channel(st, 4, EBUR128_RIGHT_SURROUND); } buffer = (double*) malloc(st->samplerate * st->channels * sizeof(double)); while ((nr_frames_read = sf_readf_double(file, buffer, (sf_count_t) st->samplerate))) { ebur128_add_frames_double(st, buffer, (size_t) nr_frames_read); } for (i = 0; i < file_info.channels; i++) { ebur128_true_peak(st, (unsigned)i, &true_peak); if (true_peak > max_true_peak) max_true_peak = true_peak; } /* clean up */ ebur128_destroy(&st); free(buffer); buffer = NULL; if (sf_close(file)) { fprintf(stderr, "Could not close input file!\n"); } return 20 * log10(max_true_peak); }
static void filter_close( mlt_filter filter ) { private_data* pdata = (private_data*)filter->child; if( pdata ) { if( pdata->r128 ) { ebur128_destroy( &pdata->r128 ); } free( pdata ); } filter->child = NULL; filter->close = NULL; filter->parent.close = NULL; mlt_service_close( &filter->parent ); }
double test_global_loudness(const char* filename) { SF_INFO file_info; SNDFILE* file; sf_count_t nr_frames_read; ebur128_state* st = NULL; double gated_loudness; double* buffer; memset(&file_info, '\0', sizeof(file_info)); file = sf_open(filename, SFM_READ, &file_info); if (!file) { fprintf(stderr, "Could not open file %s!\n", filename); return 0.0; } st = ebur128_init((unsigned) file_info.channels, (unsigned) file_info.samplerate, EBUR128_MODE_I); if (file_info.channels == 5) { ebur128_set_channel(st, 0, EBUR128_LEFT); ebur128_set_channel(st, 1, EBUR128_RIGHT); ebur128_set_channel(st, 2, EBUR128_CENTER); ebur128_set_channel(st, 3, EBUR128_LEFT_SURROUND); ebur128_set_channel(st, 4, EBUR128_RIGHT_SURROUND); } buffer = (double*) malloc(st->samplerate * st->channels * sizeof(double)); while ((nr_frames_read = sf_readf_double(file, buffer, (sf_count_t) st->samplerate))) { ebur128_add_frames_double(st, buffer, (size_t) nr_frames_read); } ebur128_loudness_global(st, &gated_loudness); /* clean up */ ebur128_destroy(&st); free(buffer); buffer = NULL; if (sf_close(file)) { fprintf(stderr, "Could not close input file!\n"); } return gated_loudness; }
int main(int ac, const char* av[]) { SF_INFO file_info; SNDFILE* file; sf_count_t nr_frames_read; ebur128_state* state = NULL; double* buffer; double loudness; if (ac != 2) { exit(1); //ERROR CODE 1: Exactly one input file is expected. } state = malloc((size_t) sizeof(ebur128_state*)); memset(&file_info, '\0', sizeof(file_info)); file = sf_open(av[1], SFM_READ, &file_info); state = ebur128_init((unsigned) file_info.channels, (unsigned) file_info.samplerate, EBUR128_MODE_I); buffer = (double*) malloc(state->samplerate * state->channels * sizeof(double)); while ((nr_frames_read = sf_readf_double(file, buffer, (sf_count_t) state->samplerate))) { ebur128_add_frames_double(state, buffer, (size_t) nr_frames_read); } ebur128_loudness_global(state, &loudness); fprintf(stdout, "%.2f\n", loudness); free(buffer); buffer = NULL; if (sf_close(file)) { exit(2); //ERROR CODE 2: File wasn't able to be closed. } ebur128_destroy(&state); free(state); return 0; // ERROR CODE 0: No errors! }
static void check_for_reset( mlt_filter filter, int channels, int frequency ) { mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); private_data* pdata = (private_data*)filter->child; if( pdata->reset ) { if( pdata->r128 ) { ebur128_destroy( &pdata->r128 ); } pdata->r128 = 0; pdata->reset = 0; pdata->prev_pos = -1; mlt_events_block( properties, filter ); mlt_properties_set( properties, "frames_processed", "0" ); mlt_properties_set( properties, "program", "-100.0" ); mlt_properties_set( properties, "shortterm", "-100.0" ); mlt_properties_set( properties, "momentary", "-100.0" ); mlt_properties_set( properties, "range", "-1.0" ); mlt_properties_set_int( properties, "reset_count", mlt_properties_get_int( properties, "reset_count") + 1 ); mlt_properties_set_int( properties, "reset", 0 ); mlt_events_unblock( properties, filter ); } if( !pdata->r128 ) { int mode = EBUR128_MODE_HISTOGRAM; if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_program" ) ) { mode |= EBUR128_MODE_I; } if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_shortterm" ) ) { mode |= EBUR128_MODE_S; } if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_momentary" ) ) { mode |= EBUR128_MODE_M; } if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_range" ) ) { mode |= EBUR128_MODE_LRA; } if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_peak" ) ) { mode |= EBUR128_MODE_SAMPLE_PEAK; } if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_true_peak" ) ) { mode |= EBUR128_MODE_TRUE_PEAK; } pdata->r128 = ebur128_init( channels, frequency, mode ); } }
void AnalyzerEbur128::cleanup() { if (isInitialized()) { ebur128_destroy(&m_pState); } DEBUG_ASSERT(!isInitialized()); }
int main(int ac, const char* av[]) { SF_INFO file_info; SNDFILE* file; sf_count_t nr_frames_read; ebur128_state** sts = NULL; double* buffer; double loudness; int i; if (ac < 2) { fprintf(stderr, "usage: %s FILENAME...\n", av[0]); exit(1); } sts = malloc((size_t) (ac - 1) * sizeof(ebur128_state*)); for (i = 0; i < ac - 1; ++i) { memset(&file_info, '\0', sizeof(file_info)); file = sf_open(av[i + 1], SFM_READ, &file_info); sts[i] = ebur128_init((unsigned) file_info.channels, (unsigned) file_info.samplerate, EBUR128_MODE_I); /* example: set channel map (note: see ebur128.h for the default map) */ if (file_info.channels == 5) { ebur128_set_channel(sts[i], 0, EBUR128_LEFT); ebur128_set_channel(sts[i], 1, EBUR128_RIGHT); ebur128_set_channel(sts[i], 2, EBUR128_CENTER); ebur128_set_channel(sts[i], 3, EBUR128_LEFT_SURROUND); ebur128_set_channel(sts[i], 4, EBUR128_RIGHT_SURROUND); } buffer = (double*) malloc(sts[i]->samplerate * sts[i]->channels * sizeof(double)); while ((nr_frames_read = sf_readf_double(file, buffer, (sf_count_t) sts[i]->samplerate))) { ebur128_add_frames_double(sts[i], buffer, (size_t) nr_frames_read); } ebur128_loudness_global(sts[i], &loudness); fprintf(stderr, "%.2f LUFS, %s\n", loudness, av[i + 1]); free(buffer); buffer = NULL; if (sf_close(file)) { fprintf(stderr, "Could not close input file!\n"); } } ebur128_loudness_global_multiple(sts, (size_t) ac - 1, &loudness); fprintf(stderr, "-----------\n%.2f LUFS\n", loudness); /* clean up */ for (i = 0; i < ac - 1; ++i) { ebur128_destroy(&sts[i]); } free(sts); return 0; }
int rg_scan (ddb_rg_scanner_settings_t *settings) { if (settings->_size != sizeof (ddb_rg_scanner_settings_t)) { return -1; } settings->sync_mutex = deadbeef->mutex_create (); if (settings->num_threads <= 0) { settings->num_threads = 4; } char *album_signature_tf = NULL; if (settings->mode == DDB_RG_SCAN_MODE_ALBUMS_FROM_TAGS) { album_signature_tf = deadbeef->tf_compile (album_signature); deadbeef->sort_track_array (NULL, settings->tracks, settings->num_tracks, album_signature, DDB_SORT_ASCENDING); } //trace ("rg_scanner: using %d thread(s)\n", settings->num_threads); ebur128_state **gain_state = NULL; ebur128_state **peak_state = NULL; if (settings->ref_loudness == 0) { settings->ref_loudness = DDB_RG_SCAN_DEFAULT_LOUDNESS; } double loudness = settings->ref_loudness; // allocate status array gain_state = calloc (settings->num_tracks, sizeof (ebur128_state *)); peak_state = calloc (settings->num_tracks, sizeof (ebur128_state *)); // used for joining threads intptr_t *rg_threads = calloc (settings->num_tracks, sizeof (intptr_t)); track_state_t *track_states = calloc (settings->num_tracks, sizeof (track_state_t)); // calculate gain for each track and album for (int i = 0; i < settings->num_tracks; ++i) { if (settings->progress_callback) { settings->progress_callback (i, settings->progress_cb_user_data); } // limit number of parallel threads if (i >= settings->num_threads) { // simple blocking mechanism: join the 'oldest' thread deadbeef->thread_join(rg_threads[i - settings->num_threads]); rg_threads[i - settings->num_threads] = 0; } if (settings->pabort && *(settings->pabort)) { goto cleanup; } // initialize arguments track_states[i].track_index = i; track_states[i].settings = settings; track_states[i].gain_state = gain_state; track_states[i].peak_state = peak_state; // run thread rg_threads[i] = deadbeef->thread_start(&rg_calc_thread, (void*)(&track_states[i])); } // wait for remaining threads to join int remaining_thread_id = settings->num_tracks - settings->num_threads; if (remaining_thread_id < 0) { remaining_thread_id = 0; } for (int i = remaining_thread_id; i < settings->num_tracks; ++i) { deadbeef->thread_join(rg_threads[i]); rg_threads[i] = 0; if (settings->pabort && *(settings->pabort)) { goto cleanup; } } if (settings->mode == DDB_RG_SCAN_MODE_ALBUMS_FROM_TAGS) { int album_start = -1; char current_album[1000] = ""; char album[1000]; ddb_tf_context_t ctx; ctx._size = sizeof (ctx); ctx.plt = NULL; ctx.idx = -1; ctx.id = -1; for (int i = 0; i <= settings->num_tracks; i++) { // set album gain when the album change is detected if (i < settings->num_tracks) { ctx.it = settings->tracks[i]; deadbeef->tf_eval(&ctx, album_signature_tf, album, sizeof (album)); } else { *album = 0; } album_start = _update_album_gain (settings, i, album_start, current_album, album, loudness, gain_state); } } if (settings->mode == DDB_RG_SOURCE_MODE_ALBUM) { float album_peak = 0; for (int i = 0; i < settings->num_tracks; ++i) { if (album_peak < settings->results[i].track_peak) { album_peak = settings->results[i].track_peak; } } // calculate gain of all tracks combined ebur128_loudness_global_multiple(gain_state, (size_t)settings->num_tracks, &loudness); float album_gain = -23 - (float)loudness + settings->ref_loudness - 84; for (int i = 0; i < settings->num_tracks; ++i) { settings->results[i].album_gain = album_gain; settings->results[i].album_peak = album_peak; } } cleanup: // free thread storage if (rg_threads) { // join the still-active threads for (int i = 0; i < settings->num_tracks; i++) { if (rg_threads[i]) { deadbeef->thread_join (rg_threads[i]); rg_threads[i] = 0; } } free (rg_threads); rg_threads = NULL; } if (track_states) { free (track_states); track_states = NULL; } if (gain_state) { for (int i = 0; i < settings->num_tracks; ++i) { if (gain_state[i]) { ebur128_destroy (&gain_state[i]); } } free (gain_state); gain_state = NULL; } if (peak_state) { for (int i = 0; i < settings->num_tracks; ++i) { if (peak_state[i]) { ebur128_destroy (&peak_state[i]); } } free (peak_state); peak_state = NULL; } if (album_signature_tf) { deadbeef->tf_free (album_signature_tf); album_signature_tf = NULL; } if (settings->sync_mutex) { deadbeef->mutex_free (settings->sync_mutex); settings->sync_mutex = 0; } return 0; }