diff options
Diffstat (limited to 'PC')
-rw-r--r-- | PC/winsound.c | 134 |
1 files changed, 99 insertions, 35 deletions
diff --git a/PC/winsound.c b/PC/winsound.c index bc96387..77572ab 100644 --- a/PC/winsound.c +++ b/PC/winsound.c @@ -9,13 +9,14 @@ /* Modified by Guido van Rossum */ /* Beep added by Mark Hammond */ +/* Win9X Beep and platform identification added by Uncle Timmy */ /* Example: import winsound import time - # Play wav file + # Play wav file winsound.PlaySound('c:/windows/media/Chord.wav', winsound.SND_FILENAME) # Play sound from control panel settings @@ -36,6 +37,7 @@ #include <windows.h> #include <mmsystem.h> +#include <conio.h> /* port functions on Win9x */ #include <Python.h> static char sound_playsound_doc[] = @@ -48,11 +50,11 @@ static char sound_beep_doc[] = "Beep(frequency, duration) - a wrapper around the Windows Beep API\n" "\n" "The frequency argument specifies frequency, in hertz, of the sound.\n" -"This parameter must be in the range 37 through 32,767 (0x25 through 0x7FFF).\n" -"The duration argument specifies the number of milli-seconds.\n" -"Note: Under Windows 95 and 98, the arguments are ignored; if the system\n" -"has a sound card, the system default sound is played; else (no sound card)\n" -"the standard system beep.\n"; +"This parameter must be in the range 37 through 32,767.\n" +"The duration argument specifies the number of milliseconds.\n" +"On WinNT and 2000, the platform Beep API is used directly. Else funky\n" +"code doing direct port manipulation is used; it's unknown whether that\n" +"will work on all systems.\n"; static char sound_module_doc[] = "PlaySound(sound, flags) - play a sound\n" @@ -68,20 +70,19 @@ static char sound_module_doc[] = "\n" "Beep(frequency, duration) - Make a beep through the PC speaker.\n"; -PyObject *sound_playsound(PyObject *s, PyObject *args) +PyObject * +sound_playsound(PyObject *s, PyObject *args) { const char *sound; int flags; int length; int ok; - if(!PyArg_ParseTuple(args,"z#i:PlaySound",&sound,&length,&flags)) - { + if(!PyArg_ParseTuple(args,"z#i:PlaySound",&sound,&length,&flags)) { return NULL; } - if(flags&SND_ASYNC && flags &SND_MEMORY) - { + if(flags&SND_ASYNC && flags &SND_MEMORY) { /* Sidestep reference counting headache; unfortunately this also prevent SND_LOOP from memory. */ PyErr_SetString(PyExc_RuntimeError,"Cannot play asynchronously from memory"); @@ -101,22 +102,73 @@ PyObject *sound_playsound(PyObject *s, PyObject *args) return Py_None; } -static PyObject *sound_beep( PyObject *self, PyObject *args ) +enum OSType {Win9X, WinNT2000}; +static enum OSType whichOS; /* set by module init */ + +static PyObject * +sound_beep(PyObject *self, PyObject *args) { int freq; int dur; - BOOL ok; if (!PyArg_ParseTuple(args, "ii:Beep", &freq, &dur)) return NULL; - Py_BEGIN_ALLOW_THREADS - ok = Beep(freq,dur); - Py_END_ALLOW_THREADS - if(!ok) - { - PyErr_SetString(PyExc_RuntimeError,"Failed to beep"); - return NULL; - } + + if (freq < 37 || freq > 32767) { + PyErr_SetString(PyExc_ValueError, + "frequency must be in 37 thru 32767"); + return NULL; + } + + /* On NT and 2000, the SDK Beep() function does the whole job. + * But while Beep() exists before NT, it ignores its arguments and + * plays the system default sound. Sheesh ... + * The Win9X code is mondo bizarre. I (Tim) pieced it together from + * crap all over the web. The original IBM PC used some particular + * pieces of hardware (Intel 8255 and 8254 chips) hardwired to + * particular port addresses and running at particular clock speeds, + * and the poor sound card folks have been forced to emulate that in + * all particulars ever since. But NT and 2000 don't support port + * manipulation, Don't know about WinME; guessing it's like 98. + */ + + if (whichOS == WinNT2000) { + BOOL ok; + Py_BEGIN_ALLOW_THREADS + ok = Beep(freq, dur); + Py_END_ALLOW_THREADS + if (!ok) { + PyErr_SetString(PyExc_RuntimeError,"Failed to beep"); + return NULL; + } + } + else if (whichOS == Win9X) { + int speaker_state; + /* Force timer into oscillator mode via timer control port. */ + _outp(0x43, 0xb6); + /* Compute ratio of ancient hardcoded timer frequency to + * frequency we want. Then feed that ratio (lowest byte + * first) into timer data port. + */ + freq = 1193180 / freq; + _outp(0x42, freq & 0xff); + _outp(0x42, (freq >> 8) & 0xff); + /* Get speaker control state. */ + speaker_state = _inp(0x61); + /* Turn the speaker on (bit 1) + * and drive speaker from timer (bit 0). + */ + _outp(0x61, speaker_state | 0x3); + /* Let it blast in peace for the duration. */ + Py_BEGIN_ALLOW_THREADS + Sleep(dur); + Py_END_ALLOW_THREADS + /* Restore speaker control to original state. */ + _outp(0x61, speaker_state); + } + else { + assert(!"winsound's whichOS has insane value"); + } Py_INCREF(Py_None); return Py_None; } @@ -128,7 +180,8 @@ static struct PyMethodDef sound_methods[] = {NULL, NULL} }; -static void add_define(PyObject *dict, const char *key, long value) +static void +add_define(PyObject *dict, const char *key, long value) { PyObject *k=PyString_FromString(key); PyObject *v=PyLong_FromLong(value); @@ -145,17 +198,28 @@ static void add_define(PyObject *dict, const char *key, long value) DL_EXPORT(void) initwinsound(void) { - PyObject *module=Py_InitModule3("winsound", sound_methods, sound_module_doc); - PyObject *dict=PyModule_GetDict(module); - - ADD_DEFINE(SND_ASYNC); - ADD_DEFINE(SND_NODEFAULT); - ADD_DEFINE(SND_NOSTOP); - ADD_DEFINE(SND_NOWAIT); - ADD_DEFINE(SND_ALIAS); - ADD_DEFINE(SND_FILENAME); - ADD_DEFINE(SND_MEMORY); - ADD_DEFINE(SND_PURGE); - ADD_DEFINE(SND_LOOP); - ADD_DEFINE(SND_APPLICATION); + OSVERSIONINFO version; + + PyObject *module = Py_InitModule3("winsound", + sound_methods, + sound_module_doc); + PyObject *dict = PyModule_GetDict(module); + + ADD_DEFINE(SND_ASYNC); + ADD_DEFINE(SND_NODEFAULT); + ADD_DEFINE(SND_NOSTOP); + ADD_DEFINE(SND_NOWAIT); + ADD_DEFINE(SND_ALIAS); + ADD_DEFINE(SND_FILENAME); + ADD_DEFINE(SND_MEMORY); + ADD_DEFINE(SND_PURGE); + ADD_DEFINE(SND_LOOP); + ADD_DEFINE(SND_APPLICATION); + + version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&version); + whichOS = Win9X; + if (version.dwPlatformId != VER_PLATFORM_WIN32s && + version.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) + whichOS = WinNT2000; } |