diff options
author | Simon Howard | 2007-03-09 22:50:48 +0000 |
---|---|---|
committer | Simon Howard | 2007-03-09 22:50:48 +0000 |
commit | d4056662a4c70bf2817d470694a3506bb35f0b7f (patch) | |
tree | 1c7d971df1f0d28bf6a57d8cb4ff77c2b405f2b5 /pcsound | |
parent | 7ebeb39398f0e7fbdda6393ef2a251b0f2a42f54 (diff) | |
download | chocolate-doom-d4056662a4c70bf2817d470694a3506bb35f0b7f.tar.gz chocolate-doom-d4056662a4c70bf2817d470694a3506bb35f0b7f.tar.bz2 chocolate-doom-d4056662a4c70bf2817d470694a3506bb35f0b7f.zip |
Move the pcsound library to the top level, alongside textscreen.
Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 849
Diffstat (limited to 'pcsound')
-rw-r--r-- | pcsound/Makefile.am | 10 | ||||
-rw-r--r-- | pcsound/pcsound.c | 114 | ||||
-rw-r--r-- | pcsound/pcsound.h | 45 | ||||
-rw-r--r-- | pcsound/pcsound_sdl.c | 179 | ||||
-rw-r--r-- | pcsound/pcsound_win32.c | 115 |
5 files changed, 463 insertions, 0 deletions
diff --git a/pcsound/Makefile.am b/pcsound/Makefile.am new file mode 100644 index 00000000..77957d72 --- /dev/null +++ b/pcsound/Makefile.am @@ -0,0 +1,10 @@ + +AM_CFLAGS= @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ + +noinst_LIBRARIES=libpcsound.a + +libpcsound_a_SOURCES = \ + pcsound.c pcsound.h \ + pcsound_sdl.c \ + pcsound_win32.c + diff --git a/pcsound/pcsound.c b/pcsound/pcsound.c new file mode 100644 index 00000000..9c18eb01 --- /dev/null +++ b/pcsound/pcsound.c @@ -0,0 +1,114 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2007 Simon Howard +// +// 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 2 +// 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. +// +// DESCRIPTION: +// PC speaker interface. +// +//----------------------------------------------------------------------------- + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pcsound.h" + +#ifdef _WIN32 +extern pcsound_driver_t pcsound_win32_driver; +#endif +extern pcsound_driver_t pcsound_sdl_driver; + +static pcsound_driver_t *drivers[] = +{ +#ifdef _WIN32 + &pcsound_win32_driver, +#endif + &pcsound_sdl_driver, + NULL, +}; + +static pcsound_driver_t *pcsound_driver = NULL; + +int PCSound_Init(pcsound_callback_func callback_func) +{ + char *driver_name; + int i; + + if (pcsound_driver != NULL) + { + return 1; + } + + // Check if the environment variable is set + + driver_name = getenv("PCSOUND_DRIVER"); + + if (driver_name != NULL) + { + for (i=0; drivers[i] != NULL; ++i) + { + if (!strcasecmp(drivers[i]->name, driver_name)) + { + // Found the driver! + + if (drivers[i]->init_func(callback_func)) + { + pcsound_driver = drivers[i]; + } + else + { + printf("Failed to initialise PC sound driver: %s\n", + drivers[i]->name); + break; + } + } + } + } + else + { + // Try all drivers until we find a working one + + for (i=0; drivers[i] != NULL; ++i) + { + if (drivers[i]->init_func(callback_func)) + { + pcsound_driver = drivers[i]; + break; + } + } + } + + if (pcsound_driver != NULL) + { + printf("Using PC sound driver: %s\n", pcsound_driver->name); + return 1; + } + else + { + printf("Failed to find a working PC sound driver.\n"); + return 0; + } +} + +void PCSound_Shutdown(void) +{ + pcsound_driver->shutdown_func(); + pcsound_driver = NULL; +} + diff --git a/pcsound/pcsound.h b/pcsound/pcsound.h new file mode 100644 index 00000000..1adee416 --- /dev/null +++ b/pcsound/pcsound.h @@ -0,0 +1,45 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2007 Simon Howard +// +// 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 2 +// 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. +// +// DESCRIPTION: +// PC speaker interface. +// +//----------------------------------------------------------------------------- + +#ifndef PCSOUND_H +#define PCSOUND_H + +typedef struct pcsound_driver_s pcsound_driver_t; +typedef void (*pcsound_callback_func)(int *duration, int *frequency); +typedef int (*pcsound_init_func)(pcsound_callback_func callback); +typedef void (*pcsound_shutdown_func)(void); + +struct pcsound_driver_s +{ + char *name; + pcsound_init_func init_func; + pcsound_shutdown_func shutdown_func; +}; + +int PCSound_Init(pcsound_callback_func callback_func); +void PCSound_Shutdown(void); + +#endif /* #ifndef PCSOUND_H */ + diff --git a/pcsound/pcsound_sdl.c b/pcsound/pcsound_sdl.c new file mode 100644 index 00000000..50820394 --- /dev/null +++ b/pcsound/pcsound_sdl.c @@ -0,0 +1,179 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2007 Simon Howard +// +// 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 2 +// 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. +// +// DESCRIPTION: +// PC speaker interface. +// +//----------------------------------------------------------------------------- + +#include <stdio.h> +#include <stdlib.h> + +#include "SDL.h" +#include "SDL_mixer.h" + +#include "pcsound.h" + +#define SQUARE_WAVE_AMP 0x2000 + +static pcsound_callback_func callback; + +// Output sound format + +static int mixing_freq; +static Uint16 mixing_format; +static int mixing_channels; + +// Currently playing sound +// current_remaining is the number of remaining samples that must be played +// before we invoke the callback to get the next frequency. + +static int current_remaining; +static int current_freq; + +static int phase_offset = 0; + +// Mixer function that does the PC speaker emulation + +static void PCSound_Mix_Callback(void *udata, Uint8 *stream, int len) +{ + Sint16 *leftptr; + Sint16 *rightptr; + Sint16 this_value; + int oldfreq; + int i; + int nsamples; + + // Number of samples is quadrupled, because of 16-bit and stereo + + nsamples = len / 4; + + leftptr = (Sint16 *) stream; + rightptr = ((Sint16 *) stream) + 1; + + // Fill the output buffer + + for (i=0; i<nsamples; ++i) + { + // Has this sound expired? If so, invoke the callback to get + // the next frequency. + + while (current_remaining == 0) + { + oldfreq = current_freq; + + // Get the next frequency to play + + callback(¤t_remaining, ¤t_freq); + + if (current_freq != 0) + { + // Adjust phase to match to the new frequency. + // This gives us a smooth transition between different tones, + // with no impulse changes. + + phase_offset = (phase_offset * oldfreq) / current_freq; + } + + current_remaining = (current_remaining * mixing_freq) / 1000; + } + + // Set the value for this sample. + + if (current_freq == 0) + { + // Silence + + this_value = 0; + } + else + { + int frac; + + // Determine whether we are at a peak or trough in the current + // sound. Multiply by 2 so that frac % 2 will give 0 or 1 + // depending on whether we are at a peak or trough. + + frac = (phase_offset * current_freq * 2) / mixing_freq; + + if ((frac % 2) == 0) + { + this_value = SQUARE_WAVE_AMP; + } + else + { + this_value = -SQUARE_WAVE_AMP; + } + + ++phase_offset; + } + + --current_remaining; + + // Use the same value for the left and right channels. + + *leftptr += this_value; + *rightptr += this_value; + + leftptr += 2; + rightptr += 2; + } +} + +static int PCSound_SDL_Init(pcsound_callback_func callback_func) +{ + // Check that SDL_mixer has been opened already + // If not, fail + + if (!Mix_QuerySpec(&mixing_freq, &mixing_format, &mixing_channels)) + { + return 0; + } + + // Only supports AUDIO_S16SYS + + if (mixing_format != AUDIO_S16SYS || mixing_channels != 2) + { + fprintf(stderr, + "PCSound_SDL only supports native signed 16-bit LSB, " + "stereo format!\n"); + return 0; + } + + callback = callback_func; + current_freq = 0; + current_remaining = 0; + + Mix_SetPostMix(PCSound_Mix_Callback, NULL); + + return 1; +} + +static void PCSound_SDL_Shutdown(void) +{ +} + +pcsound_driver_t pcsound_sdl_driver = +{ + "SDL", + PCSound_SDL_Init, + PCSound_SDL_Shutdown, +}; + diff --git a/pcsound/pcsound_win32.c b/pcsound/pcsound_win32.c new file mode 100644 index 00000000..090c0bbd --- /dev/null +++ b/pcsound/pcsound_win32.c @@ -0,0 +1,115 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2007 Simon Howard +// +// 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 2 +// 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. +// +// DESCRIPTION: +// PC speaker interface. +// +//----------------------------------------------------------------------------- + +#ifdef _WIN32 + +#include <SDL.h> +#include <windows.h> + +#include "pcsound.h" + +static SDL_Thread *sound_thread_handle; +static int sound_thread_running; +static pcsound_callback_func callback; + +static int SoundThread(void *unused) +{ + int frequency; + int duration; + + while (sound_thread_running) + { + callback(&duration, &frequency); + + if (frequency != 0) + { + Beep(frequency, duration); + } + else + { + Sleep(duration); + } + } + + return 0; +} + +static int PCSound_Win32_Init(pcsound_callback_func callback_func) +{ + OSVERSIONINFO osvi; + BOOL result; + + // Temporarily disabled - the Windows scheduler is strange and + // stupid. + + return 0; + + // Find the OS version + + osvi.dwOSVersionInfoSize = sizeof(osvi); + + result = GetVersionEx(&osvi); + + if (!result) + { + return 0; + } + + // Beep() ignores its arguments on win9x, so this driver will + // not work there. + + if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) + { + // TODO: Use _out() to write directly to the PC speaker on + // win9x: See PC/winsound.c in the Python standard library. + + return 0; + } + + // Start a thread to play sound. + + callback = callback_func; + sound_thread_running = 1; + + sound_thread_handle = SDL_CreateThread(SoundThread, NULL); + + return 1; +} + +static void PCSound_Win32_Shutdown(void) +{ + sound_thread_running = 0; + SDL_WaitThread(sound_thread_handle, NULL); +} + +pcsound_driver_t pcsound_win32_driver = +{ + "Windows", + PCSound_Win32_Init, + PCSound_Win32_Shutdown, +}; + +#endif /* #ifdef _WIN32 */ + |