Click here to Skip to main content
15,867,686 members
Please Sign up or sign in to vote.
1.80/5 (3 votes)
See more: , +
this below, it even plays a 1hz sound clearly; while it shouldn't:

import javax.sound.sampled.*;

public class soundwithdetails {
public static float SAMPLE_RATE = 44100f;

public static void sound(int hz, int msecs, double vol)
throws LineUnavailableException {

byte[] buf = new byte[(int)SAMPLE_RATE * msecs / 1000];

for (int i=0; i<buf.length; i++) {
double angle = i / (SAMPLE_RATE / hz) * 2.0 * Math.PI;
buf[i] = (byte)(Math.sin(angle) * 127.0 * vol);
}

(int i=0; i < SAMPLE_RATE / 100.0 && i < buf.length / 2; i++) {
buf[i] = (byte)(buf[i] * i / (SAMPLE_RATE / 100.0));
buf[buf.length-1-i] =
(byte)(buf[buf.length-1-i] * i / (SAMPLE_RATE / 100.0));
}

AudioFormat af = new AudioFormat(SAMPLE_RATE,16,2,true,false);
SourceDataLine sdl = AudioSystem.getSourceDataLine(af);
sdl.open(af);
sdl.start();
sdl.write(buf,0,buf.length);
sdl.drain();
sdl.close();
}

}


What I have tried:

obviously the range is 20-22000 hz and it is even so difficult to recognize sounds under 50 hz; there is a mobile app that generates frequencies and it seems like pretty correct; unless what this code represents.
Posted
Updated 1-Jul-22 10:16am
v2
Comments
Dave Kreskowiak 27-Jun-22 11:57am    
Was there supposed to be a question about this?
T1xT 27-Jun-22 12:11pm    
its clear; the sound this code makes and its supposed to be 1hz, isnt a real 1hz sound because it can be heard by you and human cant hear sounds under 20hz- as this fact is correct about sound generator apps which the 1hz sound they maje is completely a mute sound to humans-
so there should be something wrong with this code.
Richard MacCutchan 27-Jun-22 12:17pm    
Did you write this code or copy it from somewhere?
T1xT 27-Jun-22 12:59pm    
copied;but I get what it does unless the part it works with the math.sin().
0x01AA 27-Jun-22 13:17pm    
You setup the AudioFormat to Stereo. Maybe try first with Mono. Means replace AudioFormat af = new AudioFormat(SAMPLE_RATE,16,2,true,false); by
AudioFormat af = new AudioFormat(SAMPLE_RATE,16,1,true,false);

Another thing which looks supecious is the bits per sample which is 16. Ok, that can be adjusted by the volume. Maybe you show also how (with what parameter) you call public static void sound(int hz, int msecs, double vol)

About that part (int i=0; i < SAMPLE_RATE / 100.0 && i < buf.length / 2; i++) {
buf[i] = (byte)(buf[i] * i / (SAMPLE_RATE / 100.0));
buf[buf.length-1-i] =
(byte)(buf[buf.length-1-i] * i / (SAMPLE_RATE / 100.0));
}
I'm still thinking about what this should do....

***Warning*** This is my first java application after a crash course today. Take care, it is
a.) inefficient
b.) no naming conventions
c.) simply fast and dirty

But it shows the at least the steps how to build a sine sound.
I have also cross checked the result auditive with Online Tone Generator - generate pure tones of any frequency[^]

The following code implements the steps I mentioned in 'Solution 1'.
public class Main
{
	// Audio Cross checked with with:
    // https://www.szynalski.com/tone-generator/

	private static void PlaySineSound(int hz, int msecs, double volPercent)
    throws LineUnavailableException
	{
		double SAMPLE_RATE = 44100.0;
		double MAX_AMPLITUDE = 32768.0; // 16 Bit Signed
		
		double timeSeconds= msecs / 1000.0;
		double volumeMultiplier= volPercent / 100.0 * MAX_AMPLITUDE;
	  
		//
		// Calculate Sine for given frequency, timeSeconds, vol
		//
		
		// Buffer signed 16 Bit
		int shortBufferSize= (int) (timeSeconds * SAMPLE_RATE);
		short[] shortBuf = new short[shortBufferSize];
			
		// Time Signal
		double dT= timeSeconds / shortBufferSize;
		for (int tIx= 0; tIx < shortBufferSize; tIx++)
		{
		  double time= tIx * dT;
		  double sinValue= Math.sin(2.0 * Math.PI * hz * time);
		  shortBuf[tIx]= (short)(volumeMultiplier * sinValue);
		}

		// short buffer to byte buffer. Attention, very inefficient
	    byte[] byte_array = new byte[2 * shortBufferSize];
	    for (int i = 0; i < shortBuf.length; ++i)
        {
			byte_array[2*i] = (byte)shortBuf[i];
            byte_array[2*i+1] = (byte) (shortBuf[i] >> 8);
        }	

		//
		// Play sound
		//	
		//AudioFormat(float sampleRate, 
        //            int sampleSizeInBits, 
        //            int channels, boolean signed, boolean bigEndian)
		AudioFormat af = new AudioFormat((int)SAMPLE_RATE, 16, 1, true, false);
		SourceDataLine sdl = AudioSystem.getSourceDataLine (af);
		sdl.open (af);
		sdl.start ();
		sdl.write (byte_array, 0, byte_array.length);
		sdl.drain ();
	}

  public static void main (String[]args)
  {
    System.out.println ("Sound ...");

    try
    {
		PlaySineSound(60, 5000, 50.0);
		System.out.println ("... Sound Done");
    }
    catch (Exception e)
    {
      System.out.println ("Exception!" + e);
    }
  }
}


I hope it helps.
 
Share this answer
 
Comments
CPallini 2-Jul-22 8:52am    
5.
0x01AA 2-Jul-22 9:00am    
Thank you very much, Sir
Maciej Los 2-Jul-22 15:17pm    
Also 5!
0x01AA 3-Jul-22 7:20am    
Thank you very much Maciej
T1xT 12-Jul-22 19:26pm    
well, thank you for the answer. just got your code to test; everything in your code is correct and works fine (only the part about the sample size isn't clear enough to me).
I run your code and to be honest, it still plays a 2hz which you can actually hear - so just don't know where is the problem; if is with the sound setting of windows or something else. but there is something about this code, that it is better than the first code I've copied here because it clearly plays a 1hz that everyone can hear it.
anyway I am going to accept the answer since the community here agree with it, so it should be correct - thanks for the time you spent for the solution.
The pragmatic approach ...
... as soon this works one can think about to optimize it (e.g. loops instead of creating 10 Seconds of the same shape, stereo, etc.).

You like to play a sinus- sound:
Duration	    : [Sec]
SampleFrequency	: [Sample Per Second]
Frequency	    : [Hz]

The above gives us the buffer size:
bufferSize= Duration * SampleFrequency
E.g.
10 Seconds
44'100 Samlpes per second
-> 441'000 samples

Keep in mind, these 441'000 samples represent something like a 'time line'.

Now coming to calculate the shape of the buffer. Here the formula
A*sin(2π(ft))
comes into acount (the background of that is too much to explain it here).
A: Amplitude (Volume)
f: Frequency of the sound
t: time
Note: Usually the function sin expects a argument in rad

Again: We have the buffer of size bufferSize for a duration of 'Duration' [Sec], therefore we know that the time increment will be:
dt= Duration / bufferSize; // Make sure you to calculate that with double or float

Finally we need only to loop about the bufferSize.
Pseudo Code:
double dT= duration / bufferSize;
for (int tIx= 0; tIx < bufferSize; tIx++)
{
  double time= tIx * dT;
  double sinValue= sin(2π(f * time))
  buffer[tIx]= volume * sinValue;
}

All untested and written out of my memory after having my last lesson in 'communications engineering' before about 30 years and never used it since then. Nevertheless I hope it helps you ;)

[Edit]
Volume/Amplitude can be in the range of 0...about 32'000 in case you use 16 Bit Samples.
 
Share this answer
 
v4
Comments
T1xT 1-Jul-22 8:52am    
thank you for your answer; I am still reading about sound and its physics (from the link in that comment) and once I get done with that, will back to the answer - it seems to be what I needed.
0x01AA 1-Jul-22 12:46pm    
Thank you for your feedback.
I'm completely Java noob, but interesting to learn. Therefore my questions:
What is the most easy process to setup an Java Compiler on Windows?
Does it makes sense to go for visual studio plugin?

If I can setup a minimal java developing environment I can make some tests, which maybe can help you ;)
T1xT 2-Jul-22 9:13am    
well in theory, simplest way is just to install java (if its not already installed) and use a text editor and cmd; but it will really be painful to develop any application that way; best environment I know of, is eclipse which gives you almost everything you need through just one installation and few setups - without eclipse, it would take at least 10 times more effort and time to develop same app by text editor and cmd; and when it comes to debug a complex project, simply forget about working with anything but eclipse.
0x01AA 2-Jul-22 9:18am    
Thank you for your feedback. Meanwhile I 'installed jdk-18.0.1.1', really low level stuff, but ok for a first trial. See 'Solution 2' which gives now the correct output.
T1xT 2-Jul-22 9:26am    
really thanks for the answers; I will be back on them soon and I am still working on the waves and energy theories that is needed for my project.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900