xref: /third_party/python/PC/winsound.c (revision 7db96d56)
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
42PyDoc_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]
58module 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]
65winsound.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
72A wrapper around the Windows PlaySound API.
73[clinic start generated code]*/
74
75static PyObject *
76winsound_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 {
98        if (!PyUnicode_Check(sound)) {
99            PyErr_Format(PyExc_TypeError,
100                         "'sound' must be str or None, not '%s'",
101                         Py_TYPE(sound)->tp_name);
102            return NULL;
103        }
104        wsound = PyUnicode_AsWideCharString(sound, NULL);
105        if (wsound == NULL) {
106            return NULL;
107        }
108    }
109
110
111    Py_BEGIN_ALLOW_THREADS
112    ok = PlaySoundW(wsound, NULL, flags);
113    Py_END_ALLOW_THREADS
114    if (view.obj) {
115        PyBuffer_Release(&view);
116    } else if (sound != Py_None) {
117        PyMem_Free(wsound);
118    }
119    if (!ok) {
120        PyErr_SetString(PyExc_RuntimeError, "Failed to play sound");
121        return NULL;
122    }
123    Py_RETURN_NONE;
124}
125
126/*[clinic input]
127winsound.Beep
128
129    frequency: int
130        Frequency of the sound in hertz.
131        Must be in the range 37 through 32,767.
132    duration: int
133        How long the sound should play, in milliseconds.
134
135A wrapper around the Windows Beep API.
136[clinic start generated code]*/
137
138static PyObject *
139winsound_Beep_impl(PyObject *module, int frequency, int duration)
140/*[clinic end generated code: output=f32382e52ee9b2fb input=40e360cfa00a5cf0]*/
141{
142    BOOL ok;
143
144    if (frequency < 37 || frequency > 32767) {
145        PyErr_SetString(PyExc_ValueError,
146                        "frequency must be in 37 thru 32767");
147        return NULL;
148    }
149
150    Py_BEGIN_ALLOW_THREADS
151    ok = Beep(frequency, duration);
152    Py_END_ALLOW_THREADS
153    if (!ok) {
154        PyErr_SetString(PyExc_RuntimeError,"Failed to beep");
155        return NULL;
156    }
157
158    Py_RETURN_NONE;
159}
160
161/*[clinic input]
162winsound.MessageBeep
163
164    type: int(c_default="MB_OK") = MB_OK
165
166Call Windows MessageBeep(x).
167
168x defaults to MB_OK.
169[clinic start generated code]*/
170
171static PyObject *
172winsound_MessageBeep_impl(PyObject *module, int type)
173/*[clinic end generated code: output=120875455121121f input=db185f741ae21401]*/
174{
175    BOOL ok;
176
177    Py_BEGIN_ALLOW_THREADS
178    ok = MessageBeep(type);
179    Py_END_ALLOW_THREADS
180
181    if (!ok) {
182        PyErr_SetExcFromWindowsErr(PyExc_RuntimeError, 0);
183        return NULL;
184    }
185
186    Py_RETURN_NONE;
187}
188
189static struct PyMethodDef sound_methods[] =
190{
191    WINSOUND_PLAYSOUND_METHODDEF
192    WINSOUND_BEEP_METHODDEF
193    WINSOUND_MESSAGEBEEP_METHODDEF
194    {NULL,  NULL}
195};
196
197static void
198add_define(PyObject *dict, const char *key, long value)
199{
200    PyObject *k = PyUnicode_FromString(key);
201    PyObject *v = PyLong_FromLong(value);
202    if (v && k) {
203        PyDict_SetItem(dict, k, v);
204    }
205    Py_XDECREF(k);
206    Py_XDECREF(v);
207}
208
209#define ADD_DEFINE(tok) add_define(dict,#tok,tok)
210
211
212static struct PyModuleDef winsoundmodule = {
213    PyModuleDef_HEAD_INIT,
214    "winsound",
215    sound_module_doc,
216    -1,
217    sound_methods,
218    NULL,
219    NULL,
220    NULL,
221    NULL
222};
223
224PyMODINIT_FUNC
225PyInit_winsound(void)
226{
227    PyObject *dict;
228    PyObject *module = PyModule_Create(&winsoundmodule);
229    if (module == NULL)
230        return NULL;
231    dict = PyModule_GetDict(module);
232
233    ADD_DEFINE(SND_ASYNC);
234    ADD_DEFINE(SND_NODEFAULT);
235    ADD_DEFINE(SND_NOSTOP);
236    ADD_DEFINE(SND_NOWAIT);
237    ADD_DEFINE(SND_ALIAS);
238    ADD_DEFINE(SND_FILENAME);
239    ADD_DEFINE(SND_MEMORY);
240    ADD_DEFINE(SND_PURGE);
241    ADD_DEFINE(SND_LOOP);
242    ADD_DEFINE(SND_APPLICATION);
243
244    ADD_DEFINE(MB_OK);
245    ADD_DEFINE(MB_ICONASTERISK);
246    ADD_DEFINE(MB_ICONEXCLAMATION);
247    ADD_DEFINE(MB_ICONHAND);
248    ADD_DEFINE(MB_ICONQUESTION);
249    return module;
250}
251