I'm quite new in Xamarin and currently developping a music-related app. One of it's functionality is a metronome, having the bpm as an input. The metronome is set ON/OFF by the press of a single button, and it ticks with a sound using the SimpleAudioPlayer plugin.
Below is my implementation, but the feeling is off : there is some lag, which, well, is not ideal for a metronome.
// OFF by default
bool _MetronomeOn = false;
async private void btnMetronome_Clicked(object sender, EventArgs e)
{
_MetronomeOn = !_MetronomeOn;
// While Metronome is On
while (_MetronomeOn)
{
// Get the bpm from ui
double bpm;
if (!Double.TryParse(entryMetronome.Text, out bpm))
bpm = 90;
double secInterval = 60 / bpm;
var player = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current;
player.Load("metronome.mp3");
if (_MetronomeOn)
{
// NOTE : Added Xam.Plugin.SimpleAudioPlayer nugget package
player.Play();
await Task.Delay(TimeSpan.FromSeconds(secInterval));
}
}
}
I am not sure what causes this... I think it can be the while implementation, the plugin loading maybe being heavy on the ressource...
Any help would be appreciated :)
EDIT : Thanks to Jason, my first step was to load the mp3 once and not during each loop. I tried at first to push the var player globally (outside any function) but VS 2022 didn't want me to and I was too much a newbie to find the correct type. But I did :) :
I set up the player globally and loaded the mp3 once in the OnAppearing() method :
public partial class MainPage : ContentPage
{
// NOTE : Added Xam.Plugin.SimpleAudioPlayer nugget package to the Android Solution
// The sound itself is loaded (not played) in OnAppearing()
Plugin.SimpleAudioPlayer.ISimpleAudioPlayer player;
public MainPage()
{
InitializeComponent();
}
// When the main view is launched and Shuffle Button animation
protected override void OnAppearing()
{
base.OnAppearing();
// Load the mp3. It must be in :
// Android : Asset folder and build action is AndroidAsset
// iOS : Resource folder and build action is BundleResource
player = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current;
player.Load("metronome.mp3");
...
}
...
}
This had a better result. Next step is implementing the correct timer, I'm working on it.
And here is the full code, thanks to you all. Here's what I changed :
Thanks a bunch !
namespace TestMetro
{
public partial class MainPage : ContentPage
{
private static System.Timers.Timer aTimer;
// NOTE : Added Xam.Plugin.SimpleAudioPlayer nugget package to the Android Solution
// The sound itself is loaded (not played) in OnAppearing()
Plugin.SimpleAudioPlayer.ISimpleAudioPlayer player;
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
// Load the mp3. It must be in :
// Android : Asset folder and build action is AndroidAsset
// iOS : Resource folder and build action is BundleResource
player = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current;
player.Load("metronome.mp3");
// Initiate the timer -- tick rate to be set below
aTimer = new System.Timers.Timer();
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnMetronomeTick;
aTimer.AutoReset = true;
aTimer.Enabled = false;
}
private void OnMetronomeTick(object sender, ElapsedEventArgs e)
{
txtBPM.Text = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff",CultureInfo.InvariantCulture);
player.Play();
}
// REMOVED _MetronomeOn Var
private void btnClick_Clicked(object sender, EventArgs e)
{
// Get the bpm from ui
double bpm;
if (!Double.TryParse(txtBPM.Text, out bpm))
bpm = 90;
double secInterval = (60 * 1000 / bpm);
aTimer.Interval = secInterval;
if (aTimer.Enabled)
aTimer.Stop();
else
aTimer.Start();
}
}
}