File indexing completed on 2024-06-09 04:49:45
0001 /* 0002 SPDX-FileCopyrightText: 2003-2004 Mark Borgerding <Mark@Borgerding.net> 0003 SPDX-License-Identifier: BSD-3-Clause 0004 All rights reserved. 0005 0006 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 0007 0008 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 0009 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 0010 * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 0011 0012 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0013 */ 0014 0015 #include "../kiss_fft.h" 0016 #include "kiss_fftr.h" 0017 0018 #include <stdlib.h> 0019 #include <math.h> 0020 #include <stdio.h> 0021 #include <string.h> 0022 #include <unistd.h> 0023 #include <png.h> 0024 0025 int nfft=1024; 0026 FILE * fin=NULL; 0027 FILE * fout=NULL; 0028 0029 int navg=20; 0030 int remove_dc=0; 0031 int nrows=0; 0032 float * vals=NULL; 0033 int stereo=0; 0034 0035 static 0036 void config(int argc,char** argv) 0037 { 0038 while (1) { 0039 int c = getopt (argc, argv, "n:r:as"); 0040 if (c == -1) 0041 break; 0042 switch (c) { 0043 case 'n': nfft=(int)atoi(optarg);break; 0044 case 'r': navg=(int)atoi(optarg);break; 0045 case 'a': remove_dc=1;break; 0046 case 's': stereo=1;break; 0047 case '?': 0048 fprintf (stderr, "usage options:\n" 0049 "\t-n d: fft dimension(s) [1024]\n" 0050 "\t-r d: number of rows to average [20]\n" 0051 "\t-a : remove average from each fft buffer\n" 0052 "\t-s : input is stereo, channels will be combined before fft\n" 0053 "16 bit machine format real input is assumed\n" 0054 ); 0055 default: 0056 fprintf (stderr, "bad %c\n", c); 0057 exit (1); 0058 break; 0059 } 0060 } 0061 if ( optind < argc ) { 0062 if (strcmp("-",argv[optind]) !=0) 0063 fin = fopen(argv[optind],"rb"); 0064 ++optind; 0065 } 0066 0067 if ( optind < argc ) { 0068 if ( strcmp("-",argv[optind]) !=0 ) 0069 fout = fopen(argv[optind],"wb"); 0070 ++optind; 0071 } 0072 if (fin==NULL) 0073 fin=stdin; 0074 if (fout==NULL) 0075 fout=stdout; 0076 } 0077 0078 #define CHECKNULL(p) if ( (p)==NULL ) do { fprintf(stderr,"CHECKNULL failed @ %s(%d): %s\n",__FILE__,__LINE__,#p );exit(1);} while(0) 0079 0080 typedef struct 0081 { 0082 png_byte r; 0083 png_byte g; 0084 png_byte b; 0085 } rgb_t; 0086 0087 static 0088 void val2rgb(float x,rgb_t *p) 0089 { 0090 const double pi = 3.14159265358979; 0091 p->g = (int)(255*sin(x*pi)); 0092 p->r = (int)(255*abs(sin(x*pi*3/2))); 0093 p->b = (int)(255*abs(sin(x*pi*5/2))); 0094 //fprintf(stderr,"%.2f : %d,%d,%d\n",x,(int)p->r,(int)p->g,(int)p->b); 0095 } 0096 0097 static 0098 void cpx2pixels(rgb_t * res,const float * fbuf,size_t n) 0099 { 0100 size_t i; 0101 float minval,maxval,valrange; 0102 minval=maxval=fbuf[0]; 0103 0104 for (i = 0; i < n; ++i) { 0105 if (fbuf[i] > maxval) maxval = fbuf[i]; 0106 if (fbuf[i] < minval) minval = fbuf[i]; 0107 } 0108 0109 fprintf(stderr,"min ==%f,max=%f\n",minval,maxval); 0110 valrange = maxval-minval; 0111 if (valrange == 0) { 0112 fprintf(stderr,"min == max == %f\n",minval); 0113 exit (1); 0114 } 0115 0116 for (i = 0; i < n; ++i) 0117 val2rgb( (fbuf[i] - minval)/valrange , res+i ); 0118 } 0119 0120 static 0121 void transform_signal(void) 0122 { 0123 short *inbuf; 0124 kiss_fftr_cfg cfg=NULL; 0125 kiss_fft_scalar *tbuf; 0126 kiss_fft_cpx *fbuf; 0127 float *mag2buf; 0128 int i; 0129 int n; 0130 int avgctr=0; 0131 0132 int nfreqs=nfft/2+1; 0133 0134 CHECKNULL( cfg=kiss_fftr_alloc(nfft,0,0,0) ); 0135 CHECKNULL( inbuf=(short*)malloc(sizeof(short)*2*nfft ) ); 0136 CHECKNULL( tbuf=(kiss_fft_scalar*)malloc(sizeof(kiss_fft_scalar)*nfft ) ); 0137 CHECKNULL( fbuf=(kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx)*nfreqs ) ); 0138 CHECKNULL( mag2buf=(float*)malloc(sizeof(float)*nfreqs ) ); 0139 0140 memset(mag2buf,0,sizeof(float)*nfreqs); 0141 0142 while (1) { 0143 if (stereo) { 0144 n = fread(inbuf,sizeof(short)*2,nfft,fin); 0145 if (n != nfft ) 0146 break; 0147 for (i=0;i<nfft;++i) 0148 tbuf[i] = inbuf[2*i] + inbuf[2*i+1]; 0149 }else{ 0150 n = fread(inbuf,sizeof(short),nfft,fin); 0151 if (n != nfft ) 0152 break; 0153 for (i=0;i<nfft;++i) 0154 tbuf[i] = inbuf[i]; 0155 } 0156 0157 if (remove_dc) { 0158 float avg = 0; 0159 for (i=0;i<nfft;++i) avg += tbuf[i]; 0160 avg /= nfft; 0161 for (i=0;i<nfft;++i) tbuf[i] -= (kiss_fft_scalar)avg; 0162 } 0163 0164 /* do FFT */ 0165 kiss_fftr(cfg,tbuf,fbuf); 0166 0167 for (i=0;i<nfreqs;++i) 0168 mag2buf[i] += fbuf[i].r * fbuf[i].r + fbuf[i].i * fbuf[i].i; 0169 0170 if (++avgctr == navg) { 0171 float *new_vals; 0172 avgctr=0; 0173 ++nrows; 0174 new_vals = (float*)realloc(vals,sizeof(float)*nrows*nfreqs); 0175 if(new_vals == NULL) return; else vals=new_vals; 0176 float eps = 1; 0177 for (i=0;i<nfreqs;++i) 0178 vals[(nrows - 1) * nfreqs + i] = 10 * log10 ( mag2buf[i] / navg + eps ); 0179 memset(mag2buf,0,sizeof(mag2buf[0])*nfreqs); 0180 } 0181 } 0182 0183 free(cfg); 0184 free(inbuf); 0185 free(tbuf); 0186 free(fbuf); 0187 free(mag2buf); 0188 } 0189 0190 static 0191 void make_png(void) 0192 { 0193 png_bytepp row_pointers=NULL, new_row_pointers; 0194 rgb_t * row_data=NULL; 0195 int i; 0196 int nfreqs = nfft/2+1; 0197 0198 png_structp png_ptr=NULL; 0199 png_infop info_ptr=NULL; 0200 0201 CHECKNULL( png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,0,0,0) ); 0202 CHECKNULL( info_ptr = png_create_info_struct(png_ptr) ); 0203 0204 0205 png_init_io(png_ptr, fout ); 0206 png_set_IHDR(png_ptr, info_ptr ,nfreqs,nrows,8,PNG_COLOR_TYPE_RGB,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT ); 0207 0208 0209 row_data = (rgb_t*)malloc(sizeof(rgb_t) * nrows * nfreqs) ; 0210 cpx2pixels(row_data, vals, nfreqs*nrows ); 0211 0212 new_row_pointers = realloc(row_pointers, nrows*sizeof(png_bytep)); 0213 if(new_row_pointers == NULL) { 0214 free(row_pointers); 0215 free(row_data); 0216 return; 0217 } else { 0218 row_pointers=new_row_pointers; 0219 } 0220 0221 for (i=0;i<nrows;++i) { 0222 row_pointers[i] = (png_bytep)(row_data + i*nfreqs); 0223 } 0224 png_set_rows(png_ptr, info_ptr, row_pointers); 0225 0226 0227 fprintf(stderr,"creating %dx%d png\n",nfreqs,nrows); 0228 fprintf(stderr,"bitdepth %d \n",png_get_bit_depth(png_ptr,info_ptr ) ); 0229 0230 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY , NULL); 0231 0232 free(row_pointers); 0233 free(row_data); 0234 } 0235 0236 int main(int argc,char ** argv) 0237 { 0238 config(argc,argv); 0239 0240 transform_signal(); 0241 0242 make_png(); 0243 0244 if (fout!=stdout) fclose(fout); 0245 if (fin!=stdin) fclose(fin); 0246 return 0; 0247 }