#define TRACERPLUS (-5) #include "lasp_sosfilterbank.h" #include "lasp_mq.h" #include "lasp_worker.h" #include "lasp_nprocs.h" typedef struct Sosfilterbank { /// The filter_coefs matrix contains filter coefficients for a SOS filter. us filterbank_size; us nsections; /// The filter coefficients for each of the filters in the Filterbank /// The *first* axis is the filter no, the second axis contains the /// filter coefficients, in the order, b_0, b_1, b_2, a_0, a_1, a_2, which /// corresponds to the transfer function /// b_0 + b_1 z^-1 + b_2 z^-2 /// H[z] = ------------------------- /// a_0 + a_1 z^-1 + a_2 z^-2 dmat sos; /// sos[filter_no, coeff] /// Storage for the current state of the output, first axis correspond to /// the filter number axis, the second axis contains state coefficients dmat state; #ifdef LASP_PARALLEL JobQueue* jq; Workers* workers; #endif // LASP_PARALLEL } Sosfilterbank; us Sosfilterbank_getFilterbankSize(const Sosfilterbank* fb) { fsTRACE(15); assertvalidptr(fb); return fb->filterbank_size; feTRACE(15); } int filter_single(void* worker_data,void* job); static inline us min(us a, us b){ return ab?a:b; } Sosfilterbank* Sosfilterbank_create( const us nthreads_, const us filterbank_size, const us nsections) { fsTRACE(15); dbgassert(filterbank_size <= MAX_SOS_FILTER_BANK_SIZE, "Illegal filterbank size. Max size is " annestr(MAX_SOS_FILTER_BANK_SIZE)); Sosfilterbank* fb = (Sosfilterbank*) a_malloc(sizeof(Sosfilterbank)); fb->filterbank_size = filterbank_size; dbgassert(nsections < MAX_SOS_FILTER_BANK_NSECTIONS,"Illegal number of sections"); fb->nsections = nsections; /// Allocate filter coefficients matrix fb->sos = dmat_alloc(filterbank_size, nsections*6); fb->state = dmat_alloc(filterbank_size, nsections*2); dmat_set(&(fb->state), 0); /// Set all filter coefficients to unit impulse response vd imp_response = vd_alloc(6*nsections); vd_set(&imp_response,0); for(us section = 0;section < nsections; section++) { // Set b0 coefficient to 1 setvecval(&imp_response, 0 + 6*section, 1); // Set a0 coefficient to 1 setvecval(&imp_response, 3 + 6*section, 1); } // Initialize all filters with a simple impulse response, single pass for(us filter_no = 0; filter_no < filterbank_size; filter_no++) { Sosfilterbank_setFilter(fb,filter_no,imp_response); } // Check if coefficients are properly initialized // print_dmat(&(fb->sos)); vd_free(&imp_response); #ifdef LASP_PARALLEL fb->jq = NULL; fb->workers = NULL; dbgassert(nthreads_ <= LASP_MAX_NUM_THREADS, "Illegal number of threads"); us nthreads; us nprocs = getNumberOfProcs(); if(nthreads_ == 0) { nthreads = min(max(nprocs/2,1), filterbank_size); } else { nthreads = nthreads_; } iVARTRACE(15, nthreads); if(nthreads > 1) { if(!(fb->jq = JobQueue_alloc(filterbank_size))) { Sosfilterbank_free(fb); feTRACE(15); return NULL; } if(!(fb->workers = Workers_create(nthreads, fb->jq, NULL, &filter_single, NULL, NULL))) { Sosfilterbank_free(fb); feTRACE(15); return NULL; } } #endif // LASP_PARALLEL feTRACE(15); return fb; } void Sosfilterbank_setFilter(Sosfilterbank* fb,const us filter_no, const vd filter_coefs) { fsTRACE(15); assertvalidptr(fb); assert_vx(&filter_coefs); iVARTRACE(15, filter_coefs.n_rows); iVARTRACE(15, filter_no); dbgassert(filter_no < fb->filterbank_size, "Illegal filter number"); dbgassert(filter_coefs.n_rows == fb->nsections * 6, "Illegal filter coefficient length"); dmat *sos = &fb->sos; /* dmat *state = &fb->state; */ us nsections = fb->nsections; for(us index=0;indexsos)); dmat_free(&(fb->state)); #ifdef LASP_PARALLEL if(fb->workers) Workers_free(fb->workers); if(fb->jq) JobQueue_free(fb->jq); #endif // LASP_PARALLEL a_free(fb); feTRACE(15); } typedef struct { us filter_no; us nsections; us nsamples; dmat sos; dmat state; dmat ys; } Job; int filter_single(void* worker_data, void* job_) { fsTRACE(15); Job* job = (Job*) job_; us nsections = job->nsections; us nsamples = job->nsamples; dmat sos = job->sos; for(us section=0;sectionstate),job->filter_no,section*2); d w2 = *getdmatval(&(job->state),job->filter_no,section*2+1); d b0 = *getdmatval(&sos,job->filter_no,section*6+0); d b1 = *getdmatval(&sos,job->filter_no,section*6+1); d b2 = *getdmatval(&sos,job->filter_no,section*6+2); /* d a0 = *getdmatval(&sos,job->filter_no,section*6+3); */ d a1 = *getdmatval(&sos,job->filter_no,section*6+4); d a2 = *getdmatval(&sos,job->filter_no,section*6+5); d* y = getdmatval(&(job->ys), 0, job->filter_no); for(us sample=0;samplestate),job->filter_no,section*2) = w1; *getdmatval(&(job->state),job->filter_no,section*2+1) = w2; } feTRACE(15); return 0; } dmat Sosfilterbank_filter(Sosfilterbank* fb,const vd* xs) { fsTRACE(15); assertvalidptr(fb); assert_vx(xs); dmat state = fb->state; dmat sos = fb->sos; us nsections = fb->nsections; us filterbank_size = fb->filterbank_size; us nsamples = xs->n_rows; dmat ys = dmat_alloc(nsamples, filterbank_size); /// Copy input signal to output array for(us filter=0;filterworkers) { assertvalidptr(fb->jq); JobQueue_push(fb->jq, &(jobs[filter])); } else { #endif // LASP_PARALLEL /* No workers, we have to do it ourselves */ filter_single(NULL,(void*) &(jobs[filter])); #ifdef LASP_PARALLEL } #endif // LASP_PARALLEL } #ifdef LASP_PARALLEL if(fb->workers) { JobQueue_wait_alldone(fb->jq); } #endif // LASP_PARALLEL feTRACE(15); return ys; }