xref: /aosp_15_r20/external/tinyalsa_new/utils/tinywavinfo.c (revision 02e95f1a335b55495d41ca67eaf42361f13704fa)
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