I've written this small signal generating method. My goal is to generate a beep with a slight time delay between the two channels (left and right) or a slight difference in gain between the channels. Currently I create the delay by filling a buffer with zeros for one channel and values for the second and further down swapping the behavior between the channels (If you have any tips or ideas how to do this better it would be appreciated.) The next stage is doing something similar with the gain. I have seen that Java gives built in gain control via FloatControl:
FloatControl gainControl =
(FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN);
But I am not sure how to control the gain for each channel separately. Is there a built in way to do this? Would I need two separate streams, one for each channel? If so how do I play them simultaneously? I am rather new to sound programming, if there are better ways to do this please let me know. Any help is very much appreciated.
This is my code so far:
public static void generateTone(int delayR, int delayL, double gainRightDB, double gainLeftDB)
throws LineUnavailableException, IOException {
// in hz, number of samples in one second
int sampleRate = 100000; // let sample rate and frequency be the same
// how much to add to each side:
double gainLeft = 100;//Math.pow(10.0, gainLeftDB / 20.0);
double gainRight = 100;// Math.pow(10.0, gainRightDB / 20.0);;
// click duration = 40 us
double duration = 0.08;
double durationInSamples = Math.ceil(duration * sampleRate);
// single delay window duration = 225 us
double baseDelay = 0.000225;
double samplesPerDelay = Math.ceil(baseDelay * sampleRate);
AudioFormat af;
byte buf[] = new byte[sampleRate * 4]; // one second of audio in total
af = new AudioFormat(sampleRate, 16, 2, true, true); // 44100 Hz, 16 bit, 2 channels
SourceDataLine sdl = AudioSystem.getSourceDataLine(af);
sdl.open(af);
sdl.start();
// only one should be delayed at a time
int delayRight = delayR;
int delayLeft = delayL;
int freq = 1000;
/*
* NOTE:
* The buffer holds data in groups of 4. Every 4 bytes represent a single sample. The first 2 bytes
* are for the left side, the other two are for the right. We take 2 each time because of a 16 bit rate.
*
*
*/
for(int i = 0; i < sampleRate * 4; i++){
double time = ((double)i/((double)sampleRate));
// Left side:
if (i >= delayLeft * samplesPerDelay * 4 // when the left side plays
&& i % 4 < 2 // access first two bytes in sample
&& i <= (delayLeft * 4 * samplesPerDelay)
+ (4 * durationInSamples)) // make sure to stop after your delay window
buf[i] = (byte) ((1+gainLeft) * Math.sin(2*Math.PI*(freq)*time)); // sound in left ear
//Right side:
else if (i >= delayRight * samplesPerDelay * 4 // time for right side
&& i % 4 >= 2 // use second 2 bytes
&& i <= (delayRight * 4 * samplesPerDelay)
+ (4 * durationInSamples)) // stop after your delay window
buf[i] = (byte) ((1+gainRight) * Math.sin(2*Math.PI*(freq)*time)); // sound in right ear
}
for (byte b : buf)
System.out.print(b + " ");
System.out.println();
sdl.write(buf,0,buf.length);
sdl.drain();
sdl.stop();
sdl.close();
}