mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	module-equalizer-sink:
added temporary debugging output to track filter output
    removed dead code
    only a small amount of crackling remains
			
			
This commit is contained in:
		
							parent
							
								
									431555030e
								
							
						
					
					
						commit
						2e119060cb
					
				
					 1 changed files with 106 additions and 162 deletions
				
			
		| 
						 | 
				
			
			@ -1,4 +1,29 @@
 | 
			
		|||
/***
 | 
			
		||||
This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
This module is based off Lennart Poettering's LADSPA sink and swaps out
 | 
			
		||||
LADSPA functionality for a STFT OLA based digital equalizer.  All new work
 | 
			
		||||
is published under Pulseaudio's original license.
 | 
			
		||||
Copyright 2009 Jason Newton <nevion@gmail.com>
 | 
			
		||||
 | 
			
		||||
Original Author:
 | 
			
		||||
Copyright 2004-2008 Lennart Poettering
 | 
			
		||||
 | 
			
		||||
PulseAudio is free software; you can redistribute it and/or modify
 | 
			
		||||
it under the terms of the GNU Lesser General Public License as published
 | 
			
		||||
by the Free Software Foundation; either version 2.1 of the License,
 | 
			
		||||
or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
PulseAudio is distributed in the hope that it will be useful, but
 | 
			
		||||
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 | 
			
		||||
General Public License for more details.
 | 
			
		||||
 | 
			
		||||
You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
along with PulseAudio; if not, write to the Free Software
 | 
			
		||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -25,9 +50,6 @@
 | 
			
		|||
#include <pulsecore/rtpoll.h>
 | 
			
		||||
#include <pulsecore/sample-util.h>
 | 
			
		||||
#include <pulsecore/ltdl-helper.h>
 | 
			
		||||
#include <liboil/liboilfuncs.h>
 | 
			
		||||
#include <liboil/liboil.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -50,9 +72,15 @@ struct userdata {
 | 
			
		|||
    pa_sink_input *sink_input;
 | 
			
		||||
 | 
			
		||||
    size_t channels;
 | 
			
		||||
    size_t fft_size; //length (res) of fft
 | 
			
		||||
    size_t window_size;//even!
 | 
			
		||||
    size_t overlap_size;
 | 
			
		||||
    size_t fft_size;//length (res) of fft
 | 
			
		||||
    size_t window_size;/*
 | 
			
		||||
                        *sliding window size
 | 
			
		||||
                        *effectively chooses R
 | 
			
		||||
                        */
 | 
			
		||||
    size_t R;/* the hop size between overlapping windows
 | 
			
		||||
              * the latency of the filter, calculated from window_size
 | 
			
		||||
              * based on constraints of COLA and window function
 | 
			
		||||
              */
 | 
			
		||||
    size_t samples_gathered;
 | 
			
		||||
    size_t n_buffered_output;
 | 
			
		||||
    size_t max_output;
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +89,7 @@ struct userdata {
 | 
			
		|||
    float *work_buffer,**input,**overlap_accum,**output_buffer;
 | 
			
		||||
    fftwf_complex *output_window;
 | 
			
		||||
    fftwf_plan forward_plan,inverse_plan;
 | 
			
		||||
    //size_t samplings;
 | 
			
		||||
 | 
			
		||||
    pa_memblockq *memblockq;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -106,8 +135,9 @@ void hamming_window(float *W,size_t window_size){
 | 
			
		|||
        m/=(window_size-1);
 | 
			
		||||
        W[i]=.54-.46*cos(2*M_PI*m);
 | 
			
		||||
    }
 | 
			
		||||
    W[0]/=2;
 | 
			
		||||
    W[window_size-1]/=2;
 | 
			
		||||
    W[window_size-1]=0;
 | 
			
		||||
    //W[0]/=2;
 | 
			
		||||
    //W[window_size-1]/=2;
 | 
			
		||||
}
 | 
			
		||||
void blackman_window(float *W,size_t window_size){
 | 
			
		||||
    //h=.42-.5*cos(2*pi*m)+.08*cos(4*pi*m), m=(0:W-1)/(W-1)
 | 
			
		||||
| 
						 | 
				
			
			@ -132,6 +162,10 @@ void sin_window(float *W,size_t window_size){
 | 
			
		|||
 | 
			
		||||
void array_out(const char *name,float *a,size_t length){
 | 
			
		||||
    FILE *p=fopen(name,"w");
 | 
			
		||||
    if(!p){
 | 
			
		||||
        pa_log("opening %s failed!",name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    for(size_t i=0;i<length;++i){
 | 
			
		||||
        fprintf(p,"%e,",a[i]);
 | 
			
		||||
        //if(i%1000==0){
 | 
			
		||||
| 
						 | 
				
			
			@ -213,7 +247,6 @@ static void sink_update_requested_latency(pa_sink *s) {
 | 
			
		|||
static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
 | 
			
		||||
    struct userdata *u;
 | 
			
		||||
    float *src, *dst;
 | 
			
		||||
    size_t c;
 | 
			
		||||
    pa_memchunk tchunk;
 | 
			
		||||
    pa_sink_input_assert_ref(i);
 | 
			
		||||
    pa_assert(chunk);
 | 
			
		||||
| 
						 | 
				
			
			@ -229,7 +262,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
 | 
			
		|||
    if(u->n_buffered_output>0){
 | 
			
		||||
        //pa_log("outputing %ld buffered samples",u->n_buffered_output);
 | 
			
		||||
        chunk->index = 0;
 | 
			
		||||
        size_t n_outputable=PA_MIN(u->n_buffered_output,nbytes/fs);
 | 
			
		||||
        size_t n_outputable=PA_MIN(u->n_buffered_output,u->max_output);
 | 
			
		||||
        chunk->length = n_outputable*fs;
 | 
			
		||||
        chunk->memblock = pa_memblock_new(i->sink->core->mempool, chunk->length);
 | 
			
		||||
        pa_memblockq_drop(u->memblockq, chunk->length);
 | 
			
		||||
| 
						 | 
				
			
			@ -245,10 +278,11 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
 | 
			
		|||
    pa_assert_se(u->n_buffered_output==0);
 | 
			
		||||
 | 
			
		||||
    //collect the minimum number of samples
 | 
			
		||||
    while(u->samples_gathered < (u->window_size-u->overlap_size)){
 | 
			
		||||
    //TODO figure out a better way of buffering the needed
 | 
			
		||||
    //number of samples, this doesn't seem to work correctly
 | 
			
		||||
    while(u->samples_gathered < u->R){
 | 
			
		||||
        //render some new fragments to our memblockq
 | 
			
		||||
        //size_t desired_samples=PA_MIN(u->min_input-samples_gathered,u->max_output);
 | 
			
		||||
        size_t desired_samples=PA_MIN((u->window_size-u->overlap_size)-u->samples_gathered,u->max_output);
 | 
			
		||||
        size_t desired_samples=PA_MIN(u->R-u->samples_gathered,u->max_output);
 | 
			
		||||
        while (pa_memblockq_peek(u->memblockq, &tchunk) < 0) {
 | 
			
		||||
            pa_memchunk nchunk;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -259,137 +293,80 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
 | 
			
		|||
        if(tchunk.length/fs!=desired_samples){
 | 
			
		||||
            pa_log("got %ld samples, asked for %ld",tchunk.length/fs,desired_samples);
 | 
			
		||||
        }
 | 
			
		||||
        size_t n_samples=PA_MIN(tchunk.length/fs,u->window_size-u->overlap_size-u->samples_gathered);
 | 
			
		||||
        size_t n_samples=PA_MIN(tchunk.length/fs,u->R-u->samples_gathered);
 | 
			
		||||
        //TODO: figure out what to do with rest of the samples when there's too many (rare?)
 | 
			
		||||
        src = (float*) ((uint8_t*) pa_memblock_acquire(tchunk.memblock) + tchunk.index);
 | 
			
		||||
        for (size_t c=0;c<u->channels;c++) {
 | 
			
		||||
            pa_sample_clamp(PA_SAMPLE_FLOAT32NE,u->input[c]+u->overlap_size+u->samples_gathered,sizeof(float), src+c, fs, n_samples);
 | 
			
		||||
            pa_sample_clamp(PA_SAMPLE_FLOAT32NE,u->input[c]+(u->window_size-u->R)+u->samples_gathered,sizeof(float), src+c, fs, n_samples);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        u->samples_gathered+=n_samples;
 | 
			
		||||
        pa_memblock_release(tchunk.memblock);
 | 
			
		||||
        pa_memblock_unref(tchunk.memblock);
 | 
			
		||||
    }
 | 
			
		||||
    //IT should be this guy if we're buffering like how its supposed to
 | 
			
		||||
    //size_t n_outputable=PA_MIN(u->window_size-u->overlap_size,nbytes/fs);
 | 
			
		||||
    //size_t n_outputable=PA_MIN(u->window_size-u->R,u->max_output);
 | 
			
		||||
    //This one takes into account the actual data gathered but then the dsp
 | 
			
		||||
    //stuff is wrong when the buffer "underruns"
 | 
			
		||||
    size_t n_outputable=PA_MIN(u->samples_gathered,nbytes/fs);
 | 
			
		||||
    /*
 | 
			
		||||
    //debugging: tests if immediate release of freshly buffered data
 | 
			
		||||
    //plays ok and prevents any other processing
 | 
			
		||||
    chunk->index=0;
 | 
			
		||||
    chunk->length=n_outputable*fs;
 | 
			
		||||
    chunk->memblock = pa_memblock_new(i->sink->core->mempool, chunk->length);
 | 
			
		||||
    pa_memblockq_drop(u->memblockq, chunk->length);
 | 
			
		||||
    dst = (float*) pa_memblock_acquire(chunk->memblock);;
 | 
			
		||||
    for (size_t c=0;c<u->channels;c++) {
 | 
			
		||||
        pa_sample_clamp(PA_SAMPLE_FLOAT32NE, dst+c, fs, u->input[c]+u->overlap_size, sizeof(float),n_outputable);
 | 
			
		||||
    }
 | 
			
		||||
    u->samples_gathered=0;
 | 
			
		||||
    pa_memblock_release(chunk->memblock);
 | 
			
		||||
    return 0;
 | 
			
		||||
    */
 | 
			
		||||
    size_t n_outputable=PA_MIN(u->R,u->max_output);
 | 
			
		||||
 | 
			
		||||
    //pa_log("%ld dequed samples",u->samples_gathered);
 | 
			
		||||
 | 
			
		||||
    chunk->index=0;
 | 
			
		||||
    chunk->length=n_outputable*fs;
 | 
			
		||||
    chunk->memblock = pa_memblock_new(i->sink->core->mempool, chunk->length);
 | 
			
		||||
    pa_memblockq_drop(u->memblockq, chunk->length);
 | 
			
		||||
    dst = (float*) pa_memblock_acquire(chunk->memblock);
 | 
			
		||||
    //pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input, sizeof(float), src+c, fs, samples);
 | 
			
		||||
    //pa_sample_clamp(PA_SAMPLE_FLOAT32NE, dst+c,fs, u->input, sizeof(float), samples);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    struct timespec start, end;
 | 
			
		||||
    uint64_t elapsed;
 | 
			
		||||
    clock_gettime(CLOCK_MONOTONIC, &start);
 | 
			
		||||
    */
 | 
			
		||||
    //use a zero-phase sliding dft and overlap-add method
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(u->fft_size>=u->window_size);
 | 
			
		||||
    //pa_assert_se(u->window_size%2==0);
 | 
			
		||||
    pa_assert_se(u->overlap_size<u->window_size);
 | 
			
		||||
    pa_assert_se(u->samples_gathered>=u->window_size-u->overlap_size);
 | 
			
		||||
    size_t sample_rem=u->window_size-u->overlap_size-n_outputable;
 | 
			
		||||
    //size_t w_mid=u->window_size/2;
 | 
			
		||||
    //pa_log("hello world a");
 | 
			
		||||
    for (c=0;c<u->channels;c++) {
 | 
			
		||||
        //center the data for zero phase
 | 
			
		||||
        //zero-pad TODO: optimization if sure these zeros aren't overwritten
 | 
			
		||||
        //memset(u->work_buffer+w_mid,0,(u->fft_size-u->window_size)*sizeof(float));
 | 
			
		||||
    pa_assert_se(u->R<u->window_size);
 | 
			
		||||
    pa_assert_se(u->samples_gathered>=u->R);
 | 
			
		||||
    size_t sample_rem=u->R-n_outputable;
 | 
			
		||||
    //use a linear-phase sliding STFT and overlap-add method (for each channel)
 | 
			
		||||
    for (size_t c=0;c<u->channels;c++) {
 | 
			
		||||
        ////zero padd the data
 | 
			
		||||
        //memset(u->work_buffer,0,u->fft_size*sizeof(float));
 | 
			
		||||
        /*
 | 
			
		||||
        for(size_t j=0;j<u->window_size;++j){
 | 
			
		||||
            u->work_buffer[j]=u->W[j]*u->input[c][j];
 | 
			
		||||
            u->work_buffer[j]=u->input[c][j];
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
        //zero padd the data, don't worry about zerophase, shouldn't really matter
 | 
			
		||||
        memset(u->work_buffer+u->overlap_size,0,(u->fft_size-u->overlap_size)*sizeof(float));
 | 
			
		||||
        //window the data
 | 
			
		||||
        memset(u->work_buffer+u->window_size,0,(u->fft_size-u->window_size)*sizeof(float));
 | 
			
		||||
        ////window the data
 | 
			
		||||
        for(size_t j=0;j<u->window_size;++j){
 | 
			
		||||
            u->work_buffer[j]=u->W[j]*u->input[c][j];
 | 
			
		||||
        }
 | 
			
		||||
        /*
 | 
			
		||||
        //recenter for zero phase
 | 
			
		||||
        for(size_t j=0;j<w_mid;++j){
 | 
			
		||||
            float tmp=u->work_buffer[j];
 | 
			
		||||
            u->work_buffer[j]=u->input[c][j+w_mid];
 | 
			
		||||
            u->work_buffer[j+u->fft_size-w_mid]=tmp;
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
        //pa_log("hello world b");
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        //window and zero phase shift
 | 
			
		||||
        for(size_t j=0;j<w_mid;++j){
 | 
			
		||||
            //u->work_buffer[j]=u->input[c][j+w_mid];
 | 
			
		||||
            //u->work_buffer[j+u->fft_size-w_mid]=u->input[c][j];
 | 
			
		||||
            u->work_buffer[j]=u->W[j+w_mid]*u->input[c][j+w_mid];
 | 
			
		||||
            u->work_buffer[j+u->fft_size-w_mid]=u->W[j]*u->input[c][j];
 | 
			
		||||
        }*/
 | 
			
		||||
        //Processing is done here!
 | 
			
		||||
        //do fft
 | 
			
		||||
        //char fname[1024];
 | 
			
		||||
        //if(u->samplings==200){
 | 
			
		||||
        //    pa_assert_se(0);
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        //this iterations input
 | 
			
		||||
        //sprintf(fname,"/home/jason/input%ld-%ld.txt",u->samplings+1,c);
 | 
			
		||||
        //array_out(fname,u->input[c]+(u->window_size-u->R),u->R);
 | 
			
		||||
 | 
			
		||||
        fftwf_execute_dft_r2c(u->forward_plan,u->work_buffer,u->output_window);
 | 
			
		||||
        //perform filtering
 | 
			
		||||
        for(size_t j=0;j<u->fft_size/2+1;++j){
 | 
			
		||||
            ////identity transform (fft size)
 | 
			
		||||
            //u->output_window[j][0]/=u->fft_size;
 | 
			
		||||
            //u->output_window[j][1]/=u->fft_size;
 | 
			
		||||
            ////identity transform (window size)
 | 
			
		||||
            //u->output_window[j][0]/=u->window_size;
 | 
			
		||||
            //u->output_window[j][1]/=u->window_size;
 | 
			
		||||
            //filtered
 | 
			
		||||
            u->output_window[j][0]*=u->H[j];
 | 
			
		||||
            u->output_window[j][1]*=u->H[j];
 | 
			
		||||
        }
 | 
			
		||||
        //inverse fft
 | 
			
		||||
        ////inverse fft
 | 
			
		||||
        fftwf_execute_dft_c2r(u->inverse_plan,u->output_window,u->work_buffer);
 | 
			
		||||
        //the output for the previous iteration's input
 | 
			
		||||
        //sprintf(fname,"/home/jason/output%ld-%ld.txt",u->samplings,c);
 | 
			
		||||
        //array_out(fname,u->work_buffer,u->window_size);
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        //uncenter the data
 | 
			
		||||
        for(size_t j=0;j<w_mid;++j){
 | 
			
		||||
            const float tmp=u->work_buffer[j];
 | 
			
		||||
            u->work_buffer[j]=u->work_buffer[j+u->fft_size-w_mid];
 | 
			
		||||
            u->work_buffer[j+w_mid]=tmp;
 | 
			
		||||
 | 
			
		||||
        ////debug: tests overlaping add
 | 
			
		||||
        ////and negates ALL PREVIOUS processing
 | 
			
		||||
        ////yields a perfect reconstruction if COLA is held
 | 
			
		||||
        //for(size_t j=0;j<u->window_size;++j){
 | 
			
		||||
        //    u->work_buffer[j]=u->W[j]*u->input[c][j];
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        //overlap add and preserve overlap component from this window (linear phase)
 | 
			
		||||
        for(size_t j=0;j<u->R;++j){
 | 
			
		||||
            u->work_buffer[j]+=u->overlap_accum[c][j];
 | 
			
		||||
            u->overlap_accum[c][j]=u->work_buffer[u->window_size-u->R+j];
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
        /*
 | 
			
		||||
        //divide out fft gain (more stable here?)
 | 
			
		||||
        for(size_t j=0;j<u->window_size;++j){
 | 
			
		||||
            u->work_buffer[j]/=u->fft_size;
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
        /*
 | 
			
		||||
        //debug: tests overlaping add
 | 
			
		||||
        //and negates ALL PREVIOUS processing
 | 
			
		||||
        //yields a perfect reconstruction if COLA is held
 | 
			
		||||
        for(size_t j=0;j<u->window_size;++j){
 | 
			
		||||
            u->work_buffer[j]=u->W[j]*u->input[c][j];
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        //debug: tests if basic buffering works
 | 
			
		||||
        //shouldn't modify the signal AT ALL
 | 
			
		||||
| 
						 | 
				
			
			@ -398,40 +375,20 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
 | 
			
		|||
        }
 | 
			
		||||
        */
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        //overlap add and preserve overlap component from this window (zero phase)
 | 
			
		||||
        for(size_t j=0;j<u->overlap_size;++j){
 | 
			
		||||
            u->work_buffer[j]+=u->overlap_accum[c][j];
 | 
			
		||||
            u->overlap_accum[c][j]=u->work_buffer[u->window_size-u->overlap_size+j];
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
        //overlap add and preserve overlap component from this window (linear phase)
 | 
			
		||||
        for(size_t j=0;j<u->overlap_size;++j){
 | 
			
		||||
            u->work_buffer[j]+=u->overlap_accum[c][j];
 | 
			
		||||
            u->overlap_accum[c][j]=u->work_buffer[u->window_size-u->overlap_size+j];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //preseve the needed input for the next windows overlap
 | 
			
		||||
        memmove(u->input[c],u->input[c]+u->overlap_size,(u->window_size-u->overlap_size)*sizeof(float));
 | 
			
		||||
        memmove(u->input[c],u->input[c]+u->R,
 | 
			
		||||
            (u->window_size-u->R)*sizeof(float)
 | 
			
		||||
        );
 | 
			
		||||
        //output the samples that are outputable now
 | 
			
		||||
        pa_sample_clamp(PA_SAMPLE_FLOAT32NE, dst+c, fs, u->work_buffer, sizeof(float),n_outputable);
 | 
			
		||||
        //buffer the rest of them
 | 
			
		||||
        memcpy(u->output_buffer[c]+u->n_buffered_output,u->work_buffer+n_outputable,sample_rem*sizeof(float));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    /*
 | 
			
		||||
    clock_gettime(CLOCK_MONOTONIC, &end);
 | 
			
		||||
    elapsed=time_diff(&end, &start);
 | 
			
		||||
    pa_log("processed: %ld, time: %ld",u->samples_gathered,elapsed);
 | 
			
		||||
    */
 | 
			
		||||
    //u->samplings++;
 | 
			
		||||
    u->n_buffered_output+=sample_rem;
 | 
			
		||||
    u->samples_gathered=0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //pa_log("%ld samples queued",u->n_buffered_output);
 | 
			
		||||
 | 
			
		||||
    pa_memblock_release(chunk->memblock);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -456,6 +413,8 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
 | 
			
		|||
        if (amount > 0) {
 | 
			
		||||
            pa_memblockq_seek(u->memblockq, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
 | 
			
		||||
            pa_log_debug("Resetting equalizer");
 | 
			
		||||
            u->n_buffered_output=0;
 | 
			
		||||
            u->samples_gathered=0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -621,18 +580,12 @@ int pa__init(pa_module*m) {
 | 
			
		|||
    u->sink_input = NULL;
 | 
			
		||||
    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, fs, 1, 1, 0, NULL);
 | 
			
		||||
 | 
			
		||||
    //u->fft_size=44100;
 | 
			
		||||
    //u->fft_size=48000;
 | 
			
		||||
    //u->fft_size=1024;
 | 
			
		||||
    //u->samplings=0;
 | 
			
		||||
    u->channels=ss.channels;
 | 
			
		||||
    u->fft_size=pow(2,ceil(log(ss.rate)/log(2)));
 | 
			
		||||
    //u->fft_size=ss.rate;
 | 
			
		||||
    //u->fft_size=65536;
 | 
			
		||||
    pa_log("fft size: %ld",u->fft_size);
 | 
			
		||||
    u->window_size=8001;
 | 
			
		||||
    u->overlap_size=(u->window_size+1)/2;
 | 
			
		||||
    //u->overlap_size=u->window_size/2;
 | 
			
		||||
    //u->overlap_size=0;
 | 
			
		||||
    u->window_size=7999;
 | 
			
		||||
    u->R=(u->window_size+1)/2;
 | 
			
		||||
    u->samples_gathered=0;
 | 
			
		||||
    u->n_buffered_output=0;
 | 
			
		||||
    u->max_output=pa_frame_align(pa_mempool_block_size_max(m->core->mempool), &ss)/pa_frame_size(&ss);
 | 
			
		||||
| 
						 | 
				
			
			@ -645,34 +598,26 @@ int pa__init(pa_module*m) {
 | 
			
		|||
    for(size_t c=0;c<u->channels;++c){
 | 
			
		||||
        u->input[c]=(float*) fftwf_malloc(u->window_size*sizeof(float));
 | 
			
		||||
        memset(u->input[c],0,u->window_size*sizeof(float));
 | 
			
		||||
        u->overlap_accum[c]=(float*) fftwf_malloc(u->overlap_size*sizeof(float));
 | 
			
		||||
        memset(u->overlap_accum[c],0,u->overlap_size*sizeof(float));
 | 
			
		||||
        u->overlap_accum[c]=(float*) fftwf_malloc(u->R*sizeof(float));
 | 
			
		||||
        memset(u->overlap_accum[c],0,u->R*sizeof(float));
 | 
			
		||||
        u->output_buffer[c]=(float*) fftwf_malloc(u->window_size*sizeof(float));
 | 
			
		||||
    }
 | 
			
		||||
    u->output_window = (fftwf_complex *) fftwf_malloc(sizeof(fftwf_complex) * (u->fft_size/2+1));
 | 
			
		||||
    u->forward_plan=fftwf_plan_dft_r2c_1d(u->fft_size, u->work_buffer, u->output_window, FFTW_ESTIMATE);
 | 
			
		||||
    u->inverse_plan=fftwf_plan_dft_c2r_1d(u->fft_size, u->output_window, u->work_buffer, FFTW_ESTIMATE);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    //rectangular window
 | 
			
		||||
    for(size_t j=0;j<u->window_size;++j){
 | 
			
		||||
        u->W[j]=1.0;
 | 
			
		||||
        u->W[j]=.5;
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
    //hanning_normalized_window(u->W,u->window_size);
 | 
			
		||||
    hanning_window(u->W,u->window_size);
 | 
			
		||||
    //sin_window(u->W,u->window_size);
 | 
			
		||||
    array_out("/home/jason/window.txt",u->W,u->window_size);
 | 
			
		||||
    //u->forward_plan=fftwf_plan_dft_r2c_1d(u->fft_size, u->input, u->output_window, FFTW_ESTIMATE);
 | 
			
		||||
    //u->inverse_plan=fftwf_plan_dft_c2r_1d(u->fft_size, u->output_window, u->work_buffer, FFTW_ESTIMATE);
 | 
			
		||||
    //u->forward_plan=fftwf_plan_dft_r2c_1d(u->fft_size, u->input, u->output, FFTW_MEASURE);
 | 
			
		||||
    //u->inverse_plan=fftwf_plan_dft_c2r_1d(u->fft_size, u->output, u->input, FFTW_MEASURE);
 | 
			
		||||
 | 
			
		||||
    const int freqs[]={0,25,50,100,200,300,400,800,1500,
 | 
			
		||||
        2000,3000,4000,5000,6000,7000,8000,9000,10000,11000,12000,
 | 
			
		||||
        13000,14000,15000,16000,17000,18000,19000,20000,21000,22000,23000,24000,INT_MAX};
 | 
			
		||||
    const float coefficients[]={1,1,1,1,1,1,1,1,1,1,
 | 
			
		||||
        1,1,1,1,1,1,1,1,
 | 
			
		||||
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 | 
			
		||||
    const float coefficients[]={.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,
 | 
			
		||||
        .1,.1,.1,.1,.1,.1,.1,.1,
 | 
			
		||||
        .1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1};
 | 
			
		||||
    const size_t ncoefficients=sizeof(coefficients)/sizeof(float);
 | 
			
		||||
    pa_assert_se(sizeof(freqs)/sizeof(int)==sizeof(coefficients)/sizeof(float));
 | 
			
		||||
    float *freq_translated=(float *) malloc(sizeof(float)*(ncoefficients));
 | 
			
		||||
| 
						 | 
				
			
			@ -683,13 +628,13 @@ int pa__init(pa_module*m) {
 | 
			
		|||
        //pa_log("i: %ld: %d , %g",i,freqs[i],freq_translated[i]);
 | 
			
		||||
        pa_assert_se(freq_translated[i]>=freq_translated[i-1]);
 | 
			
		||||
    }
 | 
			
		||||
    freq_translated[ncoefficients-1]=DBL_MAX;
 | 
			
		||||
    freq_translated[ncoefficients-1]=FLT_MAX;
 | 
			
		||||
    //Interpolate the specified frequency band values
 | 
			
		||||
    u->H[0]=1;
 | 
			
		||||
    for(size_t i=1,j=0;i<(u->fft_size/2+1);++i){
 | 
			
		||||
        pa_assert_se(j<ncoefficients);
 | 
			
		||||
        //max frequency range passed, consider the rest as one band
 | 
			
		||||
        if(freq_translated[j+1]>=DBL_MAX){
 | 
			
		||||
        if(freq_translated[j+1]>=FLT_MAX){
 | 
			
		||||
            for(;i<(u->fft_size/2+1);++i){
 | 
			
		||||
                u->H[i]=coefficients[j];
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -709,9 +654,8 @@ int pa__init(pa_module*m) {
 | 
			
		|||
            j++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    array_out("/home/jason/coffs.txt",u->H,u->fft_size/2+1);
 | 
			
		||||
    //divide out the fft gain
 | 
			
		||||
    for(int i=0;i<(u->fft_size/2+1);++i){
 | 
			
		||||
    for(size_t i=0;i<(u->fft_size/2+1);++i){
 | 
			
		||||
        u->H[i]/=u->fft_size;
 | 
			
		||||
    }
 | 
			
		||||
    free(freq_translated);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue