play-manual-square-wave-instead-of-file #2

Merged
bjoernf merged 3 commits from play-manual-square-wave-instead-of-file into master 2025-11-15 15:48:17 +00:00
8 changed files with 101 additions and 13 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
a.out a.out
tags

View File

@@ -1,17 +1,16 @@
## countdown
Simple command line countdown timer that plays a sound when the time is up. Simple command line countdown timer that plays a sound when the time is up.
It is using `pulseaudio`s simple API. When the time has expired a square wave is sent to `pulseaudio`s simple API \
to notify the user.
#### installation #### installation
install `libpulse-dev` (debian based) or `libpulse` package depending on your distro Install `libpulse-dev` (debian based) or `libpulse` package depending on your distribution.
``` ```
sudo pacman -S libpulse pulseaudio sound-theme-freedesktop sudo pacman -S libpulse pulseaudio
```
```
ffmpeg -i /usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga ${HOME}/music/alarm-clock-elapsed.wav
``` ```
``` ```
@@ -23,6 +22,7 @@ sudo make install
#### usage #### usage
Start a 20 minute countdown:
``` ```
countdown 20 countdown 20
``` ```
@@ -35,5 +35,4 @@ sudo make uninstall
#### TODO #### TODO
- make alarm clock file wave file configurable - Arch Linux package
- fix still reachable bytes (still reachable: 42,485 bytes in 97 blocks)?

7
main.c
View File

@@ -1,9 +1,9 @@
#include "play_raw_audio.h" #include "play_raw_audio.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <unistd.h>
// debug pulse audio problems // debug pulse audio problems
#define PA_DEBUG 0 #define PA_DEBUG 0
@@ -59,7 +59,8 @@ int main(int argc, char **argv) {
} }
printf ("THE TIME IS UP!\n"); printf ("THE TIME IS UP!\n");
play_raw_audio(audio_file_path);
play_manual_alarm();
return 0; return 0;
} }

View File

@@ -1,6 +1,6 @@
.PHONY:all .PHONY:all
all: all:
gcc -Wall *.c -lpulse-simple gcc -Wall *.c -lpulse-simple -lpulse
.PHONY:run .PHONY:run
run: run:

View File

@@ -1,4 +1,5 @@
#include "play_raw_audio.h" #include "play_raw_audio.h"
#include "time_utils.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <pulse/error.h> #include <pulse/error.h>
@@ -7,6 +8,27 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
// prototypes for static functions
static int play_square_wave(float frequency, float duration);
int play_manual_alarm() {
int err = 0;
for (int i = 0; i < 3; i++) {
for (int i = 0; i < 2; i++) {
err = play_square_wave(1000.0, 0.2);
if (err != 0) {
return err;
}
sleep_ms(200);
}
sleep_ms(500);
}
return 0;
}
// UNUSED
// Playing a raw audio file has the downside of depending on a file.
int play_raw_audio(char file_name[]) { int play_raw_audio(char file_name[]) {
int pa_error = 0; int pa_error = 0;
char content[1024] = ""; char content[1024] = "";
@@ -42,3 +64,54 @@ int play_raw_audio(char file_name[]) {
return 0; return 0;
} }
// Output a tone with the audio frequency "frequency"
// for "duration" number of seconds.
// The sound signals are not sine waves but square waves.
static int play_square_wave(float frequency, float duration) {
const int sample_rate = 44100;
const int channel_count = 2;
size_t buffer_size = sample_rate * channel_count * duration;
short buffer[buffer_size] = {};
pa_simple *s;
pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
.rate = sample_rate,
.channels = channel_count,
};
// number of identical consecutive elements
// 5 would look like this:
// [0,0,0,0,0,32768,32768,32768,32768,32768,0,...]
int array_interval = sample_rate / frequency;
bool square_peak = false;
for (int i = 0; i < buffer_size; i++) {
if (i % array_interval == 0) {
// toggle the value (0 or the max value for a short)
square_peak = !square_peak;
}
if (square_peak) {
buffer[i] = SHRT_MAX;
} else {
buffer[i] = 0;
}
}
if (!(s = pa_simple_new(NULL, NULL, PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &errno))) {
fprintf(stderr, "pa_simple_new() failed: %s\n", pa_strerror(errno));
return 1;
}
if (pa_simple_write(s, buffer, sizeof(buffer), NULL) < 0) {
fprintf(stderr, "pa_simple_write() failed: %s\n", pa_strerror(errno));
return 1;
}
pa_simple_drain(s, NULL);
pa_simple_free(s);
return 0;
}

View File

@@ -1,3 +1,4 @@
#pragma once #pragma once
int play_manual_alarm();
int play_raw_audio(char file_name[]); int play_raw_audio(char file_name[]);

10
time_utils.c Normal file
View File

@@ -0,0 +1,10 @@
#include <time.h>
void sleep_ms(int milliseconds) {
struct timespec ts = {
.tv_sec = 0,
.tv_nsec = milliseconds * 1e6,
};
nanosleep(&ts, NULL);
}

3
time_utils.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
void sleep_ms(int milliseconds);