I started out trying to make a straight port of the excellent SFXR, but quickly got tired of picking through opaquely-named variables, and so made my own sound synthesis doodad instead.
Behold!
http://base.googlehosted.com/base_media?q=hand-4378782228061589590&size=1
Download the jar here.
A rundown of what does what:
The black panels control the value of some variable over time. Left click on them to add a point, right click to remove the closest point, and the points are draggable too. The top 4 panels should be self-explanatory, the fifth shows the effect of the vibrato on the final sound frequency, the final two control the delightfully-named flange effect.
Used to great effect by Hendrix and Procol Harum, flanging overlays the signal with a delayed version of itself, creating some weird effects.
The delay panel controls how delayed the overlay is, while the alpha panel controls how much of the delayed signal is added.
The “Signal” combobox controls the waveform of the sound, the “Vibrato” combobox controls the waveform of the vibrato that’s added to the base frequency, length controls the duration of the sound, in seconds.
“Export” saves the sound as a wav, “Play” plays the sound, and “Save” saves the data needed to recreate the sound if you want to generate it at runtime, like so:
TerrainSound ts = new TerrainSound( getClass().getClassLoader().getResourceAsStream( mySoundFilename ) );
ByteBuffer littleEndian16BitPCMData = ts.generate( 44100 );
All the code is available here.
If you’re hardcore and want to define the sound in code, you can do that too:
SoundSpec ss = new SoundSpec();
ss.volumeEnvelope = new Variable() {
public float getValue( float time )
{
return the volume at that time;
}
};
ss.waveform = new Waveform( ) {
public float valueForPhase( float phase )
{
return the value at this point in a wave, eg sin( 2*PI*phase);
}
};
ss.waveform.frequency = new Variable( ) {
public float getValue( float time )
{
return the frequency at that time;
}
};
ss.length = foo;
ss.postProcess = new PostProcess( ) {
public void process( ShortBuffer data, int sampleRate )
{
postprocesses are optional, but feel free to monkey with the data samples how you like
}
};
ByteBuffer littleEndian16bitPCMData = ss.generate( 44100 );
Enjoy!