Skip to main content

Help with Java sound pleez...

2 replies [Last post]
jacketyjack
Offline
Joined: 2007-04-24
Points: 0

Hey peeps,

I was juss wondering whether anyone can help me with the Java Sound API. I know this is maybe not the right forum for it but the audio forum looks really outdated (2004)!!!

I have looked on the net everywhere but there nothing customized to my need. OK, here's the thing: I found some source code on the net that I need to undertand. Here's what's goin on: It's reading data in from the microphone plugged into the line in jack through a TargetDataLine structure, putting it into a temporary byte array of size 10000, then sticking it into a ByteArrayOutputStream strcuture continously until some stop event occurs (such as clicking the stop button). Then when the play button is clicked, the information in the ByteArrayOutputStream is played out by using a SourceDataLine. Here's the source code of the capturing part:

When the Capture button is clicked:

audioFormat = getAudioFormat();
DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
targetDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
targetDataLine.open(audioFormat);
targetDataLine.start();

Thread captureThread = new Thread(new CaptureThread());
captureThread.start();

Here's the captureThread:

class CaptureThread extends Thread
{
byte tempBuffer[] = new byte[10000];

public void run()
{
byteArrayOutputStream = new ByteArrayOutputStream();
StopListening = false;
try
{int cntr = 0;
while (!StopListening)
{

int cnt = targetDataLine.read(tempBuffer, 0, tempBuffer.length);
if (cnt > 0)
{
byteArrayOutputStream.write(tempBuffer, 0, cnt);

}
}
byteArrayOutputStream.close();

}
catch (Exception e)
{
System.err.println(e);
System.exit(0);
}
}
}

Here's the problem, I need to be able to write custom sounds of any frequency not just reading from the mic. I know that to do that I would probably have to manipulate the values inside the tempBuffer before writing it to the byteArrayOutputStream. So kindly someone answer the following:

1. Why, in your expert opinion, was the tempBuffer given a size of 10000 and not something else. Can this be changed and if so how will it affect the sound wave coming out?

2. What is the format of the bits/bytes with relation to the final frequency that will come out. OK, rephrasal: how can I generate a sound wave that will be of a frequency X? What is the formula? What is the way? For example, how can I generate a sound of a frequency of exactly 216Hz? Or how would I generate a sound that goes from a low frequency and builds up to a high frequency?

I realise that I haven't been able to ask the question properly, I hope y'all won't mind. If I haven't given enough info ask me for more.
I'LL APPRECIATE ANY HELP A GREAT DEAL.

Thanks in advance.

Yours Sincerely,
Jack

Message was edited by: jacketyjack

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
twe
Offline
Joined: 2005-05-11
Points: 0

Long time ago that I did something with the sound API, so take this with a grain of salt. Further, I did the math on the fly, it might be wrong.

First, run, don't walk :-) to http://www.jsresources.org/ for all the information about the Java Sound API that should have been in Sun's documentation, but aren't. Pay particular attention to the FAQ and the example code.

> I found some source code on the net

Many problems in the programming world start with these five words "I found some source code" :-)

In all seriousness, consider writing your own code from scratch - as a learning experience. You will have to work through the existing documentation (Sun's and others). Which is hard and a pain. But at the end you should hopefully understand what you are doing, instead of having to mess with other people's code. Trust me, it feels much better to know what one is doing.

> 1. Why, in your expert opinion, was the tempBuffer
> given a size of 10000 and not something else. Can
> this be changed and if so how will it affect the
> sound wave coming out?

In my non-expert opinion the buffer size is arbitrary. Since you don't provide us with the audio format/encoding in use it is not possible to judge if the buffer is maybe sized in a way that it can hold a particular duration of sound. But even if it would it is IMHO not relevant. 8192 or 32768 or whatever number in the same magnitude should do as well for the simple recording application (for generating sound one can do a better selection, see below).

> 2. What is the format of the bits/bytes with relation
> to the final frequency that will come out.

That is what you have to tell us by looking at the audio format/encoding your code is using.

But first things first. There are two things you have to take care about:

1/ Sampling a sound signal.

More precisely, you have to sample a virtual signal, represented by some mathematical formula. All sounds can be broken down into a number of sinus waves (cf. Fourier transformation), and a sound containing just one frequency is a single sinus wave. So you have to sample the values from a sinus function. The sampling frequency needs to be at least twice the highest signal frequency (cf. Nyquist, Shannon, Kotelnikov, Whittaker sampling theorem). That's the theory. In practice you should sample more often, e.g. four times the highest frequency.

2/ Encoding the sample

When you have managed to generate your sample values, you need to encode them into a format known by the Java sound api. Since it is up to you to select one from the available ones, there are many choices. Hint: If you want to generate sound, use a simple encoding, e.g. some PCM type without a-law or μ-law companding.

Sampling and encoding go hand in hand. E.g. when you specify an audio format, you specify the number of samples per second. You have to chose this number so that the sampling theorem can be fulfilled. Once you have chosen the number you need to stick to it when actually sampling the sinus wave.

Example: If you decide to go with an encoding of 16k samples/second you can as a maximum encode a frequency of 8 kHz (in practice it is a little less). Lets say you want to generate a 6kHz frequency. So you need to provide 16/6 = 2.666... samples per period. Generating fractions of samples is not possible, so you need to sample periods until you end up at a complete period. In the example this are three periods (3 * 2.666... = 8). For the example you need to provide 8 samples from three periods of the sinus function, taken at 2 * PI * 3/8 distances (8 * (2 * PI * 3/8) = 3 * 2 * PI = 3 sinus periods) .

Yes, just eight values are enough to represent this particular signal. So a buffer of eight sampling values would do (see the Sound API's Clip class for how to repeatedly play a sample). Or, the other way around, just generating 1/750 of a second of the signal is good enough to represent it. This is different for other frequencies where you might need to compromise at frequency accuracy.

To generate the samples for the example, think of code along the line of (code does not compile, and the forum software is doing strange things at the format, therefor the strange array index { i } )

> for(i = 0; i < 8; i++) {
> sample{ i } = encode(sin(2.0 * pi * i * 3.0 / 8.0 ))
> }

Encode would be a function which you have to provide to convert the values generated by the sin() function -1 ... 1 into the encoding for the samples, e.g. PCM.

> rephrasal: how can I generate a sound wave that will
> be of a frequency X? What is the formula? What is the
> way? For example, how can I generate a sound of a
> frequency of exactly 216Hz?

Take the example above, and do 216Hz as an exercise.

> Or how would I generate a
> sound that goes from a low frequency and builds up to
> a high frequency?

That is more fun. You would have to continuously change the samples (generate a stream of data). it goes along the same line as above (I didn't check the math in detail):

1/ Adhere to the sampling theorem. So chose a sampling frequency which is good enough for the highest frequency you want to generate. E.g. 16k samples/sec. if your sound at the end does not exceed 8kHz.

2/ Construct the signal you want to sample

It consists of two steps:

a) Increase frequency over time. I assume a linear increase, starting at frequency a, ending at b (b < 2 * sampling frequency), over a period of p

> f(t) = a + t/p * (b - a)

b) construct the to-be-sampled function

> s(t) = sin(t * 2 * pi * f(t))

3/ Sample the signal

Calculate s(t) in 1/16000 (the sampling frequency) steps, for p * 16000 times.

> I'LL APPRECIATE ANY HELP A GREAT DEAL.

Please don't shout.

arunarun143
Offline
Joined: 2008-08-13
Points: 0

hello twe,

I am impressed with the answer you gave. I have a similar problem.

My task is basically a form of noise reduction for which I
1) first and foremost need to find the frequency at 3000 hz from the wav file.
2) To remove the noise(3000 hz frequency) we want to multiply it with 0, so that we will be nullifying the frequency at 3000 hz.

thanks