Sine wave alternates distortion in Java
I am trying to create a sine wave and add it to a byte array. I searched and found. However, I always get a distorted waveform as an attachment.
Please give me your opinion as to why this is happening. Thank.
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;
}
An example of a picture distortion shape
source to share
The code looks great. I suspect the renderer is interpreting the two's complement signed values โโas unsigned ( -1
becomes 255
, -2
becomes, 254
and so on).
I am writing to a wav file and drawing it using SonicVisualiser
According to WAVE PCM audio file format :
8-bit samples are stored as unsigned bytes ranging from 0 to 255. 16-bit samples are stored as signed integers "2" ranging from -32768 to 32767.
It looks like you need to shift your sine wave by 128 (so that it fits completely into the 0-255 range), or move on to using 16-bit samples.
source to share
You can use this code to convince yourself that what you are creating is suitable at the Java semantics level:
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. Correct your code by creating 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 type this, you will see the same signal that you saw in the SonicVisualizer, but in this tool it looks as you intended.
source to share