You are not logged in.

#1 2025-03-31 14:43:53

EISENFELD
Member
From: Germany
Registered: 2024-03-13
Posts: 38
Website

Darth Vader is in my terminal ;-)

C code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/kd.h>

typedef struct {
    int freq;
    int length;
} Note;

int play_note(int fd, Note note) {
       if (note.freq > 0) {
        if (ioctl(fd, KIOCSOUND, 1193180 / note.freq) < 0) {
            perror("ioctl: KIOCSOUND (Sound on)");
            return -1;
        }
    }
    
    usleep(note.length * 1000);
    
    if (ioctl(fd, KIOCSOUND, 0) < 0) {
        perror("ioctl: KIOCSOUND (Sound off)");
        return -1;
    }
    
    return 0;
}

int main() {
    int fd;
    
    Note melody[] = {
    {784, 500}, {784, 500}, {784, 500}, {622, 350}, {830, 150}, 
    {784, 500}, {622, 350}, {830, 150}, {784, 1000}, {1244, 500}, 
    {1244, 500}, {1244, 500}, {1318, 350}, {1046, 150}, {830, 500}, 
    {622, 350}, {830, 150}, {784, 1000}, {1568, 500}, {784, 350}, 
    {784, 150}, {1568, 500}, {1480, 250}, {1396, 250}, {1318, 125}, 
    {1244, 125}, {1318, 250}, {831, 250}, {1046, 500}, {988, 250}, 
    {932, 250}, {880, 125}, {831, 125}, {880, 250}, {622, 125}, 
    {784, 500}, {622, 375}, {784, 125}, {880, 500}, {784, 375}, 
    {880, 125}, {1046, 1000}
    };

    int melody_length = sizeof(melody) / sizeof(melody[0]);
        
    fd = open("/dev/console", O_WRONLY);
    if (fd == -1) {        
        fd = open("/dev/tty0", O_WRONLY);
        if (fd == -1) {
            perror("Error opening console device");
            return 1;
        }
    }
    
    printf("Darth Vader appears...\n");
       
    for (int i = 0; i < melody_length; i++) {
        if (play_note(fd, melody[i]) < 0) {
            close(fd);
            return 1;
        }
               
        usleep(50 * 1000);
    }
    
    printf("And disappears again!\n");
    
    close(fd);
    return 0;
}

Save as 'darthvader.c' for example
compile:

gcc darthvader.c -o darthvader

Program must be run as root

sudo ./darthvader

or you set the 's' bit:

sudo chown root:root darthvader
sudo chmod u+s darthvader
./darthvader

enjoy!

Last edited by EISENFELD (2025-04-01 02:57:28)


Ich weiß, dass ich nichts weiß !

Offline

#2 2025-03-31 15:17:34

ua4000
Member
Registered: 2015-10-14
Posts: 509

Re: Darth Vader is in my terminal ;-)

EISENFELD wrote:

...
Program must be run as root
...
or you set the 's' bit:

this is not a good idea. I suggest you find out, how to run as normal user.

Offline

#3 2025-03-31 16:17:29

EISENFELD
Member
From: Germany
Registered: 2024-03-13
Posts: 38
Website

Re: Darth Vader is in my terminal ;-)

Direct access to the hardware always needs root privileges in C. You could add the program to a group 'audio' for example which has the needed privileges or something like that. I didn't find an easy solution for that.


Ich weiß, dass ich nichts weiß !

Offline

#4 2025-03-31 17:01:36

schard
Forum Moderator
From: Hannover
Registered: 2016-05-06
Posts: 2,276
Website

Re: Darth Vader is in my terminal ;-)

You can also use a udev rule, as described here.


Inofficial first vice president of the Rust Evangelism Strike Force

Offline

#5 2025-03-31 20:49:32

seth
Member
Registered: 2012-09-03
Posts: 65,181

Re: Darth Vader is in my terminal ;-)

https://en.wikipedia.org/wiki/The_Imperial_March
The imperial march is set in g-minor, 440Hz is a¹ and has no business being there.
(The theme is later on referenced in a-minor during the lighthearted busy phase but then returns in full force to g-minor and that's what you think of when you see Vader)

Also, if you've pcspkr blacklisted as normal humans tongue

mpv -vo null 'https://www.youtube.com/watch?v=UOEaZOHyo6w'

Offline

#6 2025-04-01 02:55:59

EISENFELD
Member
From: Germany
Registered: 2024-03-13
Posts: 38
Website

Re: Darth Vader is in my terminal ;-)

Yes, you are absolutely right, it must be g-minor. Thanks.

This should sound a bit better (it's still not perfect)

Note melody[] = {
    {784, 500}, {784, 500}, {784, 500}, {622, 350}, {830, 150}, 
    {784, 500}, {622, 350}, {830, 150}, {784, 1000}, {1244, 500}, 
    {1244, 500}, {1244, 500}, {1318, 350}, {1046, 150}, {830, 500}, 
    {622, 350}, {830, 150}, {784, 1000}, {1568, 500}, {784, 350}, 
    {784, 150}, {1568, 500}, {1480, 250}, {1396, 250}, {1318, 125}, 
    {1244, 125}, {1318, 250}, {831, 250}, {1046, 500}, {988, 250}, 
    {932, 250}, {880, 125}, {831, 125}, {880, 250}, {622, 125}, 
    {784, 500}, {622, 375}, {784, 125}, {880, 500}, {784, 375}, 
    {880, 125}, {1046, 1000}
};

May the force be with you


Ich weiß, dass ich nichts weiß !

Offline

#7 2025-04-02 14:39:18

EISENFELD
Member
From: Germany
Registered: 2024-03-13
Posts: 38
Website

Re: Darth Vader is in my terminal ;-)

Now, I found a way to play speaker sound without root privileges in C: (It should work on Arch out of the box, "libevdev" package is needed)

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include <libevdev-1.0/libevdev/libevdev.h>

typedef struct {
    int frequency;
    int duration;
    int delay;
} Note;

void play_tone(int fd, int freq, int duration_ms) {
    struct input_event event;
    event.type = EV_SND;
    event.code = SND_TONE;
    event.value = freq;

    write(fd, &event, sizeof(event));

    usleep(duration_ms * 1000);

    event.value = 0;
    write(fd, &event, sizeof(event));
}

int main() {
    int fd = open("/dev/input/by-path/platform-pcspkr-event-spkr", O_WRONLY);
    if (fd == -1) {
        perror("Error opening PC Speaker device!");
        return 1;
    }
    
	// Converted notes from GH user "Josef-Friedrich" and his "beep-melodies" repo. Thanks!
    Note melody[] = {
        {392, 350, 100}, {392, 350, 100}, {392, 350, 100}, {311, 250, 100},
        {466, 25, 100}, {392, 350, 100}, {311, 250, 100}, {466, 25, 100},
        {392, 700, 100}, {587, 350, 100}, {587, 350, 100}, {587, 350, 100},
        {622, 250, 100}, {466, 25, 100}, {370, 350, 100}, {311, 250, 100},
        {466, 25, 100}, {392, 700, 100}, {784, 350, 100}, {392, 250, 100},
        {392, 25, 100}, {784, 350, 100}, {740, 250, 100}, {698, 25, 100},
        {659, 25, 100}, {622, 25, 100}, {659, 50, 400}, {415, 25, 200},
        {554, 350, 100}, {523, 250, 100}, {494, 25, 100}, {466, 25, 100},
        {440, 25, 100}, {466, 50, 400}, {311, 25, 200}, {370, 350, 100},
        {311, 250, 100}, {392, 25, 100}, {466, 350, 100}, {392, 250, 100},
        {466, 25, 100}, {587, 700, 100}, {784, 350, 100}, {392, 250, 100},
        {392, 25, 100}, {784, 350, 100}, {740, 250, 100}, {698, 25, 100},
        {659, 25, 100}, {622, 25, 100}, {659, 50, 400}, {415, 25, 200},
        {554, 350, 100}, {523, 250, 100}, {494, 25, 100}, {466, 25, 100},
        {440, 25, 100}, {466, 50, 400}, {311, 25, 200}, {392, 350, 100},
        {311, 250, 100}, {466, 25, 100}, {392, 300, 150}, {311, 250, 100},
        {466, 25, 100}, {392, 700, 0}
    };
    int notes = sizeof(melody) / sizeof(melody[0]);

    for (int i = 0; i < notes; i++) {
        play_tone(fd, melody[i].frequency, melody[i].duration);
        usleep(melody[i].delay * 1000);
    }

    close(fd);
    return 0;
}

compile:

gcc darthvader.c -o darthvader

run:

./darthvader

Ich weiß, dass ich nichts weiß !

Offline

Board footer

Powered by FluxBB