No audio with WAV and MediaPlayer in WPF - c#

I'm trying to add background music to my WPF program. I also want additional sounds to happen "over" the background music. I tried using a SoundPlayer however, this could only play one piece of audio at once.
I am now trying to use MediaPlayer but I cannot get any audio to play. Here is my code:
In my ShellViewModel I start the background music:
Sounds.StartBackgroundMusic()
In my sounds class I have the following:
private static MediaPlayer _backgroundMusic = new MediaPlayer();
public static void StartBackgroundMusic()
{
_backgroundMusic.Open(new Uri("pack://application:,,,/Assets/Sounds/backgroundmusic.wav"));
_backgroundMusic.MediaEnded += new EventHandler (BackgroundMusic_Ended);
_backgroundMusic.Play();
}
private static void BackgroundMusic_Ended(object sender, EventArgs e)
{
_backgroundMusic.Position = TimeSpan.Zero;
_backgroundMusic.Play();
}
Since I want the background music to loop continuously, I used the answer in this question to add the BackgroundMusic_Ended event. Can someone please help shed some light on why my audio isn't playing?

I tried to reproduce the problem but it worked as expected.
I created a new WPF application in Visual Studio and used the following code in MainWindow.xaml.cs:
using System;
using System.Windows;
using System.Windows.Media;
namespace WpfApp1
{
public partial class MainWindow : Window
{
private static MediaPlayer _backgroundMusic = new MediaPlayer();
public MainWindow()
{
InitializeComponent();
StartBackgroundMusic();
}
public static void StartBackgroundMusic()
{
_backgroundMusic.Open(new Uri(#"C:\<path-to-sound-file>\music.wav"));
_backgroundMusic.MediaEnded += new EventHandler(BackgroundMusic_Ended);
_backgroundMusic.Play();
}
private static void BackgroundMusic_Ended(object sender, EventArgs e)
{
_backgroundMusic.Position = TimeSpan.Zero;
_backgroundMusic.Play();
}
}
}
Did you try to use a "regular" file path to load a sound file instead of "pack://..."? When I used the wrong path I didn't get any sound and there was no error message or exception.

Since I couldn't use MediaPlayer to play embedded resources and SoundPlayer can only play one sound at a time, I used a combination of them and saved the embedded background music resource to disk so that MediaPlayer could play it. I make a blog about it here
Heres what I did:
I set up my SoundPlayer as this was the simplest one of the two. I created a new SoundPlayer object using the embedded resource
private static readonly SoundPlayer _soundOne = new SoundPlayer(WPF.Properties.Resources.soundOne);
Now the MediaPlayer. I make sure that my audio file is set as an Embedded Resource under the Build Actions in the file’s properties in Visual Studio. Now that we have done this, we can create the method for saving the embedded WAV file to the %temp% location on disk:
public static void SaveMusicToDisk(){
//This sets up a new temporary file in the %temp% location called "backgroundmusic.wav"
using (FileStream fileStream = File.Create(Path.GetTempPath() + "backgroundmusic.wav")){
//This them looks into the assembly and finds the embedded resource
//inside the WPF project, under the assets folder
//under the sounds folder called backgroundmusic.wav
//PLEASE NOTE: this will be different to you
Assembly.GetExecutingAssembly().GetManifestResourceStream("WPF.Assets.Sounds.backgroundmusic.wav").CopyTo(fileStream);
}
}
We play this by creating a new MediaPlayer object and using the temp file location to play the audio:
//Create a new MediaPlayer object
private static readonly MediaPlayer _backgroundMusic = new MediaPlayer();
public static void StartBackgroundMusic(){
//Open the temp WAV file saved in the temp location and called "backgroundmusic.wav"
_backgroundMusic.Open(new Uri(Path.Combine(Path.GetTempPath(), "backgroundmusic.wav")));
//Add an event handler for when the media has ended, this way
//the music can be played on a loop
_backgroundMusic.MediaEnded += new EventHandler(BackgroundMusic_Ended);
//Start the music playing
_backgroundMusic.Play();
}
My BackgroundMusic_Ended method looks like this and just makes sure that the music is always restarted once it has finished:
private static void BackgroundMusic_Ended(object sender, EventArgs e){
//Set the music back to the beginning
_backgroundMusic.Position = TimeSpan.Zro;
//Play the music
_backgroundMusic.Play();
}
Then I just had to worry about disposing of the objects and cleaning up the temp file when the program is closing.

Related

Can't play .wav file with audioplayer xamarin forms

I'm using audio recorder plugin package to record and play audio in Xamarin.Forms Android application.
here is my code in mypage.cs:
private static readonly AudioRecorderService recorder = new AudioRecorderService
{
StopRecordingOnSilence = false,
StopRecordingAfterTimeout = false,
FilePath = "/storage/emulated/0/Android/data/com.companyname.projectname/" + Guid.NewGuid().ToString()+".wav"
};
public RecordPage()
{
InitializeComponent();
}
private async void Button_Clicked(object sender, EventArgs e)
{
await recorder.StartRecording();
}
private async void Button_Clicked2(object sender, EventArgs e)
{
await recorder.StopRecording();
}
private void Button_Clicked3(object sender,EventArgs e)
{
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.Play(recorder.GetAudioFilePath());
}
there is no issue with recording audio. the audio will record, save and play in system music players.
but when I want to play it with AudioPlayer class, it doesn't play anything. also there are no exception throws. I tried to play some audios with the .mp3 extension and it's working for them. also, it's working for .wav files which they're converted from .mp3 to .wav.
it has a problem just with the audios recorded by AudioRecorderService
please someone help me!
thank you
-- notice the anroid device I'm testing on it is xiaomi poco x3 NFC, Android v-11
edit :
Xiaomi was the reason of this problem. it's working with other devices.

MediaElement is refusing to loop

So I was trying to loop Background music in my UWP App, I have a class called soundControl that handles music and sounds like this:
public class soundControl
{
private static MediaElement loop = new MediaElement();
public static async void stopLoop()
{
loop.Stop();
}
public static async void loadLoopTimeBG()
{
Windows.Storage.StorageFolder folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(#"Assets\Sounds");
Windows.Storage.StorageFile file = await folder.GetFileAsync("battle.wav");
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
loop.AutoPlay = false;
loop.SetSource(stream, file.ContentType);
loop.IsLooping = true;
}
public static void loopTimeBG()
{
loop.Play();
}
And whenever I want to play this music I call :
soundControl.loadLoopTimeBG();
soundControl.loopTimeBG();
the problem is the it plays just one time and stops and I have no Idea why
I tried another approach like:
loop.MediaEnded += mediaEnded;
and the event handler like this:
private static void mediaEnded(object sender, RoutedEventArgs e)
{
loop.Position = TimeSpan.Zero;
loop.Play();
}
it also didn't work and when debugging it doesn't even triger the mediaEnded event when music is complete.
Any help here would be most appreciated.
Thanks
MediaPlayer
Windows.Media.Playback.MediaPlayer is the recommended player for UWP that does not require to be in the XAML visual tree.
Its API is very similar to MediaElement:
private static MediaPlayer _mediaPlayer = new MediaPlayer();
public static async Task PlayUsingMediaPlayerAsync()
{
Windows.Storage.StorageFolder folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(#"Assets");
Windows.Storage.StorageFile file = await folder.GetFileAsync("Click.wav");
_mediaPlayer.AutoPlay = false;
_mediaPlayer.Source = MediaSource.CreateFromStorageFile(file);
_mediaPlayer.MediaOpened += _mediaPlayer_MediaOpened;
_mediaPlayer.IsLoopingEnabled = true;
}
private static void _mediaPlayer_MediaOpened(MediaPlayer sender, object args)
{
sender.Play();
}
You can even display the visuals of a MediaPlayer in XAML using MediaPlayerElement.
MediaPlayer allows for even more advanced playback scenarios using the MediaPlaybackList with support for looping, shuffle and gapless playback.
mediaElement.SetPlaybackSource(mediaPlaybackList);
MediaElement
After some digging around it seems that there are two issues.
MediaElement is XAML based control (in the Windows.UI.Xaml.Controls namespace), and it seems that it does not work properly until it is actually attached to a visual tree. Once you put the MediaElement on the page, it works as expected.
Secondly, loading source media does not happen immediately. Once you set the source, the control needs some time to actually load the media. For this purpose, you can use the MediaOpened event, that will notify you once it is really loaded.
So the code could look somewhat like this:
public static async Task LoadAndPlayAsync()
{
Windows.Storage.StorageFolder folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(#"Assets");
Windows.Storage.StorageFile file = await folder.GetFileAsync("Click.wav");
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
loop.AutoPlay = false;
loop.SetSource(stream, file.ContentType);
//or simpler -
//loop.Source = new Uri("ms-appx:///Assets/Click.wav", UriKind.Absolute);
loop.MediaOpened += Loop_MediaOpened;
loop.IsLooping = true;
}
private static void Loop_MediaOpened(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
//play once the media is actually ready
loop.Play();
}
And before you call the LoadAndPlayAsync method, you have to attach the control somewhere (for example in a Grid):
GridContainer.Children.Add(SoundController.loop);
await SoundController.LoadAndPlayAsync();
I have created a sample project for my tests on my GitHub, you can check it out to see how I implemented it. The first button in the app attaches the control and the second loads and plays the sound. You can see that if you click only the second one, the sound does not play.

Play audio from Assets folder in W10 universal app

I have several .wav and .mp3 files in my app under Assets/Audio, and I'm trying to play them when something is tapped in the UI. I've written the following code (with the file name hardcoded for testing purposes), but when the function is triggered, no sound plays. If I replace attempting to play from a file to playing an audio stream created by Windows.Media.SpeechSynthesis.SpeechSynthesizer, everything works fine.
private async void SoundItem_Tapped(object sender, TappedRoutedEventArgs e)
{
ListViewItem soundItem = sender as ListViewItem;
if (soundItem.IsSelected)
{
Uri sourceUri = new Uri(String.Format("ms-appx:///Assets/Audio/151Cry.wav", UriKind.Absolute));
await PlayAudio(sourceUri, soundItem);
}
else if (inUsePlayers.ContainsKey(soundItem))
{
MediaElement player = inUsePlayers[soundItem];
player.Stop();
inUsePlayers.Remove(soundItem);
players.Enqueue(player);
}
else
{
}
}
private async Task PlayAudio(Uri sourceUri, ListViewItem soundItem)
{
MediaElement player = RequestPlayer(soundItem);
player.Source = sourceUri;
player.IsLooping = true;
await player.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
player.Stop();
player.Play();
});
}
Here's the location of the file within the tree:
Aside from dragging the sound files into the project, I've haven't done anything. Maybe they need to be added to a resource file or copied to the output folder as well? I expected that something would throw an exception if the item pointed to by the URI didn't exist, but nothing's being thrown, even when I give it a bogus filename.
You need to do following things to play you media element.
Your resource files should be set to "Copy to Output directory"
value to "Copy if newer" or "Copy always". to do this right
click your resource file go to Properties and set Copy to Output directory value to Copy always and Build action to
content
Your player(MediaElement) should be added somewhere to View xaml
tree. I do not know your RequestPlayer method is adding
mediaEelement to view xaml or not. e.g
layoutRoot.Children.Add(player)
You need to register Player_MediaOpened event to play your
audio file. If you call 'play' before player is opened media will
not play the sound... and if you want that if any thing is happend
to your player not playing than register Player_MediaFailed it
will give you the reason why it is filed to play.
here is the code.
private async Task PlayAudio(Uri sourceUri, ListViewItem soundItem)
{
MediaElement player = RequestPlayer(soundItem);
player.IsLooping = true;
player.AutoPlay = false;
player.MediaOpened += Player_MediaOpened;
player.MediaFailed += Player_MediaFailed;
player.Source = sourceUri;
player.IsLooping = true;
//Add media element to xaml tree if not added by your RequestPlayer Method..
this.LayoutRoot.Children.Add(player);
}
private void Player_MediaFailed(object sender, ExceptionRoutedEventArgs e)
{
}
private async void Player_MediaOpened(object sender, RoutedEventArgs e)
{
await player.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
player.Play();
});
}
Hope this helps...

.net SoundPlayer event never firing

So I'm trying to use a soundplayer to load a wav file, and then fire an event after it's done loading it. Reason being is that I don't want my program to continue on until the WAV is fully loaded and ready to go (if there's another way to do this, let me know).
But unfortunately the LoadCompleted event is never firing!
Here's the last of what I tried. What am I doing wrong?
this.audio = new SoundPlayer();
audio.SoundLocation = "songs\\" + songname + ".wav";
audio.LoadAsync();
that belongs to the songdata object. Then I have this is the main class main method:
this.songdata.audio.LoadCompleted += new AsyncCompletedEventHandler(audio_LoadCompleted);
this.songdata.audio.Play();
lastly inside the main class:
void audio_LoadCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("aaa");
}
The file starts playing, but the message box never appears. BTW I'm using Visual Studio 2010 and .NET 4.0.
I got the following code to send me a LoadCompleted event, I had, however, the "event callback function" in the same class as the SoundPlayer object.
class MediaPlayer{
System.Media.SoundPlayer soundPlayer;
public MediaPlayer(MemoryStream stream){
soundPlayer = new System.Media.SoundPlayer(stream);
soundPlayer.LoadCompleted += new AsyncCompletedEventHandler(player_LoadCompleted);
soundPlayer.Load();
}
public void Play(){
soundPlayer.Play();
}
// Handler for the LoadCompleted event.
private void player_LoadCompleted(object sender, AsyncCompletedEventArgs e){
Console.WriteLine("LoadCompleted");
}
}

nullReferenceException when i try to play a sound effect?

I'm making a soundboard with sound effects and I'm getting :
"A first chance exception of type 'System.NullReferenceException'"
when building after 'UI Task' (Managed):
Loaded 'Microsoft.Xna.Framework.dll'
I did have it working but after changes (overwrote previous version) I have been getting this error and I'm stuck. Java is my first language and with C# I'm a beginner. I have spent countless hours looking for a solution.
The nullReferenceException is coming from loadsound(), I think! I have the sound files(.wav) in a folder called resources and build action:resources and copy to output:do not copy(have tried all options here). Also in references a reference was made to Microsoft.Xna.Framework
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Resources;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Media;
namespace Craggy_Island
{
public partial class MainPage : PhoneApplicationPage
{
// The Resources to play
private SoundEffect drink;//(plus 23 more effects)
// Flag that indicates if we need to resume Zune playback upon exiting.
bool resumeMediaPlayerAfterDone = false;
// Constructor
public MainPage()
{
InitializeComponent();
// Timer to simulate the XNA game loop (SoundEffect class is from the XNA Framework)
GameTimer gameTimer = new GameTimer();
gameTimer.UpdateInterval = TimeSpan.FromMilliseconds(33);
// Call FrameworkDispatcher.Update to update the XNA Framework internals.
gameTimer.Update += delegate { try { FrameworkDispatcher.Update(); } catch { } };
// Start the GameTimer running.
gameTimer.Start();
// Prime the pump or we'll get an exception.
FrameworkDispatcher.Update();
//LoadSound("Resources/drink.wav", out drink);
// Create and load SoundEffect objects.
LoadSound("Resources/drink.wav", out drink);
}
private void LoadSound(String SoundFilePath, out SoundEffect Sound)
{
// For error checking, assume we'll fail to load the file.
Sound = null;
try
{
// Holds informations about a file stream.
StreamResourceInfo SoundFileInfo = App.GetResourceStream(new Uri(SoundFilePath, UriKind.Relative));
// Create the SoundEffect from the Stream
Sound = SoundEffect.FromStream(SoundFileInfo.Stream);
}
catch (NullReferenceException)
{
// Display an error message
MessageBox.Show("Couldn't load sound " + SoundFilePath);
}
}
private void button_Click(object sender, RoutedEventArgs e)
{
Button Current = sender as Button;
try
{
if (Current.Equals(button1))
drink.Play();//(other buttons here for other sound effects)
}
catch (NullReferenceException)
{
MessageBox.Show("Can't play, sound file problem.");
}
}
#region Zune Pause/Resume
private void ZunePause()
{
// Please see the MainPage() constructor above where the GameTimer object is created.
// This enables the use of the XNA framework MediaPlayer class by pumping the XNA FrameworkDispatcher.
// Pause the Zune player if it is already playing music.
if (!MediaPlayer.GameHasControl)
{
MediaPlayer.Pause();
resumeMediaPlayerAfterDone = true;
}
}
private void ZuneResume()
{
// If Zune was playing music, resume playback
if (resumeMediaPlayerAfterDone)
{
MediaPlayer.Resume();
}
}
#endregion Zune Pause/Resume
}
}
Scrap my original answer unless you're using XNA for game development on Windows/Xbox. (Original poster is using it for the Zune.)
Regarding the WAV file:
First problem is that you need to set Copy to Output Directory to Copy if newer. (You could use Always, but that would be unnecessary.)
Second problem is that its type needs to be set to Content.
You are taking the hard approach. Look into ContentManager (accessible as this.Content from within the Game instance). You can use Content.Load<T>(string) to access your audio file, but you'll need to put the audio file in the content project. Don't change its type: leave it at the default. Even it's not a resource, leave it be. It will be compiled into a different format. Also, omit the file extension from the parameter passed to Content.Load<>.
You are starting the game before you are loading the sound:
gameTimer.Start();
FrameworkDispatcher.Update();
LoadSound("Resources/drink.wav", out drink);
I had almost the same problem. Finally I got it accidently as follows:
StreamResourceInfo streaminfo = Application.GetResourceStream(new Uri("project_name;component/folder_name/Sound3.wav", UriKind.RelativeOrAbsolute));
SoundEffect effect1 = SoundEffect.FromStream(streaminfo.Stream);
effect1.Play();
AND:
the Property "Build Action" of the .wav file must be setted to "Resource" and the Porperty "Copy to Output Directory" should be setted to "Copy if newer"
By the way, I´m working with Silverlight5.

Categories

Resources