-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfileio_winaudio.h
executable file
·373 lines (290 loc) · 12.6 KB
/
fileio_winaudio.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
#define MAX_BUFFERS_WAVOUT 40
#define MAX_BUFFERS_WAVIN 400
static CRITICAL_SECTION cs;
static bool cs_init = false;
static HWAVEOUT dev = NULL;
static int ScheduledBlocks = 0;
static int PlayedWaveHeadersCount = 0; // free index
static WAVEHDR* PlayedWaveHeaders [MAX_BUFFERS_WAVOUT];
/* Das ganze sollte auf einen festen Memorypool umgestellt werden, der nicht dauernd alloziert und dealloziert wird */
static int
Box ( const char* msg )
{
MessageBox ( NULL, msg, "Error Message . . .", MB_OK | MB_ICONEXCLAMATION );
return -1;
}
static int
PrintError ( const char* funcname, MMRESULT res )
{
char msg [256];
switch ( res ) {
case MMSYSERR_ALLOCATED: sprintf ( msg, "%s failed:\nresource already allocated (device already open)\n" , funcname ); break;
case MMSYSERR_INVALPARAM: sprintf ( msg, "%s failed:\ninvalid Params\n" , funcname ); break;
case MMSYSERR_BADDEVICEID: sprintf ( msg, "%s failed:\ndevice identifier out of range\n" , funcname ); break;
case MMSYSERR_NODRIVER: sprintf ( msg, "%s failed:\nno device driver present (no audio driver)\n" , funcname ); break;
case MMSYSERR_NOMEM: sprintf ( msg, "%s failed:\nunable to allocate or lock memory (for audio)\n" , funcname ); break;
case WAVERR_BADFORMAT: sprintf ( msg, "%s failed:\nattempted to open with an unsupported waveform-audio format\n", funcname ); break;
case WAVERR_SYNC: sprintf ( msg, "%s failed:\ndevice is synchronous but waveOutOpen was\n" , funcname ); break;
default: sprintf ( msg, "%s failed:\nunknown error code: 0x%02X\n" , funcname, res ); break;
case MMSYSERR_NOERROR: return 0;
}
return Box ( msg );
}
/*
* This function registers already played WAVE chunks. Freeing is done by wave_free_memory (),
*/
static void CALLBACK
wave_callback ( HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
{
if ( uMsg == WOM_DONE ) {
EnterCriticalSection ( &cs );
PlayedWaveHeaders [PlayedWaveHeadersCount++] = (WAVEHDR*) dwParam1;
LeaveCriticalSection ( &cs );
}
}
static void
wave_free_memory ( void )
{
WAVEHDR* wh;
HGLOBAL hg;
EnterCriticalSection ( &cs );
wh = PlayedWaveHeaders [--PlayedWaveHeadersCount];
ScheduledBlocks--; // decrease the number of USED blocks
LeaveCriticalSection ( &cs );
waveOutUnprepareHeader ( dev, wh, sizeof (WAVEHDR) );
hg = GlobalHandle ( wh -> lpData ); // Deallocate the buffer memory
GlobalUnlock (hg);
GlobalFree (hg);
hg = GlobalHandle ( wh ); // Deallocate the header memory
GlobalUnlock (hg);
GlobalFree (hg);
}
static int
WindowsAudio_SetupInitOutput ( unsigned int deviceno,
long double SampleFreq,
unsigned int BitsPerSample,
unsigned int Channels )
{
WAVEFORMATEX outFormat;
UINT deviceID; // = WAVE_MAPPER;
UINT devices;
MMRESULT r;
if ( (devices = waveOutGetNumDevs ()) == 0 )
return Box ( "No audio device present." );
deviceID = deviceno < devices ? deviceno : WAVE_MAPPER;
outFormat.wFormatTag = WAVE_FORMAT_PCM;
outFormat.wBitsPerSample = BitsPerSample;
outFormat.nChannels = Channels;
outFormat.nSamplesPerSec = (unsigned long)(SampleFreq + 0.5);
outFormat.nBlockAlign = (outFormat.wBitsPerSample + 7) / 8 * outFormat.nChannels;
outFormat.nAvgBytesPerSec = outFormat.nSamplesPerSec * outFormat.nBlockAlign;
outFormat.cbSize = 0;
r = waveOutOpen ( &dev, deviceID, &outFormat, (DWORD)wave_callback, 0, CALLBACK_FUNCTION );
if ( r != MMSYSERR_NOERROR )
return PrintError ( "waveOutOpen", r );
waveOutReset ( dev );
InitializeCriticalSection ( &cs );
cs_init = true;
// SetPriority ( 99 );
return 0;
}
static size_t
WindowsAudio_play ( const void* data, size_t len )
{
HGLOBAL hg;
HGLOBAL hg2;
LPWAVEHDR wh;
void* allocptr;
do {
while ( PlayedWaveHeadersCount > 0 ) // free used blocks ...
wave_free_memory ();
if ( ScheduledBlocks < sizeof(PlayedWaveHeaders)/sizeof(*PlayedWaveHeaders) ) // wait for a free block ...
break;
Sleep (26);
} while (1);
if ( (hg2 = GlobalAlloc ( GMEM_MOVEABLE, len )) == NULL ) // allocate some memory for a copy of the buffer
return Box ( "GlobalAlloc failed." );
allocptr = GlobalLock (hg2);
CopyMemory ( allocptr, data, len ); // Here we can call any modification output functions we want....
if ( (hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR))) == NULL ) // now make a header and WRITE IT!
return -1;
wh = GlobalLock (hg);
wh -> dwBufferLength = len;
wh -> lpData = allocptr;
if ( waveOutPrepareHeader ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {
GlobalUnlock (hg);
GlobalFree (hg);
return -1;
}
if ( waveOutWrite ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {
GlobalUnlock (hg);
GlobalFree (hg);
return -1;
}
EnterCriticalSection ( &cs );
ScheduledBlocks++;
LeaveCriticalSection ( &cs );
return len;
}
static int
WindowsAudio_close ( void )
{
if ( dev != NULL ) {
while ( ScheduledBlocks > 0 ) {
Sleep (ScheduledBlocks);
while ( PlayedWaveHeadersCount > 0 ) // free used blocks ...
wave_free_memory ();
}
waveOutReset (dev); // reset the device
waveOutClose (dev); // close the device
dev = NULL;
}
if ( cs_init == true ) {
cs_init = false;
DeleteCriticalSection ( &cs );
}
ScheduledBlocks = 0;
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
/*
This code is initially from a different source and works a little bit different.
It contains recording and playback code. In the final version record and playback should work
very similar, so a little bit more work must be done.
Strategies I prefer:
- play: playback of all data
- record: program works until the whole request buffer is filled, no more and not less
*/
typedef struct {
int active;
char* data;
size_t datalen;
WAVEHDR hdr;
} oblk_t;
static HWAVEIN Input_WAVHandle;
static HWAVEOUT Output_WAVHandle;
static size_t BufferBytes;
static WAVEHDR whi [MAX_BUFFERS_WAVIN];
static char* data [MAX_BUFFERS_WAVIN];
static oblk_t array [MAX_BUFFERS_WAVIN];
static unsigned int NextInputIndex;
static unsigned int NextOutputIndex;
//////////////////////////////////////////////////////////////////////////////////////////////////////
static int
WindowsAudio_SetupInitInput ( unsigned int deviceno,
long double SampleFreq,
unsigned int BitsPerSample,
unsigned int Channels )
{
WAVEFORMATEX inFormat;
UINT deviceID;
UINT devices;
MMRESULT r;
UINT i;
if ( (devices = waveInGetNumDevs ()) == 0 )
return Box ( "No audio device present." );
deviceID = deviceno < devices ? deviceno : WAVE_MAPPER;
inFormat.wFormatTag = WAVE_FORMAT_PCM;
inFormat.wBitsPerSample = BitsPerSample;
inFormat.nChannels = Channels;
inFormat.nSamplesPerSec = (unsigned long)(SampleFreq + 0.5);
inFormat.nBlockAlign = (inFormat.wBitsPerSample + 7) / 8 * inFormat.nChannels;
inFormat.nAvgBytesPerSec = inFormat.nSamplesPerSec * inFormat.nBlockAlign;
inFormat.cbSize = 0;
r = waveInOpen ( &Input_WAVHandle, deviceID, &inFormat, 0, 0, CALLBACK_EVENT );
if ( r != MMSYSERR_NOERROR )
return PrintError ( "waveInOpen", r );
BufferBytes = 44100 /*SampleCount*/ * Channels * ((BitsPerSample + 7) / 8);
for ( i = 0; i < MAX_BUFFERS_WAVIN; i++ ) {
whi [i].lpData = data [i] = malloc (BufferBytes);
whi [i].dwBufferLength = BufferBytes;
whi [i].dwFlags = 0;
whi [i].dwLoops = 0;
r = waveInPrepareHeader ( Input_WAVHandle, whi + i, sizeof (*whi) ); if ( r != MMSYSERR_NOERROR ) return PrintError ( "waveInPrepareHeader", r );
r = waveInAddBuffer ( Input_WAVHandle, whi + i, sizeof (*whi) ); if ( r != MMSYSERR_NOERROR ) return PrintError ( "waveInAddBuffer" , r );
}
NextInputIndex = 0;
waveInStart (Input_WAVHandle);
return 0;
}
static size_t
WindowsAudio_record ( void* DataPtr, size_t Bytes_to_Write ) // !!!!!!!!!!!!!!!!!!!!! Bytes_to_Write currently unused, danger !!!!!!!!!!!!!
{
MMRESULT r;
size_t Bytes;
if ( whi [NextInputIndex].dwFlags & WHDR_DONE ) {
Bytes = whi [NextInputIndex].dwBytesRecorded;
memcpy ( DataPtr, data [NextInputIndex], Bytes );
r = waveInUnprepareHeader ( Input_WAVHandle, whi + NextInputIndex, sizeof (*whi) ); if ( r != MMSYSERR_NOERROR ) return PrintError ( "waveInUnprepareHeader", r );
whi [NextInputIndex].lpData = data [NextInputIndex];
whi [NextInputIndex].dwBufferLength = BufferBytes;
whi [NextInputIndex].dwFlags = 0;
whi [NextInputIndex].dwLoops = 0;
r = waveInPrepareHeader ( Input_WAVHandle, whi + NextInputIndex, sizeof (*whi) ); if ( r != MMSYSERR_NOERROR ) return PrintError ( "waveInPrepareHeader", r );
r = waveInAddBuffer ( Input_WAVHandle, whi + NextInputIndex, sizeof (*whi) ); if ( r != MMSYSERR_NOERROR ) return PrintError ( "waveInAddBuffer" , r );
NextInputIndex = (NextInputIndex + 1) % MAX_BUFFERS_WAVIN;
return Bytes;
}
return 0;
}
static int
WindowsAudio_closeInput ( void )
{
waveInReset ( Input_WAVHandle );
waveInClose ( Input_WAVHandle );
Input_WAVHandle = NULL;
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
int
init_out ( const int SampleCount,
const int SampleFreq,
const int Channels,
const int BitsPerSample )
{
WAVEFORMATEX pwf;
MMRESULT r;
int i;
pwf.wFormatTag = WAVE_FORMAT_PCM;
pwf.nChannels = Channels;
pwf.nSamplesPerSec = SampleFreq;
pwf.nAvgBytesPerSec = SampleFreq * Channels * ((BitsPerSample + 7) / 8);
pwf.nBlockAlign = Channels * ((BitsPerSample + 7) / 8);
pwf.wBitsPerSample = BitsPerSample;
pwf.cbSize = 0;
r = waveOutOpen ( &Output_WAVHandle, WAVE_MAPPER, &pwf, 0, 0, CALLBACK_EVENT );
if ( r != MMSYSERR_NOERROR )
return PrintError ( "waveOutOpen", r );
BufferBytes = SampleCount * Channels * ((BitsPerSample + 7) / 8);
for ( i = 0; i < MAX_BUFFERS_WAVIN; i++ ) {
array [i].active = 0;
array [i].data = malloc (BufferBytes);
}
NextOutputIndex = 0;
return 0;
}
int
put_out ( const void* DataPtr,
const size_t Bytes )
{
MMRESULT r;
int i = NextOutputIndex;
if ( array [i].active )
while ( ! (array [i].hdr.dwFlags & WHDR_DONE) )
Sleep (26);
r = waveOutUnprepareHeader ( Output_WAVHandle, &(array [i].hdr), sizeof (array [i].hdr) ); if ( r != MMSYSERR_NOERROR ) return PrintError ( "waveOutUnprepareHeader", r );
array [i].active = 1;
array [i].hdr.lpData = array [i].data;
array [i].hdr.dwBufferLength = Bytes;
array [i].hdr.dwFlags = 0;
array [i].hdr.dwLoops = 0;
memcpy ( array [i].data, DataPtr, Bytes );
r = waveOutPrepareHeader ( Output_WAVHandle, &(array [i].hdr), sizeof (array [i].hdr) ); if ( r != MMSYSERR_NOERROR ) return PrintError ( "waveOutPrepareHeader", r );
r = waveOutWrite ( Output_WAVHandle, &(array [i].hdr), sizeof (array [i].hdr) ); if ( r != MMSYSERR_NOERROR ) return PrintError ( "waveOutWrite" , r );
NextInputIndex = (NextInputIndex + 1) % MAX_BUFFERS_WAVIN;
return Bytes;
}
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* end of fileio_winaudio.h */