Jump to content
  • entries
    18
  • comments
    35
  • views
    29768

Block Transfers, Buffers, and Audio

Sign in to follow this  
fastcall22

1549 views

Waiting for Visual Studio to update, so I thought I'd write something.

When working with streams such as file or audio processing, you usually run into the same problem: How to copy the most data without knowing how large the stream of data is. I solved a similar problem at work and in my audio synthesizer. In the case of the synthesizer, I wanted an echo effect that fed back N stored seconds of audio.

Here's how a simple block transfer could look:
// assuming:HANDLE src;HANDLE dst;int src_size;// and:const int block_size = 8 * 1000; // 8 KBchar* block = alloc(block_size);// then:int remaining = src_size;for ( int bytes_read = 0; bytes_read = read(src, block, block_size)); remaining -= bytes_read ){ // (process block) write(dst, block, bytes_read); remaining -= bytes_read;}For a block_size of 100 and a src_size of 550, you would make 6 writes of sizes:


100 100 100 100 100 50

The echo effect was a bit different: I have two buffers of known length, but one of the buffers is circular and has a read and write head at two different positions within that buffer.
// assuming:int samples = 44100;int audio_buffer_len = samples / 100;float* out_audio = new float[audio_buffer_len]; // 1-channel audio at 44.1KHz, 100ms buffer// and some state:struct delay_effect { float delay_amp = 0.25f; int delay_stride = samples * 2 / 3; // 667ms or 29400 samples int buffer_size = delay_stride + 320; // some extra padding float* buffer = new float[buffer_size]; int wdx = 0; // write position within buffer int rdx = delay_stride; // read position within buffer // the extra padding on buffer is needed to keep the write head from interfering // with the read head and vice-versa void apply(float* out_audio, int audio_buffer_len);};// then:void delay_effect::apply(float* out_audio, int audio_buffer_len) { float* out_ap = out_audio; int samples_remaining = audio_buffer_len; while ( samples_remaining ) { // find minimum number of samples needed such that: // 1. read head does not overflow buffer // 2. write head does not overflow buffer // 3. audio buffer is not overflowed int take = min( min(buffer_size - wdx, buffer_size - rdx), samples_remaining ); // apply effect to out_audio // (SIMD candidate: snap to 16-byte boundaries and lengths, use float4s instead) float* in_bp = buffer + rdx; float* out_bp = buffer + wdx; for ( int idx = 0; idx < take; ++idx ) { // read from buffer, apply damping, accumulate into output audio, // and store the mixed audio into y float y = (*out_ap++ += *in_bp++ * damping); // feed audio back into buffer *out_bp++ = y; } // advance read and write position, wrapping around buffer length wdx = (wdx + take) % buffer_size; rdx = (rdx + take) % buffer_size; samples_remaining -= take; }}Stepping through, you might see something like this for an audio buffer sized 50, and an echo buffer sized 190, and a delay of 85 samples:
buf# loop# take rdx wdx 1 1 50 0 85 2 1 50 50 135 3 1 5 100 185 3 2 45 105 0 4 1 40 150 45 4 2 10 0 85 5 1 50 10 95 6 1 45 60 145 6 2 5 105 0 7 1 50 110 5As you can see, the entire audio buffer is covered: sum(`take`) group by `buf#`
And neither rdx+take nor wdx+take extends past the echo buffer's 190 samples.


Okay, that's all for now.
See you around.

Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!