This is sndrmsenv.c in view mode; [Download] [Up]
/*
* sndrmsenv.c
* Compute rms level in dB (0 max) for each soundfile block.
*
* A hacked version of sndrms.c that prints out the rms of
* a soundfile at an interval of every argv[2] seconds. Also prints decibel values
* on a scale up to 0 dB.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sound/sound.h>
#include <architecture/byte_order.h>
#include <string.h>
#define amp_to_db(amp) (20 * (log10(fabs(amp))))
#define make_amps(struc, val, scl) struc.raw = val; struc.scaled = val * scl;\
struc.db = amp_to_db(struc.scaled)
#define STRINGLENGTH 128
struct amps { double raw, scaled, db; };
struct extreme { char info[STRINGLENGTH]; double rms, time1, time2; };
/* Globals to hold highest and lowest RMS sections in the file. 0 is the RMS of
* silence and 32767 is the RMS of a straight line at amp=1 so these are good starting
* values for the two. */
struct extreme Highest = { "", 0, 0.0, 0.0 };
struct extreme Lowest = { "", 32767, 0.0, 0.0 };
/* Function prototypes */
short *get_data(char *, int *, int *, double *, int *);
void calc_and_print(double, double, double, double, int, double, double, int);
/*************************************************************************************/
void main(int argc, char *argv[])
{
double sum = 0.0, sumsq = 0.0, max, min;
double complete_sum = 0.0, complete_sumsq = 0.0;
double complete_max = 0.0, complete_min = 0.0;
double interval_secs, time1 = 0.0, time2, dur;
int srate, scount, ch, interval_samples, next_print;
register short *sp;
register int temp1, temp2, i;
if (argc != 3) {
fprintf(stderr,
"%s - compute rms level in dB (0 max) for each soundfile block.\n",
argv[0]);
fprintf(stderr, "\nUsage: %s: in.snd time-interval\n(prints amplitude and RMS \
information every <time-interval> seconds in \nsound file <in.snd>\n\n", argv[0]);
exit(1);
}
sp = get_data(argv[1], &srate, &scount, &dur, &ch);
interval_secs = time2 = atof(argv[2]);
interval_samples = next_print = (int)(interval_secs * srate * ch);
max = min = (signed short) NXSwapBigShortToHost(*sp);
/* Main loop through sound file: */
for (i = 0; i < scount; i++) {
temp1 = (signed short) NXSwapBigShortToHost(*sp++);
temp2 = temp1 * temp1;
sum += temp1;
complete_sum += temp1;
sumsq += temp2;
complete_sumsq += temp2;
if (max < temp1)
max = temp1;
else if (min > temp1)
min = temp1;
if (i == next_print) {
calc_and_print(sum, sumsq, max, min, interval_samples, time1, time2, 1);
time1 = time2;
time2 += interval_secs;
if (complete_max < max)
complete_max = max;
if (complete_min > min)
complete_min = min;
next_print += interval_samples;
sum = sumsq = max = min = 0.0;
}
}
/* This time don't check for extremes as we're at the end of the sound and it
* could be a very low amplitude--what we want is the lowest point in the main
* body of the sound. */
calc_and_print(sum, sumsq, max, min, interval_samples - (next_print - scount),
time1, dur, 0);
printf("\n\t\t******** Overall values: **********");
calc_and_print(complete_sum, complete_sumsq, complete_max, complete_min, scount,
0.0, dur, 0);
printf("\n*** Lowest RMS is %s (between time %.4f and time %.4f--silent sections \
and final section ignored).\n",
Lowest.info, Lowest.time1, Lowest.time2);
printf("*** Highest RMS is %s (between time %.4f and time %.4f).\n\n",
Highest.info, Highest.time1, Highest.time2);
}
/*************************************************************************************/
void calc_and_print(double sum, double sumsq, double max, double min, int scount,
double time1, double time2, int do_extremes)
{
double mean = sum / ((double) scount);
double meansq = sumsq / ((double) scount);
double var = meansq - mean * mean;
double rms = sqrt(var);
const double scaler = pow(2, -15);
struct amps RMS, MAX, MIN;
char buf[STRINGLENGTH];
make_amps(RMS, rms, scaler);
make_amps(MAX, max, scaler);
make_amps(MIN, min, scaler);
sprintf(buf, "%.10g (%.10g) (%.10g dB)\n", RMS.raw, RMS.scaled, RMS.db);
if (do_extremes) {
if (rms > Highest.rms) {
strcpy(Highest.info, buf);
Highest.rms = rms;
Highest.time1 = time1;
Highest.time2 = time2;
}
if (rms < Lowest.rms && rms != 0.0) { /* Ignore silence */
strcpy(Lowest.info, buf);
Lowest.rms = rms;
Lowest.time1 = time1;
Lowest.time2 = time2;
}
}
printf("\n\t\t*** Time %.4f seconds to %.4f seconds: ***\n", time1, time2);
printf("RMS = %s", buf);
printf("Mean = %.10g (%.10g)\n", mean, mean * scaler);
printf("Max = %d (limit = 32767) (%.10g) (limit = 1.0) (%.10g dB)\n",
(int)MAX.raw, MAX.scaled, MAX.db);
printf("Min = %d (limit = -32768) (%.10g) (limit = -1.0) (%.10g dB)",
(int)MIN.raw, MIN.scaled, MIN.db);
}
/*************************************************************************************/
short *get_data (char *file, int *sampling_rate, int *sample_count, double *dur,
int *channels)
{
int err;
SNDSoundStruct *sndin;
short *data;
err = SNDReadSoundfile(file, &sndin);
if (err) {
fprintf(stderr, "Cannot read soundfile: %s\n", file);
exit(1);
}
if (sndin->dataFormat != SND_FORMAT_LINEAR_16) {
fprintf(stderr, "Soundfile must be 16 bit linear\n");
exit(1);
}
*sampling_rate = sndin->samplingRate;
*sample_count = sndin->dataSize / sizeof(short); /* channel independent */
*channels = sndin->channelCount;
*dur = ((double)*sample_count / (double)*sampling_rate) / (double)*channels;
data = (short *) ((char *)sndin + sndin->dataLocation);
return data;
}
/*************************************************************************************/
/* EOF sndrmsenv.c */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.