SoundPool items randomly playing/not playing when triggered - android

I have some sounds in a SoundPool that I need to play. Sometimes when they should play, there's just a low pitched click sound instead of the sound that should play. Sometimes they play just fine.
Here's the code I use for the SoundPool:
open class PingSoundPool(context: Context) {
open var mAttributes = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_GAME)
.build()
open var mSoundPool = SoundPool.Builder()
.setMaxStreams(9)
.setAudioAttributes(mAttributes)
.build()
open var babping = mSoundPool.load(context, R.raw.ab830ping, 1)
open var aaping = mSoundPool.load(context, R.raw.a220ping, 1)
open var abbping = mSoundPool.load(context, R.raw.bb233ping, 1)
open var abping = mSoundPool.load(context, R.raw.b247ping, 1)
[and others]
open fun loadPings(note: Int) {
println(note.toString())
if (note == 0) {}
if(note == 1)
mSoundPool.play(acping, 2.55f, 2.55f, 1, 0, 1f)
if(note == 2)
mSoundPool.play(adbping, 2.5f, 2.5f, 1, 0, 1f)
if(note == 3)
mSoundPool.play(adping, 2.45f, 2.45f, 1, 0, 1f)
if(note == 4)
mSoundPool.play(aebping, 2.4f, 2.4f, 1, 0, 1f)
[and so on]
}
Now I make this accessible within my activity:
companion object {
lateinit var pingSoundPool: PingSoundPool
}
And in onCreate I do pingSoundPool = PingSoundPool(this)
Like this, I should be able to play any of these sounds with FullscreenActivity.pingSoundPool.loadPings(note: Int) - as stated above, this sometimes works, sometimes it doesn't, even for repetitions of the same sound.
One observation is that println(note.toString()) prints the Int corresponding to the note that should be played, regardless of whether the note can actually be heard. However, every time the note is actually played, that number is followed by W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST denied by client; transfer 4, track 44100 Hz, output 48000 Hz - All these come up in Android Studio's logcat.
This happens in the emulator as well as on real devices.
Any ideas?

The solution is this: the volume only accepts values from 0.0f to 1.0f. I tried setting them all to 1.0f and now it works fine.
if(note == 4) mSoundPool.play(aebping, 2.4f, 2.4f, 1, 0, 1f) // wrong
if(note == 4) mSoundPool.play(aebping, 1.0f, 1.0f, 1, 0, 1f) // right

Related

SoundPool | Check stream whether it is playing or not

I am using soundpool to play short audio files . Once I click the button it should play audio and second time it should pause stream . I used function like this detectPlayPause(sound2, activity!!.applicationContext)
The problem is it is not pausing and it is playing that sound again as a two stream
fun detectPlayPause(sound: Int, context: Context) {
val audioManager = context.getSystemService(AUDIO_SERVICE) as AudioManager
if (audioManager.isStreamMute(sound)) {
soundPool.play(sound, 1F, 1F, 0, -1, 1F)
} else {
soundPool.pause(sound)
}}
**
You're mis-using audioManager.isStreamMute(). That function takes an AudioManager constant, like STREAM_MUSIC. That is a different thing than the sound ID returned from SoundPool.load().
isStreamMute() won't tell you whether or not your sound is playing. That's more for detecting the device's mute settings; whether the user has selected mute/vibrate/silent, etc.
Instead, just track your play state using a boolean variable.
if (!playing) {
playing = true
soundPool.play(sound, 1F, 1F, 0, -1, 1F)
} else {
playing = false
soundPool.pause(sound)
}

Andengine Friction between bodies

I face strange behavior with no friction between two bodies static and dynamic. I declare bodies in follow code(code in kotlin):
val WALL_FIXTURE_DEF = PhysicsFactory.createFixtureDef(0f, 0f, 50f)
val ground = Rectangle(this.mCameraWidth / 2, wallWidth / 2 , this.mCameraWidth, wallWidth, this.vertexBufferObjectManager)
PhysicsFactory.createBoxBody(this.mPhysicsWorld, ground, BodyDef.BodyType.StaticBody, WALL_FIXTURE_DEF)
...
this.mBall = UniformColorSprite(this.mCameraWidth / 2, this.mCameraHeight /2 , TILE_WIDTH, TILE_HEIGHT, mBallTextureRegion, this.vertexBufferObjectManager)
val body: Body
val objectFixtureDef = PhysicsFactory.createFixtureDef(100f, 0.3f, 10f, false, CATEGORYBIT_CIRCLE, MASKBITS_CIRCLE, 0)
body = PhysicsFactory.createCircleBody(this.mPhysicsWorld, this.mBall, BodyDef.BodyType.DynamicBody, objectFixtureDef)
this.mPhysicsWorld.registerPhysicsConnector(PhysicsConnector(this.mBall, body, true, true))
Do you have any ideas?
If the second body is circle it is getting some torque that can make an impression that fiction of not working when it is actually working and causes torque.
When you are setting setFixedRotation you are prevent circleBody of rolling and then you can observe the fiction.
Try to change circleBody to polygon and see what will happen.

Unity - Enemy AI; Run away from player (x and y)

I need some help with creating a script for the enemies in my game! I'm making a 2.5D game where you chase campers and try to kill them. I'm mostly done with the game, but I can't get the AI to work! I've looked around for scripts and help for a couple of days now but can't find anything that fits well with the rest of my game... Please help!
For my ground i have a flat surface rotated at 35 on the x-axis, which have worked pretty well for me so far (moving the character around and placing obstacles).
At this point I'm working on this script;
#pragma strict
//Attack button
var attackButton : Joystick;
var anim : Animator;
var delay = 5.0;
//Player can kill
var CanKill = false;
//Score
var scoreValue : int;
var killValue : int;
var playerControl : PlayerControl;
//AI
var speed : int = 2;
var Damp: float = 1.0;
var isRun: boolean = false;
var Target: Transform;
var detectionRange: int = 5;
private var character : CharacterController;
function Start ()
{
anim = GetComponent("Animator");
var playerControlObject : GameObject = GameObject.FindWithTag ("Player");
character = GetComponent(CharacterController);
}
function WaitAndDestroy()
{
yield WaitForSeconds(delay);
Destroy (gameObject);
}
function Update()
{
//Can the player kill?
if (attackButton.tapCount == 1)
CanKill = true;
else CanKill = false;
//AI
var FromPlayer = Vector3(Target.position.x - transform.position.x, 0);
if(FromPlayer.magnitude <= detectionRange){
isRun = true;
}
if(FromPlayer.magnitude >= detectionRange) {
isRun = false;
}
if(isRun) {
RunAway();
anim.SetBool("Walk", true);
}
else anim.SetBool("Walk", false);
}
function OnTriggerEnter (Other : Collider){
if(Other.gameObject.tag == "Player" && CanKill == true) {
playerControl.AddScore (scoreValue);
playerControl.AddKills (killValue);
anim.SetTrigger("Dead");
WaitAndDestroy();
}
}
function RunAway()
{
var moveDirection : Vector3 = transform.position;
character.Move(moveDirection.normalized * speed * Time.deltaTime);
}`
Which kinda works, but for some reason the character stops in the middle of the level and just runs in place... I would also like him to turn and run the other direction if I (the player) catches him and runs in front of him. (If the code is a little messy I apologize, but as I said I'm new to Javascript).
i would done those two changes.
At first:
var FromPlayer = transform.position - Player.transform.position;
cause you want subtract whole vectors not just x coordinates
and second:
function RunAway( FromPlayer :vector3 )
{
character.Move(FromPlayer.normalized * speed * Time.deltaTime);
}
if you have already vector FromPlayer you can directly use it for moving character
i personally never used unity but that is how you would done it anywhere else. It of course assume that positions can be substracted as vectors
You want the campers to run away from the player right? Then you should do
Vector3 moveDirection = transform.position - Player.transform.position
To get the direction they should run in. Then do the line you already have
character.Move(moveDirection.normalized * speed * Time.deltaTime);

How to Sync Sounds using SoundPool

I have been trying to get a few sounds to play at the same time; currently i'm using a shared instance of SoundPool. I would like 1, 2 or 3 sounds to be played at the exact same time with no lag.
When calling SoundPool.play(...) X number of times in succession, the sounds are played in that order as one might think. what is the proper what to achieve this where i can prepare all of the sounds to be played at the same time and then play them as one?
Sudo Code:
SoundPool _soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
_soundPool.load(_context, soundId1, 1);
_soundPool.load(_context, soundId2, 1);
_soundPool.load(_context, soundId3, 1);
_soundPool.play(soundId1, vol, vol, 1, 0, 1f);
_soundPool.play(soundId2, vol, vol, 1, 0, 1f);
_soundPool.play(soundId3, vol, vol, 1, 0, 1f);
i done the sound pool for one sound at time it might help you.
Android:sound pool and service
Thank you
You need to understand that SoundPool.load method is asyncronous, so when you call it 3 times in a row, and then call play, there is no garantee that this sounds actually loaded. So you need to wait until all sounds is loaded. For that use OnLoadCompleteListener:
fun loadAndPlay(soundPool: SoundPool, context: Context, resIds: IntArray) {
val soundIds = IntArray(resIds.size) {
soundPool.load(context, resIds[it], 1)
}
var numLoaded: Int = 0
soundPool.setOnLoadCompleteListener { sPool, sampleId, status ->
numLoaded++
if (numLoaded == resIds.size) {
soundPool.setOnLoadCompleteListener(null)
for (id in soundIds) {
soundPool.play(id, 1f, 1f, 1, 0, 1f)
}
}
}
}
To use:
loadAndPlay(soundPool, context, intArrayOf(R.raw.sound_1, R.raw.sound_2, R.raw.sound_3))

Complex sound handling (I.E. pitch change while looping)

After going through the lovely set of Java tutorials and a while spent buried in source code I'm beginning to get the feel for it. For my next step, I will dive in with a fully featured application with graphics, sound, sensor use, touch response and a full menu.
My grand idea was to make an animated screwdriver where sliding the controls up and down modulate the frequency and that frequency dictates the sensor data it returns.
Now I have a semi-working sound system but its pretty poor for what its designed to represent and I just wouldn't be happy producing a sub-par end product whether its my first or not.
the problem:
sound must begin looping when the user presses down on the control
the sound must stop when the user releases the control
when moving the control up or down the sound effect must change pitch accordingly
if the user doesn't remove there finger before backing out of the application it must plate the casing of there device with gold (Easter egg ;P)
now I'm aware of how monolithic the first 3 look and that's why I would really appreciate any help I can get.
sorry for how bad this code looks but my general plan is to create the functional components then refine the code later, no good painting the walls if the roofs not finished.
here's my user input, he set slide stuff is used in the graphics for the control
#Override
public boolean onTouchEvent(MotionEvent event)
{
//motion event for the screwdriver view
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
//make sure the users at least trying to touch the slider
if (event.getY() > SonicSlideYTop && event.getY() < SonicSlideYBottom)
{
//power setup, im using 1.5 to help out the rate on soundpool since it likes 0.5 to 1.5
SonicPower = 1.5f - ((event.getY() - SonicSlideYTop) / SonicSlideLength);
//just goes into a method which sets a private variable in my sound pool class thing
mSonicAudio.setPower(1, SonicPower);
//this handles the slides graphics
setSlideY ( (int) event.getY() );
#Override
public boolean onTouchEvent(MotionEvent event)
{
//motion event for the screwdriver view
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
//make sure the users at least trying to touch the slider
if (event.getY() > SonicSlideYTop && event.getY() < SonicSlideYBottom)
{
//power setup, im using 1.5 to help out the rate on soundpool since it likes 0.5 to 1.5
SonicPower = 1.5f - ((event.getY() - SonicSlideYTop) / SonicSlideLength);
//just goes into a method which sets a private variable in my sound pool class thing
mSonicAudio.setPower(1, SonicPower);
//this handles the slides graphics
setSlideY ( (int) event.getY() );
//this is from my latest attempt at loop pitch change, look for this in my soundPool class
mSonicAudio.startLoopedSound();
}
}
if(event.getAction() == MotionEvent.ACTION_MOVE)
{
if (event.getY() > SonicSlideYTop && event.getY() < SonicSlideYBottom)
{
SonicPower = 1.5f - ((event.getY() - SonicSlideYTop) / SonicSlideLength);
mSonicAudio.setPower(1, SonicPower);
setSlideY ( (int) event.getY() );
}
}
if(event.getAction() == MotionEvent.ACTION_UP)
{
mSonicAudio.stopLoopedSound();
SonicPower = 1.5f - ((event.getY() - SonicSlideYTop) / SonicSlideLength);
mSonicAudio.setPower(1, SonicPower);
}
return true;
}
and here's where those methods end up in my sound pool class its horribly messy but that's because I've been trying a ton of variants to get this to work, you will also notice that I begin to hard code the index, again I was trying to get the methods to work before making them work well.
package com.mattster.sonicscrewdriver;
import java.util.HashMap;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
public class SoundManager
{
private float mPowerLvl = 1f;
private SoundPool mSoundPool;
private HashMap<Integer, Integer> mSoundPoolMap;
private AudioManager mAudioManager;
private Context mContext;
private int streamVolume;
private int LoopState;
private long mLastTime;
public SoundManager()
{
}
public void initSounds(Context theContext)
{
mContext = theContext;
mSoundPool = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
mSoundPoolMap = new HashMap<Integer, Integer>();
mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
}
public void addSound(int index,int SoundID)
{
mSoundPoolMap.put(1, mSoundPool.load(mContext, SoundID, 1));
}
public void playUpdate(int index)
{
if( LoopState == 1)
{
long now = System.currentTimeMillis();
if (now > mLastTime)
{
mSoundPool.play(mSoundPoolMap.get(1), streamVolume, streamVolume, 1, 0, mPowerLvl);
mLastTime = System.currentTimeMillis() + 250;
}
}
}
public void stopLoopedSound()
{
LoopState = 0;
mSoundPool.setVolume(mSoundPoolMap.get(1), 0, 0);
mSoundPool.stop(mSoundPoolMap.get(1));
}
public void startLoopedSound()
{
LoopState = 1;
}
public void setPower(int index, float mPower)
{
mPowerLvl = mPower;
mSoundPool.setRate(mSoundPoolMap.get(1), mPowerLvl);
}
}
I almost forgot, that looks pretty ineffective but I omitted my thread which actuality updates it, nothing fancy it just calls:
mSonicAudio.playUpdate(1);
There are some confusing points in there which I think are just cut and paste issues trying to get the source into this page, but assuming you're not having problems with your onTouchEvent handling, my random comments are:
It looks like you are calling play() every 250 ms while the touch is held. I can't see the loop argument to the play() call but I assume it is -1. If so, then you are launching a brand new looped sound every 250 msc (play returns a unique streamId for every audio stream you create).
I think you wanted to modify the pitch and amplitude of a single existing stream. So I think you wanted something like this:
int mySoundStreamId = 0;
...
onDown()
if( mySoundStreamId == 0 ) {
// create the one true stream
mySoundStreamId = mySOundPool.play( initial power and freq modifiers, loop = -1 )
} else {
// resume the one true stream
mySoundPool.resume( mySoundStreamId ); // note: a STREAM id is NOT a SOUND id.
}
onUp()
if( mySoundStreamId != 0 ) {
// pause the one true stream
mySoundPool.pause( mySoundStreamId ) // stop() will release all the samples you held
}
onWiggle()
if( mySoundStreamId != 0 ) {
// modify parameters of the one true stream
mySoundPool.setPitch( mySoundStreamId, newPitch ); // too lazy to look up real soundPool command
}
onGameOver
if( mySoundStreamId != 0 ) {
// shut down and release the samples of the one true stream
mySoundPool.setLoop( mySountStreamId, 0 ); // otherwise some phones will keep looping after shutdown
mySoundPool.stop( mySoundStreamId ); // no resume possible after this, need to reload samples
mySOundStreamId = 0;
}
I omit the creation/destruction of the sound pool itself. It sounds like you were successfully loading the sound data into the sound pool ok.
Note that the LOAD returns a SOUND ID which you pass to the PLAY command
but that PLAY returns a STREAM ID which you use in most of the other soundPool methods
Of course, I have my own problems with 'resume' on a looped sound, so take what I say with a grain of salt :-)
Good Luck! I guess I should have checked the time stamp. My apologies if you posted thie 3 years ago :-)

Categories

Resources