diff --git a/.gitignore b/.gitignore index cba7efc..cdc7813 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ a.out +tags diff --git a/README.md b/README.md index d525695..374459f 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,16 @@ +## countdown + 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 -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 -``` - -``` -ffmpeg -i /usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga ${HOME}/music/alarm-clock-elapsed.wav +sudo pacman -S libpulse pulseaudio ``` ``` @@ -23,6 +22,7 @@ sudo make install #### usage +Start a 20 minute countdown: ``` countdown 20 ``` @@ -35,5 +35,4 @@ sudo make uninstall #### TODO -- make alarm clock file wave file configurable -- fix still reachable bytes (still reachable: 42,485 bytes in 97 blocks)? +- Arch Linux package diff --git a/main.c b/main.c index 388a6f5..5424544 100644 --- a/main.c +++ b/main.c @@ -1,9 +1,9 @@ #include "play_raw_audio.h" #include #include -#include -#include #include +#include +#include // debug pulse audio problems #define PA_DEBUG 0 @@ -59,7 +59,8 @@ int main(int argc, char **argv) { } printf ("THE TIME IS UP!\n"); - play_raw_audio(audio_file_path); + + play_manual_alarm(); return 0; } diff --git a/makefile b/makefile index ebb5ccf..b3c9c0a 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ .PHONY:all all: - gcc -Wall *.c -lpulse-simple + gcc -Wall *.c -lpulse-simple -lpulse .PHONY:run run: diff --git a/play_raw_audio.c b/play_raw_audio.c index 42d1c39..567efbd 100644 --- a/play_raw_audio.c +++ b/play_raw_audio.c @@ -1,4 +1,5 @@ #include "play_raw_audio.h" +#include "time_utils.h" #include #include #include @@ -7,6 +8,27 @@ #include #include +// 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 pa_error = 0; char content[1024] = ""; @@ -42,3 +64,54 @@ int play_raw_audio(char file_name[]) { 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; +} diff --git a/play_raw_audio.h b/play_raw_audio.h index b391c88..4990fb3 100644 --- a/play_raw_audio.h +++ b/play_raw_audio.h @@ -1,3 +1,4 @@ #pragma once +int play_manual_alarm(); int play_raw_audio(char file_name[]); diff --git a/time_utils.c b/time_utils.c new file mode 100644 index 0000000..1bec6c5 --- /dev/null +++ b/time_utils.c @@ -0,0 +1,10 @@ +#include + +void sleep_ms(int milliseconds) { + struct timespec ts = { + .tv_sec = 0, + .tv_nsec = milliseconds * 1e6, + }; + + nanosleep(&ts, NULL); +} diff --git a/time_utils.h b/time_utils.h new file mode 100644 index 0000000..28075ba --- /dev/null +++ b/time_utils.h @@ -0,0 +1,3 @@ +#pragma once + +void sleep_ms(int milliseconds);