Is there a way to play two sounds at the same time?
I know that SoundPlayer isn't able to do this.
I can't use SoundEffect as I believe it's only part of XNA.
The two required sounds will be called at unknown and random times. The sound needs to be be controlled after it is played. i.e., the sound must be able to be stopped before it has finished playing.
Reference PresentationCore and WindowsBase and try this...
var p1 = new System.Windows.Media.MediaPlayer();
p1.Open(new System.Uri(#"C:\windows\media\tada.wav"));
p1.Play();
// this sleep is here just so you can distinguish the two sounds playing simultaneously
System.Threading.Thread.Sleep(500);
var p2 = new System.Windows.Media.MediaPlayer();
p2.Open(new System.Uri(#"C:\windows\media\tada.wav"));
p2.Play();
EDIT
I received a downvote probably because at first glance this looks like it will play the second sound after the first is finished. It doesn't, they are played by windows asynchronously. The sleep is there so if you test this code verbatim you can hear the sounds play together, it wouldn't be noticeable without the delay since they are the same sound.
This code demonstrates the two sounds playing on separate threads on top of each other, which is sort of pointless since the playback doesn't block anyway
new System.Threading.Thread(() => {
var c = new System.Windows.Media.MediaPlayer();
c.Open(new System.Uri(#"C:\windows\media\tada.wav"));
c.Play();
}).Start();
System.Threading.Thread.Sleep(500);
new System.Threading.Thread(() => {
var c = new System.Windows.Media.MediaPlayer();
c.Open(new System.Uri(#"C:\windows\media\tada.wav"));
c.Play();
}).Start();
http://msdn.microsoft.com/en-us/library/system.windows.media.mediaplayer.stop.aspx
The class also has the control you need to stop playback
The "MediaPlayer" object will not let you play two sounds at once, even if you create two instances. You will need to bring in the native windows API "mciSendString".
[DllImport("winmm.dll")]
static extern Int32 mciSendString(string command, StringBuilder buffer, int bufferSize, IntPtr hwndCallback);
public Form1()
{
InitializeComponent();
mciSendString(#"open C:\Users\Jono\Desktop\applause.wav type waveaudio alias applause", null, 0, IntPtr.Zero);
mciSendString(#"play applause", null, 0, IntPtr.Zero);
mciSendString(#"open C:\Users\Jono\Desktop\foghorn.wav type waveaudio alias foghorn", null, 0, IntPtr.Zero);
mciSendString(#"play foghorn", null, 0, IntPtr.Zero);
}
check PlaySound method here http://msdn.microsoft.com/en-us/library/aa909766.aspx, and its flag SND_ASYNC .
Solution :
Hi,
I was developing a WP8 App and i needed multiple sounds to play simultaneously, the solutions mentioned above didnt work for me, So i used the XNA framwork. here is the link
http://msdn.microsoft.com/en-us/library/ff842408.aspx
and then play ur sound files like this...
SoundEffect Sound = SoundEffect.FromStream(Application.GetResourceStream(new Uri("Assets/Sounds/wav/sound.wav", UriKind.Relative)).Stream);
Sound.Play();
For looping...
SoundEffectInstance Sound = SoundEffect.FromStream(Application.GetResourceStream(new Uri("Assets/Sounds/wav/sound.wav", UriKind.Relative)).Stream).CreateInstance();
Sound.IsLooped = true;
Sound.Play();
Note: the files must be in ".wav" (PCM, 8 or 16-bit, 8KHz to 48KHz, mono or stereo) format
From http://alvas.net/alvas.audio,samples.aspx#sample7 and http://alvas.net/alvas.audio,samples.aspx#sample6
Player pl = new Player();
byte[] arr = File.ReadAllBytes(#"in.wav");
pl.Play(arr);
Player pl2 = new Player();
pl2.FileName = "123.mp3";
pl2.Play();
or mix audio data before playing How to mix to mix two audio file..
private void Mix(string outfile, string infile1, string infile2, int shiftSec)
{
WaveReader wr1 = new WaveReader(File.OpenRead(infile1));
WaveReader wr2 = new WaveReader(File.OpenRead(infile2));
IntPtr format1 = wr1.ReadFormat();
WaveFormat wf = AudioCompressionManager.GetWaveFormat(format1);
WaveWriter ww = new WaveWriter(File.Create(outfile), AudioCompressionManager.FormatBytes(format1));
byte[] data0 = wr1.ReadData(0, shiftSec);
byte[] data1 = wr1.ReadData(shiftSec);
byte[] data2 = wr2.ReadData();
byte[] mixData = AudioCompressionManager.Mix(format1, data2, data1);
ww.WriteData(data0);
ww.WriteData(mixData);
ww.Close();
wr2.Close();
wr1.Close();
}
The accepted answer didn't work for me.
Here is what worked:
Make sure you add references to PresentationCore and WindowsBase dlls.
private void Form1_Load(object sender, EventArgs e)
{
System.Media.SoundPlayer player = new System.Media.SoundPlayer(#"C:\Users\me\source\repos\TacticalIslandSurvival\sounds\blazer rail.wav");
player.PlayLooping();
}
private void button1_MouseEnter(object sender, EventArgs e)
{
var p1 = new System.Windows.Media.MediaPlayer();
p1.Open(new System.Uri(#"C:\Users\me\source\repos\TacticalIslandSurvival\sounds\click.wav"));
p1.Play();
}
Related
I'm making a program in Visual Studio 2015 (C#) and I want to add sound effects to it. However, I have looked up countless tutorials but none of them seem to work, and gave me tons of errors. If anyone can give me a code to play a .wav file from resource files then I would be very grateful
How to: Play Sounds in an Application
Add the following method code under the button1_Click event hander :
System.Media.SoundPlayer player =
new System.Media.SoundPlayer();
player.SoundLocation = #"C:\Users\Public\Music\Sample Music\xxxx.wav";
player.Load();
player.Play();
If the file you want to play is wav files, try this.
var player = new System.Media.SoundPlayer("c:\\tes.wav");
player.Play();
For myself I wrote this SounceController, hope it help:
using System.Windows.Media; // add reference to system.windows.presentation.
using System;
using System.IO;
public class SoundController
{
private bool isPlaying;
private MediaPlayer player;
public SoundController()
{
player = new MediaPlayer();
}
~SoundController()
{
player = null;
}
public void Play(string path)
{
if (!File.Exists(path) || isPlaying)
return;
isPlaying = true;
player.Open(new Uri(path));
player.Play();
}
public void Stop()
{
if (isPlaying)
{
isPlaying = false;
player.Stop();
}
}
}
I recommend you use PInvoke To play sound using winmm.dll
first of all import System.Runtime.InteropServices namespace in to your project.
using System.Runtime.InteropServices;
Then in your class you will have
[DllImport("winmm.dll")]
static extern Int32 mciSendString(string command, StringBuilder buffer, int bufferSize, IntPtr hwndCallback);
public void Play(string path ,string name)
{
// Open
mciSendString($#"open {path} type waveaudio alias {name}", null, 0, IntPtr.Zero);
// Play
mciSendString($#"play {name}", null, 0, IntPtr.Zero);
}
You can play the sound sending correct path of wave file with name. . given name does not need to be the same name of wave file.for example:
Play(#"C:\soundeffect.wav", "soundEffect1");
Usually sound effects are played simultaneously. you can call this method several times to play several files simultaneously.
Play(#"C:\soundeffect1.wav", "soundEffect1");
Play(#"C:\soundeffect2.wav", "soundEffect2");
Play(#"C:\soundeffect3.wav", "soundEffect3");
In my code I retrieve frames from a camera with a pointer to an unmanaged object, make some calculations on it and then I make it visualized on a picturebox control.
Before I go further in this application with all the details, I want to be sure that the base code for this process is good.
In particular I would like to:
- keep execution time minimal and avoid unnecessary operations, such as
copying more images than necessary. I want to keep only essential
operations
- understand if a delay in the calculation process on every frame could have detrimental effects on the way images are shown (i.e. if it is not printed what I expect) or some image is skipped
- prevent more serious errors, such as ones due to memory or thread management, or to image display.
For this purpose, I set up a few experimental lines of code (below), but I’m not able to explain the results of what I found. If you have the executables of OpenCv you can make a try by yourself.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
public partial class FormX : Form
{
private delegate void setImageCallback();
Bitmap _bmp;
Bitmap _bmp_draw;
bool _exit;
double _x;
IntPtr _ImgBuffer;
bool buffercopy;
bool copyBitmap;
bool refresh;
public FormX()
{
InitializeComponent();
_x = 10.1;
// set experimemental parameters
buffercopy = false;
copyBitmap = false;
refresh = true;
}
private void buttonStart_Click(object sender, EventArgs e)
{
Thread camThread = new Thread(new ThreadStart(Cycle));
camThread.Start();
}
private void buttonStop_Click(object sender, EventArgs e)
{
_exit = true;
}
private void Cycle()
{
_ImgBuffer = IntPtr.Zero;
_exit = false;
IntPtr vcap = cvCreateCameraCapture(0);
while (!_exit)
{
IntPtr frame = cvQueryFrame(vcap);
if (buffercopy)
{
UnmanageCopy(frame);
_bmp = SharedBitmap(_ImgBuffer);
}
else
{ _bmp = SharedBitmap(frame); }
// make calculations
int N = 1000000; /*1000000*/
for (int i = 0; i < N; i++)
_x = Math.Sin(0.999999 * _x);
ShowFrame();
}
cvReleaseImage(ref _ImgBuffer);
cvReleaseCapture(ref vcap);
}
private void ShowFrame()
{
if (pbCam.InvokeRequired)
{
this.Invoke(new setImageCallback(ShowFrame));
}
else
{
Pen RectangleDtPen = new Pen(Color.Azure, 3);
if (copyBitmap)
{
if (_bmp_draw != null) _bmp_draw.Dispose();
//_bmp_draw = new Bitmap(_bmp); // deep copy
_bmp_draw = _bmp.Clone(new Rectangle(0, 0, _bmp.Width, _bmp.Height), _bmp.PixelFormat);
}
else
{
_bmp_draw = _bmp; // add reference to the same object
}
Graphics g = Graphics.FromImage(_bmp_draw);
String drawString = _x.ToString();
Font drawFont = new Font("Arial", 56);
SolidBrush drawBrush = new SolidBrush(Color.Red);
PointF drawPoint = new PointF(10.0F, 10.0F);
g.DrawString(drawString, drawFont, drawBrush, drawPoint);
drawPoint = new PointF(10.0F, 300.0F);
g.DrawString(drawString, drawFont, drawBrush, drawPoint);
g.DrawRectangle(RectangleDtPen, 12, 12, 200, 400);
g.Dispose();
pbCam.Image = _bmp_draw;
if (refresh) pbCam.Refresh();
}
}
public void UnmanageCopy(IntPtr f)
{
if (_ImgBuffer == IntPtr.Zero)
_ImgBuffer = cvCloneImage(f);
else
cvCopy(f, _ImgBuffer, IntPtr.Zero);
}
// only works with 3 channel images from camera! (to keep code minimal)
public Bitmap SharedBitmap(IntPtr ipl)
{
// gets unmanaged data from pointer to IplImage:
IntPtr scan0;
int step;
Size size;
OpenCvCall.cvGetRawData(ipl, out scan0, out step, out size);
return new Bitmap(size.Width, size.Height, step, PixelFormat.Format24bppRgb, scan0);
}
// based on older version of OpenCv. Change dll name if different
[DllImport( "opencv_highgui246", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cvCreateCameraCapture(int index);
[DllImport("opencv_highgui246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvReleaseCapture(ref IntPtr capture);
[DllImport("opencv_highgui246", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cvQueryFrame(IntPtr capture);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvGetRawData(IntPtr arr, out IntPtr data, out int step, out Size roiSize);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvCopy(IntPtr src, IntPtr dst, IntPtr mask);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cvCloneImage(IntPtr src);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvReleaseImage(ref IntPtr image);
}
results [dual core 2 Duo T6600 2.2 GHz]:
A. buffercopy = false; copyBitmap = false; refresh = false;
This is the simpler configuration. Each frame is retrieved in turn, operations are made (in the reality they are based on the same frame, here just calculations), then the result of the calculations is printed on top of the image and finally it is displayed on a picturebox.
OpenCv documentation says:
OpenCV 1.x functions cvRetrieveFrame and cv.RetrieveFrame return image
stored inside the video capturing structure. It is not allowed to
modify or release the image! You can copy the frame using
cvCloneImage() and then do whatever you want with the copy.
But this doesn’t prevent us from doing experiments.
If the calculation are not intense (low number of iterations, N), everything is just ok and the fact that we manipulate the image buffer own by the unmanaged frame retriever doesn’t pose a problem here.
The reason is that probably they advise to leave untouched the buffer, in case people would modify its structure (not its values) or do operations asynchronously without realizing it. Now we retrieve frames and modify their content in turn.
If N is increased (N=1000000 or more), when the number of frames per second is not high, for example with artificial light and low exposure, everything seems ok, but after a while the video is lagged and the graphics impressed on it are blinking. With a higher frame rate the blinking appears from the beginning, even when the video is still fluid.
Is this because the mechanism of displaying images on the control (or refreshing or whatever else) is somehow asynchronous and when the picturebox is fetching its buffer of data it is modified in the meanwhile by the camera, deleting the graphics?
Or is there some other reason?
Why is the image lagged in that way, i.e. I would expect that the delay due to calculations only had the effect of skipping the frames received by the camera when the calculation are not done yet, and de facto only reducing the frame rate; or alternatively that all frames are received and the delay due to calculations brings the system to process images gotten minutes before, because the queue of images to process rises over time.
Instead, the observed behavior seems hybrid between the two: there is a delay of a few seconds, but this seems not increased much as the capturing process goes on.
B. buffercopy = true; copyBitmap = false; refresh = false;
Here I make a deep copy of the buffer into a second buffer, following the advice of the OpenCv documentation.
Nothing changes. The second buffer doesn’t change its address in memory during the run.
C. buffercopy = false; copyBitmap = true; refresh = false;
Now the (deep) copy of the bitmap is made allocating every time a new space in memory.
The blinking effect has gone, but the lagging keep arising after a certain time.
D. buffercopy = false; copyBitmap = false; refresh = true;
As before.
Please help me explain these results!
If I may be so frank, it is a bit tedious to understand all the details of your questions, but let me make a few points to help you analyse your results.
In case A, you say you perform calculations directly on the buffer. The documentation says you shouldn't do this, so if you do, you can expect undefined results. OpenCV assumes you won't touch it, so it might do stuff like suddenly delete that part of memory, let some other app process it, etc. It might look like it works, but you can never know for sure, so don't do it *slaps your wrist* In particular, if your processing takes a long time, the camera might overwrite the buffer while you're in the middle of processing it.
The way you should do it is to copy the buffer before doing anything. This will give you a piece of memory that is yours to do with whatever you wish. You can create a Bitmap that refers to this memory, and manually free the memory when you no longer need it.
If your processing rate (frames processed per second) is less than the number of frames captured per second by the camera, you have to expect some frames will be dropped. If you want to show a live view of the processed images, it will lag and there's no simple way around it. If it is vital that your application processes a fluid video (e.g. this might be necessary if you're tracking an object), then consider storing the video to disk so you don't have to process in real-time. You can also consider multithreading to process several frames at once, but the live view would have a latency.
By the way, is there any particular reason why you're not using EmguCV? It has abstractions for the camera and a system that raises an event whenever the camera has captured a new frame. This way, you don't need to continuously call cvQueryFrame on a background thread.
I think that you still have a problem with your UnmanageCopy method in that you only clone the image the first time this is called and you subsequently copy it. I believe that you need to do a cvCloneImage(f) every time as copy performs only a shallow copy, not a deep copy as you seem to think.
I'm trying to write my own VST Host and for that i need to record and play audio from an Asio Driver (in my case for an audio interface). That's why i'm trying to use NAudio's AsioOut.
For testing purposes i'm currently just trying to record the input, copy and play it to the output.
My code looks like this:
var asioout = new AsioOut();
BufferedWaveProvider wavprov = new BufferedWaveProvider(new WaveFormat(44100, 2));
asioout.AudioAvailable += new EventHandler<AsioAudioAvailableEventArgs>(asio_DataAvailable);
asioout.InitRecordAndPlayback(wavprov, 2, 25);
asioout.Play();
...
void asio_DataAvailable(object sender, AsioAudioAvailableEventArgs e)
{
Array.Copy(e.InputBuffers, e.OutputBuffers, e.InputBuffers.Length);
e.WrittenToOutputBuffers = true;
}
This way i can't hear any output. I also tried it this way:
void asio_DataAvailable(object sender, AsioAudioAvailableEventArgs e)
{
byte[] buf = new byte[e.SamplesPerBuffer];
for (int i = 0; i < e.InputBuffers.Length; i++)
{
//Marshal.Copy(e.InputBuffers[i], e.OutputBuffers, 0, e.InputBuffers.Length);
//also tried to upper one but this way i also couldn't hear anything
Marshal.Copy(e.InputBuffers[i], buf, 0, e.SamplesPerBuffer);
Marshal.Copy(buf, 0, e.OutputBuffers[i], e.SamplesPerBuffer);
}
e.WrittenToOutputBuffers = true;
}
This way i can hear sound in the volume of my input but it's very distorded.
What am i doing wrong here?
PS: I know how to record and playback.... exists but i couldn't really get a complete answer from this thread, just the idea to try it with Marshall.Copy....
Your second attempt is more correct than the first: each input buffer must be copied separately. However the final parameter of the copy method should be the number of bytes, not the number of samples in the buffer. This will typically be 3 or 4 bytes per sample, depending on your ASIO bit depth.
I need to be able to play a short[] array filled with 16-bit PCM values (after decode) in real time.
The array keeps getting longer and the player should be able to play it while the array is "growing".
I an writing in C#.
thanks ahead,
Ofek
EDIT:
I used the BufferedWaveProvider and the code looks like this:
Class Player
{
Private WaveFormat waveForamt=new WaveFormat(8000,16,1);
private BufferedWaveProvider bufferedWaveProvider;
public Player()
{
bufferedWaveProvider=new BufferedWaveProvider(waveFormat);
}
public void AddSamples(byte[] array)
{
bufferedWaveProvider.AddSamples(array,0,array.length);
WaveOut waveout=new WaveOut();
waveout.Init(bufferedWaveProvider);
waveout.Play();
}
}
the array that the AddSamples func gets is 32000 long I can see the parameters
bufferedWaveProvider.BufferedBytes = 32000
bufferedWaveProvider.BufferedBytes = 80000
bufferedWaveProvider.BufferedDuration = 00:00:02
bufferedWaveProvider.BufferDuration = 00:00:05
when I record the array I speak for 2 seconds and say: "one, two, three..."
The porblem is that when I play it, I just hear a quick sound, and nothing like what I said..
any ideas about what went wrong?
Thnaks, Ofek
EDIT 2:
Now my code looks like this, I call the AddSamples function from the Capture class.
after each time the waveout.Play() function is called - I clear the buffer and wait for it to fill up again. once it is full again I play it, and so on. the problem is that in the second time I play the buffer the sound starts fast and then it slows down... I heard something about working with two buffers.. do you know anything about this?
Thnaks a lot!
Here is the class that calls the player.AddSamples
You basically need to be able to set up a soundcard driver to read from an audio buffer and then write to that same buffer. The BufferedWaveProvider class in naudio could help. Take a look at http://naudio.codeplex.com/.
Edit : Your class works fine for me in an empty 'forms' project, playing 2 seconds of audio:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var player = new Player();
var rand = new Random();
var bytes = new byte[32000];
rand.NextBytes(bytes);
player.AddSamples(bytes);
}
}
Are you calling it in a background thread, or maybe a console app? It May be a threading or callback issue - see the 1) WaveOut section in http://naudio.codeplex.com/wikipage?title=Audio%20Output%20Driver%20Selection. You may need to pass different callback options into WaveOut()?
I just started messing around with C#/.NET/mono and stuff, and I'm trying to make a simple song player. For this, I am using winmm.dll (did not find an easy cross-platform solution). The problem is this: I need to update a trackbar along with the song playing. I have two functions, Player.GetLength and Player.GetCurrentPosition, which return the time in miliseconds. If I call them "normally", everything is ok. But I need to call them in a timer, like this:
new System.Threading.Timer((state) =>
{
length = Player.GetLength();
pos = Player.GetCurrentPosition();
trackBar1.Value = (pos / length) * 100;
}, null, 0, 100);
This is GetLength, and GetCurrentPosition is similar:
public static int GetLength()
{
StringBuilder s = new StringBuilder(128);
mciSendString("status Song length", s, s.Capacity, IntPtr.Zero);
return int.Parse(s.ToString());
}
The problem: when one of these two functions gets called, the program just stops, without any warning or exception thrown. Note: I am using .NET
So I was wondering if you can explain to me where I got it wrong :)
One thing I'd note is that System.Threading.Timer fires it's callback in it's own thread. Since you are interacting with the UI, you'd either want to use System.Windows.Forms.Timer (as a component on the form) or invoke back to the UI, as follows:
new System.Threading.Timer((state) =>
{
length = Player.GetLength();
pos = Player.GetCurrentPosition();
trackBar1.Invoke(new Action(()=>trackBar1.Value = (pos / length) * 100));
}, null, 0, 100);
Likewise, I am not sure if the Player class supports/tolerates multiple threads, but if not, there is the possibility that the whole callback needs to be invoked to the UI.