Introduction
In our company, we find ourselves in need of using the internal PC speaker (buzzer) on Windows7 64bit.
Googling around searching for the problem, we found that this problem is fully explained here.
There is no trace of an easy solution, at least searching for something like "Windows 7 64bit buzzer" or something like this.
So we started from searching on how the buzzer is implemented and we found this very useful article:
I report here the most interesting part:
-
Send the value 182 to port 43h. This sets up the speaker.
-
Send the frequency number to port 42h. Since this is an 8-bit port, you must use two <tt class="LITERAL">OUT</tt>
instructions to do this. Send the least significant byte first, then the most significant byte.
-
To start the beep, bits 1 and 0 of port 61h must be set to 1. Since the other bits of port 61h have other uses, they must not be modified. Therefore, you must use an <tt class="LITERAL">IN</tt>
instruction first to get the value from the port, then do an OR
to set the two bits, then use an <tt class="LITERAL">OUT</tt>
instruction to send the new value to the port.
-
Pause for the duration of the beep.
-
Turn off the beep by resetting bits 1 and 0 of port 61h to 0. Remember that since the other bits of this port must not be modified, you must read the value, set just bits 1 and 0 to 0, then output the new value.
So with this idea in mind, and as we didn't want to write an assembler piece of code, we looked for a library that let us access the hardware ports and we find this very useful library:
As said from the authors, "InpOut32
" is an open source windows DLL and Driver to give direct access to hardware ports".
Using the Code
Once we have downloaded the driver, we have to:
- Install the driver from highrez, there is a 32bit or 64bit different installer depending on your PC configuration.
- In CLI environment, we can include the .h file, we link the .lib library and use the given DLL (there are two directories binaries\Win32 and binaries\x64 depending on your application configuration).
First, we test if the Input-Output Driver is open, then:
#include "inpout32.h"
...
void MyClass::Beep(unsigned int freq, int ms)
{
Out32(0x43, 0xB6);
int div = 0x1234dc / frequency;
Out32(0x42, (System::Byte)(div & 0xFF));
Out32(0x42, (System::Byte)(div >> 8));
System::Threading::Thread::Sleep(10);
Out32(0x61, (System::Byte)(System::Convert::ToByte(Inp32(0x61)) | 0x03));
System::Threading::Thread::Sleep(ms);
StopBeep();
}
void MyClass::StopBeep()
{
Out32(0x61, (System::Byte)(System::Convert::ToByte(Inp32(0x61)) & 0xFC));
}
...
On the other hand, we can DLLImport
(https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute%28v=vs.90%29.aspx) the DLL without having to link the library and use the .h file.
...
[DllImport("inpout32.dll")]
extern void Out32(short PortAddress, short Data);
[DllImport("inpout32.dll")]
extern char Inp32(short PortAddress);
...
In case of C#, use...
....
[DllImport("inpout32.dll")]
extern static void Out32(short PortAddress, short Data);
[DllImport("inpout32.dll")]
extern static char Inp32(short PortAddress);
...
public void Beep(uint freq, int ms)
{
Out32(0x43, 0xB6);
int div = 0x1234dc / frequency;
Out32(0x42, (Byte)(div & 0xFF));
Out32(0x42, (Byte)(div >> 8));
System.Threading.Thread.Sleep(10);
Out32(0x61, (Byte)(System.Convert.ToByte(Inp32(0x61)) | 0x03));
System.Threading.Thread.Sleep(ms);
StopBeep();
}
public void StopBeep()
{
Out32(0x61, (Byte)(System.Convert.ToByte(Inp32(0x61)) & 0xFC));
}
...
Points of Interest
Remember to always stop the buzzer!