• Post Reply Bookmark Topic Watch Topic
  • New Topic

Recording and capturing  RSS feed

 
Redan Hassoun
Greenhorn
Posts: 29
Android AngularJS Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi ,
I am trying to develop a small java application which records audio from the microphone,
the application has two main threads :
1. The recorder thread :
This thread reads data from a TargetDataLine and records is into a file in storage.
2. The amplitude-checker thread :
This thread has to run along with the recorder thread and check the amplitude of the sound.

There is no need for me to explain exactly why i am doing that, simply the problem is that
the two threads are reading the same TargetDataLine (Because i couldn't open a second one).
and this causes a bad recording because the recorder thread does not read the data smoothly from
the TargetDataLine.

How can i solve this problem ?
Please help !
 
Carey Brown
Saloon Keeper
Posts: 3309
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What is the purpose of having two threads reading from the same TargetDataLine?
 
Campbell Ritchie
Marshal
Posts: 56518
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
…and welcome to the Ranch
 
Redan Hassoun
Greenhorn
Posts: 29
Android AngularJS Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Carey Brown wrote:What is the purpose of having two threads reading from the same TargetDataLine?



Here is an explanation :

The purpose of the application is to record a sound wave, and print out some information about that sound wave.
The problem is :
The recording should stop when the sound wave ends - Not run forever.
How do i know when the sound wave ends ?
This occurs when there is no more loud sounds coming to the microphone.
What is a loud sound ?
A loud sound happens when the amplitude of the wave exceeds a defined threshold.

So....
I tried to make another thread that works along with the recorder thread, and checks the amplitude periodically.
That other thread must have access to the microphone input (the TargetDataLine) .
But ...
When two threads are reading the same TargetDataLine - each one of them consumes half of the data - PROBLEM.
I am searching for a solution for that problem.
I will be glad if someone can help
 
Redan Hassoun
Greenhorn
Posts: 29
Android AngularJS Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:…and welcome to the Ranch

Thank you
 
Carey Brown
Saloon Keeper
Posts: 3309
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Is there a reason that you need two threads to do this?

You might have thread 1 keep track of a sliding window of maximum values over some number of samples. Then you could have thread 1 call a call-back method when the max is below some threshold.

Edit: Having two threads would imply that you have two asynchronous events taking place, which is not the scenario that you are describing.
 
Redan Hassoun
Greenhorn
Posts: 29
Android AngularJS Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Carey Brown wrote:Is there a reason that you need two threads to do this?

You might have thread 1 keep track of a sliding window of maximum values over some number of samples. Then you could have thread 1 call a call-back method when the max is below some threshold.


Ok...
Assuming i have just one thread - the recording thread.
The run method of this thread is :


And,
audioInputStream - is an audio stream that reads its data from the target data line.
targetType - is the type of the audio file (WAV).
signalFile - is the file i store data to.


The thread reads whatever exists on the TargetDataLine buffer and writes it to the signalFile.
how can i call a call-back method when the max amplitude value is greater than the threshold ?
the AudioSystem's write method blocks until the targetDataLine is closed - how can i have access to the
sample values ?
 
Carey Brown
Saloon Keeper
Posts: 3309
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Interesting. I've never worked with the AudioSystem collection of classes. Having just now looked them over I don't see any methods that allow you to get a volume. How were you doing this in your second thread? Please post the code if it's not too long.
 
Carey Brown
Saloon Keeper
Posts: 3309
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ah, I see it. TargetDataLine.getLevel()
 
Redan Hassoun
Greenhorn
Posts: 29
Android AngularJS Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Carey Brown wrote:Interesting. I've never worked with the AudioSystem collection of classes. Having just now looked them over I don't see any methods that allow you to get a volume. How were you doing this in your second thread? Please post the code if it's not too long.


The second thread :


Ignore the "SatelliteTimerService.getInstance().startTimer()", if you take a look at targetLine object - this is the
same TargetDataLine object reference that "Recorder thread" reads from.
which causes recording a distributed (discontinuous) sound.
I'm pretty new using the java sound API, i'm sure i am missing something ...
 
Carey Brown
Saloon Keeper
Posts: 3309
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You have a fundamental problem in your second thread. You retrieve a byte array full of data and presume that one byte represents one sample. The number of bits per audio sample, I believe, varies with the format and is more than likely not equal to 8 bits. This is why TargetDataLine has a getLevel() method that returns a float between 0 and 1. I'm not sure though how one would go about setting up the TargetDataLine and level sample rate.
 
Dave Tolls
Ranch Foreman
Posts: 3056
37
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Redan Hassoun wrote:The problem is :
The recording should stop when the sound wave ends - Not run forever.
How do i know when the sound wave ends ?
This occurs when there is no more loud sounds coming to the microphone.
What is a loud sound ?
A loud sound happens when the amplitude of the wave exceeds a defined threshold.


To me that says you want your amplitude checking thing between the data line and the writing to a file.
Acting as a filter, where it stops forwarding things when the input goes 'quiet'.

Of course how you do that with the classes you are using is the question.
 
Dave Tolls
Ranch Foreman
Posts: 3056
37
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Since you're looking at amplitude , isn't that what the getLevel method is for?

How about extending the AudioInputStream so you can check the current level on each read call?
If it's OK then pass it on to the underlying AIS read method, if not then return -1?

Feels a bit clunky offhand, but just throwing out some ideas.
 
Redan Hassoun
Greenhorn
Posts: 29
Android AngularJS Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Carey Brown wrote:You have a fundamental problem in your second thread. You retrieve a byte array full of data and presume that one byte represents one sample. The number of bits per audio sample, I believe, varies with the format and is more than likely not equal to 8 bits. This is why TargetDataLine has a getLevel() method that returns a float between 0 and 1. I'm not sure though how one would go about setting up the TargetDataLine and level sample rate.


According to my format, the sample size in bits is 8.
I didn't know there is a getLevel() method, i will check that up.
 
Redan Hassoun
Greenhorn
Posts: 29
Android AngularJS Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dave Tolls wrote:Since you're looking at amplitude , isn't that what the getLevel method is for?

How about extending the AudioInputStream so you can check the current level on each read call?
If it's OK then pass it on to the underlying AIS read method, if not then return -1?

Feels a bit clunky offhand, but just throwing out some ideas.



Looks like a good idea, i will give it a try
 
Carey Brown
Saloon Keeper
Posts: 3309
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Redan Hassoun wrote:According to my format, the sample size in bits is 8.

Just out of curiosity, which format are you using?
 
Redan Hassoun
Greenhorn
Posts: 29
Android AngularJS Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Carey Brown wrote:
Redan Hassoun wrote:According to my format, the sample size in bits is 8.

Just out of curiosity, which format are you using?


Iv'e changed it several times, now it's :
Sample rate = 44100 HZ
Sample size in bits = 16
Big Endian= false
Data signed = true
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!