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 }