winsound.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /* Author: Toby Dickenson <htrd90@zepler.org>
  2. *
  3. * Copyright (c) 1999 Toby Dickenson
  4. *
  5. * Permission to use this software in any way is granted without
  6. * fee, provided that the copyright notice above appears in all
  7. * copies. This software is provided "as is" without any warranty.
  8. */
  9. /* Modified by Guido van Rossum */
  10. /* Beep added by Mark Hammond */
  11. /* Win9X Beep and platform identification added by Uncle Timmy */
  12. /* Example:
  13. import winsound
  14. import time
  15. # Play wav file
  16. winsound.PlaySound('c:/windows/media/Chord.wav', winsound.SND_FILENAME)
  17. # Play sound from control panel settings
  18. winsound.PlaySound('SystemQuestion', winsound.SND_ALIAS)
  19. # Play wav file from memory
  20. data=open('c:/windows/media/Chimes.wav',"rb").read()
  21. winsound.PlaySound(data, winsound.SND_MEMORY)
  22. # Start playing the first bit of wav file asynchronously
  23. winsound.PlaySound('c:/windows/media/Chord.wav',
  24. winsound.SND_FILENAME|winsound.SND_ASYNC)
  25. # But don't let it go for too long...
  26. time.sleep(0.1)
  27. # ...Before stopping it
  28. winsound.PlaySound(None, 0)
  29. */
  30. #include <Python.h>
  31. #include <windows.h>
  32. #include <mmsystem.h>
  33. PyDoc_STRVAR(sound_module_doc,
  34. "PlaySound(sound, flags) - play a sound\n"
  35. "SND_FILENAME - sound is a wav file name\n"
  36. "SND_ALIAS - sound is a registry sound association name\n"
  37. "SND_LOOP - Play the sound repeatedly; must also specify SND_ASYNC\n"
  38. "SND_MEMORY - sound is a memory image of a wav file\n"
  39. "SND_PURGE - stop all instances of the specified sound\n"
  40. "SND_ASYNC - PlaySound returns immediately\n"
  41. "SND_NODEFAULT - Do not play a default beep if the sound can not be found\n"
  42. "SND_NOSTOP - Do not interrupt any sounds currently playing\n" // Raising RuntimeError if needed
  43. "SND_NOWAIT - Return immediately if the sound driver is busy\n" // Without any errors
  44. "\n"
  45. "Beep(frequency, duration) - Make a beep through the PC speaker.\n"
  46. "MessageBeep(type) - Call Windows MessageBeep.");
  47. /*[clinic input]
  48. module winsound
  49. [clinic start generated code]*/
  50. /*[clinic end generated code: output=da39a3ee5e6b4b0d input=a18401142d97b8d5]*/
  51. #include "clinic/winsound.c.h"
  52. /*[clinic input]
  53. winsound.PlaySound
  54. sound: object
  55. The sound to play; a filename, data, or None.
  56. flags: int
  57. Flag values, ored together. See module documentation.
  58. A wrapper around the Windows PlaySound API.
  59. [clinic start generated code]*/
  60. static PyObject *
  61. winsound_PlaySound_impl(PyObject *module, PyObject *sound, int flags)
  62. /*[clinic end generated code: output=49a0fd16a372ebeb input=c63e1f2d848da2f2]*/
  63. {
  64. int ok;
  65. wchar_t *wsound;
  66. Py_buffer view = {NULL, NULL};
  67. if (sound == Py_None) {
  68. wsound = NULL;
  69. } else if (flags & SND_MEMORY) {
  70. if (flags & SND_ASYNC) {
  71. /* Sidestep reference counting headache; unfortunately this also
  72. prevent SND_LOOP from memory. */
  73. PyErr_SetString(PyExc_RuntimeError,
  74. "Cannot play asynchronously from memory");
  75. return NULL;
  76. }
  77. if (PyObject_GetBuffer(sound, &view, PyBUF_SIMPLE) < 0) {
  78. return NULL;
  79. }
  80. wsound = (wchar_t *)view.buf;
  81. } else if (PyBytes_Check(sound)) {
  82. PyErr_Format(PyExc_TypeError,
  83. "'sound' must be str, os.PathLike, or None, not '%s'",
  84. Py_TYPE(sound)->tp_name);
  85. return NULL;
  86. } else {
  87. PyObject *obj = PyOS_FSPath(sound);
  88. // Either <obj> is unicode/bytes/NULL, or a helpful message
  89. // has been surfaced to the user about how they gave a non-path.
  90. if (obj == NULL) return NULL;
  91. if (PyBytes_Check(obj)) {
  92. PyErr_Format(PyExc_TypeError,
  93. "'sound' must resolve to str, not bytes");
  94. Py_DECREF(obj);
  95. return NULL;
  96. }
  97. wsound = PyUnicode_AsWideCharString(obj, NULL);
  98. Py_DECREF(obj);
  99. if (wsound == NULL) return NULL;
  100. }
  101. Py_BEGIN_ALLOW_THREADS
  102. ok = PlaySoundW(wsound, NULL, flags);
  103. Py_END_ALLOW_THREADS
  104. if (view.obj) {
  105. PyBuffer_Release(&view);
  106. } else if (sound != Py_None) {
  107. PyMem_Free(wsound);
  108. }
  109. if (!ok) {
  110. PyErr_SetString(PyExc_RuntimeError, "Failed to play sound");
  111. return NULL;
  112. }
  113. Py_RETURN_NONE;
  114. }
  115. /*[clinic input]
  116. winsound.Beep
  117. frequency: int
  118. Frequency of the sound in hertz.
  119. Must be in the range 37 through 32,767.
  120. duration: int
  121. How long the sound should play, in milliseconds.
  122. A wrapper around the Windows Beep API.
  123. [clinic start generated code]*/
  124. static PyObject *
  125. winsound_Beep_impl(PyObject *module, int frequency, int duration)
  126. /*[clinic end generated code: output=f32382e52ee9b2fb input=40e360cfa00a5cf0]*/
  127. {
  128. BOOL ok;
  129. if (frequency < 37 || frequency > 32767) {
  130. PyErr_SetString(PyExc_ValueError,
  131. "frequency must be in 37 thru 32767");
  132. return NULL;
  133. }
  134. Py_BEGIN_ALLOW_THREADS
  135. ok = Beep(frequency, duration);
  136. Py_END_ALLOW_THREADS
  137. if (!ok) {
  138. PyErr_SetString(PyExc_RuntimeError,"Failed to beep");
  139. return NULL;
  140. }
  141. Py_RETURN_NONE;
  142. }
  143. /*[clinic input]
  144. winsound.MessageBeep
  145. type: int(c_default="MB_OK") = MB_OK
  146. Call Windows MessageBeep(x).
  147. x defaults to MB_OK.
  148. [clinic start generated code]*/
  149. static PyObject *
  150. winsound_MessageBeep_impl(PyObject *module, int type)
  151. /*[clinic end generated code: output=120875455121121f input=db185f741ae21401]*/
  152. {
  153. BOOL ok;
  154. Py_BEGIN_ALLOW_THREADS
  155. ok = MessageBeep(type);
  156. Py_END_ALLOW_THREADS
  157. if (!ok) {
  158. PyErr_SetExcFromWindowsErr(PyExc_RuntimeError, 0);
  159. return NULL;
  160. }
  161. Py_RETURN_NONE;
  162. }
  163. static struct PyMethodDef sound_methods[] =
  164. {
  165. WINSOUND_PLAYSOUND_METHODDEF
  166. WINSOUND_BEEP_METHODDEF
  167. WINSOUND_MESSAGEBEEP_METHODDEF
  168. {NULL, NULL}
  169. };
  170. #define ADD_DEFINE(CONST) do { \
  171. if (PyModule_AddIntConstant(module, #CONST, CONST) < 0) { \
  172. return -1; \
  173. } \
  174. } while (0)
  175. static int
  176. exec_module(PyObject *module)
  177. {
  178. ADD_DEFINE(SND_ASYNC);
  179. ADD_DEFINE(SND_NODEFAULT);
  180. ADD_DEFINE(SND_NOSTOP);
  181. ADD_DEFINE(SND_NOWAIT);
  182. ADD_DEFINE(SND_ALIAS);
  183. ADD_DEFINE(SND_FILENAME);
  184. ADD_DEFINE(SND_MEMORY);
  185. ADD_DEFINE(SND_PURGE);
  186. ADD_DEFINE(SND_LOOP);
  187. ADD_DEFINE(SND_APPLICATION);
  188. ADD_DEFINE(MB_OK);
  189. ADD_DEFINE(MB_ICONASTERISK);
  190. ADD_DEFINE(MB_ICONEXCLAMATION);
  191. ADD_DEFINE(MB_ICONHAND);
  192. ADD_DEFINE(MB_ICONQUESTION);
  193. #undef ADD_DEFINE
  194. return 0;
  195. }
  196. static PyModuleDef_Slot sound_slots[] = {
  197. {Py_mod_exec, exec_module},
  198. {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
  199. {0, NULL}
  200. };
  201. static struct PyModuleDef winsoundmodule = {
  202. .m_base = PyModuleDef_HEAD_INIT,
  203. .m_name = "winsound",
  204. .m_doc = sound_module_doc,
  205. .m_methods = sound_methods,
  206. .m_slots = sound_slots,
  207. };
  208. PyMODINIT_FUNC
  209. PyInit_winsound(void)
  210. {
  211. return PyModuleDef_Init(&winsoundmodule);
  212. }