I've just released a long-overdue update to Blip_Buffer, my band-limited synthesis sound library, which is good for implementing things like the NES APU and expansion sound chips. You configure the clock rate and output sample rate, then generate the waveforms by specifying the timestamps (in NES clocks) where the amplitude changes. It handles the rest, including adjustable treble and bass filtering. It's written in portable, conservative C++ and licensed under the GNU Lesser General Public License (LGPL). Some C programmers have used it without problem, due to its light use of C++. Examples of sound quality and programs using it are available.
Blip_Buffer-0.4.0.zip
I've done a lot to simplify the interface and make the demos clearer. Now they play sound live and show the waveform on screen, using SDL (they can still be made to write output to a sound file for examination with a sound editor). This allows you to experiment with the code and hear/see the results immediately, and use the mouse to adjust parameters in real-time.
On the implementation side I trimmed the library down to just two files (header and source) and rewrote it to use an internal 32-bit sample buffer and fixed some problems with the filter kernel windowing and phase resolution, resulting in slightly better sound quality. It's based on my efficient synthesis algorithm.
Feedback welcome, especially critique.
Blip_Buffer-0.4.0.zip
I've done a lot to simplify the interface and make the demos clearer. Now they play sound live and show the waveform on screen, using SDL (they can still be made to write output to a sound file for examination with a sound editor). This allows you to experiment with the code and hear/see the results immediately, and use the mouse to adjust parameters in real-time.
Code:
#include "Blip_Buffer.h"
// Waveform synthesizer for amplitude range of -10 to 10
static Blip_Synth<blip_good_quality,20> synth;
static Blip_Buffer buf; // Sample buffer
int main()
{
buf.clock_rate( 1789773 ); // 1.79 MHz clock rate
if ( buf.set_sample_rate( 48000 ) ) // 48 kHz sample rate
return 1; // out of memory
synth.output( &buf ); // output to buffer
synth.volume( 0.50 ); // 50% volume
// Generate this waveform:
// 10 ___
// 5 ___ | |
// 0 ____| |___ | |________
// -5 | |
//-10 |___|
// 0 100 200 300 400 500 600 700 (time in NES clocks)
synth.update( 100, 5 );
synth.update( 200, 0 );
synth.update( 300, -10 );
synth.update( 400, 10 );
synth.update( 500, 0 );
buf.end_frame( 700 );
// Read and play however many samples were generated
blip_sample_t temp [1000];
int count = buf.read_samples( temp, 1000 );
play_samples( temp, count );
return 0;
}
// Waveform synthesizer for amplitude range of -10 to 10
static Blip_Synth<blip_good_quality,20> synth;
static Blip_Buffer buf; // Sample buffer
int main()
{
buf.clock_rate( 1789773 ); // 1.79 MHz clock rate
if ( buf.set_sample_rate( 48000 ) ) // 48 kHz sample rate
return 1; // out of memory
synth.output( &buf ); // output to buffer
synth.volume( 0.50 ); // 50% volume
// Generate this waveform:
// 10 ___
// 5 ___ | |
// 0 ____| |___ | |________
// -5 | |
//-10 |___|
// 0 100 200 300 400 500 600 700 (time in NES clocks)
synth.update( 100, 5 );
synth.update( 200, 0 );
synth.update( 300, -10 );
synth.update( 400, 10 );
synth.update( 500, 0 );
buf.end_frame( 700 );
// Read and play however many samples were generated
blip_sample_t temp [1000];
int count = buf.read_samples( temp, 1000 );
play_samples( temp, count );
return 0;
}
On the implementation side I trimmed the library down to just two files (header and source) and rewrote it to use an internal 32-bit sample buffer and fixed some problems with the filter kernel windowing and phase resolution, resulting in slightly better sound quality. It's based on my efficient synthesis algorithm.
Feedback welcome, especially critique.