I'm trying to use AudioTrack to generate sine, square, and sawtooth waves. However, the audio this is creating doesn't sound like a pure sine wave, but like it has some kind of other wave overlayed. How would I go about getting the pure sine wave like in the second code example, while using the method in my first example? Since the top example only moves around some of the arithmetic used in the second, shouldn't they produce an identical wave?
@Override
protected Void doInBackground(Void... foo) {
short[] buffer = new short[1024];
this.track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
float samples[] = new float[1024];
this.track.play();
while (true) {
for (int i = 0; i < samples.length; i++) {
samples[i] = (float) Math.sin( (float)i * ((float)(2*Math.PI) * frequency / 44100)); //the part that makes this a sine wave....
buffer[i] = (short) (samples[i] * Short.MAX_VALUE);
}
this.track.write( buffer, 0, samples.length ); //write to the audio buffer.... and start all over again!
}
}
Note: This does give me a pure sine wave:
@Override
protected Void doInBackground(Void... foo) {
short[] buffer = new short[1024];
this.track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
float increment = (float)(2*Math.PI) * frequency / 44100; // angular increment for each sample
float angle = 0;
float samples[] = new float[1024];
this.track.play();
while (true) {
for (int i = 0; i < samples.length; i++) {
samples[i] = (float) Math.sin(angle); //the part that makes this a sine wave....
buffer[i] = (short) (samples[i] * Short.MAX_VALUE);
angle += increment;
}
this.track.write( buffer, 0, samples.length ); //write to the audio buffer.... and start all over again!
}
}
Thanks to Martijn: The problem is that the wave is getting cut off between wavelengths in the buffer. Increasing the buffer size solves the problem in the second example. It appears that the Math.PI * 2 arithmetic was the most intensive of the loop, so moving that value to an external variable that is only computed once solves everything.
Try to optimise your code by
Why? Because I suspect the buffer to taking to long to prepare, what causes a lag between two buffer pushes to big, which might be causing the noise.
The only material difference that I can see in your two code samples is that the equation in your first example contains an integer (I
), and therefore you're probably doing integer (not floating-point) arithmetic. This would cause a staircasing effect, adding unwanted harmonics to your waveform.
I suspect that if you simply cast I
to a float in your equation, it will produce a pure sine wave.
samples[i]
= (float) Math.sin( (float)i * ((float)(2*Math.PI) * frequency / 44100));
None of these anwers fixes the problem. The buffer length should be a multiple of the sample rate, or at least the length of one rotation. Let's break it in ton of variables to show what's happening:
int sampleRate = 44100;
int bitsPerChannel = 16;
int bytesPerChannel = bitsPerChannel / 8;
int channelCount = 1;
int bytesPerSample = channelCount * bytesPerChannel;
int bytesPerRotation = sampleRate * bytesPerSample * (1d / (double) frequency);
Then you can multiply this bytesPerRotation
by anything, it won't change a fact: there won't be glitch in the sound.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With