Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 25a9ce3

Browse files
committed
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!
1 parent c761fc8 commit 25a9ce3

3 files changed

Lines changed: 113 additions & 43 deletions

File tree

Doc/lib/libwinsound.tex

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@ \section{\module{winsound} ---
1717
\begin{funcdesc}{Beep}{frequency, duration}
1818
Beep the PC's speaker.
1919
The \var{frequency} parameter specifies frequency, in hertz, of the
20-
sound, and must be in the range 37 through 32,767 (\code{0x25}
21-
through \code{0x7fff}). The \var{duration} parameter specifies the
22-
number of milliseconds the sound should last. If the system is not
20+
sound, and must be in the range 37 through 32,767.
21+
The \var{duration} parameter specifies the number of milliseconds the
22+
sound should last. If the system is not
2323
able to beep the speaker, \exception{RuntimeError} is raised.
24-
\strong{Note:} Under Windows 95 and 98, the arguments are ignored;
25-
if the system has a sound card, the system default sound is played
26-
(typically \file{ding.wav}, or whatever is registered as the default
27-
sound via Control Panel -> Sounds); else (no sound card) the
28-
standard system beep.
24+
\strong{Note:} Under Windows 95 and 98, the Windows \cfunction{Beep()}
25+
function exists but is useless (it ignores its arguments). In rhat
26+
case Python simulates it via direct port manipulation (added in version
27+
2.1). It's unknown whether that will work on all systems.
2928
\versionadded{1.6}
3029
\end{funcdesc}
3130

Misc/NEWS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ Windows changes
99

1010
- Build: Subproject _test (effectively) renamed to _testcapi.
1111

12+
- winsound module: Under Win9x, winsound.Beep() now attempts to simulate
13+
what it's supposed to do (and does do under NT and 2000) via direct
14+
port manipulation. It's unknown whether this will work on all systems,
15+
but it does work on my Win98SE system now and was known to be useless on
16+
all Win9x systems before.
17+
18+
1219
What's New in Python 2.1 alpha 2?
1320
=================================
1421

PC/winsound.c

Lines changed: 99 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99

1010
/* Modified by Guido van Rossum */
1111
/* Beep added by Mark Hammond */
12+
/* Win9X Beep and platform identification added by Uncle Timmy */
1213

1314
/* Example:
1415
1516
import winsound
1617
import time
1718
18-
# Play wav file
19+
# Play wav file
1920
winsound.PlaySound('c:/windows/media/Chord.wav', winsound.SND_FILENAME)
2021
2122
# Play sound from control panel settings
@@ -36,6 +37,7 @@
3637

3738
#include <windows.h>
3839
#include <mmsystem.h>
40+
#include <conio.h> /* port functions on Win9x */
3941
#include <Python.h>
4042

4143
static char sound_playsound_doc[] =
@@ -48,11 +50,11 @@ static char sound_beep_doc[] =
4850
"Beep(frequency, duration) - a wrapper around the Windows Beep API\n"
4951
"\n"
5052
"The frequency argument specifies frequency, in hertz, of the sound.\n"
51-
"This parameter must be in the range 37 through 32,767 (0x25 through 0x7FFF).\n"
52-
"The duration argument specifies the number of milli-seconds.\n"
53-
"Note: Under Windows 95 and 98, the arguments are ignored; if the system\n"
54-
"has a sound card, the system default sound is played; else (no sound card)\n"
55-
"the standard system beep.\n";
53+
"This parameter must be in the range 37 through 32,767.\n"
54+
"The duration argument specifies the number of milliseconds.\n"
55+
"On WinNT and 2000, the platform Beep API is used directly. Else funky\n"
56+
"code doing direct port manipulation is used; it's unknown whether that\n"
57+
"will work on all systems.\n";
5658

5759
static char sound_module_doc[] =
5860
"PlaySound(sound, flags) - play a sound\n"
@@ -68,20 +70,19 @@ static char sound_module_doc[] =
6870
"\n"
6971
"Beep(frequency, duration) - Make a beep through the PC speaker.\n";
7072

71-
PyObject *sound_playsound(PyObject *s, PyObject *args)
73+
PyObject *
74+
sound_playsound(PyObject *s, PyObject *args)
7275
{
7376
const char *sound;
7477
int flags;
7578
int length;
7679
int ok;
7780

78-
if(!PyArg_ParseTuple(args,"z#i:PlaySound",&sound,&length,&flags))
79-
{
81+
if(!PyArg_ParseTuple(args,"z#i:PlaySound",&sound,&length,&flags)) {
8082
return NULL;
8183
}
8284

83-
if(flags&SND_ASYNC && flags &SND_MEMORY)
84-
{
85+
if(flags&SND_ASYNC && flags &SND_MEMORY) {
8586
/* Sidestep reference counting headache; unfortunately this also
8687
prevent SND_LOOP from memory. */
8788
PyErr_SetString(PyExc_RuntimeError,"Cannot play asynchronously from memory");
@@ -101,22 +102,73 @@ PyObject *sound_playsound(PyObject *s, PyObject *args)
101102
return Py_None;
102103
}
103104

104-
static PyObject *sound_beep( PyObject *self, PyObject *args )
105+
enum OSType {Win9X, WinNT2000};
106+
static enum OSType whichOS; /* set by module init */
107+
108+
static PyObject *
109+
sound_beep(PyObject *self, PyObject *args)
105110
{
106111
int freq;
107112
int dur;
108-
BOOL ok;
109113

110114
if (!PyArg_ParseTuple(args, "ii:Beep", &freq, &dur))
111115
return NULL;
112-
Py_BEGIN_ALLOW_THREADS
113-
ok = Beep(freq,dur);
114-
Py_END_ALLOW_THREADS
115-
if(!ok)
116-
{
117-
PyErr_SetString(PyExc_RuntimeError,"Failed to beep");
118-
return NULL;
119-
}
116+
117+
if (freq < 37 || freq > 32767) {
118+
PyErr_SetString(PyExc_ValueError,
119+
"frequency must be in 37 thru 32767");
120+
return NULL;
121+
}
122+
123+
/* On NT and 2000, the SDK Beep() function does the whole job.
124+
* But while Beep() exists before NT, it ignores its arguments and
125+
* plays the system default sound. Sheesh ...
126+
* The Win9X code is mondo bizarre. I (Tim) pieced it together from
127+
* crap all over the web. The original IBM PC used some particular
128+
* pieces of hardware (Intel 8255 and 8254 chips) hardwired to
129+
* particular port addresses and running at particular clock speeds,
130+
* and the poor sound card folks have been forced to emulate that in
131+
* all particulars ever since. But NT and 2000 don't support port
132+
* manipulation, Don't know about WinME; guessing it's like 98.
133+
*/
134+
135+
if (whichOS == WinNT2000) {
136+
BOOL ok;
137+
Py_BEGIN_ALLOW_THREADS
138+
ok = Beep(freq, dur);
139+
Py_END_ALLOW_THREADS
140+
if (!ok) {
141+
PyErr_SetString(PyExc_RuntimeError,"Failed to beep");
142+
return NULL;
143+
}
144+
}
145+
else if (whichOS == Win9X) {
146+
int speaker_state;
147+
/* Force timer into oscillator mode via timer control port. */
148+
_outp(0x43, 0xb6);
149+
/* Compute ratio of ancient hardcoded timer frequency to
150+
* frequency we want. Then feed that ratio (lowest byte
151+
* first) into timer data port.
152+
*/
153+
freq = 1193180 / freq;
154+
_outp(0x42, freq & 0xff);
155+
_outp(0x42, (freq >> 8) & 0xff);
156+
/* Get speaker control state. */
157+
speaker_state = _inp(0x61);
158+
/* Turn the speaker on (bit 1)
159+
* and drive speaker from timer (bit 0).
160+
*/
161+
_outp(0x61, speaker_state | 0x3);
162+
/* Let it blast in peace for the duration. */
163+
Py_BEGIN_ALLOW_THREADS
164+
Sleep(dur);
165+
Py_END_ALLOW_THREADS
166+
/* Restore speaker control to original state. */
167+
_outp(0x61, speaker_state);
168+
}
169+
else {
170+
assert(!"winsound's whichOS has insane value");
171+
}
120172
Py_INCREF(Py_None);
121173
return Py_None;
122174
}
@@ -128,7 +180,8 @@ static struct PyMethodDef sound_methods[] =
128180
{NULL, NULL}
129181
};
130182

131-
static void add_define(PyObject *dict, const char *key, long value)
183+
static void
184+
add_define(PyObject *dict, const char *key, long value)
132185
{
133186
PyObject *k=PyString_FromString(key);
134187
PyObject *v=PyLong_FromLong(value);
@@ -145,17 +198,28 @@ static void add_define(PyObject *dict, const char *key, long value)
145198
DL_EXPORT(void)
146199
initwinsound(void)
147200
{
148-
PyObject *module=Py_InitModule3("winsound", sound_methods, sound_module_doc);
149-
PyObject *dict=PyModule_GetDict(module);
150-
151-
ADD_DEFINE(SND_ASYNC);
152-
ADD_DEFINE(SND_NODEFAULT);
153-
ADD_DEFINE(SND_NOSTOP);
154-
ADD_DEFINE(SND_NOWAIT);
155-
ADD_DEFINE(SND_ALIAS);
156-
ADD_DEFINE(SND_FILENAME);
157-
ADD_DEFINE(SND_MEMORY);
158-
ADD_DEFINE(SND_PURGE);
159-
ADD_DEFINE(SND_LOOP);
160-
ADD_DEFINE(SND_APPLICATION);
201+
OSVERSIONINFO version;
202+
203+
PyObject *module = Py_InitModule3("winsound",
204+
sound_methods,
205+
sound_module_doc);
206+
PyObject *dict = PyModule_GetDict(module);
207+
208+
ADD_DEFINE(SND_ASYNC);
209+
ADD_DEFINE(SND_NODEFAULT);
210+
ADD_DEFINE(SND_NOSTOP);
211+
ADD_DEFINE(SND_NOWAIT);
212+
ADD_DEFINE(SND_ALIAS);
213+
ADD_DEFINE(SND_FILENAME);
214+
ADD_DEFINE(SND_MEMORY);
215+
ADD_DEFINE(SND_PURGE);
216+
ADD_DEFINE(SND_LOOP);
217+
ADD_DEFINE(SND_APPLICATION);
218+
219+
version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
220+
GetVersionEx(&version);
221+
whichOS = Win9X;
222+
if (version.dwPlatformId != VER_PLATFORM_WIN32s &&
223+
version.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
224+
whichOS = WinNT2000;
161225
}

0 commit comments

Comments
 (0)