开发者

How to use PC speaker in linux?

开发者 https://www.devze.com 2023-01-31 04:33 出处:网络
How to use PC speaker in linux 开发者_如何转开发for c/c++ programming ? Can I control the beep time and freq?Taken from here:

How to use PC speaker in linux 开发者_如何转开发for c/c++ programming ? Can I control the beep time and freq?


Taken from here:

#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/kd.h>
int main(void)
{
    int freq[] = { /* C   D    E    F    G    A    B    C */
                    523, 587, 659, 698, 784, 880, 988, 1046 };
    int i;

    for (i=0; i<8; i++)
    {
            ioctl(STDOUT_FILENO, KIOCSOUND, 1193180/freq[i]);
            usleep(500000);
    }
    ioctl(STDOUT_FILENO, KIOCSOUND, 0); /*Stop silly sound*/
    return 0;
}


Yes, open a console device (such as /dev/console or /dev/tty0), then issue the KIOCSOUND ioctl to it, as described in the console_ioctl(4) man page.

It's yucky and Linux-specific, but I think it answers your question.


EDIT: Unbelivably, there's a PC-speaker driver in the kernel for ALSA which gives you digital sound playback in the PC speaker. Its sound quality will be poor and it will use a lot of CPU though :)


Presumably if there's still an 8253 equivalent in the chipset connected to something approximating a speaker, you can access it according to the data sheet registers or ancient PC guides (I'm relieved to admit I no longer have this information in my head) either from a kernel module or after calling ioperm() as root.

There was also once upon a time a kernel PWM "analog" audio driver for the PC speaker. I believe that was the first time I compiled a kernel. This was in the days before kernel modules, or at least before they'd made it into popular distributions.


In my case using Ubuntu 16.04, the 'ioctl' function did not worked.

So, finally, the following codes worked well without installing any additional library.

/* This outputs a tone to the speaker */

#include <alsa/asoundlib.h>
#include <math.h>

#define RATE 44100 // PCM rate [Hz]
#define FREQ 440 // Tone frequence [Hz]
#define DURATION 5 // Tone duration [s]

void info_format(snd_pcm_format_t format);

int main(void)
{
    snd_pcm_t *handle;
    unsigned char buffer[RATE * DURATION];

    for (int i = 0; i < sizeof(buffer); i++)
    {
        buffer[i] = 0xFF * sin(2 * M_PI * FREQ * i / RATE);
    }

    snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0 /* blocked mode */);

    snd_pcm_set_params(handle, SND_PCM_FORMAT_U8, SND_PCM_ACCESS_RW_INTERLEAVED, 1 /* channels */, RATE /* rate [Hz] */, 1 /* soft resample */, 500000 /* latency [us] */);

    snd_pcm_writei(handle, buffer, sizeof(buffer));

    snd_pcm_close(handle);

    return 0;
}

If the file name of the code is 'beep.c', it can be compiled as following:

gcc beep.c -lasound -lm -o beep

And it can be executed as following:

./beep


The timer is present even in modern systems on the addresses 0x41 .. 0x43 and 0x61. (I have code in Forth that runs on a MSI motherboard with an 8 core AMD). Using a 0x65 ioperm system call (that allows to unlock ports) and running with root privilege solves a rosetta code challenge to play a scale.

  • You must make accessable the ports 0x41 0x42 0x43 and 0x62 with the unlock system call

    Store 0xB6 into address 0x43 (unlock the timer)

    set the low byte of the frequency into 0x42, then the high byte. (choose e.g 2000 for the frequency)

    start beeping you by storing 3 into port 0x61

This is the rosetta code challenge to play a scale. Musical_scale

The Forth code is the most illuminating.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号