diff options
author | Wincent Balin <wincent@rockbox.org> | 2010-06-03 00:39:13 +0000 |
---|---|---|
committer | Wincent Balin <wincent@rockbox.org> | 2010-06-03 00:39:13 +0000 |
commit | c1ae4414d4ac6504992434b949b252c30daf0c48 (patch) | |
tree | 696c5781e9a00cea694117eb3ef404d37f10930e /apps/plugins/pdbox/PDa/src/s_audio_mmio.c | |
parent | 5edd8cf736232a240e2f4f47eb847e1901d18379 (diff) | |
download | rockbox-c1ae4414d4ac6504992434b949b252c30daf0c48.tar.gz rockbox-c1ae4414d4ac6504992434b949b252c30daf0c48.zip |
pdbox: Source cleanup. Removed unneeded files.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26497 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/s_audio_mmio.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/s_audio_mmio.c | 795 |
1 files changed, 0 insertions, 795 deletions
diff --git a/apps/plugins/pdbox/PDa/src/s_audio_mmio.c b/apps/plugins/pdbox/PDa/src/s_audio_mmio.c deleted file mode 100644 index 4a4a8f7354..0000000000 --- a/apps/plugins/pdbox/PDa/src/s_audio_mmio.c +++ /dev/null | |||
@@ -1,795 +0,0 @@ | |||
1 | /* Copyright (c) 1997-1999 Miller Puckette. | ||
2 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
3 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
4 | |||
5 | /* modified 2/98 by Winfried Ritsch to deal with up to 4 synchronized | ||
6 | "wave" devices, which is how ADAT boards appear to the WAVE API. */ | ||
7 | |||
8 | #include "m_pd.h" | ||
9 | #include "s_stuff.h" | ||
10 | #include <stdio.h> | ||
11 | |||
12 | #include <windows.h> | ||
13 | |||
14 | #include <MMSYSTEM.H> | ||
15 | |||
16 | /* ------------------------- audio -------------------------- */ | ||
17 | |||
18 | static void nt_close_midiin(void); | ||
19 | static void nt_noresync( void); | ||
20 | |||
21 | static void postflags(void); | ||
22 | |||
23 | #define NAPORTS 16 /* wini hack for multiple ADDA devices */ | ||
24 | #define CHANNELS_PER_DEVICE 2 | ||
25 | #define DEFAULTCHANS 2 | ||
26 | #define DEFAULTSRATE 44100 | ||
27 | #define SAMPSIZE 2 | ||
28 | |||
29 | int nt_realdacblksize; | ||
30 | #define DEFREALDACBLKSIZE (4 * DEFDACBLKSIZE) /* larger underlying bufsize */ | ||
31 | |||
32 | #define MAXBUFFER 100 /* number of buffers in use at maximum advance */ | ||
33 | #define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */ | ||
34 | static int nt_naudiobuffer = DEFBUFFER; | ||
35 | float sys_dacsr = DEFAULTSRATE; | ||
36 | |||
37 | static int nt_whichapi = API_MMIO; | ||
38 | static int nt_meters; /* true if we're metering */ | ||
39 | static float nt_inmax; /* max input amplitude */ | ||
40 | static float nt_outmax; /* max output amplitude */ | ||
41 | static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */ | ||
42 | |||
43 | typedef struct _sbuf | ||
44 | { | ||
45 | HANDLE hData; | ||
46 | HPSTR lpData; // pointer to waveform data memory | ||
47 | HANDLE hWaveHdr; | ||
48 | WAVEHDR *lpWaveHdr; // pointer to header structure | ||
49 | } t_sbuf; | ||
50 | |||
51 | t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */ | ||
52 | HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */ | ||
53 | static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */ | ||
54 | |||
55 | t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */ | ||
56 | HWAVEIN ntsnd_indev[NAPORTS]; /* input device */ | ||
57 | static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */ | ||
58 | |||
59 | static void nt_waveinerror(char *s, int err) | ||
60 | { | ||
61 | char t[256]; | ||
62 | waveInGetErrorText(err, t, 256); | ||
63 | fprintf(stderr, s, t); | ||
64 | } | ||
65 | |||
66 | static void nt_waveouterror(char *s, int err) | ||
67 | { | ||
68 | char t[256]; | ||
69 | waveOutGetErrorText(err, t, 256); | ||
70 | fprintf(stderr, s, t); | ||
71 | } | ||
72 | |||
73 | static void wave_prep(t_sbuf *bp, int setdone) | ||
74 | { | ||
75 | WAVEHDR *wh; | ||
76 | short *sp; | ||
77 | int i; | ||
78 | /* | ||
79 | * Allocate and lock memory for the waveform data. The memory | ||
80 | * for waveform data must be globally allocated with | ||
81 | * GMEM_MOVEABLE and GMEM_SHARE flags. | ||
82 | */ | ||
83 | |||
84 | if (!(bp->hData = | ||
85 | GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, | ||
86 | (DWORD) (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize)))) | ||
87 | printf("alloc 1 failed\n"); | ||
88 | |||
89 | if (!(bp->lpData = | ||
90 | (HPSTR) GlobalLock(bp->hData))) | ||
91 | printf("lock 1 failed\n"); | ||
92 | |||
93 | /* Allocate and lock memory for the header. */ | ||
94 | |||
95 | if (!(bp->hWaveHdr = | ||
96 | GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR)))) | ||
97 | printf("alloc 2 failed\n"); | ||
98 | |||
99 | if (!(wh = bp->lpWaveHdr = | ||
100 | (WAVEHDR *) GlobalLock(bp->hWaveHdr))) | ||
101 | printf("lock 2 failed\n"); | ||
102 | |||
103 | for (i = CHANNELS_PER_DEVICE * nt_realdacblksize, | ||
104 | sp = (short *)bp->lpData; i--; ) | ||
105 | *sp++ = 0; | ||
106 | |||
107 | wh->lpData = bp->lpData; | ||
108 | wh->dwBufferLength = (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize); | ||
109 | wh->dwFlags = 0; | ||
110 | wh->dwLoops = 0L; | ||
111 | wh->lpNext = 0; | ||
112 | wh->reserved = 0; | ||
113 | /* optionally (for writing) set DONE flag as if we had queued them */ | ||
114 | if (setdone) | ||
115 | wh->dwFlags = WHDR_DONE; | ||
116 | } | ||
117 | |||
118 | static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER; | ||
119 | |||
120 | int mmio_do_open_audio(void) | ||
121 | { | ||
122 | PCMWAVEFORMAT form; | ||
123 | int i, j; | ||
124 | UINT mmresult; | ||
125 | int nad, nda; | ||
126 | static int naudioprepped = 0, nindevsprepped = 0, noutdevsprepped = 0; | ||
127 | if (sys_verbose) | ||
128 | post("%d devices in, %d devices out", | ||
129 | nt_nwavein, nt_nwaveout); | ||
130 | |||
131 | form.wf.wFormatTag = WAVE_FORMAT_PCM; | ||
132 | form.wf.nChannels = CHANNELS_PER_DEVICE; | ||
133 | form.wf.nSamplesPerSec = sys_dacsr; | ||
134 | form.wf.nAvgBytesPerSec = sys_dacsr * (CHANNELS_PER_DEVICE * SAMPSIZE); | ||
135 | form.wf.nBlockAlign = CHANNELS_PER_DEVICE * SAMPSIZE; | ||
136 | form.wBitsPerSample = 8 * SAMPSIZE; | ||
137 | |||
138 | if (nt_nwavein <= 1 && nt_nwaveout <= 1) | ||
139 | nt_noresync(); | ||
140 | |||
141 | if (nindevsprepped < nt_nwavein) | ||
142 | { | ||
143 | for (i = nindevsprepped; i < nt_nwavein; i++) | ||
144 | for (j = 0; j < naudioprepped; j++) | ||
145 | wave_prep(&ntsnd_invec[i][j], 0); | ||
146 | nindevsprepped = nt_nwavein; | ||
147 | } | ||
148 | if (noutdevsprepped < nt_nwaveout) | ||
149 | { | ||
150 | for (i = noutdevsprepped; i < nt_nwaveout; i++) | ||
151 | for (j = 0; j < naudioprepped; j++) | ||
152 | wave_prep(&ntsnd_outvec[i][j], 1); | ||
153 | noutdevsprepped = nt_nwaveout; | ||
154 | } | ||
155 | if (naudioprepped < nt_naudiobuffer) | ||
156 | { | ||
157 | for (j = naudioprepped; j < nt_naudiobuffer; j++) | ||
158 | { | ||
159 | for (i = 0; i < nt_nwavein; i++) | ||
160 | wave_prep(&ntsnd_invec[i][j], 0); | ||
161 | for (i = 0; i < nt_nwaveout; i++) | ||
162 | wave_prep(&ntsnd_outvec[i][j], 1); | ||
163 | } | ||
164 | naudioprepped = nt_naudiobuffer; | ||
165 | } | ||
166 | for (nad=0; nad < nt_nwavein; nad++) | ||
167 | { | ||
168 | /* Open waveform device(s), sucessively numbered, for input */ | ||
169 | |||
170 | mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad, | ||
171 | (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL); | ||
172 | |||
173 | if (sys_verbose) | ||
174 | printf("opened adc device %d with return %d\n", | ||
175 | nt_whichadc+nad,mmresult); | ||
176 | |||
177 | if (mmresult != MMSYSERR_NOERROR) | ||
178 | { | ||
179 | nt_waveinerror("waveInOpen: %s\n", mmresult); | ||
180 | nt_nwavein = nad; /* nt_nwavein = 0 wini */ | ||
181 | } | ||
182 | else | ||
183 | { | ||
184 | for (i = 0; i < nt_naudiobuffer; i++) | ||
185 | { | ||
186 | mmresult = waveInPrepareHeader(ntsnd_indev[nad], | ||
187 | ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR)); | ||
188 | if (mmresult != MMSYSERR_NOERROR) | ||
189 | nt_waveinerror("waveinprepareheader: %s\n", mmresult); | ||
190 | mmresult = waveInAddBuffer(ntsnd_indev[nad], | ||
191 | ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR)); | ||
192 | if (mmresult != MMSYSERR_NOERROR) | ||
193 | nt_waveinerror("waveInAddBuffer: %s\n", mmresult); | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | /* quickly start them all together */ | ||
198 | for (nad = 0; nad < nt_nwavein; nad++) | ||
199 | waveInStart(ntsnd_indev[nad]); | ||
200 | |||
201 | for (nda = 0; nda < nt_nwaveout; nda++) | ||
202 | { | ||
203 | /* Open a waveform device for output in sucessiv device numbering*/ | ||
204 | mmresult = waveOutOpen(&ntsnd_outdev[nda], nt_whichdac + nda, | ||
205 | (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL); | ||
206 | |||
207 | if (sys_verbose) | ||
208 | fprintf(stderr,"opened dac device %d, with return %d\n", | ||
209 | nt_whichdac +nda, mmresult); | ||
210 | |||
211 | if (mmresult != MMSYSERR_NOERROR) | ||
212 | { | ||
213 | fprintf(stderr,"Wave out open device %d + %d\n",nt_whichdac,nda); | ||
214 | nt_waveouterror("waveOutOpen device: %s\n", mmresult); | ||
215 | nt_nwaveout = nda; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | return (0); | ||
220 | } | ||
221 | |||
222 | void mmio_close_audio( void) | ||
223 | { | ||
224 | int errcode; | ||
225 | int nda, nad; | ||
226 | if (sys_verbose) | ||
227 | post("closing audio..."); | ||
228 | |||
229 | for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */ | ||
230 | { | ||
231 | errcode = waveOutReset(ntsnd_outdev[nda]); | ||
232 | if (errcode != MMSYSERR_NOERROR) | ||
233 | printf("error resetting output %d: %d\n", nda, errcode); | ||
234 | errcode = waveOutClose(ntsnd_outdev[nda]); | ||
235 | if (errcode != MMSYSERR_NOERROR) | ||
236 | printf("error closing output %d: %d\n",nda , errcode); | ||
237 | } | ||
238 | nt_nwaveout = 0; | ||
239 | |||
240 | for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */ | ||
241 | { | ||
242 | errcode = waveInReset(ntsnd_indev[nad]); | ||
243 | if (errcode != MMSYSERR_NOERROR) | ||
244 | printf("error resetting input: %d\n", errcode); | ||
245 | errcode = waveInClose(ntsnd_indev[nad]); | ||
246 | if (errcode != MMSYSERR_NOERROR) | ||
247 | printf("error closing input: %d\n", errcode); | ||
248 | } | ||
249 | nt_nwavein = 0; | ||
250 | } | ||
251 | |||
252 | |||
253 | #define ADCJITTER 10 /* We tolerate X buffers of jitter by default */ | ||
254 | #define DACJITTER 10 | ||
255 | |||
256 | static int nt_adcjitterbufsallowed = ADCJITTER; | ||
257 | static int nt_dacjitterbufsallowed = DACJITTER; | ||
258 | |||
259 | /* ------------- MIDI time stamping from audio clock ------------ */ | ||
260 | |||
261 | #ifdef MIDI_TIMESTAMP | ||
262 | |||
263 | static double nt_hibuftime; | ||
264 | static double initsystime = -1; | ||
265 | |||
266 | /* call this whenever we reset audio */ | ||
267 | static void nt_resetmidisync(void) | ||
268 | { | ||
269 | initsystime = clock_getsystime(); | ||
270 | nt_hibuftime = sys_getrealtime(); | ||
271 | } | ||
272 | |||
273 | /* call this whenever we're idled waiting for audio to be ready. | ||
274 | The routine maintains a high and low water point for the difference | ||
275 | between real and DAC time. */ | ||
276 | |||
277 | static void nt_midisync(void) | ||
278 | { | ||
279 | double jittersec, diff; | ||
280 | |||
281 | if (initsystime == -1) nt_resetmidisync(); | ||
282 | jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ? | ||
283 | nt_dacjitterbufsallowed : nt_adcjitterbufsallowed) | ||
284 | * nt_realdacblksize / sys_getsr(); | ||
285 | diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime); | ||
286 | if (diff > nt_hibuftime) nt_hibuftime = diff; | ||
287 | if (diff < nt_hibuftime - jittersec) | ||
288 | { | ||
289 | post("jitter excess %d %f", dac, diff); | ||
290 | nt_resetmidisync(); | ||
291 | } | ||
292 | } | ||
293 | |||
294 | static double nt_midigettimefor(LARGE_INTEGER timestamp) | ||
295 | { | ||
296 | /* this is broken now... used to work when "timestamp" was derived from | ||
297 | QueryPerformanceCounter() instead of the gates approved | ||
298 | timeGetSystemTime() call in the MIDI callback routine below. */ | ||
299 | return (nt_tixtotime(timestamp) - nt_hibuftime); | ||
300 | } | ||
301 | #endif /* MIDI_TIMESTAMP */ | ||
302 | |||
303 | |||
304 | static int nt_fill = 0; | ||
305 | #define WRAPFWD(x) ((x) >= nt_naudiobuffer ? (x) - nt_naudiobuffer: (x)) | ||
306 | #define WRAPBACK(x) ((x) < 0 ? (x) + nt_naudiobuffer: (x)) | ||
307 | #define MAXRESYNC 500 | ||
308 | |||
309 | #if 0 /* this is used for debugging */ | ||
310 | static void nt_printaudiostatus(void) | ||
311 | { | ||
312 | int nad, nda; | ||
313 | for (nad = 0; nad < nt_nwavein; nad++) | ||
314 | { | ||
315 | int phase = ntsnd_inphase[nad]; | ||
316 | int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0; | ||
317 | int firstphasedone = -1, firstphasebusy = -1; | ||
318 | for (count = 0; count < nt_naudiobuffer; count++) | ||
319 | { | ||
320 | int donethis = | ||
321 | (ntsnd_invec[nad][phase2].lpWaveHdr->dwFlags & WHDR_DONE); | ||
322 | int donenext = | ||
323 | (ntsnd_invec[nad][phase3].lpWaveHdr->dwFlags & WHDR_DONE); | ||
324 | if (donethis && !donenext) | ||
325 | { | ||
326 | if (firstphasebusy >= 0) goto multipleadc; | ||
327 | firstphasebusy = count; | ||
328 | } | ||
329 | if (!donethis && donenext) | ||
330 | { | ||
331 | if (firstphasedone >= 0) goto multipleadc; | ||
332 | firstphasedone = count; | ||
333 | } | ||
334 | phase2 = phase3; | ||
335 | phase3 = WRAPFWD(phase2 + 1); | ||
336 | } | ||
337 | post("nad %d phase %d busy %d done %d", nad, phase, firstphasebusy, | ||
338 | firstphasedone); | ||
339 | continue; | ||
340 | multipleadc: | ||
341 | startpost("nad %d phase %d: oops:", nad, phase); | ||
342 | for (count = 0; count < nt_naudiobuffer; count++) | ||
343 | { | ||
344 | char buf[80]; | ||
345 | sprintf(buf, " %d", | ||
346 | (ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE)); | ||
347 | poststring(buf); | ||
348 | } | ||
349 | endpost(); | ||
350 | } | ||
351 | for (nda = 0; nda < nt_nwaveout; nda++) | ||
352 | { | ||
353 | int phase = ntsnd_outphase[nad]; | ||
354 | int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0; | ||
355 | int firstphasedone = -1, firstphasebusy = -1; | ||
356 | for (count = 0; count < nt_naudiobuffer; count++) | ||
357 | { | ||
358 | int donethis = | ||
359 | (ntsnd_outvec[nda][phase2].lpWaveHdr->dwFlags & WHDR_DONE); | ||
360 | int donenext = | ||
361 | (ntsnd_outvec[nda][phase3].lpWaveHdr->dwFlags & WHDR_DONE); | ||
362 | if (donethis && !donenext) | ||
363 | { | ||
364 | if (firstphasebusy >= 0) goto multipledac; | ||
365 | firstphasebusy = count; | ||
366 | } | ||
367 | if (!donethis && donenext) | ||
368 | { | ||
369 | if (firstphasedone >= 0) goto multipledac; | ||
370 | firstphasedone = count; | ||
371 | } | ||
372 | phase2 = phase3; | ||
373 | phase3 = WRAPFWD(phase2 + 1); | ||
374 | } | ||
375 | if (firstphasebusy < 0) post("nda %d phase %d all %d", | ||
376 | nda, phase, (ntsnd_outvec[nad][0].lpWaveHdr->dwFlags & WHDR_DONE)); | ||
377 | else post("nda %d phase %d busy %d done %d", nda, phase, firstphasebusy, | ||
378 | firstphasedone); | ||
379 | continue; | ||
380 | multipledac: | ||
381 | startpost("nda %d phase %d: oops:", nda, phase); | ||
382 | for (count = 0; count < nt_naudiobuffer; count++) | ||
383 | { | ||
384 | char buf[80]; | ||
385 | sprintf(buf, " %d", | ||
386 | (ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE)); | ||
387 | poststring(buf); | ||
388 | } | ||
389 | endpost(); | ||
390 | } | ||
391 | } | ||
392 | #endif /* 0 */ | ||
393 | |||
394 | /* this is a hack to avoid ever resyncing audio pointers in case for whatever | ||
395 | reason the sync testing below gives false positives. */ | ||
396 | |||
397 | static int nt_resync_cancelled; | ||
398 | |||
399 | static void nt_noresync( void) | ||
400 | { | ||
401 | nt_resync_cancelled = 1; | ||
402 | } | ||
403 | |||
404 | static void nt_resyncaudio(void) | ||
405 | { | ||
406 | UINT mmresult; | ||
407 | int nad, nda, count; | ||
408 | if (nt_resync_cancelled) | ||
409 | return; | ||
410 | /* for each open input device, eat all buffers which are marked | ||
411 | ready. The next one will thus be "busy". */ | ||
412 | post("resyncing audio"); | ||
413 | for (nad = 0; nad < nt_nwavein; nad++) | ||
414 | { | ||
415 | int phase = ntsnd_inphase[nad]; | ||
416 | for (count = 0; count < MAXRESYNC; count++) | ||
417 | { | ||
418 | WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; | ||
419 | if (!(inwavehdr->dwFlags & WHDR_DONE)) break; | ||
420 | if (inwavehdr->dwFlags & WHDR_PREPARED) | ||
421 | waveInUnprepareHeader(ntsnd_indev[nad], | ||
422 | inwavehdr, sizeof(WAVEHDR)); | ||
423 | inwavehdr->dwFlags = 0L; | ||
424 | waveInPrepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR)); | ||
425 | mmresult = waveInAddBuffer(ntsnd_indev[nad], inwavehdr, | ||
426 | sizeof(WAVEHDR)); | ||
427 | if (mmresult != MMSYSERR_NOERROR) | ||
428 | nt_waveinerror("waveInAddBuffer: %s\n", mmresult); | ||
429 | ntsnd_inphase[nad] = phase = WRAPFWD(phase + 1); | ||
430 | } | ||
431 | if (count == MAXRESYNC) post("resync error 1"); | ||
432 | } | ||
433 | /* Each output buffer which is "ready" is filled with zeros and | ||
434 | queued. */ | ||
435 | for (nda = 0; nda < nt_nwaveout; nda++) | ||
436 | { | ||
437 | int phase = ntsnd_outphase[nda]; | ||
438 | for (count = 0; count < MAXRESYNC; count++) | ||
439 | { | ||
440 | WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; | ||
441 | if (!(outwavehdr->dwFlags & WHDR_DONE)) break; | ||
442 | if (outwavehdr->dwFlags & WHDR_PREPARED) | ||
443 | waveOutUnprepareHeader(ntsnd_outdev[nda], | ||
444 | outwavehdr, sizeof(WAVEHDR)); | ||
445 | outwavehdr->dwFlags = 0L; | ||
446 | memset((char *)(ntsnd_outvec[nda][phase].lpData), | ||
447 | 0, (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize)); | ||
448 | waveOutPrepareHeader(ntsnd_outdev[nda], outwavehdr, | ||
449 | sizeof(WAVEHDR)); | ||
450 | mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr, | ||
451 | sizeof(WAVEHDR)); | ||
452 | if (mmresult != MMSYSERR_NOERROR) | ||
453 | nt_waveouterror("waveOutAddBuffer: %s\n", mmresult); | ||
454 | ntsnd_outphase[nda] = phase = WRAPFWD(phase + 1); | ||
455 | } | ||
456 | if (count == MAXRESYNC) post("resync error 2"); | ||
457 | } | ||
458 | |||
459 | #ifdef MIDI_TIMESTAMP | ||
460 | nt_resetmidisync(); | ||
461 | #endif | ||
462 | |||
463 | } | ||
464 | |||
465 | #define LATE 0 | ||
466 | #define RESYNC 1 | ||
467 | #define NOTHING 2 | ||
468 | static int nt_errorcount; | ||
469 | static int nt_resynccount; | ||
470 | static double nt_nextreporttime = -1; | ||
471 | |||
472 | void nt_logerror(int which) | ||
473 | { | ||
474 | #if 0 | ||
475 | post("error %d %d", count, which); | ||
476 | if (which < NOTHING) nt_errorcount++; | ||
477 | if (which == RESYNC) nt_resynccount++; | ||
478 | if (sys_getrealtime() > nt_nextreporttime) | ||
479 | { | ||
480 | post("%d audio I/O error%s", nt_errorcount, | ||
481 | (nt_errorcount > 1 ? "s" : "")); | ||
482 | if (nt_resynccount) post("DAC/ADC sync error"); | ||
483 | nt_errorcount = nt_resynccount = 0; | ||
484 | nt_nextreporttime = sys_getrealtime() - 5; | ||
485 | } | ||
486 | #endif | ||
487 | } | ||
488 | |||
489 | /* system buffer with t_sample types for one tick */ | ||
490 | t_sample *sys_soundout; | ||
491 | t_sample *sys_soundin; | ||
492 | float sys_dacsr; | ||
493 | |||
494 | int mmio_send_dacs(void) | ||
495 | { | ||
496 | HMMIO hmmio; | ||
497 | UINT mmresult; | ||
498 | HANDLE hFormat; | ||
499 | int i, j; | ||
500 | short *sp1, *sp2; | ||
501 | float *fp1, *fp2; | ||
502 | int nextfill, doxfer = 0; | ||
503 | int nda, nad; | ||
504 | if (!nt_nwavein && !nt_nwaveout) return (0); | ||
505 | |||
506 | |||
507 | if (nt_meters) | ||
508 | { | ||
509 | int i, n; | ||
510 | float maxsamp; | ||
511 | for (i = 0, n = 2 * nt_nwavein * DEFDACBLKSIZE, maxsamp = nt_inmax; | ||
512 | i < n; i++) | ||
513 | { | ||
514 | float f = sys_soundin[i]; | ||
515 | if (f > maxsamp) maxsamp = f; | ||
516 | else if (-f > maxsamp) maxsamp = -f; | ||
517 | } | ||
518 | nt_inmax = maxsamp; | ||
519 | for (i = 0, n = 2 * nt_nwaveout * DEFDACBLKSIZE, maxsamp = nt_outmax; | ||
520 | i < n; i++) | ||
521 | { | ||
522 | float f = sys_soundout[i]; | ||
523 | if (f > maxsamp) maxsamp = f; | ||
524 | else if (-f > maxsamp) maxsamp = -f; | ||
525 | } | ||
526 | nt_outmax = maxsamp; | ||
527 | } | ||
528 | |||
529 | /* the "fill pointer" nt_fill controls where in the next | ||
530 | I/O buffers we will write and/or read. If it's zero, we | ||
531 | first check whether the buffers are marked "done". */ | ||
532 | |||
533 | if (!nt_fill) | ||
534 | { | ||
535 | for (nad = 0; nad < nt_nwavein; nad++) | ||
536 | { | ||
537 | int phase = ntsnd_inphase[nad]; | ||
538 | WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; | ||
539 | if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle; | ||
540 | } | ||
541 | for (nda = 0; nda < nt_nwaveout; nda++) | ||
542 | { | ||
543 | int phase = ntsnd_outphase[nda]; | ||
544 | WAVEHDR *outwavehdr = | ||
545 | ntsnd_outvec[nda][phase].lpWaveHdr; | ||
546 | if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle; | ||
547 | } | ||
548 | for (nad = 0; nad < nt_nwavein; nad++) | ||
549 | { | ||
550 | int phase = ntsnd_inphase[nad]; | ||
551 | WAVEHDR *inwavehdr = | ||
552 | ntsnd_invec[nad][phase].lpWaveHdr; | ||
553 | if (inwavehdr->dwFlags & WHDR_PREPARED) | ||
554 | waveInUnprepareHeader(ntsnd_indev[nad], | ||
555 | inwavehdr, sizeof(WAVEHDR)); | ||
556 | } | ||
557 | for (nda = 0; nda < nt_nwaveout; nda++) | ||
558 | { | ||
559 | int phase = ntsnd_outphase[nda]; | ||
560 | WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; | ||
561 | if (outwavehdr->dwFlags & WHDR_PREPARED) | ||
562 | waveOutUnprepareHeader(ntsnd_outdev[nda], | ||
563 | outwavehdr, sizeof(WAVEHDR)); | ||
564 | } | ||
565 | } | ||
566 | |||
567 | /* Convert audio output to fixed-point and put it in the output | ||
568 | buffer. */ | ||
569 | for (nda = 0, fp1 = sys_soundout; nda < nt_nwaveout; nda++) | ||
570 | { | ||
571 | int phase = ntsnd_outphase[nda]; | ||
572 | |||
573 | for (i = 0, sp1 = (short *)(ntsnd_outvec[nda][phase].lpData) + | ||
574 | CHANNELS_PER_DEVICE * nt_fill; | ||
575 | i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++) | ||
576 | { | ||
577 | for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE; | ||
578 | j++, fp2++, sp2 += CHANNELS_PER_DEVICE) | ||
579 | { | ||
580 | int x1 = 32767.f * *fp2; | ||
581 | if (x1 > 32767) x1 = 32767; | ||
582 | else if (x1 < -32767) x1 = -32767; | ||
583 | *sp2 = x1; | ||
584 | } | ||
585 | } | ||
586 | } | ||
587 | memset(sys_soundout, 0, | ||
588 | (DEFDACBLKSIZE *sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout); | ||
589 | |||
590 | /* vice versa for the input buffer */ | ||
591 | |||
592 | for (nad = 0, fp1 = sys_soundin; nad < nt_nwavein; nad++) | ||
593 | { | ||
594 | int phase = ntsnd_inphase[nad]; | ||
595 | |||
596 | for (i = 0, sp1 = (short *)(ntsnd_invec[nad][phase].lpData) + | ||
597 | CHANNELS_PER_DEVICE * nt_fill; | ||
598 | i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++) | ||
599 | { | ||
600 | for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE; | ||
601 | j++, fp2++, sp2 += CHANNELS_PER_DEVICE) | ||
602 | { | ||
603 | *fp2 = ((float)(1./32767.)) * (float)(*sp2); | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | |||
608 | nt_fill = nt_fill + DEFDACBLKSIZE; | ||
609 | if (nt_fill == nt_realdacblksize) | ||
610 | { | ||
611 | nt_fill = 0; | ||
612 | |||
613 | for (nad = 0; nad < nt_nwavein; nad++) | ||
614 | { | ||
615 | int phase = ntsnd_inphase[nad]; | ||
616 | HWAVEIN device = ntsnd_indev[nad]; | ||
617 | WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; | ||
618 | waveInPrepareHeader(device, inwavehdr, sizeof(WAVEHDR)); | ||
619 | mmresult = waveInAddBuffer(device, inwavehdr, sizeof(WAVEHDR)); | ||
620 | if (mmresult != MMSYSERR_NOERROR) | ||
621 | nt_waveinerror("waveInAddBuffer: %s\n", mmresult); | ||
622 | ntsnd_inphase[nad] = WRAPFWD(phase + 1); | ||
623 | } | ||
624 | for (nda = 0; nda < nt_nwaveout; nda++) | ||
625 | { | ||
626 | int phase = ntsnd_outphase[nda]; | ||
627 | HWAVEOUT device = ntsnd_outdev[nda]; | ||
628 | WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; | ||
629 | waveOutPrepareHeader(device, outwavehdr, sizeof(WAVEHDR)); | ||
630 | mmresult = waveOutWrite(device, outwavehdr, sizeof(WAVEHDR)); | ||
631 | if (mmresult != MMSYSERR_NOERROR) | ||
632 | nt_waveouterror("waveOutWrite: %s\n", mmresult); | ||
633 | ntsnd_outphase[nda] = WRAPFWD(phase + 1); | ||
634 | } | ||
635 | |||
636 | /* check for DAC underflow or ADC overflow. */ | ||
637 | for (nad = 0; nad < nt_nwavein; nad++) | ||
638 | { | ||
639 | int phase = WRAPBACK(ntsnd_inphase[nad] - 2); | ||
640 | WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; | ||
641 | if (inwavehdr->dwFlags & WHDR_DONE) goto late; | ||
642 | } | ||
643 | for (nda = 0; nda < nt_nwaveout; nda++) | ||
644 | { | ||
645 | int phase = WRAPBACK(ntsnd_outphase[nda] - 2); | ||
646 | WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; | ||
647 | if (outwavehdr->dwFlags & WHDR_DONE) goto late; | ||
648 | } | ||
649 | } | ||
650 | return (1); | ||
651 | |||
652 | late: | ||
653 | |||
654 | nt_logerror(LATE); | ||
655 | nt_resyncaudio(); | ||
656 | return (1); | ||
657 | |||
658 | idle: | ||
659 | |||
660 | /* If more than nt_adcjitterbufsallowed ADC buffers are ready | ||
661 | on any input device, resynchronize */ | ||
662 | |||
663 | for (nad = 0; nad < nt_nwavein; nad++) | ||
664 | { | ||
665 | int phase = ntsnd_inphase[nad]; | ||
666 | WAVEHDR *inwavehdr = | ||
667 | ntsnd_invec[nad] | ||
668 | [WRAPFWD(phase + nt_adcjitterbufsallowed)].lpWaveHdr; | ||
669 | if (inwavehdr->dwFlags & WHDR_DONE) | ||
670 | { | ||
671 | nt_resyncaudio(); | ||
672 | return (0); | ||
673 | } | ||
674 | } | ||
675 | |||
676 | /* test dac sync the same way */ | ||
677 | for (nda = 0; nda < nt_nwaveout; nda++) | ||
678 | { | ||
679 | int phase = ntsnd_outphase[nda]; | ||
680 | WAVEHDR *outwavehdr = | ||
681 | ntsnd_outvec[nda] | ||
682 | [WRAPFWD(phase + nt_dacjitterbufsallowed)].lpWaveHdr; | ||
683 | if (outwavehdr->dwFlags & WHDR_DONE) | ||
684 | { | ||
685 | nt_resyncaudio(); | ||
686 | return (0); | ||
687 | } | ||
688 | } | ||
689 | #ifdef MIDI_TIMESTAMP | ||
690 | nt_midisync(); | ||
691 | #endif | ||
692 | return (0); | ||
693 | } | ||
694 | |||
695 | /* ------------------- public routines -------------------------- */ | ||
696 | |||
697 | void mmio_open_audio(int naudioindev, int *audioindev, | ||
698 | int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, | ||
699 | int nchoutdev, int *choutdev, int rate) /* IOhannes */ | ||
700 | { | ||
701 | int nbuf; | ||
702 | |||
703 | nt_realdacblksize = (sys_blocksize ? sys_blocksize : DEFREALDACBLKSIZE); | ||
704 | nbuf = sys_advance_samples/nt_realdacblksize; | ||
705 | if (nbuf >= MAXBUFFER) | ||
706 | { | ||
707 | fprintf(stderr, "pd: audio buffering maxed out to %d\n", | ||
708 | (int)(MAXBUFFER * ((nt_realdacblksize * 1000.)/44100.))); | ||
709 | nbuf = MAXBUFFER; | ||
710 | } | ||
711 | else if (nbuf < 4) nbuf = 4; | ||
712 | fprintf(stderr, "%d audio buffers\n", nbuf); | ||
713 | nt_naudiobuffer = nbuf; | ||
714 | if (nt_adcjitterbufsallowed > nbuf - 2) | ||
715 | nt_adcjitterbufsallowed = nbuf - 2; | ||
716 | if (nt_dacjitterbufsallowed > nbuf - 2) | ||
717 | nt_dacjitterbufsallowed = nbuf - 2; | ||
718 | |||
719 | nt_nwavein = sys_inchannels / 2; | ||
720 | nt_nwaveout = sys_outchannels / 2; | ||
721 | nt_whichadc = (naudioindev < 1 ? | ||
722 | (nt_nwavein > 1 ? WAVE_MAPPER : -1) : audioindev[0]); | ||
723 | nt_whichdac = (naudiooutdev < 1 ? | ||
724 | (nt_nwaveout > 1 ? WAVE_MAPPER : -1) : audiooutdev[0]); | ||
725 | if (naudiooutdev > 1 || naudioindev > 1) | ||
726 | post("separate audio device choice not supported; using sequential devices."); | ||
727 | mmio_do_open_audio(); | ||
728 | } | ||
729 | |||
730 | |||
731 | void mmio_reportidle(void) | ||
732 | { | ||
733 | } | ||
734 | |||
735 | #if 0 | ||
736 | /* list the audio and MIDI device names */ | ||
737 | void mmio_listdevs(void) | ||
738 | { | ||
739 | UINT wRtn, ndevices; | ||
740 | unsigned int i; | ||
741 | |||
742 | ndevices = waveInGetNumDevs(); | ||
743 | for (i = 0; i < ndevices; i++) | ||
744 | { | ||
745 | WAVEINCAPS wicap; | ||
746 | wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, | ||
747 | sizeof(wicap)); | ||
748 | if (wRtn) nt_waveinerror("waveInGetDevCaps: %s\n", wRtn); | ||
749 | else fprintf(stderr, | ||
750 | "audio input device #%d: %s\n", i+1, wicap.szPname); | ||
751 | } | ||
752 | |||
753 | ndevices = waveOutGetNumDevs(); | ||
754 | for (i = 0; i < ndevices; i++) | ||
755 | { | ||
756 | WAVEOUTCAPS wocap; | ||
757 | wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, | ||
758 | sizeof(wocap)); | ||
759 | if (wRtn) nt_waveouterror("waveOutGetDevCaps: %s\n", wRtn); | ||
760 | else fprintf(stderr, | ||
761 | "audio output device #%d: %s\n", i+1, wocap.szPname); | ||
762 | } | ||
763 | } | ||
764 | #endif | ||
765 | |||
766 | void mmio_getdevs(char *indevlist, int *nindevs, | ||
767 | char *outdevlist, int *noutdevs, int *canmulti, | ||
768 | int maxndev, int devdescsize) | ||
769 | { | ||
770 | int wRtn, ndev, i; | ||
771 | |||
772 | *canmulti = 2; /* supports multiple devices */ | ||
773 | ndev = waveInGetNumDevs(); | ||
774 | if (ndev > maxndev) | ||
775 | ndev = maxndev; | ||
776 | *nindevs = ndev; | ||
777 | for (i = 0; i < ndev; i++) | ||
778 | { | ||
779 | WAVEINCAPS wicap; | ||
780 | wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, sizeof(wicap)); | ||
781 | sprintf(indevlist + i * devdescsize, (wRtn ? "???" : wicap.szPname)); | ||
782 | } | ||
783 | |||
784 | ndev = waveOutGetNumDevs(); | ||
785 | if (ndev > maxndev) | ||
786 | ndev = maxndev; | ||
787 | *noutdevs = ndev; | ||
788 | for (i = 0; i < ndev; i++) | ||
789 | { | ||
790 | WAVEOUTCAPS wocap; | ||
791 | wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, sizeof(wocap)); | ||
792 | sprintf(outdevlist + i * devdescsize, (wRtn ? "???" : wocap.szPname)); | ||
793 | } | ||
794 | } | ||
795 | |||