Kaydet (Commit) 25a9ce37 authored tarafından Tim Peters's avatar Tim Peters

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!
üst c761fc87
...@@ -17,15 +17,14 @@ two functions and several constants. ...@@ -17,15 +17,14 @@ two functions and several constants.
\begin{funcdesc}{Beep}{frequency, duration} \begin{funcdesc}{Beep}{frequency, duration}
Beep the PC's speaker. Beep the PC's speaker.
The \var{frequency} parameter specifies frequency, in hertz, of the The \var{frequency} parameter specifies frequency, in hertz, of the
sound, and must be in the range 37 through 32,767 (\code{0x25} sound, and must be in the range 37 through 32,767.
through \code{0x7fff}). The \var{duration} parameter specifies the The \var{duration} parameter specifies the number of milliseconds the
number of milliseconds the sound should last. If the system is not sound should last. If the system is not
able to beep the speaker, \exception{RuntimeError} is raised. able to beep the speaker, \exception{RuntimeError} is raised.
\strong{Note:} Under Windows 95 and 98, the arguments are ignored; \strong{Note:} Under Windows 95 and 98, the Windows \cfunction{Beep()}
if the system has a sound card, the system default sound is played function exists but is useless (it ignores its arguments). In rhat
(typically \file{ding.wav}, or whatever is registered as the default case Python simulates it via direct port manipulation (added in version
sound via Control Panel -> Sounds); else (no sound card) the 2.1). It's unknown whether that will work on all systems.
standard system beep.
\versionadded{1.6} \versionadded{1.6}
\end{funcdesc} \end{funcdesc}
......
...@@ -9,6 +9,13 @@ Windows changes ...@@ -9,6 +9,13 @@ Windows changes
- Build: Subproject _test (effectively) renamed to _testcapi. - Build: Subproject _test (effectively) renamed to _testcapi.
- winsound module: Under Win9x, winsound.Beep() now attempts to simulate
what it's supposed to do (and does do under NT and 2000) via direct
port manipulation. It's unknown whether this will work on all systems,
but it does work on my Win98SE system now and was known to be useless on
all Win9x systems before.
What's New in Python 2.1 alpha 2? What's New in Python 2.1 alpha 2?
================================= =================================
......
...@@ -9,13 +9,14 @@ ...@@ -9,13 +9,14 @@
/* Modified by Guido van Rossum */ /* Modified by Guido van Rossum */
/* Beep added by Mark Hammond */ /* Beep added by Mark Hammond */
/* Win9X Beep and platform identification added by Uncle Timmy */
/* Example: /* Example:
import winsound import winsound
import time import time
# Play wav file # Play wav file
winsound.PlaySound('c:/windows/media/Chord.wav', winsound.SND_FILENAME) winsound.PlaySound('c:/windows/media/Chord.wav', winsound.SND_FILENAME)
# Play sound from control panel settings # Play sound from control panel settings
...@@ -36,6 +37,7 @@ ...@@ -36,6 +37,7 @@
#include <windows.h> #include <windows.h>
#include <mmsystem.h> #include <mmsystem.h>
#include <conio.h> /* port functions on Win9x */
#include <Python.h> #include <Python.h>
static char sound_playsound_doc[] = static char sound_playsound_doc[] =
...@@ -48,11 +50,11 @@ static char sound_beep_doc[] = ...@@ -48,11 +50,11 @@ static char sound_beep_doc[] =
"Beep(frequency, duration) - a wrapper around the Windows Beep API\n" "Beep(frequency, duration) - a wrapper around the Windows Beep API\n"
"\n" "\n"
"The frequency argument specifies frequency, in hertz, of the sound.\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" "This parameter must be in the range 37 through 32,767.\n"
"The duration argument specifies the number of milli-seconds.\n" "The duration argument specifies the number of milliseconds.\n"
"Note: Under Windows 95 and 98, the arguments are ignored; if the system\n" "On WinNT and 2000, the platform Beep API is used directly. Else funky\n"
"has a sound card, the system default sound is played; else (no sound card)\n" "code doing direct port manipulation is used; it's unknown whether that\n"
"the standard system beep.\n"; "will work on all systems.\n";
static char sound_module_doc[] = static char sound_module_doc[] =
"PlaySound(sound, flags) - play a sound\n" "PlaySound(sound, flags) - play a sound\n"
...@@ -68,20 +70,19 @@ static char sound_module_doc[] = ...@@ -68,20 +70,19 @@ static char sound_module_doc[] =
"\n" "\n"
"Beep(frequency, duration) - Make a beep through the PC speaker.\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; const char *sound;
int flags; int flags;
int length; int length;
int ok; int ok;
if(!PyArg_ParseTuple(args,"z#i:PlaySound",&sound,&length,&flags)) if(!PyArg_ParseTuple(args,"z#i:PlaySound",&sound,&length,&flags)) {
{
return NULL; return NULL;
} }
if(flags&SND_ASYNC && flags &SND_MEMORY) if(flags&SND_ASYNC && flags &SND_MEMORY) {
{
/* Sidestep reference counting headache; unfortunately this also /* Sidestep reference counting headache; unfortunately this also
prevent SND_LOOP from memory. */ prevent SND_LOOP from memory. */
PyErr_SetString(PyExc_RuntimeError,"Cannot play asynchronously from memory"); PyErr_SetString(PyExc_RuntimeError,"Cannot play asynchronously from memory");
...@@ -101,22 +102,73 @@ PyObject *sound_playsound(PyObject *s, PyObject *args) ...@@ -101,22 +102,73 @@ PyObject *sound_playsound(PyObject *s, PyObject *args)
return Py_None; 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 freq;
int dur; int dur;
BOOL ok;
if (!PyArg_ParseTuple(args, "ii:Beep", &freq, &dur)) if (!PyArg_ParseTuple(args, "ii:Beep", &freq, &dur))
return NULL; return NULL;
Py_BEGIN_ALLOW_THREADS
ok = Beep(freq,dur); if (freq < 37 || freq > 32767) {
Py_END_ALLOW_THREADS PyErr_SetString(PyExc_ValueError,
if(!ok) "frequency must be in 37 thru 32767");
{ return NULL;
PyErr_SetString(PyExc_RuntimeError,"Failed to beep"); }
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); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -128,7 +180,8 @@ static struct PyMethodDef sound_methods[] = ...@@ -128,7 +180,8 @@ static struct PyMethodDef sound_methods[] =
{NULL, NULL} {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 *k=PyString_FromString(key);
PyObject *v=PyLong_FromLong(value); PyObject *v=PyLong_FromLong(value);
...@@ -145,17 +198,28 @@ static void add_define(PyObject *dict, const char *key, long value) ...@@ -145,17 +198,28 @@ static void add_define(PyObject *dict, const char *key, long value)
DL_EXPORT(void) DL_EXPORT(void)
initwinsound(void) initwinsound(void)
{ {
PyObject *module=Py_InitModule3("winsound", sound_methods, sound_module_doc); OSVERSIONINFO version;
PyObject *dict=PyModule_GetDict(module);
PyObject *module = Py_InitModule3("winsound",
ADD_DEFINE(SND_ASYNC); sound_methods,
ADD_DEFINE(SND_NODEFAULT); sound_module_doc);
ADD_DEFINE(SND_NOSTOP); PyObject *dict = PyModule_GetDict(module);
ADD_DEFINE(SND_NOWAIT);
ADD_DEFINE(SND_ALIAS); ADD_DEFINE(SND_ASYNC);
ADD_DEFINE(SND_FILENAME); ADD_DEFINE(SND_NODEFAULT);
ADD_DEFINE(SND_MEMORY); ADD_DEFINE(SND_NOSTOP);
ADD_DEFINE(SND_PURGE); ADD_DEFINE(SND_NOWAIT);
ADD_DEFINE(SND_LOOP); ADD_DEFINE(SND_ALIAS);
ADD_DEFINE(SND_APPLICATION); 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;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment