javaaudiosine-wave

Play a sine wave indefinitely - java


I'm trying to make a piece of code that can play a sine wave continually. I want to be able to play a frequency of a MIDI note. The MIDI library in java feels a bit sloppy (when I tell it to play there is a small delay between the press of the key and the playing of the note).

I have seen the example where you generate a sine wave of determined length and then you play it by giving a SourceDataLine a byte array. This worked but the byte array can only be so long and it would stop playing eventually.

My next idea was to constantly write a single byte to the line, calculate the next line and continue. Here is my code:

int i = 0;
int sampleRate = 8000;
int freq = 440;

while (true) {
    double samplingInterval = (double) (sampleRate / freq);
    double angle = (2.0 * Math.PI * i) / samplingInterval;
    byte toPlay = (byte) (Math.sin(angle) * 127);
    line.write(new byte[] {toPlay}, 0, 1);
    i++;
}

I hoped this would give me a constant output of frequency 440hz but it gave me this error:

java.lang.IllegalArgumentException: illegal request to write non-integral number of frames (1 bytes, frameSize = 2 bytes)

If not, is there a way to speed up the MIDI library in java or have I just made a silly mistake? Thanks in advance.


Solution

  • A frame of audio is one or more concurrently timed audio samples. In your case, stereo (frames ==2). In the stream they are typically interleaved (e.g. L, R, L, R....).

    You can fix this by writing each sample twice.

    Whilst Java (or any other JITd language runtime with stop-the-world garbage collection) is never the implementation choice for low-latency audio software, I suspect the 'sloppiness' you detect is in fact a long audio buffer period: The default setting for the buffer period might a substantial fraction of a second.