patternjavaMinor
Playing pure sinusoidal tones
Viewed 0 times
playingpuresinusoidaltones
Problem
I wrote a simple sound player to use as part of my
The method takes a specific frequency and a duration as parameters, and plays the frequency for the specified duration.
Please explain in as much detail as possible, as I'm new and might not understand.
MorseString class. I am new to using sounds (in fact, I was helped a lot by Google) and I don't know if this is the correct way to play a sound.The method takes a specific frequency and a duration as parameters, and plays the frequency for the specified duration.
private static final int SAMPLING_FREQUENCY_IN_HZ = 8000;
private static final int NUMBER_OF_FADE_SAMPLES = 80;
private static void sound(int hz, int msecs) throws LineUnavailableException {
byte[] buf = new byte[msecs * Byte.SIZE];
for (int i = 0; i < buf.length; i++) {
double angle = i / (SAMPLING_FREQUENCY_IN_HZ / hz) * 2 * Math.PI;
buf[i] = (byte) (Math.sin(angle) * Byte.MAX_VALUE);
}
for (int i = 0; i < NUMBER_OF_FADE_SAMPLES && i < buf.length / 2; i++) {
buf[i] = (byte) (buf[i] * i / NUMBER_OF_FADE_SAMPLES);
buf[buf.length - 1 - i] = (byte) (buf[buf.length - 1 - i] * i / NUMBER_OF_FADE_SAMPLES);
}
AudioFormat af = new AudioFormat(SAMPLING_FREQUENCY_IN_HZ, Byte.SIZE, 1, true, false);
SourceDataLine sdl = AudioSystem.getSourceDataLine(af);
sdl.open(af);
sdl.start();
sdl.write(buf, 0, buf.length);
sdl.drain();
sdl.close();
}- The sound sounds like it is low-quality. Is there a way to improve that?
- Did I do my math wrong?
Please explain in as much detail as possible, as I'm new and might not understand.
Solution
In a sense, your math is wrong. In
… both of the divisions are done using integer arithmetic. As a result, I get nothing more than a clicking noise. To get the intended signal, you have to cast
By the Nyquist criterion, a sample rate of 8000 Hz means that you can play a frequency no higher than 4000 Hz. Therefore, for robustness, you should do one of three things:
It would also be wise to define the fade-in / fade-out period as a multiple of the sampling rate.
double angle = i / (SAMPLING_FREQUENCY_IN_HZ / hz) * 2 * Math.PI;… both of the divisions are done using integer arithmetic. As a result, I get nothing more than a clicking noise. To get the intended signal, you have to cast
i to a double. Better yet, write it instead asdouble angle = 2 * Math.PI * i * hz / SAMPLING_FREQUENCY_IN_HZ;By the Nyquist criterion, a sample rate of 8000 Hz means that you can play a frequency no higher than 4000 Hz. Therefore, for robustness, you should do one of three things:
- Throw an exception if
hz >= SAMPLING_FREQUENCY_IN_HZ / 2.
- Let the sampling frequency vary, by setting it to
16 * hz, for example.
- Set
SAMPLING_FREQUENCY_IN_HZhigh enough so that it covers the range of human hearing (44.1 kHz for CD audio, 48 kHz for DVD video soundtracks).
It would also be wise to define the fade-in / fade-out period as a multiple of the sampling rate.
Code Snippets
double angle = i / (SAMPLING_FREQUENCY_IN_HZ / hz) * 2 * Math.PI;double angle = 2 * Math.PI * i * hz / SAMPLING_FREQUENCY_IN_HZ;Context
StackExchange Code Review Q#75438, answer score: 5
Revisions (0)
No revisions yet.