1*02e95f1aSMarcin Radomski /* tinywavinfo.c
2*02e95f1aSMarcin Radomski **
3*02e95f1aSMarcin Radomski ** Copyright 2015, The Android Open Source Project
4*02e95f1aSMarcin Radomski **
5*02e95f1aSMarcin Radomski ** Redistribution and use in source and binary forms, with or without
6*02e95f1aSMarcin Radomski ** modification, are permitted provided that the following conditions are met:
7*02e95f1aSMarcin Radomski ** * Redistributions of source code must retain the above copyright
8*02e95f1aSMarcin Radomski ** notice, this list of conditions and the following disclaimer.
9*02e95f1aSMarcin Radomski ** * Redistributions in binary form must reproduce the above copyright
10*02e95f1aSMarcin Radomski ** notice, this list of conditions and the following disclaimer in the
11*02e95f1aSMarcin Radomski ** documentation and/or other materials provided with the distribution.
12*02e95f1aSMarcin Radomski ** * Neither the name of The Android Open Source Project nor the names of
13*02e95f1aSMarcin Radomski ** its contributors may be used to endorse or promote products derived
14*02e95f1aSMarcin Radomski ** from this software without specific prior written permission.
15*02e95f1aSMarcin Radomski **
16*02e95f1aSMarcin Radomski ** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
17*02e95f1aSMarcin Radomski ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*02e95f1aSMarcin Radomski ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*02e95f1aSMarcin Radomski ** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
20*02e95f1aSMarcin Radomski ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*02e95f1aSMarcin Radomski ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22*02e95f1aSMarcin Radomski ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23*02e95f1aSMarcin Radomski ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*02e95f1aSMarcin Radomski ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*02e95f1aSMarcin Radomski ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26*02e95f1aSMarcin Radomski ** DAMAGE.
27*02e95f1aSMarcin Radomski */
28*02e95f1aSMarcin Radomski
29*02e95f1aSMarcin Radomski #include <stdio.h>
30*02e95f1aSMarcin Radomski #include <stdlib.h>
31*02e95f1aSMarcin Radomski #include <stdint.h>
32*02e95f1aSMarcin Radomski #include <string.h>
33*02e95f1aSMarcin Radomski #include <signal.h>
34*02e95f1aSMarcin Radomski #include <math.h>
35*02e95f1aSMarcin Radomski
36*02e95f1aSMarcin Radomski #define ID_RIFF 0x46464952
37*02e95f1aSMarcin Radomski #define ID_WAVE 0x45564157
38*02e95f1aSMarcin Radomski #define ID_FMT 0x20746d66
39*02e95f1aSMarcin Radomski #define ID_DATA 0x61746164
40*02e95f1aSMarcin Radomski
41*02e95f1aSMarcin Radomski struct riff_wave_header {
42*02e95f1aSMarcin Radomski uint32_t riff_id;
43*02e95f1aSMarcin Radomski uint32_t riff_sz;
44*02e95f1aSMarcin Radomski uint32_t wave_id;
45*02e95f1aSMarcin Radomski };
46*02e95f1aSMarcin Radomski
47*02e95f1aSMarcin Radomski struct chunk_header {
48*02e95f1aSMarcin Radomski uint32_t id;
49*02e95f1aSMarcin Radomski uint32_t sz;
50*02e95f1aSMarcin Radomski };
51*02e95f1aSMarcin Radomski
52*02e95f1aSMarcin Radomski struct chunk_fmt {
53*02e95f1aSMarcin Radomski uint16_t audio_format;
54*02e95f1aSMarcin Radomski uint16_t num_channels;
55*02e95f1aSMarcin Radomski uint32_t sample_rate;
56*02e95f1aSMarcin Radomski uint32_t byte_rate;
57*02e95f1aSMarcin Radomski uint16_t block_align;
58*02e95f1aSMarcin Radomski uint16_t bits_per_sample;
59*02e95f1aSMarcin Radomski };
60*02e95f1aSMarcin Radomski
61*02e95f1aSMarcin Radomski static int close = 0;
62*02e95f1aSMarcin Radomski
63*02e95f1aSMarcin Radomski void analyse_sample(FILE *file, unsigned int channels, unsigned int bits,
64*02e95f1aSMarcin Radomski unsigned int data_chunk_size);
65*02e95f1aSMarcin Radomski
stream_close(int sig)66*02e95f1aSMarcin Radomski void stream_close(int sig)
67*02e95f1aSMarcin Radomski {
68*02e95f1aSMarcin Radomski /* allow the stream to be closed gracefully */
69*02e95f1aSMarcin Radomski signal(sig, SIG_IGN);
70*02e95f1aSMarcin Radomski close = 1;
71*02e95f1aSMarcin Radomski }
72*02e95f1aSMarcin Radomski
xfread(void * ptr,size_t size,size_t nmemb,FILE * stream)73*02e95f1aSMarcin Radomski size_t xfread(void *ptr, size_t size, size_t nmemb, FILE *stream)
74*02e95f1aSMarcin Radomski {
75*02e95f1aSMarcin Radomski size_t sz = fread(ptr, size, nmemb, stream);
76*02e95f1aSMarcin Radomski
77*02e95f1aSMarcin Radomski if (sz != nmemb && ferror(stream)) {
78*02e95f1aSMarcin Radomski fprintf(stderr, "Error: fread failed\n");
79*02e95f1aSMarcin Radomski exit(1);
80*02e95f1aSMarcin Radomski }
81*02e95f1aSMarcin Radomski return sz;
82*02e95f1aSMarcin Radomski }
83*02e95f1aSMarcin Radomski
main(int argc,char ** argv)84*02e95f1aSMarcin Radomski int main(int argc, char **argv)
85*02e95f1aSMarcin Radomski {
86*02e95f1aSMarcin Radomski FILE *file;
87*02e95f1aSMarcin Radomski struct riff_wave_header riff_wave_header;
88*02e95f1aSMarcin Radomski struct chunk_header chunk_header;
89*02e95f1aSMarcin Radomski struct chunk_fmt chunk_fmt;
90*02e95f1aSMarcin Radomski char *filename;
91*02e95f1aSMarcin Radomski int more_chunks = 1;
92*02e95f1aSMarcin Radomski
93*02e95f1aSMarcin Radomski if (argc < 2) {
94*02e95f1aSMarcin Radomski fprintf(stderr, "Usage: %s file.wav \n", argv[0]);
95*02e95f1aSMarcin Radomski return 1;
96*02e95f1aSMarcin Radomski }
97*02e95f1aSMarcin Radomski
98*02e95f1aSMarcin Radomski filename = argv[1];
99*02e95f1aSMarcin Radomski file = fopen(filename, "rb");
100*02e95f1aSMarcin Radomski if (!file) {
101*02e95f1aSMarcin Radomski fprintf(stderr, "Unable to open file '%s'\n", filename);
102*02e95f1aSMarcin Radomski return 1;
103*02e95f1aSMarcin Radomski }
104*02e95f1aSMarcin Radomski
105*02e95f1aSMarcin Radomski xfread(&riff_wave_header, sizeof(riff_wave_header), 1, file);
106*02e95f1aSMarcin Radomski if ((riff_wave_header.riff_id != ID_RIFF) ||
107*02e95f1aSMarcin Radomski (riff_wave_header.wave_id != ID_WAVE)) {
108*02e95f1aSMarcin Radomski fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename);
109*02e95f1aSMarcin Radomski fclose(file);
110*02e95f1aSMarcin Radomski return 1;
111*02e95f1aSMarcin Radomski }
112*02e95f1aSMarcin Radomski
113*02e95f1aSMarcin Radomski do {
114*02e95f1aSMarcin Radomski xfread(&chunk_header, sizeof(chunk_header), 1, file);
115*02e95f1aSMarcin Radomski
116*02e95f1aSMarcin Radomski switch (chunk_header.id) {
117*02e95f1aSMarcin Radomski case ID_FMT:
118*02e95f1aSMarcin Radomski xfread(&chunk_fmt, sizeof(chunk_fmt), 1, file);
119*02e95f1aSMarcin Radomski /* If the format header is larger, skip the rest */
120*02e95f1aSMarcin Radomski if (chunk_header.sz > sizeof(chunk_fmt))
121*02e95f1aSMarcin Radomski fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
122*02e95f1aSMarcin Radomski break;
123*02e95f1aSMarcin Radomski case ID_DATA:
124*02e95f1aSMarcin Radomski /* Stop looking for chunks */
125*02e95f1aSMarcin Radomski more_chunks = 0;
126*02e95f1aSMarcin Radomski break;
127*02e95f1aSMarcin Radomski default:
128*02e95f1aSMarcin Radomski /* Unknown chunk, skip bytes */
129*02e95f1aSMarcin Radomski fseek(file, chunk_header.sz, SEEK_CUR);
130*02e95f1aSMarcin Radomski }
131*02e95f1aSMarcin Radomski } while (more_chunks);
132*02e95f1aSMarcin Radomski
133*02e95f1aSMarcin Radomski printf("Input File : %s \n", filename);
134*02e95f1aSMarcin Radomski printf("Channels : %u \n", chunk_fmt.num_channels);
135*02e95f1aSMarcin Radomski printf("Sample Rate : %u \n", chunk_fmt.sample_rate);
136*02e95f1aSMarcin Radomski printf("Bits per sample : %u \n\n", chunk_fmt.bits_per_sample);
137*02e95f1aSMarcin Radomski
138*02e95f1aSMarcin Radomski analyse_sample(file, chunk_fmt.num_channels, chunk_fmt.bits_per_sample,
139*02e95f1aSMarcin Radomski chunk_header.sz);
140*02e95f1aSMarcin Radomski
141*02e95f1aSMarcin Radomski fclose(file);
142*02e95f1aSMarcin Radomski
143*02e95f1aSMarcin Radomski return 0;
144*02e95f1aSMarcin Radomski }
145*02e95f1aSMarcin Radomski
analyse_sample(FILE * file,unsigned int channels,unsigned int bits,unsigned int data_chunk_size)146*02e95f1aSMarcin Radomski void analyse_sample(FILE *file, unsigned int channels, unsigned int bits,
147*02e95f1aSMarcin Radomski unsigned int data_chunk_size)
148*02e95f1aSMarcin Radomski {
149*02e95f1aSMarcin Radomski void *buffer;
150*02e95f1aSMarcin Radomski int size;
151*02e95f1aSMarcin Radomski int num_read;
152*02e95f1aSMarcin Radomski int i;
153*02e95f1aSMarcin Radomski unsigned int ch;
154*02e95f1aSMarcin Radomski int frame_size = 1024;
155*02e95f1aSMarcin Radomski unsigned int bytes_per_sample = 0;
156*02e95f1aSMarcin Radomski float *power;
157*02e95f1aSMarcin Radomski int total_sample_per_channel;
158*02e95f1aSMarcin Radomski float normalization_factor;
159*02e95f1aSMarcin Radomski
160*02e95f1aSMarcin Radomski if (bits == 32)
161*02e95f1aSMarcin Radomski bytes_per_sample = 4;
162*02e95f1aSMarcin Radomski else if (bits == 16)
163*02e95f1aSMarcin Radomski bytes_per_sample = 2;
164*02e95f1aSMarcin Radomski
165*02e95f1aSMarcin Radomski normalization_factor = (float)pow(2.0, (bits-1));
166*02e95f1aSMarcin Radomski
167*02e95f1aSMarcin Radomski size = channels * bytes_per_sample * frame_size;
168*02e95f1aSMarcin Radomski
169*02e95f1aSMarcin Radomski buffer = malloc(size);
170*02e95f1aSMarcin Radomski if (!buffer) {
171*02e95f1aSMarcin Radomski fprintf(stderr, "Unable to allocate %d bytes\n", size);
172*02e95f1aSMarcin Radomski free(buffer);
173*02e95f1aSMarcin Radomski return;
174*02e95f1aSMarcin Radomski }
175*02e95f1aSMarcin Radomski
176*02e95f1aSMarcin Radomski power = (float *) calloc(channels, sizeof(float));
177*02e95f1aSMarcin Radomski
178*02e95f1aSMarcin Radomski total_sample_per_channel = data_chunk_size / (channels * bytes_per_sample);
179*02e95f1aSMarcin Radomski
180*02e95f1aSMarcin Radomski /* catch ctrl-c to shutdown cleanly */
181*02e95f1aSMarcin Radomski signal(SIGINT, stream_close);
182*02e95f1aSMarcin Radomski
183*02e95f1aSMarcin Radomski do {
184*02e95f1aSMarcin Radomski num_read = xfread(buffer, 1, size, file);
185*02e95f1aSMarcin Radomski if (num_read > 0) {
186*02e95f1aSMarcin Radomski if (2 == bytes_per_sample) {
187*02e95f1aSMarcin Radomski short *buffer_ptr = (short *)buffer;
188*02e95f1aSMarcin Radomski for (i = 0; i < num_read / bytes_per_sample; i += channels) {
189*02e95f1aSMarcin Radomski for (ch = 0; ch < channels; ch++) {
190*02e95f1aSMarcin Radomski int temp = *buffer_ptr++;
191*02e95f1aSMarcin Radomski /* Signal Normalization */
192*02e95f1aSMarcin Radomski float f = (float) temp / normalization_factor;
193*02e95f1aSMarcin Radomski *(power + ch) += (float) (f * f);
194*02e95f1aSMarcin Radomski }
195*02e95f1aSMarcin Radomski }
196*02e95f1aSMarcin Radomski }
197*02e95f1aSMarcin Radomski if (4 == bytes_per_sample) {
198*02e95f1aSMarcin Radomski int *buffer_ptr = (int *)buffer;
199*02e95f1aSMarcin Radomski for (i = 0; i < num_read / bytes_per_sample; i += channels) {
200*02e95f1aSMarcin Radomski for (ch = 0; ch < channels; ch++) {
201*02e95f1aSMarcin Radomski int temp = *buffer_ptr++;
202*02e95f1aSMarcin Radomski /* Signal Normalization */
203*02e95f1aSMarcin Radomski float f = (float) temp / normalization_factor;
204*02e95f1aSMarcin Radomski *(power + ch) += (float) (f * f);
205*02e95f1aSMarcin Radomski }
206*02e95f1aSMarcin Radomski }
207*02e95f1aSMarcin Radomski }
208*02e95f1aSMarcin Radomski }
209*02e95f1aSMarcin Radomski }while (!close && num_read > 0);
210*02e95f1aSMarcin Radomski
211*02e95f1aSMarcin Radomski for (ch = 0; ch < channels; ch++) {
212*02e95f1aSMarcin Radomski float average_power = 10 * log10((*(power + ch)) / total_sample_per_channel);
213*02e95f1aSMarcin Radomski if(isinf (average_power)) {
214*02e95f1aSMarcin Radomski printf("Channel [%2u] Average Power : NO signal or ZERO signal\n", ch);
215*02e95f1aSMarcin Radomski } else {
216*02e95f1aSMarcin Radomski printf("Channel [%2u] Average Power : %.2f dB\n", ch, average_power);
217*02e95f1aSMarcin Radomski }
218*02e95f1aSMarcin Radomski }
219*02e95f1aSMarcin Radomski
220*02e95f1aSMarcin Radomski free(buffer);
221*02e95f1aSMarcin Radomski free(power);
222*02e95f1aSMarcin Radomski
223*02e95f1aSMarcin Radomski }
224*02e95f1aSMarcin Radomski
225