Reputation: 31
I'm trying to generate sine wave and add it to byte array. I searched and found. However, I always get distorted waveform like an attachment.
Please give me your opinion why it happens. Thanks.
My code is here
private byte[] getData(int freq) { // taking pitch data
double pha = Math.PI/2; // defining phase
final int LENGTH = 44100 * 10; // defining length of sine wave, byte array
final byte[] arr = new byte[LENGTH];
for(int i = 0; i < arr.length; i++) {
double angle = (2.0 * Math.PI * i*freq+pha) / (44100);
arr[i] = (byte) (Math.cos(angle) *127* 0.3); // 0.3 is amplitude scale
}
return arr;
}
Upvotes: 3
Views: 589
Reputation: 200196
You can use this code to convince yourself that what you generate is appropriate at the level of Java semantics:
public static void main(String[] args) {
for (byte b : getData(300)) System.out.println(sample(b));
}
static String sample(byte val) {
final int len = (val-Byte.MIN_VALUE)/2;
final StringBuilder b = new StringBuilder();
for (int i = 0; i < len; i++) b.append(i < len-1? ' ' : '#');
return b.toString();
}
It will print a nice vertical sine. Fix your code by producing unsigned bytes with this method:
static byte[] getData(int freq) {
double pha = Math.PI/2;
final int LENGTH = 44100 * 10;
final byte[] arr = new byte[LENGTH];
for(int i = 0; i < arr.length; i++) {
double angle = (2.0 * Math.PI * i*freq+pha) / (44100);
int unsignedSample = (int) (Math.cos(angle)*Byte.MAX_VALUE*0.3 - Byte.MIN_VALUE);
arr[i] = (byte) (unsignedSample & 0xFF);
}
return arr;
}
If you print this, you'll see the same waveform which you saw in SonicVisualizer, but in that tool it will look the way you intended to.
Upvotes: 0
Reputation: 500663
The code looks fine. I suspect it's the visualiser interpreting the two's complement signed values as unsigned (-1
becoming 255
, -2
becoming 254
and so on).
I write to a wav file and plot it with SonicVisualiser
According to WAVE PCM soundfile format:
8-bit samples are stored as unsigned bytes, ranging from 0 to 255. 16-bit samples are stored as 2's-complement signed integers, ranging from -32768 to 32767.
It looks like you either need to shift your sine wave up by 128 (so that it fits fully within the 0-255 range), or move to using 16-bit samples.
Upvotes: 5