I am writing a theater mode section in music player. The requirements is to loop through a folder containing images of any type(png, jpeg, gif) and show in a picture box with 5 seconds delay for images of type (png,jpeg) and delay time for gif should be the actual gif time duration. Also there should be fade transition between images when switch from one image to another in a single picture box. All need to be done when software is idle lets say for 60 seconds
Problem
Currently the playing song directory has 'img' folder containing 3 png
images and 3 gif. The first attempt to read
Helper.theaterImagesInfo.ToList() works pretty well
foreach (var img in Helper.theaterImagesInfo.ToList())
It starts to display 3 png images with 5 seconds delay and gif images
with the actual gif duration delay. but if i click picturebox to close theaterform as soon as the form is opened again after 60 seconds of idle state of software and loop continue
to iterate again. The default image is shown with
starting 2 png images from 'img' folder the 3rd png is skipped and then 4th gif starts
to play for few seconds not the actual gif duration and continued in wrong order as well as incorrect delay, Seems like while loop is always running in background. therfore it becomes choppy.
Desired Solution
Whenever i play song theaterform should be displayed and start to show images from folder ( in the same sequence and delay) even if the theaterform is opened again after 60 seconds if the song is still playing. Also if there is a way to show fade when changing image in a single picturebox
Code here
Program.cs
internal static class Program
{
public static Timer IdleTimer = new Timer();
readonly static int miliseconds =
Convert.ToInt32(TimeSpan.FromSeconds(60).TotalMilliseconds);
internal static MainForm f = null;
static public TheaterForm tf;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MessageFilter limf = new MessageFilter();
Application.AddMessageFilter(limf);
Application.Idle += new EventHandler(Application_Idle);
IdleTimer.Interval = miliseconds;
IdleTimer.Tick += TimeDone;
IdleTimer.Start();
f = new MainForm();
tf = new TheaterForm();
var app = new MyApplication();
app.Run(Environment.GetCommandLineArgs());
Application.Idle -= new EventHandler(Application_Idle);
}
static private void Application_Idle(Object sender, EventArgs e)
{
if (!IdleTimer.Enabled) // not yet idling?
IdleTimer.Start();
}
static private void TimeDone(object sender, EventArgs e)
{
IdleTimer.Stop();
if (MainForm.waveOut.PlaybackState == PlaybackState.Playing)
{
if (!Helper.IsTheaterOpen)
{
if (Form.ActiveForm == f)
{
Helper.IsTheaterOpen = true;
tf.WindowState = FormWindowState.Maximized;
tf.Bounds = Screen.PrimaryScreen.Bounds;
tf.x = 1;
tf.ShowDialog(f);
}
}
}
else
{
if (!Helper.IsTheaterOpen)
{
if (Form.ActiveForm == f)
{
Helper.IsTheaterOpen = true;
tf.WindowState = FormWindowState.Maximized;
tf.Bounds = Screen.PrimaryScreen.Bounds;
tf.x = 0;
tf.ShowDialog(f);
}
}
}
}
}
public class MyApplication : WindowsFormsApplicationBase
{
protected override void OnCreateMainForm()
{
MainForm = Program.f;
}
protected override void OnCreateSplashScreen()
{
SplashScreen = new SplashForm();
}
}
Helper.cs
internal class Helper
{
public static bool IsTheaterOpen { get; set; }
public struct ImageInfo
{
public bool IsAnimated;
public int durationInMilliseconds;
public Image ImageHere;
}
public static List<ImageInfo> theaterImagesInfo = new List<ImageInfo>(10);
}
MainForm.cs
/*
* Every song directory has one folder named img that contains images and gif relevant
to the song album
*/
private int GetGifDuration(Image img)
{
int delay = 0, this_delay = 0, index = 0;
FrameDimension frameDimension = new FrameDimension(img.FrameDimensionsList[0]);
int frameCount = img.GetFrameCount(frameDimension);
for (int f = 0; f < frameCount; f++)
{
this_delay = BitConverter.ToInt32(img.GetPropertyItem(20736).Value, index) * 10;
delay += (this_delay < 100 ? 100 : this_delay); // Minimum delay is 100 ms
index += 4;
}
return delay;
}
private void PlayAudio()
{
// Getting images from folder and storing in struct on every song play
if (Directory.Exists(Path.GetDirectoryName(CurrentPlayingMusicUrl) + "\\img"))
{
var files =
Directory.EnumerateFiles(Path.GetDirectoryName(CurrentPlayingMusicUrl) +
"\\img", "*", SearchOption.AllDirectories).Where(s => s.EndsWith(".png") ||
s.EndsWith(".jpg") || s.EndsWith(".jpeg") || s.EndsWith(".gif"));
Helper.theaterImagesInfo.Clear();
foreach (var imagePath in files.ToArray())
{
using (System.Drawing.Image image = System.Drawing.Image.FromFile(imagePath))
{
if (image.RawFormat.Equals(ImageFormat.Gif))
{
Helper.theaterImagesInfo.Add(new Helper.ImageInfo { IsAnimated = true, durationInMilliseconds = GetGifDuration(image), ImageHere = Image.FromFile(imagePath) });
}
else
{
Helper.theaterImagesInfo.Add(new Helper.ImageInfo { IsAnimated = false, durationInMilliseconds = 5000, ImageHere = Image.FromFile(imagePath) });
}
}
}
}
else
{
Helper.theaterImagesInfo.Clear();
Program.tf.x = 0;
}
}
TheaterForm.cs
public partial class TheaterForm : Form
{
public TheaterForm()
{
InitializeComponent();
SetDefaultImage();
}
/*
* Getting Default image from top(root) directory ex. AllMusic. If no 'img' folder
found in song album directory ex. AllMusic -> Justin Bieber -> (img folder not
exist)song1, song2, song3 etc.
*/
private async void SetDefaultImage()
{
string path = KJ_Player.Properties.Settings.Default["MusicFolder"] + "\\img";
if (Directory.Exists(path))
{
var files = Directory.EnumerateFiles(path, "*",
SearchOption.AllDirectories).Where(s => s.EndsWith(".png") ||
s.EndsWith(".jpg") || s.EndsWith(".jpeg"));
await Task.Run(() =>
{
if(files != null && files.Count()>0)
{
PictureBox1.Image = Image.FromFile(files.FirstOrDefault());
}
});
}
}
public int x=1;
private async void TheaterForm_Shown(object sender, EventArgs e)
{
if (this.PictureBox1.Image == null) SetDefaultImage();
if (Helper.theaterImagesInfo != null && Helper.theaterImagesInfo.Count > 0)
{
while (x == 1)
{
foreach (var img in Helper.theaterImagesInfo.ToList())
{
if (img.IsAnimated)
{
try
{
this.PictureBox1.Image = img.ImageHere;
await Task.Delay(img.durationInMilliseconds);
}
catch { }
}
else
{
try
{
await Task.Delay(img.durationInMilliseconds);
this.PictureBox1.Image = img.ImageHere;
}
catch { }
}
}
}
SetDefaultImage();
}
}
private void PictureBoxTheater_Click(object sender, EventArgs e)
{
this.x = 0;
if (this.PictureBox1.Image != null) this.PictureBox1.Image=null;
Helper.IsTheaterOpen = false;
this.Close();
}
}
Most likely you just need to break out of that foreach loop:
foreach (var img in Helper.theaterImagesInfo.ToList())
{
if (img.IsAnimated)
{
try
{
this.PictureBox1.Image = img.ImageHere;
await Task.Delay(img.durationInMilliseconds);
}
catch { }
}
else
{
try
{
await Task.Delay(img.durationInMilliseconds);
if (this.x == 1) {
this.PictureBox1.Image = img.ImageHere;
}
}
catch { }
}
if (this.x == 0) {
break; // exit the for loop early
}
}
Related
I have made a new windows forms application, and I'm trying to use a button to allow the user to save the application startup location when the button is clicked. I have tried to look the problem up, but I can't find anything about using a button to do it.
Here is what I have found so far which saves the location on the screen when the form is closed, I just don't know how to make it only save the location when a button is clicked:
public static void GeometryFromString(string thisWindowGeometry, Form formIn)
{
if (string.IsNullOrEmpty(thisWindowGeometry) == true)
{
return;
}
string[] numbers = thisWindowGeometry.Split('|');
string windowString = numbers[4];
if (windowString == "Normal")
{
Point windowPoint = new Point(int.Parse(numbers[0]),
int.Parse(numbers[1]));
Size windowSize = new Size(int.Parse(numbers[2]),
int.Parse(numbers[3]));
bool locOkay = GeometryIsBizarreLocation(windowPoint, windowSize);
bool sizeOkay = GeometryIsBizarreSize(windowSize);
if (locOkay == true && sizeOkay == true)
{
formIn.Location = windowPoint;
formIn.Size = windowSize;
formIn.StartPosition = FormStartPosition.Manual;
formIn.WindowState = FormWindowState.Normal;
}
else if (sizeOkay == true)
{
formIn.Size = windowSize;
}
}
else if (windowString == "Maximized")
{
formIn.Location = new Point(100, 100);
formIn.StartPosition = FormStartPosition.Manual;
formIn.WindowState = FormWindowState.Maximized;
}
}
private static bool GeometryIsBizarreLocation(Point loc, Size size)
{
bool locOkay;
if (loc.X < 0 || loc.Y < 0)
{
locOkay = false;
}
else if (loc.X + size.Width > Screen.PrimaryScreen.WorkingArea.Width)
{
locOkay = false;
}
else if (loc.Y + size.Height > Screen.PrimaryScreen.WorkingArea.Height)
{
locOkay = false;
}
else
{
locOkay = true;
}
return locOkay;
}
private static bool GeometryIsBizarreSize(Size size)
{
return (size.Height <= Screen.PrimaryScreen.WorkingArea.Height &&
size.Width <= Screen.PrimaryScreen.WorkingArea.Width);
}
public static string GeometryToString(Form mainForm)
{
return mainForm.Location.X.ToString() + "|" +
mainForm.Location.Y.ToString() + "|" +
mainForm.Size.Width.ToString() + "|" +
mainForm.Size.Height.ToString() + "|" +
mainForm.WindowState.ToString();
}
Here's one of many ways to implement a button to save the Location (and optionally Size).
First, Create a Settings resource if one doesn't already exist. Right-click on the Project and select Properties.
Choose the Settings tab and click the link to create the resource.
Make entries for Size and Location:
Add a Click handler for your Save button:
public MainForm()
{
InitializeComponent();
buttonSaveSizeAndPosition.Click += saveSizeAndPosition;
}
private async void saveSizeAndPosition(object sender, EventArgs e)
{
Properties.Settings.Default.Location = Location;
Properties.Settings.Default.Size = Size;
Properties.Settings.Default.Save();
var textB4 = Text;
Text = $"Location = {Location} Size = {Size}";
await Task.Delay(1000);
Text = textB4;
}
Then, when you load the main form check to see whether the Size has moved off of the default value before reloading these properties:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!Properties.Settings.Default.Size.Equals(new Size()))
{
Location = Properties.Settings.Default.Location;
Size = Properties.Settings.Default.Size;
}
}
I have a simple WinForms solution with 2 video players one is Vlc.DotNet and the second is libvlcsharp
and besides that, I have a simple button that plays both videos.
for libvlcsharp i followed this example
and for Vlc.DotNet i used this example
further more im attaching both logFiles
Loglibvlcsharp.txt and LogVlcDotNet
this is my code
public partial class QueueDisplayVideoView : Form
{
private string[] paths, files;
private int videoIndex = 0;
public LibVLC _libVLC;
public MediaPlayer _mp;
public LibVLCSharp.Shared.Media media;
public QueueDisplayVideoView()
{
InitializeComponent();
Core.Initialize();
_libVLC = new LibVLC(enableDebugLogs:true);
_libVLC.SetLogFile(#"C:\Temp\LogLib.txt");
_mp = new MediaPlayer(_libVLC);
videoView.MediaPlayer = _mp;
}
protected override void OnLoad(EventArgs e)
{
_presenter.OnViewReady();
base.OnLoad(e);
LoadVideoFiles();
SetPlayerAspectRatio();
//StartAutoPlay();
}
private void StartAutoPlay()
{
vlcControl.Play(new Uri(paths[videoIndex]));
_mp.Play(new LibVLCSharp.Shared.Media(_libVLC, new Uri(paths[videoIndex])));
}
private void LoadVideoFiles()
{
var path = some path
paths = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
files = new string[paths.Length];
for (int i = 0; i < paths.Length; i++)
{
files[i] = Path.GetFileName(paths[i]);
}
}
private void SetPlayerAspectRatio()
{
var videoWidth = vlcControl.Width.ToString();
var videoHieght = vlcControl.Height.ToString();
vlcControl.Video.AspectRatio = videoWidth + ":" + videoHieght;
}
private void vlcControl_VlcLibDirectoryNeeded(object sender, Vlc.DotNet.Forms.VlcLibDirectoryNeededEventArgs e)
{
// var currentAssembly = System.Reflection.Assembly.GetEntryAssembly();
var currentDirectory = #"Q:\bin"; //new FileInfo(currentAssembly.Location).DirectoryName;
// Default installation path of VideoLAN.LibVLC.Windows
var fullPath = Path.Combine(currentDirectory, "libvlc", IntPtr.Size == 4 ? "win-x86" : "win-x64");
e.VlcLibDirectory = new DirectoryInfo(fullPath);
}
private void vlcControl_EndReached(object sender, Vlc.DotNet.Core.VlcMediaPlayerEndReachedEventArgs e)
{
GetNextVideoIndex();
ThreadPool.QueueUserWorkItem(_ => vlcControl.Play(new Uri(paths[videoIndex])));
}
private void button1_Click(object sender, EventArgs e)
{
StartAutoPlay();
}
private void GetNextVideoIndex()
{
if (videoIndex < files.Length - 1)
{
videoIndex = videoIndex + 1;
}
else
{
videoIndex = 0;
}
}
}
Have you tried using this?
it should be native to winforms,all you have to do choose the right .dll at toolbox-> choose items-> com compoents-> windows media player.
I need to save an image to disk that came from a web-cam between 5 and 10 seconds ago from when the "save" command comes in via serial port.
To get there, I have the webcam going into a pictureBox.Image (using opencv4), and then 2 Bitmap variables. Every 5 seconds a timer ticks, and Stored_bitmap_2 = Stored_bitmap_1, then Stored_bitmap_1 = (bitmap) pictureBox.Image.
When the right serial command comes in, I try to
Stored_image_2.Save("C:\Users\GreenWorld\Desktop\test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
and I get a run-time error of invalid parameter.
When I do the same thing in a stand-alone project with some buttons (inside the button-click event handler), it works every time.
When I do this inside the serialPort_DataReceived handler, I get all kinds of cross-thread errors. So, I moved the save attempt to its own subroutine, and that fixed that but now this.
I am by no means a professional programmer, I'm an engineer with a simple problem and I can usually write a little simplistic code to fix my immediate issue. Please go easy on me in the explanation :-)
Sample code:
using OpenCvSharp;
using OpenCvSharp.Extensions;
namespace Weld_picture
{
public partial class Form1 : Form
{
// Create class-level accessible variables
int Welding_camera_ID = 1;
VideoCapture capture;
Mat frame;
Bitmap image;
private Thread camera;
bool isCameraRunning = false;
string Serial_command = "";
Bitmap Stored_image_1;
Bitmap Stored_image_2;
bool Image_saved = false;
string Station_ID = "GWM-PWS-01";
string File_name = "";
private void CaptureCamera() // from someone else's sample code
{
camera = new Thread(new ThreadStart(CaptureCameraCallback));
camera.Start();
}
private void CaptureCameraCallback() // from someone else's sample code
{
frame = new Mat();
capture = new VideoCapture(Welding_camera_ID);
capture.Open(Welding_camera_ID);
if (capture.IsOpened())
{
while (isCameraRunning)
{
capture.Read(frame);
image = BitmapConverter.ToBitmap(frame);
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}
pictureBox1.Image = image;
}
}
}
public Form1()
{
InitializeComponent();
SerialPort1.Open();
}
private void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string dummy;
char CR = (char)0x0D;
while (SerialPort1.BytesToRead > 0)
{
Serial_command += (char)SerialPort1.ReadByte();
}
while (Serial_command.IndexOf(CR) > 0)
{
dummy = Serial_command.Substring(0, Serial_command.IndexOf(CR));
Serial_command = Serial_command.Substring(Serial_command.IndexOf(CR) + 1, (Serial_command.Length - (Serial_command.IndexOf(CR) + 1)));
Serial_command.Trim();
dummy.Trim();
proc_Process_serial_data(dummy);
}
}
//*************************************************************************************************************************************
/* the first timer is a 5-second interval. It's the "memory" function so that if/when the save-to-disk is triggered I can store the last-time-shutter-open image */
//*************************************************************************************************************************************
private void Timer_picture_interval_Tick(object sender, EventArgs e)
{
checkBox1.Checked = !checkBox1.Checked;
Timer_picture_interval.Stop();
Stored_image_2 = Stored_image_1;
Stored_image_1 = (Bitmap) pictureBox1.Image;
Timer_picture_interval.Start();
}
//*************************************************************************************************************************************
// the second timer is a 30-second interval. It's the way to turn capture off if the PLC/camera box somehow goes off-line
//*************************************************************************************************************************************
private void Timer_camera_powerdown_Tick(object sender, EventArgs e)
{
if (isCameraRunning)
capture.Release();
isCameraRunning = false;
Timer_picture_interval.Stop();
}
//*************************************************************************************************************************************
private void proc_Process_serial_data(string Serial_string)
{
if (Serial_string.IndexOf("Still here") > 0)
{
if (!isCameraRunning)
CaptureCamera();
isCameraRunning = true;
}
if (Serial_string.IndexOf("Sun's up") > 0)
{
Timer_picture_interval.Start();
Timer_camera_powerdown.Start();
}
if (Serial_string.IndexOf("It's dark") > 0)
{
if ((Stored_image_2 != null) && (!Image_saved)) // in case there's 2 subsequent requests to save the same thing (weld stutter)
{
File_name = "C:\\Users\\GreenWorld\\Desktop\\" + Station_ID + " D" + DateTime.Now.ToString("yyyy_MM_dd THH_mm_ss") + ".jpg";
Stored_image_2.Image.Save("C:\\Users\\GreenWorld\\Desktop\\test.bmp" , System.Drawing.Imaging.ImageFormat.Bmp );
Image_saved = true;
Timer_picture_interval.Stop();
}
Timer_camera_powerdown.Start();
}
}
}
}
You likely be able to fix the cros-threading error by simply calling your proc_Process_serial_data() method within an Invoke() call.
Change:
proc_Process_serial_data(dummy);
To:
this.Invoke((MethodInvoker)delegate ()
{
proc_Process_serial_data(dummy);
});
Also, these two lines aren't actually doing anything:
Serial_command.Trim();
dummy.Trim();
To Trim() the strings, you have capture the returned strings and re-assign them to the original variables:
Serial_command = Serial_command.Trim();
dummy = dummy.Trim();
I want to play three sounds simultaneously, but second sound must play after one seconds, third sound after two seconds. I have this code:
private void Play()
{
AxWindowsMediaPlayer player1 = new AxWindowsMediaPlayer();
player1.CreateControl();
AxWindowsMediaPlayer player2 = new AxWindowsMediaPlayer();
player2.CreateControl();
AxWindowsMediaPlayer player3 = new AxWindowsMediaPlayer();
player3.CreateControl();
player1.URL = "sounds\\1.wav";
player1.Ctlcontrols.play();
System.Threading.Thread.Sleep(1000);
player2.URL = "sounds\\2.wav";
player2.Ctlcontrols.play();
System.Threading.Thread.Sleep(1000);
player3.URL = "sounds\\3.wav";
player3.Ctlcontrols.play();
Why all this sounds are playing in one time after two seconds?
I ended up using SharpDX (available via NuGet packages SharpDX
and SharpDX.XAudio2.
An example of its usage can be found in one of my GitHub projects: 2DAI
You can hear the various sounds overlapping in this screen recording as well.
Playing a sound:
var backgroundMusicSound = new AudioClip(#".\Assets\Sounds\Music\Background.wav" /*Sound path*/, 1.0 /* Volumne*/, true /*Loop Forever?*/)
backgroundMusicSound.Play();
The class that I pieced together:
public class AudioClip
{
private XAudio2 _xaudio = new XAudio2();
private WaveFormat _waveFormat;
private AudioBuffer _buffer;
private SoundStream _soundstream;
private SourceVoice _singleSourceVoice;
private bool _loopForever;
private bool _isPlaying = false; //Only applicable when _loopForever == false;
private bool _isFading;
private string _wavFilePath; //For debugging.
private float _initialVolumne;
public AudioClip(string wavFilePath, float initialVolumne = 1, bool loopForever = false)
{
_loopForever = loopForever;
_wavFilePath = wavFilePath;
_initialVolumne = initialVolumne;
var masteringsound = new MasteringVoice(_xaudio); //Yes, this is required.
var nativefilestream = new NativeFileStream(wavFilePath,
NativeFileMode.Open, NativeFileAccess.Read, NativeFileShare.Read);
_soundstream = new SoundStream(nativefilestream);
_waveFormat = _soundstream.Format;
_buffer = new AudioBuffer
{
Stream = _soundstream.ToDataStream(),
AudioBytes = (int)_soundstream.Length,
Flags = BufferFlags.EndOfStream
};
if (loopForever)
{
_buffer.LoopCount = 100;
}
}
public void Play()
{
lock (this)
{
if (_loopForever == true)
{
if (_isPlaying)
{
if (_isFading)
{
_isFading = false;
_singleSourceVoice.SetVolume(_initialVolumne);
}
return;
}
_singleSourceVoice = new SourceVoice(_xaudio, _waveFormat, true);
_singleSourceVoice.SubmitSourceBuffer(_buffer, _soundstream.DecodedPacketsInfo);
_singleSourceVoice.SetVolume(_initialVolumne);
_singleSourceVoice.Start();
_isPlaying = true;
return;
}
}
var sourceVoice = new SourceVoice(_xaudio, _waveFormat, true);
sourceVoice.SubmitSourceBuffer(_buffer, _soundstream.DecodedPacketsInfo);
sourceVoice.SetVolume(_initialVolumne);
sourceVoice.Start();
}
public void Fade()
{
if (_isPlaying && _isFading == false)
{
_isFading = true;
(new Thread(FadeThread)).Start();
}
}
private void FadeThread()
{
float volumne;
_singleSourceVoice.GetVolume(out volumne);
while (_isFading && volumne > 0)
{
volumne -= 0.25f;
volumne = volumne < 0 ? 0 : volumne;
_singleSourceVoice.SetVolume(volumne);
Thread.Sleep(100);
}
Stop();
}
public void Stop()
{
if (_loopForever == true)
{
if (_singleSourceVoice != null && _isPlaying)
{
_singleSourceVoice.Stop();
}
_isPlaying = false;
_isFading = false;
}
else
{
throw new Exception("Cannot stop overlapped audio.");
}
}
}
It should also be notes that loading the sounds can be a heavy process, so if you are doing it a lot then you might want to cache them as I did:
private Dictionary<string, AudioClip> _audioClips { get; set; } = new Dictionary<string, AudioClip>();
public AudioClip GetSoundCached(string wavFilePath, float initialVolumne, bool loopForever = false)
{
lock (_audioClips)
{
AudioClip result = null;
wavFilePath = wavFilePath.ToLower();
if (_audioClips.ContainsKey(wavFilePath))
{
result = _audioClips[wavFilePath];
}
else
{
result = new AudioClip(wavFilePath, initialVolumne, loopForever);
_audioClips.Add(wavFilePath, result);
}
return result;
}
}
I have an array which is populated by MusicNotes. Each MusicNote is an object with it's properties, e.g. pitch and duration. Duration is created using a timer in the MusicNote class.
The problem is that when I iterate through the array and play all the sounds the duration of each MusicNote is lost and it will play the whole wav file (for each note).
I know that the problem is related to the timer and I know that it maybe related to the Play() method in the MusicNote but I don't have any ideas on how to fix it. I have posted my the code related to this problem.
public class MusicNote : PictureBox
{
Timer tmr1 = new Timer();
int tmr1duration;
public SoundPlayer sp = new SoundPlayer();
public Timer tmr = new Timer();
public int pitch; //The no. of the music key (e.g. the sound freuency).
public int noteDuration; //Shape of note.
public string noteShape;
static int xLoc = 0;
int yLoc = 100;
public MusicNote(int iPitch, int iNoteDuration)
: base()
{
pitch = iPitch;
noteDuration = iNoteDuration;
Size = new Size(40, 40);
this.BackColor = Color.Transparent;
this.MouseClick += new MouseEventHandler(MusicNote_MouseClick);
this.MouseDown += new MouseEventHandler(MusicNote_MouseDown);
this.MouseUp += new MouseEventHandler(MusicNote_MouseUp);
tmr1.Tick += new EventHandler(tmr1_Tick);
tmr.Tick += new EventHandler(ClockTick);
}
public void ShowNote()
{
if (this.noteDuration == 1) noteShape = "Quaver.png";
if (this.noteDuration == 4) noteShape = "Crotchet.png";
if (this.noteDuration == 7) noteShape = "minim.png";
if (this.noteDuration == 10) noteShape = "DotMin.png";
if (this.noteDuration == 12) noteShape = "SemiBreve.png";
this.BackgroundImage = Image.FromFile(noteShape);
this.BackColor = Color.Transparent;
Location = new Point(xLoc, yLoc);
xLoc = xLoc + 40;
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
public void Play()
{
sp.SoundLocation = this.pitch + ".wav";
sp.Play();
//Timer to play the duration
this.tmr.Interval = 100 * this.noteDuration;
this.tmr.Start();
}
void ClockTick(object sender, EventArgs e)
{
sp.Stop();
tmr.Stop();
}
private void MusicNote_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Play();
}
}
}
}
And this is the class were I have the array...
public class MusicStaff: Panel
{
public ArrayList musicNotes = new ArrayList(); //Array to store the Music Notes.
SoundPlayer sp = new SoundPlayer();
public void AddNote(MusicNote newNote) //Method to add the notes.
{
musicNotes.Add(newNote);
}
public int ListSize()
{
return musicNotes.Count; //Returns the size of the list.
}
public void PlayAll()
{
foreach (MusicNote m in musicNotes)
{
m.Play();
}
I have removed some code from the classes which is not replated to the problem so that question is not too long. Any help how can I solve this would be greatly appreciated. Tks.
Try something like this:
public void PlayAll()
{
foreach (MusicNote m in musicNotes)
{
m.sp.Stop();
m.sp.PlaySync();
Thread.Sleep(m.noteDuration); //duration should be in milliseconds
}
}
Should this work you can remove your timer completely.
I suggest you look into the use of Properties in C# to not let fields be public.
By the way I did this assignment two years ago :)