Пример #1
0
TrackScanner::Data TrackScanner::global(const QList<TrackScanner *> &scanners)
{
    Data d;
    if (scanners.count()<1) {
        return d;
    } else if(scanners.count()==1) {
        return scanners.first()->results();
    } else {
        ebur128_state **states = new ebur128_state * [scanners.count()];
        for (int i=0; i<scanners.count(); ++i) {
            TrackScanner *s=scanners.at(i);
            states[i]=s->state;
            if (s->results().peak>d.peak) {
                d.peak=s->results().peak;
            }
            if (s->results().truePeak>d.truePeak) {
                d.truePeak=s->results().truePeak;
            }
        }

        double l=0.0;
        int rv=ebur128_loudness_global_multiple(states, scanners.count(), &l);
        delete [] states;
        d.loudness=0==rv ? l : 0.0;
        return d;
    }
}
Пример #2
0
static int
_update_album_gain (ddb_rg_scanner_settings_t *settings, int i, int album_start, char *current_album, char *album, double loudness, ebur128_state **gain_state) {
    if (strcmp (album, current_album)) {
        if (i > 0) {
            // update current album gain/peak
            float album_peak = 0;

            for (int n = album_start; n < i; ++n) {
                if (album_peak < settings->results[n].track_peak) {
                    album_peak = settings->results[n].track_peak;
                }
            }

            // calculate gain of all tracks of the current album
            ebur128_loudness_global_multiple(&gain_state[album_start], (size_t)i-album_start, &loudness);

            float album_gain = -23 - (float)loudness + settings->ref_loudness - 84;

            for (int n = album_start; n < i; ++n) {
                settings->results[n].album_gain = album_gain;
                settings->results[n].album_peak = album_peak;
            }
        }

        // proceed to next album
        strcpy (current_album, album);

        //trace ("next album found %d -> %d\n", album_start, i);
        return i;
    }
    return album_start;
}
Пример #3
0
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;
}
Пример #4
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;
}