summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMichael R Sweet <michael.r.sweet@gmail.com>2005-12-05 00:55:01 +0000
committerMichael R Sweet <michael.r.sweet@gmail.com>2005-12-05 00:55:01 +0000
commit2f40b8b80b6c990a3c340d345c89f8e39c4d2d54 (patch)
treefc5b27d266e5d67849d4fb333f276eb648a66504 /test
parent29a41762fbed2af058abe60fa76c38a01a4542c2 (diff)
Start adding support for sound in Sudoku via ALSA.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@4684 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'test')
-rw-r--r--test/Makefile4
-rw-r--r--test/sudoku.cxx209
2 files changed, 209 insertions, 4 deletions
diff --git a/test/Makefile b/test/Makefile
index dbce0c021..acb516929 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -335,14 +335,14 @@ subwindow$(EXEEXT): subwindow.o
sudoku: sudoku.o
echo Linking $@...
- $(CXX) -I.. $(CXXFLAGS) sudoku.o -o $@ $(LINKFLTKIMG) $(LDLIBS)
+ $(CXX) -I.. $(CXXFLAGS) sudoku.o -o $@ $(AUDIOLIBS) $(LINKFLTKIMG) $(LDLIBS)
$(CP) sudoku$(EXEEXT) sudoku.app/Contents/MacOS
$(POSTBUILD) $@ ../FL/mac.r
sudoku.exe: sudoku.o sudoku.rc
echo Linking $@...
windres sudoku.rc sudokures.o
- $(CXX) -I.. $(CXXFLAGS) sudoku.o sudokures.o -o $@ $(LINKFLTKIMG) $(LDLIBS)
+ $(CXX) -I.. $(CXXFLAGS) sudoku.o sudokures.o -o $@ $(AUDIOLIBS) $(LINKFLTKIMG) $(LDLIBS)
symbols$(EXEEXT): symbols.o
diff --git a/test/sudoku.cxx b/test/sudoku.cxx
index 3bc45e687..4699f6dcd 100644
--- a/test/sudoku.cxx
+++ b/test/sudoku.cxx
@@ -40,6 +40,7 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include <math.h>
#ifdef WIN32
# include "sudokurc.h"
@@ -47,6 +48,13 @@
# include "sudoku.xbm"
#endif // WIN32
+#include <config.h>
+
+#ifdef HAVE_ALSA_ASOUNDLIB_H
+# define ALSA_PCM_NEW_HW_PARAMS_API
+# include <alsa/asoundlib.h>
+#endif // HAVE_ALSA_ASOUNDLIB_H
+
//
// Default sizes...
@@ -61,6 +69,181 @@
# define MENU_OFFSET 25
#endif // __APPLE__
+// Sound class
+class SudokuSound {
+ // Private, OS-specific data...
+#ifdef __APPLE__
+#elif defined(WIN32)
+#else
+# ifdef HAVE_ALSA_ASOUNDLIB_H
+ snd_pcm_t *handle;
+# endif // HAVE_ALSA_ASOUNDLIB_H
+#endif // __APPLE__
+
+ // Common data...
+ static int frequencies[9];
+ static short *sample_data[9];
+ static int sample_size;
+
+ public:
+
+ SudokuSound();
+ ~SudokuSound();
+
+ void play(char note);
+};
+
+
+int SudokuSound::frequencies[9] = {
+ 880, // A(5)
+ 988, // B(5)
+ 1046, // C(5)
+ 1174, // D(5)
+ 1318, // E(5)
+ 1396, // F(5)
+ 1568, // G(5)
+ 1760, // H (A6)
+ 1976 // I (B6)
+};
+short *SudokuSound::sample_data[9] = { 0 };
+int SudokuSound::sample_size = 0;
+
+
+// Initialize the SudokuSound class
+SudokuSound::SudokuSound() {
+ sample_size = 0;
+
+#ifdef __APPLE__
+#elif defined(WIN32)
+#else
+# ifdef HAVE_ALSA_ASOUNDLIB_H
+ handle = NULL;
+
+ if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) >= 0) {
+ // Initialize PCM sound stuff...
+ snd_pcm_hw_params_t *params;
+
+ snd_pcm_hw_params_alloca(&params);
+ snd_pcm_hw_params_any(handle, params);
+ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
+ snd_pcm_hw_params_set_channels(handle, params, 2);
+ unsigned rate = 44100;
+ int dir;
+ snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir);
+ snd_pcm_uframes_t period = (int)rate / 4;
+ snd_pcm_hw_params_set_period_size_near(handle, params, &period, &dir);
+
+ sample_size = rate / 20;
+
+ if (snd_pcm_hw_params(handle, params) < 0) {
+ sample_size = 0;
+ snd_pcm_close(handle);
+ handle = NULL;
+ }
+ }
+# endif // HAVE_ALSA_ASOUNDLIB_H
+#endif // __APPLE__
+
+ if (sample_size) {
+ // Make each of the notes using a combination of sine and sawtooth waves
+ int attack = sample_size / 10;
+ int decay = 4 * sample_size / 5;
+
+ for (int i = 0; i < 9; i ++) {
+ sample_data[i] = new short[2 * sample_size];
+
+ short *sample_ptr = sample_data[i];
+
+ for (int j = 0; j < sample_size; j ++, sample_ptr += 2) {
+ double theta = 0.05 * frequencies[i] * j / sample_size;
+ double val = 0.5 * sin(2.0 * M_PI * theta) + theta - (int)theta - 0.5;
+
+ if (j < attack) {
+ *sample_ptr = (int)(32767 * val * j / attack);
+ } else if (j > decay) {
+ *sample_ptr = (int)(32767 * val * (sample_size - j + decay) /
+ sample_size);
+ } else *sample_ptr = (int)(32767 * val);
+
+ sample_ptr[1] = *sample_ptr;
+ }
+ }
+ }
+}
+
+
+// Cleanup the SudokuSound class
+SudokuSound::~SudokuSound() {
+#ifdef __APPLE__
+#elif defined(WIN32)
+#else
+# ifdef HAVE_ALSA_ASOUNDLIB_H
+ if (handle) {
+ snd_pcm_drain(handle);
+ snd_pcm_close(handle);
+ }
+# endif // HAVE_ALSA_ASOUNDLIB_H
+#endif // __APPLE__
+
+ if (sample_size) {
+ for (int i = 0; i < 9; i ++) {
+ delete[] sample_data[i];
+ }
+ }
+}
+
+
+// Play a note for 250ms...
+void SudokuSound::play(char note) {
+ Fl::check();
+
+#ifdef __APPLE__
+ // TODO
+#elif defined(WIN32)
+ Beep(frequencies[note - 'A'], 50);
+#else
+# ifdef HAVE_ALSA_ASOUNDLIB_H
+ if (handle) {
+ // Use ALSA to play the sound...
+ if (snd_pcm_writei(handle, sample_data[note - 'A'], sample_size) < 0) {
+ snd_pcm_prepare(handle);
+ snd_pcm_writei(handle, sample_data[note - 'A'], sample_size);
+ }
+ usleep(50000);
+ return;
+ }
+# endif // HAVE_ALSA_ASOUNDLIB_H
+
+ // Just use standard X11 stuff...
+ XKeyboardState state;
+ XKeyboardControl control;
+
+ // Get original pitch and duration...
+ XGetKeyboardControl(fl_display, &state);
+
+ // Sound a tone for the given note...
+ control.bell_percent = 100;
+ control.bell_pitch = frequencies[note - 'A'];
+ control.bell_duration = 50;
+
+ XChangeKeyboardControl(fl_display,
+ KBBellPercent | KBBellPitch | KBBellDuration,
+ &control);
+ XBell(fl_display, 100);
+ XFlush(fl_display);
+
+ // Restore original pitch and duration...
+ control.bell_percent = state.bell_percent;
+ control.bell_pitch = state.bell_pitch;
+ control.bell_duration = state.bell_duration;
+
+ XChangeKeyboardControl(fl_display,
+ KBBellPercent | KBBellPitch | KBBellDuration,
+ &control);
+#endif // __APPLE__
+}
+
// Sudoku cell class...
class SudokuCell : public Fl_Widget {
@@ -228,6 +411,7 @@ class Sudoku : public Fl_Window {
SudokuCell *grid_cells_[9][9];
Fl_Group *grid_groups_[3][3];
int difficulty_;
+ SudokuSound *sound_;
static void check_cb(Fl_Widget *widget, void *);
static void close_cb(Fl_Widget *widget, void *);
@@ -244,6 +428,7 @@ class Sudoku : public Fl_Window {
public:
Sudoku();
+ ~Sudoku();
void check_game(bool highlight = true);
void load_game();
@@ -287,6 +472,9 @@ Sudoku::Sudoku()
};
+ // Setup sound output...
+ sound_ = new SudokuSound();
+
// Menubar...
prefs_.get("difficulty", difficulty_, 0);
if (difficulty_ < 0 || difficulty_ > 3) difficulty_ = 0;
@@ -349,12 +537,16 @@ Sudoku::Sudoku()
resize(X, X, W, H);
}
- // Load the previous game...
- load_game();
set_title();
}
+// Destroy the sudoku window...
+Sudoku::~Sudoku() {
+ delete sound_;
+}
+
+
// Check for a solution to the game...
void
Sudoku::check_cb(Fl_Widget *widget, void *) {
@@ -634,6 +826,8 @@ Sudoku::new_game(time_t seed) {
break;
}
}
+
+ sound_->play('A' + t - 1);
}
}
}
@@ -727,10 +921,15 @@ Sudoku::solve_game() {
for (i = 0; i < 9; i ++)
for (j = 0; j < 9; j ++) {
SudokuCell *cell = grid_cells_[i][j];
+ bool play_note = false;
+
+ if (cell->value() != grid_values_[i][j]) play_note = true;
cell->value(grid_values_[i][j]);
cell->readonly(1);
cell->color(fl_color_average(FL_GRAY, FL_GREEN, 0.5f));
+
+ if (play_note) sound_->play('A' + cell->value() - 1);
}
}
@@ -740,7 +939,13 @@ int
main(int argc, char *argv[]) {
Sudoku s;
+ // Show the game...
s.show(argc, argv);
+
+ // Load the previous game...
+ s.load_game();
+
+ // Run until the user quits...
return (Fl::run());
}