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.