I am working on an Audio recording function. I want the recorded Audio to be saved into the internal cache directory of my app so that I can later process it and send it to my server. I have taken the RECORD_AUDIO_PERMISSION in my Android Manifest.
Below is the code I plan to use for recording audio and save it to a file.
String uuid = UUID.randomUUID().toString();
fileName = getExternalCacheDir().getAbsolutePath() + "/" + uuid + ".3gp";
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setOutputFile(fileName);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
recorder.prepare();
recorder.start();
} catch (IOException e) {}
I expect the above code to work fine but I am facing another issue. I want to create a Waveform effect for my app for which I am using this library. This library works with the below code:
//get a reference to the visualizer
mVisualizer = findViewById(R.id.blast);
//TODO: get the raw audio bytes
//pass the bytes to visualizer
mVisualizer.setRawAudioBytes(bytes);
Now, my question is how can I get the Bytes in real-time of the Audio which is being recorded and being saved? Should I read the file and extract recent bytes from it at regular intervals or is there any other method to achieve this.
Any help would be appreciated.
Thanks.
As per the logic what you can do is take input of small intervals, say 1 second(1000 ms), and then show the waveform of that and after that save the data you got. Now after saving take new input and then add that new data in the previous data after forming a waveform (or doing any operation) of new data.
Just do these things on separate Threads.
Related
I am writing an app that takes Morse code, and plays it over the speakers.
Currently I am able to record audio over the microphone using this code:
public void startRecord() throws Exception{
if (record != null){
record.release();
}
File fileOut = new File(FILE);
if (fileOut != null){
fileOut.delete(); // delete any existing file at that location.
}
record = new MediaRecorder();
record.setAudioSource(MediaRecorder.AudioSource.MIC);
record.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
record.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
record.setOutputFile(FILE);
record.prepare();
record.start();
}
and i am able to generate morse code in a string formatted like this:
"-.... .---- -.... -.-. -.... ..... --... ---.."
I can iterate over this string using a for loop such as this:
char[] chars = message.toCharArray();
for (char ch : chars) {
//add to audio file
}
But I am not sure how to create a file out of strung together wav files. Ive seen some posts that mention setting the audio source as a file from the device, but Im not sure how to pick and choose which file and where to insert them, or how to compile it all into a single audio file.
Instead of creating a new sound file and playing that, it would probably be easier to just play each sound individually and when that sound finishes, you play the next sound, or you wait for a brief pause if it's a space.
I think you are trying to do this the harder way. What if you were to simply have the program read the first letter, play the appropriate sound, do the same for the next letter and so on throughout the text. I believe it is much simpler but if you are really set on trying to put it into one file you could have the program make an empty file but in the name it sets have the extension `.wav` or `.mp3` and do research into how they are encoded.
I'm using VLCJ and I wish to save a video clip I'm playing using mediaPlayer.playMedia(); to my desktop. I know this can be accomplished by setting media options using a :sout string but I don't know which options to set and I'm having trouble understanding the example option strings on the web. Could someone help by explaining the following :sout option string?
String[] options = {":sout=#transcode{vcodec=mp4v,vb=4096,scale=1,acodec=mpga,ab=128,channels=2,samplerate=44100}:duplicate{dst=file{dst=" + fileName + "},dst=display}", ":input-slave=alsa://hw:0,0"};
I just need an options array that creates an mp4 video using the fileName destination. These options fail/error out for me.
Also, VLCJ seems to be dropping a ton of frames with this error
avcodec decoder error: more than 5 seconds of late video -> dropping frame
by using these options
String[] options = {":sout=#transcode{vcodec=mp1v,vb=2048,scale=1,acodec=mpga,ab=128,channels=2,samplerate=44100}:duplicate{dst=file{mux=mpeg1,dst=" + fileName + "},dst=display}", ":input-slave=dshow://hw:0,0" };
To save a raw stream, use media options similar to the following when you play the media:
String mrl = "your-streaming-mrl";
String[] opts = {"sout=#duplicate{dst=std{access=file,mux=raw,dst=output-file.ext}}"};
Clearly you replace "your-streaming-mrl" and "output-file.ext" with whatever is appropriate.
And then:
mediaPlayer.playMedia(mrl, opts);
You will need to wait (listen) for a media player "finished" event before your saved file is ready.
You may also need to explicitly invoke release() on the media player before your saved file is ready.
Basically, I built an app in android that records my message and saves it as .m4a or .3gpp format.
When I plays the records in my app it works fine, but when I'm trying to play it on my website it doesnt work...
Android(Java)
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(OUTPUT_FILE);
recorder.prepare();
recorder.start();
Website(HTML)
<audio controls="controls" preload="none">
<source src="my_record.m4a" type="audio/mp4"/>
</audio>
P.S: When I tried to open some other m4a audio files(files that i found online), I succeded.
The audio tag is quite sensitive about this. Anything above 128mbps it will not play. A lot of encoders automatically choose the highest quality bit rate (usually around 320mbps) and the audio tag won't play them. Sample rate should be 44100hz.
the sampling rate supported by AAC audio coding standard ranges from 8 to 96 kHz, the sampling rate supported by AMRNB is 8kHz, and the sampling rate supported by AMRWB is 16kHz.
Hence change Audioencoder to AAC in your code
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
to
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
and then set filename extension to .mp3
Hope this works for you.:)
I created a small program to record sound (I use JavaSound with TargetDataLine to reach my sound card).
I did some testing with the class " DualOscilloscope.java " of JSYN for a visual of the sound .
The problem is that their class opens a line with " Synthesizer " so I have two line tapping on my soundcard and me that triggers an exception (as you can not open two line on a sound card).
Is it possible to use my instantiating my TargetDataLine to initialize the synthesizer of JSYN ?
The Latest JSyn JAR File
Source code class DualOscilloscope (author Phil Burk )
protected void startAudio(int itemIndex) {
// Both stereo.
int numInputChannels = deviceMaxInputs.get(itemIndex);
if (numInputChannels > 2)
numInputChannels = 2;
int inputDeviceIndex = deviceIds.get(itemIndex);
synth.start(16000, inputDeviceIndex, numInputChannels, AudioDeviceManager.USE_DEFAULT_DEVICE, 0);
channel1.output.connect(pass1.input);
// Only connect second channel if more than one input channel.
if (numInputChannels > 1) {
channel2.output.connect(pass2.input);
}
// We only need to start the LineOut. It will pull data from the
// channels.
scope.start();
JSyn does not currently support being passed a TargetDataLine. You could, however, implement your own AudioDeviceManager based on the source code on GitHub. Replace JavaSoundAudioDevice.java with one that used your TargetDataLine instead of creating a new one.
An easier way would be to let JSyn open the audio input and then use that input in your program. Don't open your own TargetDataLine.
You can use JSyn to process audio or to save it as a WAVE file. If you need to do custom processing then you could write a custom unit generator. Or you could use an AudioStreamReader to stream the audio data to your own thread.
AudioStreamReader reader = new AudioStreamReader(synth, 2); // stereo
lineIn.connect(0, read.getInput(), 0);
lineIn.connect(1, read.getInput(), 1);
Then you can read the data from that reader instead of from your own TargetDataLine.
reader.read(buffer, start, count);
I am building a speech synthesizer, and everything works except the audio. I have a list of phonemes that are stored as .wav files, and I am calling them with AudioInputStreams, but they won't repeat. I have no idea what could be the issue, so any help would be appreciated.
The code that initializes a HashMap full of phones is
for(File phone : listOfFiles){
String path = phone.getPath();
if(path.startsWith(".")){continue;}
path = path.replace(".wav", "").replace("phones/", "");
AudioInputStream clip1 = AudioSystem.getAudioInputStream(phone);
phonemes.put(path,clip1);
}
and the code that combines and outputs the sound is
public void speak(String[] input){
AudioInputStream phrase = phonemes.get(input[0]);
AudioInputStream phone;
int x = input.length;
for(int i=1; i<input.length; i++){
phone = phonemes.get(input[i]);
phrase = new AudioInputStream(new SequenceInputStream(phrase, phone), phrase.getFormat(), phrase.getFrameLength() + phone.getFrameLength());
}
try {
Clip clip = AudioSystem.getClip();
clip.open(phrase);
clip.start();
} catch (Exception e) {
e.printStackTrace();
}
}
To replay a Clip, you have to stop it and reposition it, then start it. I don't think you can close and reopen a given Clip. But attempts to do that should have generated a LineUnavailable exception, and you say you got no exceptions.
To troubleshoot, I'd first verify that it is possible to play the .wav files prior to placing them in the hash table. Sometimes an unexpected format (e.g., 24-bit or 32-bit encoding, or big-endian rather than little-endian) can lead to .wav files not playing.
If you are trying to concatenate a series of clips or audio data into a single clip, that could also be problematic. I think that AudioInputStream expects a single set of "header" data from the .wav file, but the SequenceInputStream could in effect be sending multiple "headers", one for each source file. I've never seen concatenation attempted like that before.
You might need to make your own data storage for the raw audio for each phoneme, and then build your combined phonemes from that rather than directly from .wav files. Instead of loading to Clips, load the raw PCM from the AudioInputStream into byte arrays. To output the raw audio bytes, you can use a SourceDataLine.