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