C#: Produce a continuous tone until interrupted

我怕爱的太早我们不能终老 提交于 2019-12-18 05:21:12

问题


I have a device that a user interacts with alongside of a C# WPF program. This program must beep when the user presses a button on the device, for either a specified amount of time or for as long as the user presses the button, whichever is shorter. The only speaker available to produce the beep/tone is the computer BIOS speaker; we cannot assume that other speakers are around (and it's actually safe to assume that there won't be any other speakers).

How can I produce a continuous tone for the necessary duration?

What I have so far produces lots of beeps, but not a continuous tone.

First, a thread is started:

    private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) {
        if(this.Visibility == Visibility.Visible){
            mBeepThread = new Thread(new ThreadStart(ProduceTone));
            mBeepThread.Name = "Beep Thread";
            mBeepThread.Start();
        }
    }

The thread itself:

    bool mMakeTone = false;
    private void ProduceTone(){
        while(this.Visibility == Visibility.Visible){
            if(mMakeTone ){
                Console.Beep();
            }
            else{
                Thread.Sleep(10);
            }
        }
    }

And then the mMakeTone boolean is flipped to true during the duration of the button press, up to a time specified by the device itself.

I suspect that it's just a quick change to the Console.Beep() line above, but I'm not sure what it would be.


回答1:


There is an overload for Console.Beep that takes a frequency and duration, which is useful if you want to produce a sound for a specified duration. The ability to turn on a sound and then later turn it off using the BIOS speaker is not directly supported by the Console.Beep method, or any other API that I am aware of, without perhaps installing a fake sound card driver.

A little experimentation has discovered the following:

  • Console.Beep() is synchronous and does not return until the sound is finished.
  • Calling Console.Beep() from a separate thread interrupts whatever is currently in progress.

So... You should be able to accomplish your task by creating a new background thread to call Console.Beep() with the frequency of your choosing and a very long duration. To later terminate the sound, you may just call Console.Beep() on your main thread with any frequency and an extremely, non-zero duration (e.g. 1) to terminate the sound playing from the background thread. You should not make the sound playing on the background thread any longer that a reasonable duration because the thread will live until the sound would have ordinarily stopped playing and you don't want a lot of background threads piling up on you.

private void button1_Click(object sender, EventArgs e)
{
    // Starts beep on background thread
    Thread beepThread = new Thread(new ThreadStart(PlayBeep));
    beepThread.IsBackground = true;
    beepThread.Start();
}

private void button2_Click(object sender, EventArgs e)
{
    // Terminates beep from main thread
    Console.Beep(1000, 1);
}

private void PlayBeep()
{
    // Play 1000 Hz for 5 seconds
    Console.Beep(1000, 5000);
}



回答2:


If you have a wave file of a continuous sound, you could use a SoundPlayer:

SoundPlayer player = new SoundPlayer();
player.SoundLocation = @"C:\Program Files\MyApp\sound.wav";
player.PlayLooping();
...
// Later, when you know it's time to stop the sound:
player.Stop();

I don't know if you would be able to hear the start and stop.

If that won't work for you, you probably need to go down a level to Win32 calls. You might want to look at Multimedia Audio or DirectSound.




回答3:


Unfortunately I don't think what you are wanting is possible without some low level hardware access.

The Console.Beep() method has two overloads, the one you are using without any parameters just sounds a short beep. The second overload takes two integers, the first for the frequency of the tone and the second for the number of milliseconds to sound the tone for.

Even if you bypass .NET and go to the Windows API calls you still have basically the same Beep function (with the frequency and length parameters).

So the best you can hope for, without some much lower level coding is to do something like sound a 500 millisecond tone and end up with a series of interrupted half second beeps strung together.

bool mMakeTone = false;
private void ProduceTone(){
    while(this.Visibility == Visibility.Visible){
        if(mMakeTone ){
            Console.Beep(800, 500); // 800 Hz tone for half a second
        }
        else{
            Thread.Sleep(10);
        }
    }
}

And be prepared to drive yourself mad during testing due to the lack of volume control on most PC beepers nowadays...




回答4:


You may use Console.Beep(frequency,duration); This method allows you to choose the frequency of the beep and the duration. The frequency ranges from 37-32767 hertz and the duration is measured in milliseconds and has no limit. For example:

using System;


namespace beeptesthd
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Beep(1000,60000);
        }
    }
}

In the follow in example the beeps frequency is 1000 hertz and its duration is 60000 milliseconds in other words 1 minute.



来源:https://stackoverflow.com/questions/1195828/c-produce-a-continuous-tone-until-interrupted

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!