diff options
Diffstat (limited to 'wm_pasori.c')
| -rw-r--r-- | wm_pasori.c | 143 |
1 files changed, 113 insertions, 30 deletions
diff --git a/wm_pasori.c b/wm_pasori.c index 51b8bee..f6cdab1 100644 --- a/wm_pasori.c +++ b/wm_pasori.c @@ -2,16 +2,25 @@ #include <stdlib.h> #include <stdint.h> #include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> #include <libdockapp/dockapp.h> #include <libpafe/libpafe.h> - #define APP_NAME "wm_pasori" +#include <ao/ao.h> +#define DR_WAV_IMPLEMENTATION +#include "dr_wav.h" + + #define APP_WIDTH 58 #define APP_HEIGHT 58 #define SCAN_INTERVAL_MS 700 #define PASORI_TIMEOUT_MS 200 #define SUICA_SERVICE_CODE 0x090f #define SUICA_BLOCK_NUMBER 0 +#define SOUND_DIR "/usr/local/share/wm_pasori" typedef enum { DISPLAY_START, @@ -27,7 +36,7 @@ static unsigned int current_balance = 0; static int current_error = 0; static XFontStruct *font_small = NULL; static XFontStruct *font_large = NULL; - +static int last_card_detected = 0; static void close_pasori(void) { if (reader != NULL) { @@ -36,7 +45,6 @@ static void close_pasori(void) { } } - static int open_pasori(void) { int result; @@ -68,6 +76,61 @@ static int open_pasori(void) { return 0; } +static void play_sound(const char *sound_file) { + char path[256]; + drwav wav; + ao_device *dev = NULL; + ao_sample_format fmt; + int default_driver; + static pid_t sound_pid = 0; + int status; + + if (sound_pid > 0) { + kill(sound_pid, SIGTERM); + waitpid(sound_pid, &status, 0); + sound_pid = 0; + } + + snprintf(path, sizeof(path), "%s/%s", SOUND_DIR, sound_file); + + sound_pid = fork(); + if (sound_pid != 0) return; + + ao_initialize(); + default_driver = ao_default_driver_id(); + + memset(&fmt, 0, sizeof(fmt)); + fmt.bits = 16; + fmt.channels = 2; + fmt.rate = 48000; + fmt.byte_format = AO_FMT_NATIVE; + + if (!drwav_init_file(&wav, path, NULL)) { + fprintf(stderr, "dr_wav: failed to open %s\n", path); + _exit(1); + } + fmt.bits = wav.bitsPerSample; + fmt.channels = wav.channels; + fmt.rate = wav.sampleRate; + + dev = ao_open_live(default_driver, &fmt, NULL); + if (!dev) { + fprintf(stderr, "ao_open_live failed\n"); + drwav_uninit(&wav); + _exit(1); + } + + size_t frames_read; + int16_t pcm_buf[4096]; + while ((frames_read = drwav_read_pcm_frames_s16(&wav, 4096 / wav.channels, pcm_buf)) > 0) { + ao_play(dev, (char *)pcm_buf, (int)(frames_read * wav.channels * sizeof(int16_t))); + } + + ao_close(dev); + drwav_uninit(&wav); + ao_shutdown(); + _exit(0); +} static void draw_centered_text(Drawable drawable, GC gc, XFontStruct *font, int y, const char *text) { int width; @@ -106,7 +169,6 @@ static void draw_centered_text(Drawable drawable, GC gc, XFontStruct *font, int ); } - static void redraw_display(void) { Pixmap back; XGCValues values; @@ -153,8 +215,8 @@ static void redraw_display(void) { ); /* - * 内枠 - */ + * 内枠 + */ values.foreground = DAGetColor("#56616d"); border_light_gc = XCreateGC( @@ -185,8 +247,8 @@ static void redraw_display(void) { ); /* - * ステータス - */ + * 残高表示 + */ values.foreground = DAGetColor("#d0d7de"); normal_gc = XCreateGC( @@ -209,7 +271,7 @@ static void redraw_display(void) { ); /* - * 読取り警告 + * 読み取り警告 */ values.foreground = DAGetColor("#ffd75f"); @@ -384,7 +446,7 @@ static void redraw_display(void) { * DockAppのicon windowへ反映する * * DASetPixmap()は渡した内容を表示側へ設定する - */ + */ DASetPixmap(back); XFreePixmap(DADisplay, back); @@ -401,16 +463,15 @@ static void redraw_display(void) { XFlush(DADisplay); } - /* * Suica残高を読み取る * * 戻り値: - * 0 成功 - * 1 Suicaなし - * -1 読取り失敗 - * -2 PaSoRiなし・初期化失敗 - */ + * 0 成功 + * 1 Suicaなし + * -1 読取り失敗 + * -2 PaSoRiなし・初期化失敗 + */ static int read_suica_balance(unsigned int *balance, int *read_error) { felica *card; uint8_t block_data[16]; @@ -486,7 +547,7 @@ static int read_suica_balance(unsigned int *balance, int *read_error) { * * オフセット10が下位バイト、 * オフセット11が上位バイト。 - */ + */ *balance = (unsigned int)block_data[10] | ((unsigned int)block_data[11] << 8); @@ -494,15 +555,20 @@ static int read_suica_balance(unsigned int *balance, int *read_error) { return 0; } - /* - * libdockappのタイマーコールバック。 - */ +* libdockappのタイマーコールバック。 +*/ static void timeout_callback(void) { unsigned int balance; int read_error; int result; DisplayState new_state; + static int skip_next = 0; + + if (skip_next) { + skip_next = 0; + return; + } result = read_suica_balance( &balance, @@ -514,22 +580,41 @@ static void timeout_callback(void) { new_state = DISPLAY_BALANCE; current_balance = balance; current_error = 0; + + if (!last_card_detected) { + if (balance == 0) { + play_sound("sound_02.wav"); + } else if (balance <= 1000) { + play_sound("sound_05.wav"); + } else { + play_sound("sound_03.wav"); + } + } + last_card_detected = 1; + skip_next = 1; break; case 1: new_state = DISPLAY_WAIT; current_error = 0; + last_card_detected = 0; break; case -1: new_state = DISPLAY_READ_ERROR; current_error = read_error; + if (!last_card_detected) { + play_sound("sound_06.wav"); + } + last_card_detected = 1; + skip_next = 1; break; default: new_state = DISPLAY_NO_DEVICE; current_error = 0; close_pasori(); + last_card_detected = 0; break; } @@ -537,7 +622,6 @@ static void timeout_callback(void) { redraw_display(); } - /* * 終了処理 */ @@ -557,19 +641,18 @@ static void destroy_callback(void) { fprintf(stderr, "wm_pasori terminated\n"); } - /* * メイン */ int main(int argc, char **argv) { DACallbacks callbacks = { - destroy_callback, /* destroy */ - NULL, /* buttonPress */ - NULL, /* buttonRelease */ - NULL, /* motion */ - NULL, /* mouse enters window */ - NULL, /* mouse leaves window */ - timeout_callback /* timeout */ + destroy_callback, /* destroy */ + NULL, /* buttonPress */ + NULL, /* buttonRelease */ + NULL, /* motion */ + NULL, /* mouse enters window */ + NULL, /* mouse leaves window */ + timeout_callback /* timeout */ }; DAParseArguments( @@ -583,7 +666,7 @@ int main(int argc, char **argv) { /* * FreeBSD libdockapp 0.7.2サンプル - */ + */ DASetExpectedVersion(20020126); DAOpenDisplay( |
