/*
* sound.c from GAIM.
*
* Copyright (C) 1998-1999, Mark Spencer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 or later of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* File modified by Joern Thyssen for use with
* GNU Backgammon.
*
* $Id: sound.c,v 1.82 2011/02/14 17:07:15 c_anthon Exp $
*/
#include "config.h"
#include
#if USE_GTK
#include "gtkgame.h"
#else
#include "backgammon.h"
#include
#endif
#include "sound.h"
#include "util.h"
#if defined(WIN32)
/* for PlaySound */
#include "windows.h"
#include
#elif defined(__APPLE__) && !defined(__LP64__)
#include
#include
#include "lib/list.h"
static int fQTInitialised = FALSE;
static int fQTPlaying = FALSE;
listOLD movielist;
static pthread_mutex_t mutexQTAccess;
void * Thread_PlaySound_QuickTime (void *data)
{
int done = FALSE;
fQTPlaying = TRUE;
do {
listOLD *pl;
pthread_mutex_lock (&mutexQTAccess);
/* give CPU time to QT to process all running movies */
MoviesTask (NULL, 0);
/* check if there are any running movie left */
pl = &movielist;
done = TRUE;
do {
listOLD *next = pl->plNext;
if (pl->p != NULL) {
Movie *movie = (Movie *) pl->p;
if (IsMovieDone (*movie)) {
DisposeMovie (*movie);
free (movie);
ListDelete (pl);
}
else
done = FALSE;
}
pl = next;
} while (pl != &movielist);
pthread_mutex_unlock (&mutexQTAccess);
} while (!done && fQTPlaying);
fQTPlaying = FALSE;
return NULL;
}
void PlaySound_QuickTime (const char *cSoundFilename)
{
int err;
Str255 pSoundFilename; /* file pathname in Pascal-string format */
FSSpec fsSoundFile; /* movie file location descriptor */
short resRefNum; /* open movie file reference */
if (!fQTInitialised) {
pthread_mutex_init (&mutexQTAccess, NULL);
ListCreate (&movielist);
fQTInitialised = TRUE;
}
/* QuickTime is NOT reentrant in Mac OS (it is in MS Windows!) */
pthread_mutex_lock (&mutexQTAccess);
EnterMovies (); /* can be called multiple times */
err = NativePathNameToFSSpec(cSoundFilename, &fsSoundFile, 0);
if (err != 0) {
fprintf (stderr, "PlaySound_QuickTime: error #%d, can't find %s.\n", err, cSoundFilename);
}
else {
/* open movie (WAV or whatever) file */
err = OpenMovieFile (&fsSoundFile, &resRefNum, fsRdPerm);
if (err != 0) {
fprintf (stderr, "PlaySound_QuickTime: error #%d opening %s.\n", err, cSoundFilename);
}
else {
/* create movie from movie file */
Movie *movie = (Movie *) malloc (sizeof (Movie));
err = NewMovieFromFile (movie, resRefNum, NULL, NULL, 0, NULL);
CloseMovieFile (resRefNum);
if (err != 0) {
fprintf (stderr, "PlaySound_QuickTime: error #%d reading %s.\n", err, cSoundFilename);
}
else {
/* reset movie timebase */
TimeRecord t = { 0 };
t.base = GetMovieTimeBase (*movie);
SetMovieTime (*movie, &t);
/* add movie to list of running movies */
ListInsert (&movielist, movie);
/* run movie */
StartMovie (*movie);
}
}
}
pthread_mutex_unlock (&mutexQTAccess);
if (!fQTPlaying) {
/* launch playing thread if necessary */
int err;
pthread_t qtthread;
fQTPlaying = TRUE;
err = pthread_create (&qtthread, 0L, Thread_PlaySound_QuickTime, NULL);
if (err == 0) pthread_detach (qtthread);
else fQTPlaying = FALSE;
}
}
#elif HAVE_CANBERRA
#include
#include
#endif
const char *sound_description[ NUM_SOUNDS ] = {
N_("Starting GNU Backgammon"),
N_("Exiting GNU Backgammon"),
N_("Agree"),
N_("Doubling"),
N_("Drop"),
N_("Chequer movement"),
N_("Move"),
N_("Redouble"),
N_("Resign"),
N_("Roll"),
N_("Take"),
N_("Human fans"),
N_("Human wins game"),
N_("Human wins match"),
N_("Bot fans"),
N_("Bot wins game"),
N_("Bot wins match"),
N_("Analysis is finished")
};
const char *sound_command[ NUM_SOUNDS ] = {
"start",
"exit",
"agree",
"double",
"drop",
"chequer",
"move",
"redouble",
"resign",
"roll",
"take",
"humanfans",
"humanwinsgame",
"humanwinsmatch",
"botfans",
"botwinsgame",
"botwinsmatch",
"analysisfinished"
};
int fSound = TRUE;
int fQuiet = FALSE;
static char *sound_cmd = NULL;
void
playSoundFile (char *file, /*lint -e{715}*/gboolean sync)
{
GError *error = NULL;
#if HAVE_CANBERRA
static ca_context *canberracontext = NULL;
#endif
if (!g_file_test(file, G_FILE_TEST_EXISTS))
{
outputf(_("The sound file (%s) doesn't exist.\n"), file);
return;
}
if (sound_cmd && *sound_cmd)
{
char *commandString;
commandString = g_strdup_printf ("%s %s", sound_cmd, file);
if (!g_spawn_command_line_async (commandString, &error))
{
outputf (_("sound command (%s) could not be launched: %s\n"),
commandString, error->message);
g_error_free (error);
}
return;
}
#if defined(WIN32)
SetLastError (0);
while (!PlaySound
(file, NULL,
SND_FILENAME | SND_ASYNC | SND_NOSTOP | SND_NODEFAULT))
{
static int soundDeviceAttached = -1;
if (soundDeviceAttached == -1)
{ /* Check for sound card */
soundDeviceAttached = (int)waveOutGetNumDevs ();
}
if (!soundDeviceAttached)
{ /* No sound card found - disable sound */
g_print ("No soundcard found - sounds disabled\n");
fSound = FALSE;
return;
}
/* Check for errors */
if (GetLastError ())
{
PrintSystemError("Playing sound");
SetLastError (0);
return;
}
Sleep (1); /* Wait (1ms) for current sound to finish */
}
#elif defined(__APPLE__) && !defined(__LP64__)
PlaySound_QuickTime (file);
#elif HAVE_CANBERRA
if (!canberracontext)
{
#if USE_GTK
if (fX)
canberracontext = ca_gtk_context_get();
else
#endif
ca_context_create(&canberracontext);
}
ca_context_play(canberracontext, 0, CA_PROP_MEDIA_FILENAME, file, NULL);
#endif
}
extern void playSound(const gnubgsound gs)
{
char *sound;
if (!fSound || fQuiet)
/* no sounds for this user */
return;
sound = GetSoundFile(gs);
if (!*sound) {
g_free(sound);
return;
}
#if USE_GTK
if (!fX || gs == SOUND_EXIT)
playSoundFile(sound, TRUE);
else
playSoundFile(sound, FALSE);
#else
playSoundFile(sound, TRUE);
#endif
g_free(sound);
}
extern void SoundWait( void )
{
if (!fSound)
return;
#ifdef WIN32
/* Wait 1/10 of a second to make sure sound has started */
Sleep(100);
while (!PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC | SND_NOSTOP | SND_NODEFAULT))
Sleep(1); /* Wait (1ms) for previous sound to finish */
return;
#endif
}
char *sound_file[ NUM_SOUNDS ] = {0};
extern char *GetDefaultSoundFile(gnubgsound sound)
{
static char aszDefaultSound[ NUM_SOUNDS ][ 80 ] = {
/* start and exit */
"fanfare.wav",
"haere-ra.wav",
/* commands */
"drop.wav",
"double.wav",
"drop.wav",
"chequer.wav",
"move.wav",
"double.wav",
"resign.wav",
"roll.wav",
"take.wav",
/* events */
"dance.wav",
"gameover.wav",
"matchover.wav",
"dance.wav",
"gameover.wav",
"matchover.wav",
"fanfare.wav"
};
return BuildFilename2("sounds", aszDefaultSound[sound]);
}
extern char *GetSoundFile(gnubgsound sound)
{
if (!sound_file[sound])
return GetDefaultSoundFile(sound);
if (!(*sound_file[sound]))
return g_strdup("");
if (g_file_test(sound_file[sound], G_FILE_TEST_EXISTS))
return g_strdup(sound_file[sound]);
if (g_path_is_absolute(sound_file[sound]))
return GetDefaultSoundFile(sound);
return BuildFilename(sound_file[sound]);
}
extern void SetSoundFile(const gnubgsound sound, const char *file)
{
char *old_file = GetSoundFile(sound);
const char *new_file = file ? file : "";
if (!strcmp(new_file, old_file))
{
g_free(old_file);
return; /* No change */
}
g_free(old_file);
if (!*new_file) {
outputf(_("No sound played for: %s\n"),
gettext(sound_description[sound]));
} else {
outputf(_("Sound for: %s: %s\n"),
gettext(sound_description[sound]),
new_file);
}
g_free(sound_file[sound]);
sound_file[sound] = g_strdup(new_file);
}
extern const char *sound_get_command(void)
{
return (sound_cmd ? sound_cmd : "");
}
extern char *sound_set_command(const char *sz)
{
g_free(sound_cmd);
sound_cmd = g_strdup(sz ? sz : "");
return sound_cmd;
}
extern void SetExitSoundOff(void)
{
sound_file[SOUND_EXIT] = g_strdup("");
}