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

enter image description here

+3


source to share


2 answers


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.

+5


source


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.

0


source







All Articles