I use in a java code a wav file that I load into an AudioInputStream using AudioInputStream ais = AudioSystem.getAudioInputStream("file.wav")
Once I have done that, I wish to basically pick up the n amount of seconds at the end (let's say the 5 last seconds) and "fade out" the volume (FloatControl.Type.MASTER_GAIN??).
Once done I could transfert my audiostreaminput back into a wav file using: AudioSystem.write(ais, Type.WAVE, file_output);
the result is a same wav file but with the last 5 seconds fading out (volume decreasing).
Any idea on how to do this? I tried changing the ais into bytes[], or a sourcedataline... but didn't find what I wanted, as most examples are about changing volume of an audio "in-play" (I also saw things around using Clip which also seems to be dealing an audio file in-play)
Many thanks everyone
Start by turning the sound into a byte array. Then turn the bytes into samples: you'll need to find a tutorial specifically for this, it's a little involved in Java (http://www.jsresources.org/ is a good resource). Samples are the direct representation of the sound wave.
To decrease the volume, multiply all the samples by something less than 1, and then save them back to a byte array. To fade out you'll need to multiply the last n samples by a decreasing function. Then write out the file with the proper WAV headers.
These are just a few pointers for a complex process, hopefully they will send you in the right direction.
Related
How can I save an opened audio file with changed volume?
I trying this:
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("some_file.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(-30.0f); // Reduce volume by 10 decibels.
File file = new File("new.wav");
AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, file);
But this is saving an empty file.
I think your best bet will be to take the bytes from the AudioInputStream and convert them to PCM values, then multiply the PCM values by a factor that matches -10 db. I don't know what that factor would be. Then convert back to bytes and write that.
The first code example in the tutorial Using Files and Format Converters shows a while loop where the conversions would take place, at the comment: "// Here, do something useful with the audio..."
The prior tutorial on the Audio Trail: "Processing Audio with Controls" might also be helpful, but the built-in controls are limited and dependent on the host computer and OS. For example, if you want to change volumes (put in a fade-in or fade-out) the control lines probably don't work very well due to the granularity being tied to the size of the audio buffer. So I recommend the advice of the final paragraphs of the "Processing Audio with Controls" tutorial, the section "Manipulating the Audio Data Directly".
I am working on a speech recognizer project as a part of it want from a wav file want to find the presence of silence or detect the presence of word .and if a word is found then copy that word from start to end into a new wav file so it original wav file has 10 words then output is 10 file..problem is with detecting the silence or word
want suggestion on how to implement this in java..
please suggest..
Well, wav is just PCM data. I'd start by reading this:
http://en.wikipedia.org/wiki/Pulse-code_modulation
I've done this before...
You start be pulling samples out of the PCM data. You then check each to see if it is greater than a threshold values that you've set. For instance assuming 16 bit samples...Example any value from zero to 15000 is silence, anything greater than 15001 is sound. Just remember to deal with unsigned ints or you'll have negative in the PCM. Also, remember log vs linear when you're playing with the threshold.
I'm trying to record from the microphone to a wav file as per this example. At the same time, I need to be able to test for input level/volume and send an alert if it's too low. I've tried what's described in this link and seems to work ok.
The issue comes when trying to record and read bytes at the same time using one TargetDataLine (bytes read for monitoring are being skipped for recording and vice-versa.
Another thing is that these are long processes (hours probably) so memory usage should be considered.
How should I proceed here? Any way to clone TargetDataLine? Can I buffer a number of bytes while writing them with AudioSystem.write()? Is there any other way to write to a .wav file without filling the system memory?
Thanks!
If you are using a TargetDataLine for capturing audio similar to the example given in the Java Tutorials, then you have access to a byte array called "data". You can loop through this array to test the volume level before outputting it.
To do the volume testing, you will have to convert the bytes to some sort of sensible PCM data. For example, if the format is 16-bit stereo little-endian, you might take two bytes and assemble to either a signed short or a signed, normalized float, and then test.
I apologize for not looking more closely at your examples before posting my "solution".
I'm going to suggest that you extend InputStream, making a customized version that also performs the volume test. Override the 'read' method so that it obtains the byte that it returns from the code you have that tests the volume. You'll have to modify the volume-testing code to work on a per-byte basis and to pass through the required byte.
You should then be able to use this extended InputStream as an argument when you create the AudioInputStream for the output-to-wav stage.
I've used this approach to save audio successfully via two data sources: once from an array that is populated beforehand, once from a streaming audio mix passing through a "mixer" I wrote to combine audio data sources. The latter would be more like what you need to do. I haven't done it from a microphone source, though. But the same approach should work, as far as I can tell.
I want to change the volume of an audio file
and save the new file using java.sound.sampled.
I tried to use the mixer to create a source line
from the file given and a target line to the new file.
So that I can change the mixer settings to change the volume.
But the sound is being played to the system speaker.
Am I thinking along correct way or not?
Is there any other way to record a file from a line?
The code is available here
A solution I got is www.jsresources.org/examples/AmplitudeConverter.html.
But can the same be done within java.sound.sampled
without using external libraries.
To change the volume, if you don't use a "Control" (see the Java Sound Tutorials), there is the option of directly modifying the samples themselves.
In your innermost loop, convert the bytes in the innermost buffer into a sample (if it is WAV 16-bit encoding, then you need to put the two bytes together to make the single SHORT value), then multiply that value by a float that ranges from 0 to 1, where 0 is the quietest and 1 leaves the sound at full volume. Then take the result and break it back down into two bytes and pass it along.
Do you need the code to do this? There are several other posts here where folks convert from bytes to INTs or Float and back.
Hmmm. This question is pretty old. Well maybe my answer will help someone new to the same problem.
If any of my fellow Xuggler users can tell me what I'm doing wrong, that would be awesome! I am doing the following:
Reading from ogv (ogg video)
Queueing the audio and video
Writing back to ogv
sounds simple right? The problem I am experiencing in my QueueMixer class is that the output file plays the audio 2x too fast, and no matter what I check or change with regards to pts it doesnt improve.
The eclipse project and all files being used are at this link:
http://dl.dropbox.com/u/7316897/paul-xuggled.zip
To run a test, compile and execute the StreamManager class; a test ogv file is included. Before anyone asks, yes I have to queue the data as it will be mixed with other data in a future version.
Audio has a sample rate. Make sure that you copy the sample rate from the input to the output, otherwise the system might use a default (like 44KHz while the original data was sampled at 22KHz which would create such an effect).
The fix is to multiply the sample count by two when extracting them from the ShortBuffer.
samples = new short[(int) audioSamples.getNumSamples() * 2];
audioSamples.getByteBuffer().asShortBuffer().get(samples);
Having half the samples causes the audio to play twice as fast.