c++ - How to efficiently determine the minimum necessary size of a pre-rendered sine wave audio buffer for looping? -


i've written program generates sine-wave @ user-specified frequency, , plays on 96khz audio channel. save few cpu cycles employ old trick of pre-rendering short section of audio buffer, , playing buffer in loop, can avoid calling sin() function 96000 times per second duration of program , simple memory-copying instead.

my problem efficiently determining minimum usable size of pre-rendered buffer be. frequencies easy -- example, 8khz sine wave can represented generating 12-sample buffer , playing in looping, because (8000*12 == 96000). other frequencies, however, single cycle of sine wave requires non-integral number of samples represent, , therefore looping single cycle's worth of samples cause unacceptable glitching.

for of frequencies, however, it's possible around problem pre-rendering more 1 cycle of sine wave , looping -- if can figure out how many cycles required number of cycles present in buffer integral, while guaranteeing number of samples in buffer integral. example, sine-wave frequency of 12.8khz translates single-cycle buffer-size of 7.5 samples, won't loop cleanly, if render 2 consecutive cycles of sine wave 15-sample buffer, can cleanly loop result.

my current approach solving issue brute force: try possible cycle-counts , see if of them result in buffer size integral number of samples in it. think approach unsatisfactory following reasons:

1) it's inefficient. example, program shown below (which prints buffer-size results 480,000 possible frequency values between 0hz , 48khz) takes 35 minutes complete on 2.7ghz machine. think there must faster way this.

2) suspect results not 100% accurate, due floating-point errors.

3) algorithm gives if can't find acceptable buffer size less 10 seconds long. (i make limit higher, of course make algorithm slower).

so, there way calculate minimum-usable-buffer-size analytically, preferably in o(1) time? seems should easy, haven't been able figure out kind of math should use.

thanks in advance advice!

#include <stdio.h> #include <math.h> static const long long samples_per_second = 96000; static const long long max_allowed_buffer_size_samples = (samples_per_second * 10); // returns length of pre-render buffer needed // loop sine wave @ given frequence, or -1 on failure. static int getnumcyclesneededforprerenderedbuffer(float freqhz) { double onecyclelengthsamples = samples_per_second/freqhz; (int count=1; (count*onecyclelengthsamples) < max_allowed_buffer_size_samples; count++) { double remainder = fmod(onecyclelengthsamples*count, 1.0); if (remainder > 0.5) remainder = 1.0-remainder; if (remainder <= 0.0) return count; } return -1; } int main(int, char **) { (int i=0; i<48000*10; i++) { double freqhz = ((double)i)/10.0f; int numcyclesneeded = getnumcyclesneededforprerenderedbuffer(freqhz); if (numcyclesneeded >= 0) { double onecyclelengthsamples = samples_per_second/freqhz; printf("for %.1fhz, use pre-render-buffer size of %f samples (%i cycles, %f samples/cycle)\n", freqhz, (numcyclesneeded*onecyclelengthsamples), numcyclesneeded, onecyclelengthsamples); } else printf("for %.1fhz, there no suitable pre-render-buffer size under allowed limit!\n", freqhz); } return 0; } 

number_of_cycles/size_of_buffer = frequency/samples_per_second 

this implies if can simplify frequency/samples_per_second fraction, can find size of buffer , number of cycles in buffer. if frequency , samples_per_second integers, can simplify fraction finding greatest common divisor, otherwise can use method of continued fractions.

example:

say frequency 1234.5, , samples_per_second 96000. can make these 2 integers multiplying 10, ratio:

frequency/samples_per_second = 12345/960000

the greatest common divisor 15, can reduced 823/64000.

so need 823 cycles in 64000 sample buffer reproduce frequency exactly.


Comments

Popular posts from this blog

javascript - backbone.js Collection.add() doesn't `construct` (`initialize`) an object -

php - Get uncommon values from two or more arrays -

Adding duplicate array rows in Php -