XNA MediaPlayer loading music timing - xna

I load music with the following code in my load content function:
song = Content.Load<Song>("music/game");
MediaPlayer.IsRepeating = false;
MediaPlayer.Play(song);
nothing strange there, but each round in my game is 2 minutes long and should sync up with the music (that is 2 minutes long) but the music ends betweem 2-4s early. This wouldn't be a problem if it was always the same time.
My guess is that it has something to do with load times? any advice?

One thing you could do is move the Content.Load<Song> to Load method and check if it is playing in the update, and if not, play. Eg,
public void LoadContent(ConentManager content)
{
song = content.Load<Song>("music/game");
gameSongStartedPlaying = false; // this variable to hold if you have starting playing this song already
MediaPlayer.IsRepeating = false;
}
public void Update(GameTime gameTime)
{
if(MediaPlayer.State == MediaState.Stopped && !gameSongStartedPlaying)
{
MediaPlayer.Play(song);
gameSongStartedPlaying = true;
}
}
This should start playing the song on the first pass of the Update method rather than in the Loading phase where the song is 'playing' while all resources after Content.Load<Song> are still loading (this would be the reason your song finishes early).

Related

AVAudioPlayerNode playAt() not synchronized

I have one main AVAudioPlayerNode that plays constantly. And there are other players that are put in the queue and play when the main player reaches a certain point.
These AVAudioPlayerNode`s should be synchronized to a millisecond. Sometimes 4-10 pieces can be started at a time.
How its works - I store lastRenderTime of the main player on point when need start all scheduled players and then start all needed player with
player.start(at: lastRenderTime)
Usually, it's working well and without any latency between sounds.
But, I got some latency on this case:
Running on OLD devices(iPad 2, iPhone 5 etc)
ONLY when MANY players the first time after application startup (For example on iPhone 7 I run 8 players in same time after the application is running and I hear desynchronization between sounds), but all players are running with same player.start(at: lastRenderTime) time.
All player actions I run async with custom concurrent queue.
Spend 3 days on trying fix this. I would like for any pieces of advice.
Some code:
Here is how I starting main player -
self.scheduleBuffer(audioFileBuffer, at: nil, options: [], completionHandler: {
lastRenderTime = lastRenderTime + audioBufferLength //Schematic showing logic that after each loop I calculate current render time value.
if self.isStopPressed == false { //Run fileEndCompletion only when player seek to end.
fileEndCompletionHandler() //here is callback that running all scheduled players.
if loop { // Recursive play this file again.
self.playAudioBuffer(audioFileBuffer: audioFileBuffer, loop: loop, fileEndCompletionHandler: fileEndCompletionHandler)
}
}
})
Example of code that running all scheduled player.
AudioEnginePlayer.sharedInstance.audioQueue.async {
if !self.isPlaying {
self.volume = 1.0
self.audioFile.framePosition = frameCount.startingFrame
self.prepare(withFrameCount: frameCount.frameCount)
self.play(at: AudioEnginePlayer.sharedInstance.loopMsLastStartRenderTime) //Calculated lastRenderTime
}
self.scheduleSegment(self.audioFile, startingFrame: frameCount.startingFrame, frameCount: frameCount.frameCount, at: nil) {
//WARNING: COMPLETION HANDLER RUNNING EARLY THEN FILE IS COMPLETED
if self.isStopPressed == false { //Run fileEndCompletion only when player seek to end.
fileEndCompletionHandler()
if loop {
self.playAudioFile(loop: loop, startTime: 0, fileEndCompletionHandler: fileEndCompletionHandler)
}
}
}
}

CMAltitude always returns as nil when run outside loop in swift

Recently I've been writing a game that requires the Pitch of the device in order to move the character. However, to make it so the user doesn't have to play the game with the device fixed in one starting point every time, every time the user presses play I want the app to acquire the initial tilt. This does not work however, I've added a test button that is suppose to run the code:
func recordTilt() {
InitialTilt = MovementManager.deviceMotion?.attitude
print(InitialTilt)
}
The problem with this is that whenever the button is pressed, InitialTilt will return nil. However, if InitialTilt is run in a the Loop it will return a value every time.
Movement Manager Loop:
func setup() {
MovementManager = CMMotionManager()
MovementManager.deviceMotionUpdateInterval = 0.1
MovementManager.startDeviceMotionUpdates()
InintialTilt = Movementmanager.deviceMotion?.attitude
}
func movementManaging() {
//...
InintialTilt = Movementmanager.deviceMotion?.attitude // returns every
time
//...
}
func update() {
movementManaging()
}
Can someone please help explain to me why the (InintialTilt = Movementmanager.deviceMotion?.attitude) only returns a value while it is in a loop.
(Note: The movementManaging is basically a loop that controls the player's movements, if one were to expand the ...'s all they would get are a bunch of if methods that keep the player on screen. + InintialTilt = Movementmanager.deviceMotion?.attitude)

MonoGame Mediaplayer plays only one song

I use:
MediaPlayer.Play(song1);
to play a song.
Then I use
MediaPlayer.Play(song2);
to play second song. But Mediaplayer still plays song1. I tried to stop player and play song2 again but it doesn't work. When I swap song1 and song2, it plays only song2.
Edit:
I have this class:
public class SoundHelper
{
public static void PlaySong(Song song)
{
MediaPlayer.Stop();
MediaPlayer.Play(song);
}
public static void StopSong()
{
MediaPlayer.Stop();
}
}
I use:
SoundHelper.PlaySong(Content.Load<Song>("Sounds/Songs/MenuTheme"));
to play song when game starts and it works.
Then I use:
SoundHelper.PlaySong(Content.Load<Song>("Sounds/Songs/Battle"));
to play next song in battle but then MenuTheme is played from beginning.
you have to stop playing current song
if (PlaySong1) {
MediaPlayer.Stop();
MediaPlayer.Play(Song1);
}
else{
MediaPlayer.Stop();
MediaPlayer.Play(Song2);
}
EDIT
you code looks fine, make sure that you call "SoundHelper" only once,
on loading menu or battle.
also try with "try" and "catch" on MediaPlayser.Stop() not sure, but
maybe will throw exception if no song is loaded.
it's better to load songs in your "loadcontent" instead.
song1 = Content.Load<Song>("song1"); song2 = Content.Load<Song>("song2");
also maybe adding MediaPlayer.IsRepeating = true; could be solve.
this is so far all i could remember.
Unfortunately it seems to be a bug in MonoGame. Had that same issue.
With version 3.3 your approach should work.

AVFoundation.AVAudioPlayer stops randomly

I'm trying to play multiple sounds at the same time. However sometimes the sounds just stops playing or never starts at all.
I have an eventhandler that recieves an event when a sound effect should be played:
void HandlePlaySound (object sender, EventArgs e)
{
this.InvokeOnMainThread (()=>{
...
[set url to path]
...
MonoTouch.AVFoundation.AVAudioPlayer player = MonoTouch.AVFoundation.AVAudioPlayer.FromUrl(url);
player.Play();
});
}
This works fine most of the time but when two sounds gets triggered at the same time it's seems like one of them will be killed or both. I must be doing something really wrong here.
Is there a more correct way of playing sounds in an iPhone app. Each sound is supposed to play till end and there could be multiple sounds playing at the same time.
If I were to guess, I'd say that sometimes, the GC comes in and disposes the player that has gone out of scope, causing your random stop behaviour. I found a stable solution being first establishing how many simultaneous audio streams you'd like to able to play, and then enforcing those rules:
// I'd like a maximum of 5 simultaneous audio streams
Queue<AVAudioPlayer> players = new Queue<AVAudioPlayer>(5);
void PlayAudio (string fileName)
{
NSUrl url = NSUrl.FromFilename(fileName);
AVAudioPlayer player = AVAudioPlayer.FromUrl(url);
if (players.Count == 5) {
players.Dequeue().Dispose();
}
players.Enqueue(player);
player.Play();
}
// In my example, I'll select files from my Sounds folder (containing a couple of .wav, a couple of .mp3 and an .aif)
string[] files;
int fileIndex = 0;
string GetNextFileName ()
{
if (files == null)
files = Directory.GetFiles("Sounds");
if (fileIndex == files.Length)
fileIndex = 0;
return files[fileIndex++];
}
partial void OnPlayButtonTapped (NSObject sender)
{
string fileName = GetNextFileName();
PlayAudio(fileName);
}

Control sound to only play once in XNA

I use a sound each time a key is pressed to fire a missile. But it doesn't sound nice. I guess it's because the the sound is repeated so many times while the key is pressed down and that the code is within the Update method. I'm looking for a simple solution to just play the sound once when key is pressed? (I have tested to use a boolean variable to be true the first time and then false after det the sound has been played, but this didn't worked well because, when and where should I set it to true again) Help is preciated!
// Fire
if (keyboardState.IsKeyDown(Keys.Space))
{
missile.launchMissile(spaceship.spaceshipPosition, spaceship.spaceshipDirection);
soundExplosion.Play();
}
EDIT New code that isn't working!?
KeyboardState keyboardState = Keyboard.GetState();
KeyboardState prevKeyboardState;
prevKeyboardState = keyboardState;
keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.Space) && prevKeyboardState.IsKeyUp(Keys.Space))
{
missile.launchMissile(spaceship.spaceshipPosition, spaceship.spaceshipDirection);
soundExplosion.Play();
}
Store your previous keyboard state as well
KeyBoardState prevKeyboardState;
then in your update
prevKeyboardState = keyboardState;
keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.Space) && prevKeyboardState.IsKeyUp(Keys.Space))
{
//your code
}
You're basically just triggering the sound tons of times every second making it sound awful.

Resources