I am attempting to create a simple Morse code application. When the user presses a button the Morse sound should start before ending when released.
The problem is the latency- the Morse sound does not start until roughly 400ms after the user presses the button. I am not sure why this is exactly but after researching the problem i think it is the way my code is structured. The file i am trying to play is in Mp3 format and is located in the raw folder.
I had this completed using the Media Player but i ran into the same problem in regard it not being responsive enough so i opted to try and use Sound pool. Does anyone have any advice/suggestions as to how i can speed up the operation? This is new territory to me in regards development.
public int S1 = R.raw.morse;
private SoundPool soundPool;
private boolean loaded;
static int x;
public void initSounds(Context context) {
soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
final int y = soundPool.load(context, R.raw.morse, 1);
soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId,
int status) {
loaded = true;
playSound(y);
}
});
}
public void playSound(int soundID) {
if(loaded) {
x = soundPool.play(soundID, 0.5f, 0.5f, 1, 0, 1f);
}
}
//Calling code
pad.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
//State of a toggle button
if(audioOnOff==true) {
//Sound pool object is created and initialized as a global variabe
sp.initSounds(getApplicationContext());
}
}
It looks to me like what's happening here is that each time the button is pressed, you're loading the sound, waiting for it to finish loading, then playing it. What you actually want is to load the sound once, then just play it each time the button is pressed.
So instead of calling initSounds in your onTouchListener, call initSounds somewhere else before the button is pressed. Then in your onTouchListener you just call your playSound method.
Finally, make sure you remove the playSound method call from your onLoadCompleteListener so you don't get a mysterious noise when you initially load up the sound ;)
Related
When i click button plays sound on my app, but keep clicking for a while doesn`t play anymore. Maybe it is memory issue? Could you solve me my issue? Here is implemented play sound via SoundPool: when i click button i called play method: and play method works background thread
private void play(int resId) {
soundPool = buildBeforeAPI21();//TODO: refactor with deprecated constructor
soundPool.load(activity, Integer.parseInt(resId), 1);
}
public SoundPool buildBeforeAPI21() {
if (soundPool == null) {
soundPool = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
if (status == 0) {
soundPool.play(sampleId, 1.0f, 1.0f, 1, 0, 1.0f);
}
}
});
}
return soundPool;
}
Don't create a new SoundPool with each click. That is extremely wasteful. Do this instead:
1) Create the SoundPool just once
2) Load it with all the sounds you want to play, just once
3) Wait for all the sounds to load
4) Just call soundPool.play() with each click.
Maybe this answer cames too late; but here we go. The problem is in the line
soundPool = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
That '2' number is the int maxStreams, following the documentation "the maximum number of simultaneous streams for this SoundPool object" (you can go deep on this here). Now change it and set it to 10, for example, and try again. And after that, you cand adjust it as your wishes. So:
soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
Hope this helps (if it is still necessary).
I am having a bit of difficulty with my SoundPool. I have an ArrayList<Integer> of my soundIDs located in my res/raw folder. I'm creating the SoundPool like so in my ViewHolder class for my RecyclerView:
//create the SoundPool
sp = new SoundPool(20, AudioManager.STREAM_MUSIC, 0);
//create the AudioManager for managing volume
audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
//store the streamVolume in an int
streamVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
//set the load listener for my soundfiles
sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
loaded = true;
}
});
I am playing the sound on the click of an ImageView like so:
#Override
public void onClick(View v) {
if (v.equals(cardImg)) {
sp.load(context, cardData.getSoundId(), 1);
if (loaded) {
sp.play(cardData.getSoundId(), streamVolume, streamVolume, 1, 0, 1f);
}
}
}
And every time I click on the cardImg it gives me this error:
W/SoundPool﹕ sample 2130968609 not READY
Where the sample int changes depending on which card I click, like it should.
So I know that it's GETTING the proper soundID from my ArrayList (stored in CardData class), and it definitely sees that it's loaded, because it wouldn't try to play otherwise because loaded would never be true. My question is: Why are my sounds never ready?
My sounds are .m4a format which Android says is supported in the documentation. I've tried on an Android 5.0 device and an Android 4.4 device but nothing changes.
I have tried using a MediaPlayer but I am running into memory errors as I have many short clips that need to be able to be spammed and I read that a SoundPool was a much better way to manage this (?).
Any help would be appreciated! I am super vexxed here.
You're using the wrong id. SoundPool.load returns an id that is suppose to be passed in to SoundPool.play.
I'm trying to have a SoundPool play while a view object is being clicked.
I have successfully implemented it but found out that the sound of the click will lag.
I've been researching on StackOverFlow and on the internet for solutions and the best solution seems to be to have the SoundPool on a separate Thread.
I'm very new to the whole Thread thing and so I don't really know what to do at the moment.
I have followed THIS guide on creating a SoundPool thread, however, I don't know how to access it, or even to assign the clips that I wished to play.
Can someone please give me an example of how I should call the SoundPool thread to play my clip while an object in the view is being clicked.
Please find my onClick code below:
#Override
public boolean onTouch(View v, MotionEvent event) {
int actionPerformed = event.getAction();
switch(actionPerformed) {
case MotionEvent.ACTION_DOWN: {
if (Math.pow((event.getX() - a_Ball.getX()),2)
+ Math.pow((event.getY() - a_Ball.getY()), 2)
<= Math.pow(a_Ball.getDiameter(),2)) {
//pCheck = !pCheck;
if (pauseBall == false) {
SoundPool soundPool = new SoundPool(1,AudioManager.STREAM_MUSIC,1);
clickSound = soundPool.load(MainActivity.this, R.raw.click, 1);
/*soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
public void onLoadComplete(SoundPool soundPool, int sampleId,int status) {
soundPool.play(clickSound,1.0f, 1.0f, 0, 0, 1.0f);
}
});*/
//Increase Ball Speed
sIncrease = true;
}
} else {
if (pauseBall == false) {
//set minus health when not touch on ball
health--;
TextView txtHealth = (TextView)findViewById(R.id.health);
String tempHealth = txtHealth.getText().toString();
tempHealth = getResources().getString(R.string.health) + String.valueOf(health);
txtHealth.setText(tempHealth);
}
}
break;
}
default:
return false;
}
return true;
} //onTouch end
Thanks in advance.
You don't need threads to make sounds without lag. The lag comes from the loading of the sound file, try create the SoundPool and load the sound (soundPool.load) in advance (e.g. onCreate), then just call soundPool.play in your onTouch method.
Ok, so instead of doing it in another class, I decided to do it in one class and created a new thread by myself. Seems to be working well enough.
I'll mark this thread as answer.
By default, on my phone, clicking on apps, widgets, home button, etc makes a click noise. How do I override that click noise in a widget? I have a widget that plays a noise on click but right now it plays both my noise and the click noise. In the widget, I use soundpool to play the noise. This is the only code I use to access the noise.
public class MakeState { ...
SoundPool snd =new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
int soundID;
...
public void OnClick() {
soundID = snd.load(getcontext(), R.raw.noise, 1);
snd.setOnLoadCompleteListener(new OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool sound pool, int sampleid, int status) {
soundPool.play(soundID, .6f, .6f, 1, 0, 1f);
}
});
}
Try to disable the standard onClick noise using setSoundEffectsEnabled(false);
I'm making an app where I'm trying to load a single sound onto a SoundPool so I can manage the playback rate when I want, play it when I want, and release it when I want. However, my SoundPool is not loading. I've tried to change a lot of different things and nothing seems to work. I put a Log.d in the OnLoadComplete function to see if it loads, and the log doesn't appear when running... Maybe after looking at my code somebody else could help me. Thanks!
private int currentVoice = 0;
private SoundPool voices = null;
....
public void onCreate(Bundle savedInstanceState) {
....
voices = new SoundPool(1, 3, 0);
voices.setOnLoadCompleteListener(this);
....
}
private void giveSentence() throws IOException {
....
voices.release();
currentVoice = voices.load(this, sentences[index].voice, 1);
voices.play(currentVoice, 1, 1, 1, 0, 1f);
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
soundPool.play(sampleId, 1, 1, 1, 0, 1f);
boolean loaded = true;
Log.d("Game","Is it loaded? " + loaded);
}
You should initialize your sound pool somewhere in a onCreate method, I guess.
private SoundPool voices;
#Override
public void onCreate(Bundle savedInstanceState) {
voices = new SoundPool(1, 3, 0);
voices.setOnLoadCompleteListener(this);
}
Fixed myself, I was doing voices.release(); before anything was loaded. For some reason that just turned the SoundPool off. Took out that line and did voices.release() after I checked if it was already loaded. Now it works.