| /* |
| * 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; |
| } |
| |