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
3637
3738#include <windows.h>
3839#include <mmsystem.h>
40+ #include <conio.h> /* port functions on Win9x */
3941#include <Python.h>
4042
4143static 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
5759static 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)
145198DL_EXPORT (void )
146199initwinsound (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