blob: 52212cba98744701a7c8b440b6d6b8a850e733a5 [file] [log] [blame]
/*
* rms.c
*
* calculate RMS of a wav file per channel
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <inttypes.h>
#include "rms.h"
#define MAX_FILENAME_LEN 256
#define MAX_CHANNELS 8
#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT 0x20746d66
#define ID_DATA 0x61746164
struct wav_header {
uint32_t riff_id;
uint32_t riff_sz;
uint32_t riff_fmt;
uint32_t fmt_id;
uint32_t fmt_sz;
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bits_per_sample;
uint32_t data_id;
uint32_t data_sz;
};
/* Reuse tinyplay/tinycap code for header parsing */
static int parse_header (char * filename, struct wav_header * wav_header) {
FILE* file;
file = fopen(filename, "rb");
if (!file) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
return 1;
}
fread(wav_header, sizeof(struct wav_header), 1, file);
if ((wav_header->riff_id != ID_RIFF) ||
(wav_header->riff_fmt != ID_WAVE) ||
(wav_header->data_id != ID_DATA)) {
fprintf(stderr, "Error: '%s' is not a PCM Wav file\n", filename);
fclose(file);
return 1;
}
fclose(file);
return 0;
}
static int rms (char *filename, const struct wav_header * wav_header) {
char outname[MAX_FILENAME_LEN];
uint8_t i = 0;
char *extension_pos;
FILE *fp; /* input file pointer */
uint16_t data[MAX_CHANNELS];
uint64_t rms[MAX_CHANNELS];
uint64_t num_samples = 0;
fp = fopen(filename, "rb");
/* Jump to data block */
fseek(fp, sizeof(struct wav_header), SEEK_SET);
strncpy(outname, filename, sizeof(outname));
/* Get extension index of filename */
extension_pos = strrchr(outname, '.');
/* Point to '\0' instead if no extension is found */
if (!extension_pos)
extension_pos = strrchr(outname, '\0');
if (!extension_pos) {
fprintf(stderr, "Filename is too long!\n");
return 1;
}
/* Split data block */
while(fread(data, wav_header->block_align, 1, fp) == 1) {
num_samples++;
for (i = 0; i < wav_header->num_channels; i++)
rms[i] += data[i]*data[i];
}
for (i = 0; i < wav_header->num_channels; i++) {
printf("channel %d rms is %f\n",i, sqrt((float)rms[i])/num_samples);
}
fclose(fp);
return 0;
}
int rms_main (int argc, char* argv[]) {
char *filename;
struct wav_header wav_header, wav_header_out;
if (argc != 2) {
fprintf(stderr, "Usage: audio-tool rms file.wav\n");
return 1;
}
filename = argv[1];
if (parse_header(filename, &wav_header))
return 1;
if (wav_header.num_channels > MAX_CHANNELS) {
fprintf(stderr, "Error: only support %d or less channels\n", MAX_CHANNELS);
return 1;
}
if(rms(filename, &wav_header))
return 1;
return 0;
}