I've got a SoundPool[] that I use to play mixed audio files.
Soundpools play together without any problem, and it's very efficient!
Very briefly:
private SoundPool[] sound = new SoundPool[C.ROWS];
// every sound is initizialized with a load()
// and when asked...
public void play(int row, int variation) {
if (mute[row]) return;
if (variation != 0)
sound[row].play(variation_scheme[row][variation-1], volume[row], volume[row], PRI, 0, 1f);
}
This is just to show! :)
I don't put other pieces of code because everything works very fine and it is not really a problem.
My question, instead, is:
how can I redirect the whole output of the application to a file, instead of (or in addition to) the audio speaker?
In other words, there are two main solutions:
1. how can I instruct AudioPool to play() the sounds to a file instead of to an audio device?
2. or how can I redirect all the audio output of my app (or even of all the phone) to a file?
Thank you.
The only way I found how to record audio is by recording each information of the sound being press such as, duration (using mediaplayer), soundID, millisecond time stamp to do play back to the millisecond, volume, rate (if needed). Then write these to a text file (internally or externally) for later use. Create a play back system that decodes that saved information from text file and organize it in some arrays or hashmaps and play back throught some sort of play back method with maybe using a handler and postDelay to play sound and desired time and then plug in necessary data to play sound from array or hashmap.
In this way you can have your own data files for playing sound sequences.
Related
When I play a sound in my app it comes off as clippy and distorted. Here is a recording: recording.
Here is the sound file as it was uploaded to android studio: success sound cue
Here is the function that calls the sound from the .raw
public void playCorrectAnswerSound() {
final MediaPlayer mp = MediaPlayer.create(this, R.raw.correct);
mp.start();
}
Heres how I call it:
Thread t = new Thread(){
public void run(){
playCorrectAnswerSound();
}
};
t.start()
This is my first time debugging a sound related issue. I don't know what else to include in this post, so if you need more info please say so.
EDIT: I was asked to record more of the distortion. Here it is. Also I should say that after more testing, my physical device lacks the sound distortion while the sound distortion is present on 3 different emulators.
I'm going to say this is stuttering due to underrun (starvation) of the MediaPlayer's internal playback buffer. That is, the MediaPlayer can't supply data fast enough to keep up with the sound hardware (which suggests a severe lack of processing power). If the buffer starves, it'll start to play back old data (because it's a circular buffer). This causes a sharp phase transition, which sounds like a "click". Presumably the MediaPlayer recovers quickly enough that the "correct" sound resumes playing shortly thereafter.
Here is a picture of the spectrum from Audacity. 0-4KHz. The first row is the clean .mp3; the next four rows are the distorted recordings (in no particular order). All rows have been aligned in time, and are roughly the same amplitude. The large vertical stripes in the last four rows represent the distortion/clicks that you hear.
hi ive been working on my app and have found a hurdle in an activity i just cant seem to overcome. the activity is essentially a large novelty piano with 8 keys that play sounds there are 6 buttons along the side that change the picture of the notes and the notes themselves, this i accomplished :-) now i would like to add a background song to each different set of notes (instruments) only when i do the app crashes i have set the mediaplayer at the top (globally?) using MediaPlayer mp; MediaPlayer mp2; etc and im using this in my code to check if any music is playing, stop it, release it, and then play the piece i want,
if(mp!=null&&mp.isPlaying()){
mp.stop();
mp.release();
}
if(mp2!=null&&mp2.isPlaying()){
mp2.stop();
mp2.release();
}
if(mp3!=null&&mp3.isPlaying()){
mp3.stop();
mp3.release();
}
mp3 = MediaPlayer.create(MusicActivity.this, R.raw.snaps);
mp3.setLooping(true);
mp3.start();
this again works but going from one to another and then back crashes the app. is there something else i should be doing? or is just an out of memory error?
EDIT--
Thanks to ranjk89 for his help
changed to soundpools but they wont stop ranjk89 suggests referring to the stream id and not the sound id looking for a little more clarification if possible i have
farmback =0;
drumback =0;
at the top then its loaded in oncreate using
drumback = sp.load(this, R.raw.snaps,1);
farmback = sp.load(this, R.raw.oldmacdonaldbeta,1);
and then way down, in the same method i change the button icons, not the same method i change all my other sounds for my notes i call
sp.stop(drumback);
sp.play(farmback, 1, 1, 0, -1, 1);
in one and
sp.stop(farmback);
sp.play(drumback, 1, 1, 0, -1, 1);
in another but there are 6 different instruments in total that all need a different backing track which should stop when the instrument is changed and play the one associated to it so something like
if (sp !=null && sp.isplaying()){
sp.stop();
sp.play(dumback);
}
but obviously this is not possible any help appreciated
My Initial reaction is, you shouldn't be using multiple MediaPlayer at all in the first place.
I would suggest you to use SoundPool as you can load all the media(audio) initially, once they are all loaded you can play them at will. Plus you won't have multiple players which would downsize the complexity of your code.
But if you do want to use Media player,
See this. But be aware that once you release you will not be able to reuse that instance of MediaPlayer. Even if you are using multiple MediaPlayers, do not call release on them unless you are sure you don't want to use them any more. Use stop()/prepare() combination.
For application doing too much work on the Main Thread,
If you either use a SoundPool or only one MediaPlayer and still bump in to the same issue, Use AsyncTask. Android dev site has a very good tutorial on this
I am using SoundPool to play sfx sounds in a game on Android. In most cases it works perfectly, except sometimes I need to stop all sounds at once not pause (doesn't matter if they are set to loop or not).
I can't figure out how to stop a sound from playing without knowing the StreamID of that sound. What I know:
soundpool.load(...some sound...) returns a soundID
soundpool.play(soundID) plays the sound and returns a streamID
soundpool.stop(streamID) stops the sound
My question is, how can I stop a sound without knowing the streamID ? I tried tracking all streamIDs in a list, but sometimes there are so many short streams playing at once, that it won't work. And I can't find any method in SoundPoolto get the active streamIDs. Does anyone know how to stop all sounds?
Any hint is appreciated! thanks
I'd recommend using autoPause() and autoResume() to pause and restart your sounds. This function is part of the soundpool:
http://developer.android.com/reference/android/media/SoundPool.html#autoPause()
What about using .release() ? Accourding to the documentation:
Release the SoundPool resources. Release all memory and native resources used by the SoundPool object. The SoundPool can no longer be used and the reference should be set to null.
I think it also stops everything. (Actually it was causing a bug at one of my apps, that's why I say it)
However, I believe that if you want to play any sounds later, you may have to load them again.
SoundPool doesn't have a method to retrieve the streamID from the index of the stream, like it should. So even when you know the maximum number of streams, you can't just iterate through like the following:
for(int index=0;index<MAXSTREAMS;index++){
int streamid = SoundPool.getStreamID(index);//getStreamID action doesn't exist :(
soundpool.stop(streamid);
}
As you mentioned, the coder has to manage this himself with a list. I implement the declaration as follows:
List<Integer> streams = new ArrayList<Integer>();
You can add and remove soundIDs to this list as you play and stop sounds as follows:
streams.add(batattack_soundID);
streams.remove(Integer.valueOf(batattack_soundID));//NOT streams.remove(batattack_soundID);
Be sure to use Integer.valueOf() or .remove() will interpret your parameter as an index position, likely giving you an IndexOutOfBoundsException.
To clean everything up you can code as follows:
for (Integer stream : streams) {
soundPool.stop(stream);
}
streams.clear();
When using MediaPlayer, I noticed that whenever my phone stucks, the MediaPlayer glitches and then continues playing from the position in the audio it glitched.
This is bad for my implementation since I want the audio to be played at a specific time.
If I have a song of 1000 millisecond length, I want is the ability to set MediaPlayer to start playing at some specific time t, and then exactly stop at at time t+1000.
This means that I actually need two things:
1) Start MediaPlayer at a specific time with a very small delay.
2) Making MediaPlayer glitches ignore the audio they glitched on and continue playing in order to finish the song on time.
The delay of the functions is very important to me and I need the audio to be played exactly(~) at the time it was supposed to be played.
Thanks!
You will need to use possibly mp.getDuration(); and/or mp.getCurrentPosition(); although it's impossible to know exactly what you mean by "I need the audio to be played exactly(~) at the time it was supposed to be played."
Something like this should get you started:
int a = (mp.getCurrentPosition() + b);
Thanks for the answer Mike. but unfortunately this won't help me. Let's say that I asked MediaPlayer to start playing a song of length 3:45 at 00:00. At 01:00 I started using the phone's resources, due to the heavy usage my phone glitched making MediaPlayer pause for 2 seconds.
Time:
00:00-01:00 - I heard the audio at 00:00-01:00
01:00-01:02 - I heard silence because the phone glitched
01:02-03:47 - I heard the audio at 01:00-03:45 with 2 second time skew
Now from what I understood MediaPlayer is a bad choice of usage on this problem domain, since MediaPlayer provides a high level API.I am currently experimenting with the
AudioTrack class which should provide me with what I need:
//Creating a new audio track
AudioTrack audioTrack = new AudioTrack(...)
//Get start time
long start = System.currentTimeMillis();
// loop until finished
for (...) {
// Get time in song
long now = System.currentTimeMillis();
long nowInSong = now - start;
// get a buffer from the song at time nowInSong with a length of 1 second
byte[] b = getAudioBuffer(nowInSong);
// play 1 second of music
audioTrack.write(b, 0, b.length);
// remove any unplayed data
audioTrack.flush();
}
Now if I glitch I only glitch for 1 second and then I correct myself by playing the right audio at the right time!
NOTE
I haven't tested this code but it seems like the right way to do it. If it will actually work I will update this post again.
P.S. seeking in MediaPlayer is:
1. A heavy operation that will surely delay my music (every millisecond counts here)
2. Is not thread safe and cannot be used from multiple threads (seeks, starts etc...)
I have some audio data (raw AAC) inside a byte array for playback. During playback, I need to get its volume/amplitude to draw (something like an audio wave when playing).
What I'm thinking now is to get the volume/amplitude of the current audio every 200 milliseconds and use that for drawing (using a canvas), but I'm not sure how to do that.
.
.
.
.
** 2011/07/13 add following **
Sorry just been delayed on other project until now.
What I tried is run the following codes in a thread, and playing my AAC audio.
a loop
{
// int v=audio.getStreamVolume(AudioManager.MODE_NORMAL);
// int v=audio.getStreamVolume(AudioManager.STREAM_MUSIC);
int v=audio.getStreamVolume(AudioManager.STREAM_DTMF);
// Tried 3 settings above
Log.i(HiCardConstants.TAG, "Volume - "+v);
try{Thread.sleep(200);}
catch(InterruptedException ie){}
}
But only get a fixed value, not dynamic volume...
And I also found a class named Visualizer, but unfortunately, my target platform is Android 2.2 ... :-(
Any suggestions are welcome :-)
After days and nights, I found that an Android app project called ringdroid
can solve my problem.
It helps me to get an audio gain value array, so that I can use to to draw my sound wave.
BTW, as my experience, some .AMR or .MP3 can't be parsed correctly, due to too low bitrate...