Updated copyright notices
[opus.git] / tools / wave_out.c
1 /* Copyright (c) 2002, John Edwards\r
2 \r
3    Redistribution and use in source and binary forms, with or without\r
4    modification, are permitted provided that the following conditions\r
5    are met:\r
6 \r
7    - Redistributions of source code must retain the above copyright\r
8    notice, this list of conditions and the following disclaimer.\r
9 \r
10    - Redistributions in binary form must reproduce the above copyright\r
11    notice, this list of conditions and the following disclaimer in the\r
12    documentation and/or other materials provided with the distribution.\r
13 \r
14    - Neither the name of the Xiph.org Foundation nor the names of its\r
15    contributors may be used to endorse or promote products derived from\r
16    this software without specific prior written permission.\r
17 \r
18    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
19    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
20    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
21    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\r
22    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
23    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
24    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
25    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
26    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
27    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
28    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
29 */\r
30 \r
31 #ifdef HAVE_CONFIG_H\r
32 # include "config.h"\r
33 #endif\r
34 \r
35 /* Set TABS = 4 */\r
36 /********************************************************************\r
37 \r
38  function: To provide playback of 16 bit PCM wave data in Win32\r
39            environments from decoded compressed files.\r
40 \r
41  ********************************************************************/\r
42 \r
43 #if defined WIN32 || defined _WIN32\r
44 \r
45 #include <string.h>\r
46 #include <errno.h>\r
47 #include "wave_out.h"\r
48 \r
49 #define MAXWAVESIZE     4294967040LU\r
50 #define MAX_WAVEBLOCKS    32\r
51 \r
52 // This is modified for USE_WIN_AUDIO - ONLY 2002-02-27\r
53 \r
54 \r
55 static CRITICAL_SECTION  cs;\r
56 static HWAVEOUT          dev                    = NULL;\r
57 static int               ScheduledBlocks        = 0;\r
58 static int               PlayedWaveHeadersCount = 0;          // free index\r
59 static WAVEHDR*          PlayedWaveHeaders [MAX_WAVEBLOCKS];\r
60 \r
61 static int\r
62 Box ( const char* msg )\r
63 {\r
64         MessageBox ( NULL, msg, " "VERSION_STRING": Error Message . . .", MB_OK | MB_ICONEXCLAMATION );\r
65         return -1;\r
66 }\r
67 \r
68 \r
69 /*\r
70  *  This function registers already played WAVE chunks. Freeing is done by free_memory(),\r
71  */\r
72 \r
73 static void CALLBACK\r
74 wave_callback ( HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )\r
75 {\r
76         if ( uMsg == WOM_DONE ) {\r
77                 EnterCriticalSection ( &cs );\r
78                 PlayedWaveHeaders [PlayedWaveHeadersCount++] = (WAVEHDR*) dwParam1;\r
79                 LeaveCriticalSection ( &cs );\r
80         }\r
81 }\r
82 \r
83 \r
84 static void\r
85 free_memory ( void )\r
86 {\r
87         WAVEHDR*  wh;\r
88         HGLOBAL   hg;\r
89 \r
90         EnterCriticalSection ( &cs );\r
91         wh = PlayedWaveHeaders [--PlayedWaveHeadersCount];\r
92         ScheduledBlocks--;                               // decrease the number of USED blocks\r
93         LeaveCriticalSection ( &cs );\r
94 \r
95         waveOutUnprepareHeader ( dev, wh, sizeof (WAVEHDR) );\r
96 \r
97         hg = GlobalHandle ( wh -> lpData );       // Deallocate the buffer memory\r
98         GlobalUnlock (hg);\r
99         GlobalFree   (hg);\r
100 \r
101         hg = GlobalHandle ( wh );                 // Deallocate the header memory\r
102         GlobalUnlock (hg);\r
103         GlobalFree   (hg);\r
104 }\r
105 \r
106 \r
107 Int\r
108 Set_WIN_Params ( FILE_T   dummyFile ,\r
109                  Ldouble  SampleFreq,\r
110                  Uint     BitsPerSample,\r
111                  Uint     Channels )\r
112 {\r
113         WAVEFORMATEX  outFormat;\r
114         UINT          deviceID = WAVE_MAPPER;\r
115 \r
116         (void) dummyFile;\r
117 \r
118         if ( waveOutGetNumDevs () == 0 )\r
119                 return Box ( "No audio device present." );\r
120 \r
121         outFormat.wFormatTag      = WAVE_FORMAT_PCM;\r
122         outFormat.wBitsPerSample  = BitsPerSample;\r
123         outFormat.nChannels       = Channels;\r
124         outFormat.nSamplesPerSec  = (unsigned long)(SampleFreq + 0.5);\r
125         outFormat.nBlockAlign     = (outFormat.wBitsPerSample + 7) / 8 * outFormat.nChannels;\r
126         outFormat.nAvgBytesPerSec = outFormat.nSamplesPerSec * outFormat.nBlockAlign;\r
127 \r
128         switch ( waveOutOpen ( &dev, deviceID, &outFormat, (DWORD)wave_callback, 0, CALLBACK_FUNCTION ) )\r
129         {\r
130                 case MMSYSERR_ALLOCATED:   return Box ( "Device is already open." );\r
131                 case MMSYSERR_BADDEVICEID: return Box ( "The specified device is out of range." );\r
132                 case MMSYSERR_NODRIVER:    return Box ( "There is no audio driver in this system." );\r
133                 case MMSYSERR_NOMEM:       return Box ( "Unable to allocate sound memory." );\r
134                 case WAVERR_BADFORMAT:     return Box ( "This audio format is not supported." );\r
135                 case WAVERR_SYNC:          return Box ( "The device is synchronous." );\r
136                 default:                   return Box ( "Unknown media error." );\r
137                 case MMSYSERR_NOERROR:     break;\r
138         }\r
139 \r
140         waveOutReset ( dev );\r
141         InitializeCriticalSection ( &cs );\r
142         SetPriorityClass ( GetCurrentProcess (), HIGH_PRIORITY_CLASS );\r
143         return 0;\r
144 }\r
145 \r
146 \r
147 int\r
148 WIN_Play_Samples ( const void* data, size_t len )\r
149 {\r
150         HGLOBAL    hg;\r
151         HGLOBAL    hg2;\r
152         LPWAVEHDR  wh;\r
153         void*      allocptr;\r
154 \r
155         do {\r
156                 while ( PlayedWaveHeadersCount > 0 )                // free used blocks ...\r
157                         free_memory ();\r
158 \r
159                 if ( ScheduledBlocks < sizeof(PlayedWaveHeaders)/sizeof(*PlayedWaveHeaders) ) // wait for a free block ...\r
160                         break;\r
161                 Sleep (26);\r
162         } while (1);\r
163 \r
164         if ( (hg2 = GlobalAlloc ( GMEM_MOVEABLE, len )) == NULL )   // allocate some memory for a copy of the buffer\r
165                 return Box ( "GlobalAlloc failed." );\r
166 \r
167         allocptr = GlobalLock (hg2);\r
168         CopyMemory ( allocptr, data, len );                         // Here we can call any modification output functions we want....\r
169 \r
170         if ( (hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR))) == NULL ) // now make a header and WRITE IT!\r
171                 return -1;\r
172 \r
173         wh                   = GlobalLock (hg);\r
174         wh -> dwBufferLength = len;\r
175         wh -> lpData         = allocptr;\r
176 \r
177         if ( waveOutPrepareHeader ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {\r
178                 GlobalUnlock (hg);\r
179                 GlobalFree   (hg);\r
180                 return -1;\r
181         }\r
182 \r
183         if ( waveOutWrite ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {\r
184                 GlobalUnlock (hg);\r
185                 GlobalFree   (hg);\r
186                 return -1;\r
187         }\r
188 \r
189         EnterCriticalSection ( &cs );\r
190         ScheduledBlocks++;\r
191         LeaveCriticalSection ( &cs );\r
192 \r
193         return len;\r
194 }\r
195 \r
196 \r
197 int\r
198 WIN_Audio_close ( void )\r
199 {\r
200         if ( dev != NULL ) {\r
201 \r
202                 while ( ScheduledBlocks > 0 ) {\r
203                         Sleep (ScheduledBlocks);\r
204                         while ( PlayedWaveHeadersCount > 0 )         // free used blocks ...\r
205                                 free_memory ();\r
206                 }\r
207 \r
208                 waveOutReset (dev);      // reset the device\r
209                 waveOutClose (dev);      // close the device\r
210                 dev = NULL;\r
211         }\r
212 \r
213         DeleteCriticalSection ( &cs );\r
214         ScheduledBlocks = 0;\r
215         return 0;\r
216 }\r
217 \r
218 #endif\r
219 \r
220 /* end of wave_out.c */\r