/* Feed the meter. Scan a single frame of audio. */ int meter_feed(struct dr_meter *self, void *buf, size_t buf_size) { size_t samples = buf_size / (self->sample_size * self->channels); int err; while (samples) { if (!self->fragment_started) { err = meter_fragment_start(self); if (err) return err; } size_t fragment_left = self->fragment_size - self->fragment_read; size_t to_scan = min(fragment_left, samples); #define CASE(fmt) case fmt: meter_scan_internal(self, buf, to_scan, fmt); break switch (self->sample_fmt) { CASE(AV_SAMPLE_FMT_U8); CASE(AV_SAMPLE_FMT_S16); CASE(AV_SAMPLE_FMT_S32); CASE(AV_SAMPLE_FMT_FLT); CASE(AV_SAMPLE_FMT_DBL); default: meter_scan_internal(self, buf, to_scan, self->sample_fmt); } #undef CASE buf = (char *)buf + self->sample_size * self->channels * to_scan; self->fragment_read += to_scan; if (self->fragment_size <= self->fragment_read) { meter_fragment_finish(self); } samples -= to_scan; } return 0; }
int meter_finish(struct dr_meter *self, struct track_info *info) { if (self->fragment_started) { // process any leftover audio meter_fragment_finish(self); } sample rms_score[MAX_CHANNELS]; sample rms[MAX_CHANNELS]; sample peak_score[MAX_CHANNELS]; sample dr_channel[MAX_CHANNELS]; sample dr_sum = 0; sample peak_max = 0; sample rms_sum = 0; size_t values_to_use = 0; values_to_use = max(self->fragment / 5, 1); if (!values_to_use) { info->peak = 0; info->rms = 0; info->dr = -INFINITY; info->duration = 0; return 0; } for (int ch = 0; ch < self->channels; ch++) { qsort(self->rms_values[ch], self->fragment, sizeof(*self->rms_values[ch]), compare_samples); sample rms_ch_sum = 0; for (size_t i = 0; i < values_to_use; i++) { sample value = self->rms_values[ch][i]; rms_ch_sum += value * value; } rms_score[ch] = sqrt(rms_ch_sum / values_to_use); for (size_t i = values_to_use; i < self->fragment; i++) { sample value = self->rms_values[ch][i]; rms_ch_sum += value * value; } rms[ch] = sqrt(rms_ch_sum / self->fragment); rms_sum += rms_ch_sum / self->fragment; qsort(self->peak_values[ch], self->fragment, sizeof(*self->peak_values[ch]), compare_samples); peak_score[ch] = self->peak_values[ch][min(1, self->fragment)]; peak_max = max(peak_max, self->peak_values[ch][0]); dr_channel[ch] = to_db(peak_score[ch] / rms_score[ch]); dr_sum += dr_channel[ch]; printf("Ch. %2i: Peak %8.2f (%8.2f) RMS %8.2f (%8.2f) DR = %6.2f\n", ch, to_db(self->peak_values[ch][0]), to_db(peak_score[ch]), to_db(rms[ch]), to_db(rms_score[ch]), dr_channel[ch]); } info->peak = peak_max; info->rms = sqrt(rms_sum / (sample)self->channels); info->dr = dr_sum / (sample)self->channels; info->duration = (self->total_samples + self->sample_rate/2) / self->sample_rate; //printf("%lld\n", self->total_samples); printf("DR%d\n", (int)round(info->dr)); return 0; }
/* Feed the meter. Scan a single frame of audio. */ int meter_feed(struct dr_meter *self, void **buf, size_t samples) { size_t start = 0, end = samples; int err; if (debug && 0) { fprintf(stdout, "%zd\n", samples); } while (start < samples) { if (!self->fragment_started) { err = meter_fragment_start(self); if (err) return err; } size_t fragment_left = self->fragment_size - self->fragment_read; end = min(fragment_left, samples); #define CASE(fmt) case fmt: meter_scan_internal(self, buf, start, end, samples, fmt); break switch (self->sample_fmt) { CASE(AV_SAMPLE_FMT_U8); CASE(AV_SAMPLE_FMT_U8P); CASE(AV_SAMPLE_FMT_S16); CASE(AV_SAMPLE_FMT_S16P); CASE(AV_SAMPLE_FMT_S32); CASE(AV_SAMPLE_FMT_S32P); CASE(AV_SAMPLE_FMT_FLT); CASE(AV_SAMPLE_FMT_FLTP); CASE(AV_SAMPLE_FMT_DBL); CASE(AV_SAMPLE_FMT_DBLP); default: meter_scan_internal(self, buf, start, end, samples, self->sample_fmt); } #undef CASE self->fragment_read += end - start; start = end; if (self->fragment_size <= self->fragment_read) { meter_fragment_finish(self); } } //printf("%lld += %zu\n", self->total_samples, samples); self->total_samples += samples; return 0; }
int meter_finish(struct dr_meter *self) { if (self->fragment_started) { meter_fragment_finish(self); } fprintf(stderr, "\nDoing some statistics...\n"); sample rms_score[MAX_CHANNELS]; sample rms[MAX_CHANNELS]; sample peak_score[MAX_CHANNELS]; sample dr_channel[MAX_CHANNELS]; sample dr_sum = 0; for (int ch = 0; ch < self->channels; ch++) { qsort(self->rms_values[ch], self->fragment, sizeof(**self->rms_values), compare_samples); sample rms_sum = 0; size_t values_to_use = self->fragment / 5; for (size_t i = 0; i < values_to_use; i++) { sample value = self->rms_values[ch][i]; rms_sum += value * value; } rms_score[ch] = sqrt(rms_sum / values_to_use); rms_sum = 0; for (size_t i = 0; i < self->fragment; i++) { sample value = self->rms_values[ch][i]; rms_sum += value * value; } rms[ch] = sqrt(rms_sum / self->fragment); qsort(self->peak_values[ch], self->fragment, sizeof(*self->peak_values[ch]), compare_samples); peak_score[ch] = self->peak_values[ch][min(1, self->fragment)]; dr_channel[ch] = to_db(peak_score[ch] / rms_score[ch]); printf("Ch. %2i: Peak %8.2f (%8.2f) RMS %8.2f (%8.2f) DR = %6.2f\n", ch, to_db(self->peak_values[ch][0]), to_db(peak_score[ch]), to_db(rms[ch]), to_db(rms_score[ch]), dr_channel[ch]); dr_sum += dr_channel[ch]; } printf("Overall dynamic range: DR%i\n", (int)round(dr_sum / ((sample)self->channels))); return 0; }