void update_pwelch(double *buffer) { unsigned int ctr = 0; // Hanning window the new segment window(buffer); // Do the FFT, we get square magnitudes in return do_fft(buffer); // If this is the first segment, just update the global estimate if (estimates == 0) { for (ctr = 0; ctr < N; ctr++) { global_estimate[ctr] += buffer[ctr]; } estimates++; } else { for (ctr = 0; ctr < N; ctr++) { // Unroll the last time average, generate a new time average per bin global_estimate[ctr] = global_estimate[ctr]*estimates + buffer[ctr]; global_estimate[ctr] /= (float)(estimates+1); } estimates++; } }
// want compiler to be able to make the tail recursion optimisation static int real_add_audio(struct simple_soft_ctx *ctx, const float *in, size_t n, int buf_count) { int bufp = ctx->audio_bufp; const int nr_samp = ctx->nr_samp; size_t remain = 0; size_t cpy = MIN(n, nr_samp/2-bufp); if(ctx->channels == 1) { memcpy(ctx->cur_buf+bufp, in, sizeof(float)*cpy); in += cpy; } else { float *p = ctx->cur_buf+bufp; for(unsigned int i=0; i<cpy; i++, p++, in += 2) *p = (in[0]+in[1])/2; } remain = n - cpy; bufp = (bufp + cpy)%(nr_samp/2); //ctx->sample_count += cpy; ctx->audio_bufp = bufp; if(bufp == 0) { // do we have enough samples to do beat detection? float *fft = do_fft(ctx, ctx->cur_buf, ctx->prev_buf); beat_ctx_update(ctx->beat, fft, nr_samp/2); float *tmp = ctx->cur_buf; ctx->cur_buf = ctx->prev_buf; ctx->prev_buf = tmp; buf_count++; } if(remain > 0) return real_add_audio(ctx, in, remain, buf_count); return buf_count; }
void do_reverse_fft(vector<Data>& b) { do_fft(b); int n = b.size(); reverse(b.begin() + 1, b.end()); for (int i = 0; i < n; i++) b[i] /= n; }
/*! \brief Get FFT data. * \param fftPoints Buffer to copy FFT data * \param fftSize Current FFT size (output). */ void rx_fft_c::get_fft_data(std::complex<float>* fftPoints, unsigned int &fftSize) { boost::mutex::scoped_lock lock(d_mutex); if(d_fftmode >= 1) { if(averagecount > 0) { float normalize = 1.0 / averagecount; //printf("%d ", averagecount); for(unsigned int s=0; s<d_fftsize; s++) { fftPoints[s] = sqrt(normalize * averager[s]); averager[s] = 0; } averagecount = 0; fftSize = d_fftsize; } else { fftSize = 0; } } else { if (d_cbuf.size() < d_fftsize) { // not enough samples in the buffer fftSize = 0; return; } /* perform FFT */ do_fft(d_cbuf.linearize(), d_cbuf.size()); // FIXME: array_one() and two() may be faster //d_cbuf.clear(); /* get FFT data */ memcpy(fftPoints, d_fft->get_outbuf(), sizeof(gr_complex)*d_fftsize); fftSize = d_fftsize; } }
/*! \brief Receiver FFT work method. * \param noutput_items * \param input_items * \param output_items * * This method does nothing except throwing the incoming samples into the * circular buffer. * FFT is only executed when the GUI asks for new FFT data via get_fft_data(). */ int rx_fft_c::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { int i; const gr_complex *in = (const gr_complex*)input_items[0]; (void) output_items; /* just throw new samples into the buffer */ boost::mutex::scoped_lock lock(d_mutex); int fftcount = d_fftsize/2; // 50% overlap for (i = 0; i < noutput_items; i++) { d_cbuf.push_back(in[i]); if(d_fftmode >= 1 && --fftcounter <= 0 && d_cbuf.size() >= d_fftsize) { fftcounter = fftcount; do_fft(d_cbuf.linearize(), d_fftsize); const gr_complex *ob = d_fft->get_outbuf(); if(d_fftmode == 1) { // average for(unsigned int s=0; s<d_fftsize; s++) { gr_complex c = ob[s]; averager[s] += c.real()*c.real() + c.imag()*c.imag(); } averagecount++; } else { // peak for(unsigned int s=0; s<d_fftsize; s++) { gr_complex c = ob[s]; float power = c.real()*c.real() + c.imag()*c.imag(); if(power > averager[s]) averager[s] = power; } averagecount = 1; } } } return noutput_items; }
/*! \brief Get FFT data. * \param fftPoints Buffer to copy FFT data * \param fftSize Current FFT size (output). */ void rx_fft_f::get_fft_data(std::complex<float>* fftPoints, unsigned int &fftSize) { boost::mutex::scoped_lock lock(d_mutex); if (d_cbuf.size() < d_fftsize) { // not enough samples in the buffer fftSize = 0; return; } /* perform FFT */ do_fft(d_cbuf.linearize(), d_cbuf.size()); // FIXME: array_one() and two() may be faster //d_cbuf.clear(); /* get FFT data */ memcpy(fftPoints, d_fft->get_outbuf(), sizeof(gr_complex)*d_fftsize); fftSize = d_fftsize; }
int main(int argc, char **argv) { SNDFILE *file1, *file2; SF_INFO info1, info2; double *in1, *in2; int min_frames, i; int like = 0, unlike = 0; int total = 0; int max1, max2; struct fft_average *avg; memset(&info1, 0, sizeof(SF_INFO)); memset(&info2, 0, sizeof(SF_INFO)); if (argc < 3) { printf("compare file1 file2"); return 1; } file1 = sf_open(argv[1], SFM_READ, &info1); if (!file1) { printf("Error opening wave file %s\n", argv[1]); exit(1); } file2 = sf_open(argv[2], SFM_READ, &info2); if (!file2) { printf("Error opening wave file %s\n", argv[2]); sf_close(file2); exit(1); } /* seconds = (float)info1.frames/(float)info1.samplerate; printf("Opened %s\n", argv[1]); printf("frames: %d\n", info1.frames); printf("samplerate: %d\n", info1.samplerate); printf("length (in seconds): %f\n", seconds); printf("channels: %d\n", info1.channels); printf("format: %x\n", info1.format); printf("sections: %d\n", info1.sections); printf("seekable: %d\n", info1.seekable); */ in1 = (double *)malloc(sizeof(double) * info1.frames); if (!in1) { printf("Failed to allocate input array\n"); sf_close(file1); sf_close(file2); return 1; } in2 = (double *)malloc(sizeof(double) * info2.frames); if (!in2) { printf("Failed to allocate input array\n"); free(in1); sf_close(file1); sf_close(file2); return 1; } normalize_wave(file1, in1, info1.frames, info1.channels); normalize_wave(file2, in2, info2.frames, info2.channels); max1 = shift_wave(in1, info1.frames); max2 = shift_wave(in2, info2.frames); // max1 = find_max(in1, info1.frames); // max2 = find_max(in2, info2.frames); /* shift_wave(in1, info1.frames); shift_wave(in2, info2.frames); */ plsdev("xwin"); plinit(); plenv(0.0f, info1.frames, -1, 1, 0, 0); for (i = 0; i < info1.frames; i++) { PLFLT x; PLFLT sample = i; if (in1[i] == -2) continue; x = in1[i]; plpoin(1, &sample, &x, 1); } plend(); plsdev("xwin"); plinit(); plenv(0.0f, info2.frames, -1, 1, 0, 0); for (i = 0; i < info2.frames; i++) { PLFLT x; PLFLT sample = i; if (in2[i] == -2) continue; x = in2[i]; plpoin(1, &sample, &x, 1); } plend(); avg = do_fft(in1, max1); printf("yavg = %f, xavg=%f\n", avg->yavg, avg->xavg); free(avg); avg = do_fft(in2, max2); printf("yavg = %f, xavg=%f\n", avg->yavg, avg->xavg); free(avg); min_frames = (info1.frames < info2.frames) ? info1.frames : info2.frames; for (i = 0; i < min_frames; i++) { double diff; if (in1[i] == -2 || in2[i] == -2) break; if (in1[i] > in2[i]) diff = in1[i] - in2[i]; else diff = in2[i] - in1[i]; if (diff <= 0.05) like++; else unlike++; total++; } printf("Minimum frames: %d\n", min_frames); printf("Total compares: %d\n", total); printf("Like: %d\n", like); printf("Unlike: %d\n", unlike); printf("Percentage alike: %f\n", ((double)like / (double)total) * 100); printf("Max1: %d\n", max1); printf("Max2: %d\n", max2); free(in1); free(in2); sf_close(file1); sf_close(file2); return 0; }
//static int threshold = -60; void sanalyzer_render_freq (gint16 /*in_data*/[]) { #if 0 gint i, c; gint y; gint16 freq_data[1024]; static int fl = 0; #ifdef DEBUG struct timeval tv1, tv2; gettimeofday (&tv1, NULL); #endif do_fft (freq_data, in_data); CVFD::getInstance ()->Clear (); #ifdef DEBUG //gettimeofday (&tv1, NULL); #endif for (i = 0; i < NUM_BANDS; i++) { y = 0; #if 0 // using max value for (c = xscale[i]; c < xscale[i + 1]; c++) { if(freq_data[c] > threshold) { int val = freq_data[c]-threshold; if (val > y) y = val; } } #else int val = 0; int cnt = 0; for (c = xscale[i]; c < xscale[i + 1]; c++) { if(freq_data[c] > threshold) { val += freq_data[c]-threshold; cnt++; } } if(cnt) y = val/cnt; #endif if (y > HEIGHT - 1) y = HEIGHT - 1; if (y > bar_heights[i]) bar_heights[i] = y; else if (bar_heights[i] > FALL) bar_heights[i] -= FALL; else bar_heights[i] = 0; if (y > falloffs[i]) falloffs[i] = y; else if (falloffs[i] > FALLOFF) { fl ++; if(fl > 2) { fl = 0; falloffs[i] -= FALLOFF; } } else falloffs[i] = 0; CVFD::getInstance ()->drawBar (i*WIDTH, 64-falloffs[i]-5, WIDTH, 2); y = bar_heights[i]; CVFD::getInstance ()->drawBar (i*WIDTH, 64-y, WIDTH, y); } #ifdef DEBUG gettimeofday (&tv2, NULL); printf("Calc takes %dns\n", (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec)); #endif CVFD::getInstance ()->Update (); #endif }
int main( int argc, char **argv ) { if ( use_gui ) { printf("init_sdl()\n"); if ( init_sdl() ) return 1; printf("init_gl()\n"); init_gl(); } printf("init_fft()\n"); init_fft(); #ifdef USE_FIFO printf("init_mpd()\n"); if ( init_mpd() ) return 1; #endif #ifdef USE_ALSA printf("init_alsa()\n"); if ( init_alsa() ) return 1; #endif if ( use_serial ) { printf("init_serial()\n"); if ( init_serial() ) use_serial = FALSE; } init_lights(); init_table(); pthread_t sample_thread; pthread_create(&sample_thread, NULL, &get_samples, NULL); while ( !done ) { // check to see if we have a new sample if (new_sample == 1) { // we are going to process this sample, it is no longer new pthread_mutex_lock(&sample_mutex); new_sample = 0; pthread_mutex_unlock(&sample_mutex); do_fft(); detect_beats(); assign_lights(); //assign_cells(); if ( use_gui ) { if (handle_sdl_events()) return 1; draw_all(); } if ( use_serial ) send_serial_fpga(); } usleep(5000); } return 0; }
static gboolean spectrogram_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data) { w_spectrogram_t *w = user_data; GtkAllocation a; gtk_widget_get_allocation (widget, &a); if (!w->samples || a.height < 1) { return FALSE; } int width, height; width = a.width; height = a.height; int ratio = ftoi (FFT_SIZE/(a.height*2)); ratio = CLAMP (ratio,0,1023); if (deadbeef->get_output ()->state () == OUTPUT_STATE_PLAYING) { do_fft (w); float log_scale = (log2f(w->samplerate/2)-log2f(25.))/(a.height); float freq_res = w->samplerate / FFT_SIZE; if (a.height != w->height) { w->height = MIN (a.height, MAX_HEIGHT); for (int i = 0; i < w->height; i++) { w->log_index[i] = ftoi (powf(2.,((float)i) * log_scale + log2f(25.)) / freq_res); if (i > 0 && w->log_index[i-1] == w->log_index [i]) { w->low_res_end = i; } } } } // start drawing if (!w->surf || cairo_image_surface_get_width (w->surf) != a.width || cairo_image_surface_get_height (w->surf) != a.height) { if (w->surf) { cairo_surface_destroy (w->surf); w->surf = NULL; } w->surf = cairo_image_surface_create (CAIRO_FORMAT_RGB24, a.width, a.height); } cairo_surface_flush (w->surf); unsigned char *data = cairo_image_surface_get_data (w->surf); if (!data) { return FALSE; } int stride = cairo_image_surface_get_stride (w->surf); if (deadbeef->get_output ()->state () == OUTPUT_STATE_PLAYING) { for (int i = 0; i < a.height; i++) { // scrolling: move line i 1px to the left memmove (data + (i*stride), data + sizeof (uint32_t) + (i*stride), stride - sizeof (uint32_t)); } for (int i = 0; i < a.height; i++) { float f = 1.0; int index0, index1; int bin0, bin1, bin2; if (CONFIG_LOG_SCALE) { bin0 = w->log_index[CLAMP (i-1,0,height-1)]; bin1 = w->log_index[i]; bin2 = w->log_index[CLAMP (i+1,0,height-1)]; } else { bin0 = (i-1) * ratio; bin1 = i * ratio; bin2 = (i+1) * ratio; } index0 = bin0 + ftoi ((bin1 - bin0)/2.f); if (index0 == bin0) index0 = bin1; index1 = bin1 + ftoi ((bin2 - bin1)/2.f); if (index1 == bin2) index1 = bin1; index0 = CLAMP (index0,0,FFT_SIZE/2-1); index1 = CLAMP (index1,0,FFT_SIZE/2-1); f = spectrogram_get_value (w, index0, index1); float x = 10 * log10f (f); // interpolate if (i <= w->low_res_end && CONFIG_LOG_SCALE) { int j = 0; // find index of next value while (i+j < height && w->log_index[i+j] == w->log_index[i]) { j++; } float v0 = x; float v1 = w->data[w->log_index[i+j]]; if (v1 != 0) { v1 = 10 * log10f (v1); } int k = 0; while ((k+i) >= 0 && w->log_index[k+i] == w->log_index[i]) { j++; k--; } x = linear_interpolate (v0,v1,(1.0/(j-1)) * ((-1 * k) - 1)); } // TODO: get rid of hardcoding x += CONFIG_DB_RANGE - 63; x = CLAMP (x, 0, CONFIG_DB_RANGE); int color_index = GRADIENT_TABLE_SIZE - ftoi (GRADIENT_TABLE_SIZE/(float)CONFIG_DB_RANGE * x); color_index = CLAMP (color_index, 0, GRADIENT_TABLE_SIZE-1); _draw_point (data, stride, width-1, height-1-i, w->colors[color_index]); } } cairo_surface_mark_dirty (w->surf); cairo_save (cr); cairo_set_source_surface (cr, w->surf, 0, 0); cairo_rectangle (cr, 0, 0, a.width, a.height); cairo_fill (cr); cairo_restore (cr); return FALSE; }