[Python-checkins] CVS: python/dist/src/PC winsound.c,1.4,1.5

Tim Peters tim_one@users.sourceforge.net
Sun, 18 Feb 2001 23:06:38 -0800


Update of /cvsroot/python/python/dist/src/PC
In directory usw-pr-cvs1:/tmp/cvs-serv29022/python/dist/src/PC

Modified Files:
	winsound.c 
Log Message:
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!


Index: winsound.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/PC/winsound.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -r1.4 -r1.5
*** winsound.c	2001/01/25 20:40:28	1.4
--- winsound.c	2001/02/19 07:06:36	1.5
***************
*** 10,13 ****
--- 10,14 ----
  /* Modified by Guido van Rossum */
  /* Beep added by Mark Hammond */
+ /* Win9X Beep and platform identification added by Uncle Timmy */
  
  /* Example:
***************
*** 16,20 ****
     import time
  
!    # Play wav file 
     winsound.PlaySound('c:/windows/media/Chord.wav', winsound.SND_FILENAME)
  
--- 17,21 ----
     import time
  
!    # Play wav file
     winsound.PlaySound('c:/windows/media/Chord.wav', winsound.SND_FILENAME)
  
***************
*** 37,40 ****
--- 38,42 ----
  #include <windows.h>
  #include <mmsystem.h>
+ #include <conio.h>	/* port functions on Win9x */
  #include <Python.h>
  
***************
*** 49,57 ****
  "\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";
  
  static char sound_module_doc[] =
--- 51,59 ----
  "\n"
  "The frequency argument specifies frequency, in hertz, of the sound.\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[] =
***************
*** 69,73 ****
  "Beep(frequency, duration) - Make a beep through the PC speaker.\n";
  
! PyObject *sound_playsound(PyObject *s, PyObject *args)
  {
      const char *sound;
--- 71,76 ----
  "Beep(frequency, duration) - Make a beep through the PC speaker.\n";
  
! PyObject *
! sound_playsound(PyObject *s, PyObject *args)
  {
      const char *sound;
***************
*** 76,86 ****
      int ok;
  
!     if(!PyArg_ParseTuple(args,"z#i:PlaySound",&sound,&length,&flags))
!     {
          return NULL;
      }
  
!     if(flags&SND_ASYNC && flags &SND_MEMORY)
!     {
  	/* Sidestep reference counting headache; unfortunately this also
  	   prevent SND_LOOP from memory. */
--- 79,87 ----
      int ok;
  
!     if(!PyArg_ParseTuple(args,"z#i:PlaySound",&sound,&length,&flags)) {
          return NULL;
      }
  
!     if(flags&SND_ASYNC && flags &SND_MEMORY) {
  	/* Sidestep reference counting headache; unfortunately this also
  	   prevent SND_LOOP from memory. */
***************
*** 101,121 ****
      return Py_None;
  }
  
! 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;
!     }
  	Py_INCREF(Py_None);
  	return Py_None;
--- 102,173 ----
      return Py_None;
  }
+ 
+ enum OSType {Win9X, WinNT2000};
+ static enum OSType whichOS;	/* set by module init */
  
! static PyObject *
! sound_beep(PyObject *self, PyObject *args)
  {
  	int freq;
  	int dur;
  
  	if (!PyArg_ParseTuple(args, "ii:Beep", &freq,  &dur))
  		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;
***************
*** 129,133 ****
  };
  
! static void add_define(PyObject *dict, const char *key, long value)
  {
      PyObject *k=PyString_FromString(key);
--- 181,186 ----
  };
  
! static void
! add_define(PyObject *dict, const char *key, long value)
  {
      PyObject *k=PyString_FromString(key);
***************
*** 146,161 ****
  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);
  }
--- 199,225 ----
  initwinsound(void)
  {
! 	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;
  }