21

Possible Duplicate:
Creating sine or square wave in C#

I want to generate sounds. Either something like:

MakeSound(frequency, duration);

Or:

MakeSound(MyArrayOfSamples);

I've found something called: Microsoft.Directx.DirectSound but have read that it has been discontinued. And I couldn't find it as an option for a reference in Visual Studio (2010). I've found this link which according to what I've read, is supposed to include it, but am hesitant to use something from 2006 since it might not be supported anymore. And this one says it's for C/C++ (despite also saying: "managed code") and I don't want to waste weeks trying to understand how to wrap that into managed code, just to find out I can't do it. The most promising link I've found is WaveFormat but I couldn't find how to use it.

I'm not asking how to get the mathematical representation for the sound wave. Nor am I asking how to play an mp3 file or the like. Nor am I looking for third party software or wrappers. Just for a C# / .net solution for a very specific objective.

Community
  • 1
  • 1
ispiro
  • 26,556
  • 38
  • 136
  • 291
  • 1
    Are you not trying to play a tone at a specified frequency and duration? – Jon B Dec 26 '12 at 15:37
  • @ispiro: I think that’s probably going to be about the way to do it, though; make a WAV using NAudio, then play it. – Ry- Dec 26 '12 at 15:37
  • 1
    Amazing. Even after spelling out what I'm _not_ looking for - I still get a close vote for the question being a duplicate of that! – ispiro Dec 26 '12 at 15:38
  • Some more: http://stackoverflow.com/questions/3502311/how-to-play-a-sound-in-c-net – Jüri Ruut Dec 26 '12 at 15:42
  • 1
    @JüriRuut From my question: Nor am I asking how to play an mp3 file or the like. – ispiro Dec 26 '12 at 15:45
  • ispiro, if you are *not* looking to play a tone using c#, then whare *are* you looking to do? – Jon B Dec 26 '12 at 15:46
  • @ispiro: Have you actually looked at the first link you dismissed as as not being a duplicate? `NAudio` _can_ actually play the sound generated using multiple output types – SztupY Dec 26 '12 at 18:17
  • @SztupY From my question: "...Nor am I looking for third party software or wrappers." – ispiro Dec 26 '12 at 18:19
  • Generating audio on the fly is never straightforward (you need a buffer and constantly fill that buffer with samples). If you want to skip the hard part then you should stick with a wrapper. If not then why don't you check NAudio on how it does the acutal sound output? It has output drivers for ASIO, DirectSound and simple WaveOut, so you can learn the one you want. – SztupY Dec 26 '12 at 18:25
  • @SztupY Thanks. What you mentioned about seeing how they use DirectSound sounds promising. I'm searching here: http://naudio.codeplex.com/SourceControl/changeset/view/8a937910ee9c but don't know under which file that would be. Do you know? – ispiro Dec 26 '12 at 18:40
  • http://naudio.codeplex.com/SourceControl/changeset/view/8a937910ee9c#NAudio/Wave/WaveOutputs/DirectSoundOut.cs – SztupY Dec 26 '12 at 18:48
  • 1
    This post helped me http://social.msdn.microsoft.com/Forums/vstudio/en-US/18fe83f0-5658-4bcf-bafc-2e02e187eb80/beep-beep – Pro-grammar Oct 03 '13 at 12:55
  • @vternal3 Thanks a lot! I've now upvoted your similar answer [here](http://stackoverflow.com/questions/1355062/audio-generation-software-or-net-library/19159847#19159847) . :) Thanks again. – ispiro Oct 03 '13 at 19:29

2 Answers2

29

Either way you look at it, unless you want to used unmanaged code, you're going to have to build a WAV to play it. However, below is a code snippet from Eric Lippert's blog that will show you how to roll your own WAV file using frequencies.

namespace Wave
{
   using System;
   using System.IO;
   class MainClass {
      public static void Main() {
         FileStream stream = new FileStream("test.wav", FileMode.Create);
         BinaryWriter writer = new BinaryWriter(stream);
         int RIFF = 0x46464952;
         int WAVE = 0x45564157;
         int formatChunkSize = 16;
         int headerSize = 8;
         int format = 0x20746D66;
         short formatType = 1;
         short tracks = 1;
         int samplesPerSecond = 44100;
         short bitsPerSample = 16;
         short frameSize = (short)(tracks * ((bitsPerSample + 7)/8));
         int bytesPerSecond = samplesPerSecond * frameSize;
         int waveSize = 4;
         int data = 0x61746164;
         int samples = 88200 * 4;
         int dataChunkSize = samples * frameSize;
         int fileSize = waveSize + headerSize + formatChunkSize + headerSize + dataChunkSize;
         writer.Write(RIFF);
         writer.Write(fileSize);
         writer.Write(WAVE);
         writer.Write(format);
         writer.Write(formatChunkSize);
         writer.Write(formatType);
         writer.Write(tracks); 
         writer.Write(samplesPerSecond);
         writer.Write(bytesPerSecond);
         writer.Write(frameSize);
         writer.Write(bitsPerSample); 
         writer.Write(data);
         writer.Write(dataChunkSize);
         double aNatural = 220.0;
         double ampl = 10000;
         double perfect = 1.5;
         double concert = 1.498307077;
         double freq = aNatural * perfect;
         for (int i = 0; i < samples / 4; i++) {
            double t = (double)i / (double)samplesPerSecond;
            short s = (short)(ampl * (Math.Sin(t * freq * 2.0 * Math.PI)));
            writer.Write(s);
         }
         freq = aNatural * concert;
         for (int i = 0; i < samples / 4; i++) {
            double t = (double)i / (double)samplesPerSecond;
            short s = (short)(ampl * (Math.Sin(t * freq * 2.0 * Math.PI)));
            writer.Write(s);
         }
         for (int i = 0; i < samples / 4; i++) {
            double t = (double)i / (double)samplesPerSecond;
            short s = (short)(ampl * (Math.Sin(t * freq * 2.0 * Math.PI) + Math.Sin(t * freq * perfect * 2.0 * Math.PI)));
            writer.Write(s);
         }
         for (int i = 0; i < samples / 4; i++) {
            double t = (double)i / (double)samplesPerSecond;
            short s = (short)(ampl * (Math.Sin(t * freq * 2.0 * Math.PI) + Math.Sin(t * freq * concert * 2.0 * Math.PI)));
            writer.Write(s);
         }
         writer.Close();
         stream.Close();
      }
   }
}

Break it apart for your needs, but notice the aNatural variable - it's a frequency - just like what you're looking for.

Now, you can place that into a MemoryStream and then play it with SoundPlayer if you like.

Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232
  • 1
    "Either way you look at it, unless you want to used unmanaged code, you're going to have to build a WAV to play it" - Not necessarily. It seems that `DirectSound` is supposed to do what I'm looking for. But as I wrote - I'm hesitant to use it unless someone can tell me how I get it running (and: If it will run at all!). – ispiro Dec 26 '12 at 15:51
  • 3
    @ispiro, the code I provided is a `raw` .NET solution that does exactly what you want. ***Further,*** `DirectSound` **will be** using unmanaged code to talk to the *sound card* and any other lower level devices. I would say that rolling a simple WAV file with the aforementioned code will produce the results you want with no overhead and no dependencies that you need to worry about. – Mike Perrenoud Dec 26 '12 at 15:53
  • using this code, how do i change the length of the wave file, right now im limited to only 8 seconds of audio – Code Disease May 10 '23 at 04:32
17

Here is a wrapper around the Beep function in the kernel, taking a duration and a frequency. Nowadays Beep uses the soundcard; in my days it used some piezo device glued on the motherboard.

using System;
using System.Runtime.InteropServices;

class BeepSample
{
    [DllImport("kernel32.dll", SetLastError=true)]
    static extern bool Beep(uint dwFreq, uint dwDuration);

    static void Main()
    {
        Console.WriteLine("Testing PC speaker...");
        for (uint i = 100; i <= 20000; i++)
        {
            Beep(i, 5);
        }
        Console.WriteLine("Testing complete.");
    }
}

On my Win10 box I need to set the duration (last parameter) much larger then the 5 ms here, more up to 50 ms but to get something reasonable I have to make it 100 ms.

Or use the Console.Beep(Int32, Int32) method if you want to take the easy route. That method was introduced in .Net 2.0.

rene
  • 41,474
  • 78
  • 114
  • 152
  • Beep does not work on x64 systems. – Ivan Kochurkin Dec 26 '12 at 21:49
  • 4
    @KvanTTT Can you back that claim by evidence? Msdn says it was dropped from win xp x64 and vista all together (x86 and x64) but is fully reimplemented in the Windows 7 using the default soundcard. I loosely cite the implementer of that functionality, [Larry Osterman](http://blogs.msdn.com/b/larryosterman/archive/2010/01/04/what-s-up-with-the-beep-driver-in-windows-7.aspx) – rene Dec 27 '12 at 08:55
  • No, beep is not working on my Win 7 x64 and Win 8 x64. [Here](http://blogs.msdn.com/b/larryosterman/archive/2010/01/04/what-s-up-with-the-beep-driver-in-windows-7.aspx) is an explanation and [here](http://stackoverflow.com/questions/1488531/net-winform-system-beep-on-a-64-bit-os) is a question on SO. – Ivan Kochurkin Jan 05 '13 at 09:52
  • funny that we both cite the same blog to prove are point :-) – rene Jan 05 '13 at 10:38
  • 4
    I just verified it on my win7 x64 and this does work as advertised. I guess I have to upvote Larry Osterman. – rene Jan 05 '13 at 11:00
  • Beep behaves/plays differently on different systems. – Jan Dec 19 '16 at 13:08
  • @Jan yeah, I had to adjust it a bit to hear something now that my box is upgraded to Win10. Experimenting with the two parameters seems advisable and your mileage may vary. – rene Dec 19 '16 at 13:21