summaryrefslogtreecommitdiff
path: root/PC/winsound.c
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-02-19 07:06:36 +0000
committerTim Peters <tim.peters@gmail.com>2001-02-19 07:06:36 +0000
commit25a9ce371c1b43094f5e108c3fff834833c68342 (patch)
tree653eb080911882bd491c39832f9e17c4ccdbcba2 /PC/winsound.c
parentc761fc87d294f223b124239544b1cf2479ac5e18 (diff)
downloadcpython-git-25a9ce371c1b43094f5e108c3fff834833c68342.tar.gz
Take a tour of hell's seedier neighborhoods to try to make winsound.Beep()
do something non-useless on Win9X boxes. WinME unknown to me. Someone with NT/2000 make sure it still works there!
Diffstat (limited to 'PC/winsound.c')
-rw-r--r--PC/winsound.c134
1 files changed, 99 insertions, 35 deletions
diff --git a/PC/winsound.c b/PC/winsound.c
index bc96387a6b..77572abac2 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;
}