Fix some greedy sed changes in imported code. Also provide a sys/types.h for compatib...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / s_audio_mmio.c
blob4a4a8f73545878f2c0bbcfa70510e80931b5d474
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. */
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. */
8 #include "m_pd.h"
9 #include "s_stuff.h"
10 #include <stdio.h>
12 #include <windows.h>
14 #include <MMSYSTEM.H>
16 /* ------------------------- audio -------------------------- */
18 static void nt_close_midiin(void);
19 static void nt_noresync( void);
21 static void postflags(void);
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
29 int nt_realdacblksize;
30 #define DEFREALDACBLKSIZE (4 * DEFDACBLKSIZE) /* larger underlying bufsize */
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;
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 */
43 typedef struct _sbuf
45 HANDLE hData;
46 HPSTR lpData; // pointer to waveform data memory
47 HANDLE hWaveHdr;
48 WAVEHDR *lpWaveHdr; // pointer to header structure
49 } t_sbuf;
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 */
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 */
59 static void nt_waveinerror(char *s, int err)
61 char t[256];
62 waveInGetErrorText(err, t, 256);
63 fprintf(stderr, s, t);
66 static void nt_waveouterror(char *s, int err)
68 char t[256];
69 waveOutGetErrorText(err, t, 256);
70 fprintf(stderr, s, t);
73 static void wave_prep(t_sbuf *bp, int setdone)
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 */
84 if (!(bp->hData =
85 GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
86 (DWORD) (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize))))
87 printf("alloc 1 failed\n");
89 if (!(bp->lpData =
90 (HPSTR) GlobalLock(bp->hData)))
91 printf("lock 1 failed\n");
93 /* Allocate and lock memory for the header. */
95 if (!(bp->hWaveHdr =
96 GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR))))
97 printf("alloc 2 failed\n");
99 if (!(wh = bp->lpWaveHdr =
100 (WAVEHDR *) GlobalLock(bp->hWaveHdr)))
101 printf("lock 2 failed\n");
103 for (i = CHANNELS_PER_DEVICE * nt_realdacblksize,
104 sp = (short *)bp->lpData; i--; )
105 *sp++ = 0;
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;
118 static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER;
120 int mmio_do_open_audio(void)
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);
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;
138 if (nt_nwavein <= 1 && nt_nwaveout <= 1)
139 nt_noresync();
141 if (nindevsprepped < nt_nwavein)
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;
148 if (noutdevsprepped < nt_nwaveout)
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;
155 if (naudioprepped < nt_naudiobuffer)
157 for (j = naudioprepped; j < nt_naudiobuffer; j++)
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);
164 naudioprepped = nt_naudiobuffer;
166 for (nad=0; nad < nt_nwavein; nad++)
168 /* Open waveform device(s), sucessively numbered, for input */
170 mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad,
171 (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
173 if (sys_verbose)
174 printf("opened adc device %d with return %d\n",
175 nt_whichadc+nad,mmresult);
177 if (mmresult != MMSYSERR_NOERROR)
179 nt_waveinerror("waveInOpen: %s\n", mmresult);
180 nt_nwavein = nad; /* nt_nwavein = 0 wini */
182 else
184 for (i = 0; i < nt_naudiobuffer; i++)
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);
197 /* quickly start them all together */
198 for (nad = 0; nad < nt_nwavein; nad++)
199 waveInStart(ntsnd_indev[nad]);
201 for (nda = 0; nda < nt_nwaveout; nda++)
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);
207 if (sys_verbose)
208 fprintf(stderr,"opened dac device %d, with return %d\n",
209 nt_whichdac +nda, mmresult);
211 if (mmresult != MMSYSERR_NOERROR)
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;
219 return (0);
222 void mmio_close_audio( void)
224 int errcode;
225 int nda, nad;
226 if (sys_verbose)
227 post("closing audio...");
229 for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */
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);
238 nt_nwaveout = 0;
240 for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */
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);
249 nt_nwavein = 0;
253 #define ADCJITTER 10 /* We tolerate X buffers of jitter by default */
254 #define DACJITTER 10
256 static int nt_adcjitterbufsallowed = ADCJITTER;
257 static int nt_dacjitterbufsallowed = DACJITTER;
259 /* ------------- MIDI time stamping from audio clock ------------ */
261 #ifdef MIDI_TIMESTAMP
263 static double nt_hibuftime;
264 static double initsystime = -1;
266 /* call this whenever we reset audio */
267 static void nt_resetmidisync(void)
269 initsystime = clock_getsystime();
270 nt_hibuftime = sys_getrealtime();
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. */
277 static void nt_midisync(void)
279 double jittersec, diff;
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)
289 post("jitter excess %d %f", dac, diff);
290 nt_resetmidisync();
294 static double nt_midigettimefor(LARGE_INTEGER timestamp)
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);
301 #endif /* MIDI_TIMESTAMP */
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
309 #if 0 /* this is used for debugging */
310 static void nt_printaudiostatus(void)
312 int nad, nda;
313 for (nad = 0; nad < nt_nwavein; nad++)
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++)
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)
326 if (firstphasebusy >= 0) goto multipleadc;
327 firstphasebusy = count;
329 if (!donethis && donenext)
331 if (firstphasedone >= 0) goto multipleadc;
332 firstphasedone = count;
334 phase2 = phase3;
335 phase3 = WRAPFWD(phase2 + 1);
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++)
344 char buf[80];
345 sprintf(buf, " %d",
346 (ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
347 poststring(buf);
349 endpost();
351 for (nda = 0; nda < nt_nwaveout; nda++)
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++)
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)
364 if (firstphasebusy >= 0) goto multipledac;
365 firstphasebusy = count;
367 if (!donethis && donenext)
369 if (firstphasedone >= 0) goto multipledac;
370 firstphasedone = count;
372 phase2 = phase3;
373 phase3 = WRAPFWD(phase2 + 1);
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++)
384 char buf[80];
385 sprintf(buf, " %d",
386 (ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
387 poststring(buf);
389 endpost();
392 #endif /* 0 */
394 /* this is a hack to avoid ever resyncing audio pointers in case for whatever
395 reason the sync testing below gives false positives. */
397 static int nt_resync_cancelled;
399 static void nt_noresync( void)
401 nt_resync_cancelled = 1;
404 static void nt_resyncaudio(void)
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++)
415 int phase = ntsnd_inphase[nad];
416 for (count = 0; count < MAXRESYNC; count++)
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);
431 if (count == MAXRESYNC) post("resync error 1");
433 /* Each output buffer which is "ready" is filled with zeros and
434 queued. */
435 for (nda = 0; nda < nt_nwaveout; nda++)
437 int phase = ntsnd_outphase[nda];
438 for (count = 0; count < MAXRESYNC; count++)
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);
456 if (count == MAXRESYNC) post("resync error 2");
459 #ifdef MIDI_TIMESTAMP
460 nt_resetmidisync();
461 #endif
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;
472 void nt_logerror(int which)
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)
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;
486 #endif
489 /* system buffer with t_sample types for one tick */
490 t_sample *sys_soundout;
491 t_sample *sys_soundin;
492 float sys_dacsr;
494 int mmio_send_dacs(void)
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);
507 if (nt_meters)
509 int i, n;
510 float maxsamp;
511 for (i = 0, n = 2 * nt_nwavein * DEFDACBLKSIZE, maxsamp = nt_inmax;
512 i < n; i++)
514 float f = sys_soundin[i];
515 if (f > maxsamp) maxsamp = f;
516 else if (-f > maxsamp) maxsamp = -f;
518 nt_inmax = maxsamp;
519 for (i = 0, n = 2 * nt_nwaveout * DEFDACBLKSIZE, maxsamp = nt_outmax;
520 i < n; i++)
522 float f = sys_soundout[i];
523 if (f > maxsamp) maxsamp = f;
524 else if (-f > maxsamp) maxsamp = -f;
526 nt_outmax = maxsamp;
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". */
533 if (!nt_fill)
535 for (nad = 0; nad < nt_nwavein; nad++)
537 int phase = ntsnd_inphase[nad];
538 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
539 if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle;
541 for (nda = 0; nda < nt_nwaveout; nda++)
543 int phase = ntsnd_outphase[nda];
544 WAVEHDR *outwavehdr =
545 ntsnd_outvec[nda][phase].lpWaveHdr;
546 if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle;
548 for (nad = 0; nad < nt_nwavein; nad++)
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));
557 for (nda = 0; nda < nt_nwaveout; nda++)
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));
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++)
571 int phase = ntsnd_outphase[nda];
573 for (i = 0, sp1 = (short *)(ntsnd_outvec[nda][phase].lpData) +
574 CHANNELS_PER_DEVICE * nt_fill;
575 i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
577 for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
578 j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
580 int x1 = 32767.f * *fp2;
581 if (x1 > 32767) x1 = 32767;
582 else if (x1 < -32767) x1 = -32767;
583 *sp2 = x1;
587 memset(sys_soundout, 0,
588 (DEFDACBLKSIZE *sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout);
590 /* vice versa for the input buffer */
592 for (nad = 0, fp1 = sys_soundin; nad < nt_nwavein; nad++)
594 int phase = ntsnd_inphase[nad];
596 for (i = 0, sp1 = (short *)(ntsnd_invec[nad][phase].lpData) +
597 CHANNELS_PER_DEVICE * nt_fill;
598 i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
600 for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
601 j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
603 *fp2 = ((float)(1./32767.)) * (float)(*sp2);
608 nt_fill = nt_fill + DEFDACBLKSIZE;
609 if (nt_fill == nt_realdacblksize)
611 nt_fill = 0;
613 for (nad = 0; nad < nt_nwavein; nad++)
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);
624 for (nda = 0; nda < nt_nwaveout; nda++)
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);
636 /* check for DAC underflow or ADC overflow. */
637 for (nad = 0; nad < nt_nwavein; nad++)
639 int phase = WRAPBACK(ntsnd_inphase[nad] - 2);
640 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
641 if (inwavehdr->dwFlags & WHDR_DONE) goto late;
643 for (nda = 0; nda < nt_nwaveout; nda++)
645 int phase = WRAPBACK(ntsnd_outphase[nda] - 2);
646 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
647 if (outwavehdr->dwFlags & WHDR_DONE) goto late;
650 return (1);
652 late:
654 nt_logerror(LATE);
655 nt_resyncaudio();
656 return (1);
658 idle:
660 /* If more than nt_adcjitterbufsallowed ADC buffers are ready
661 on any input device, resynchronize */
663 for (nad = 0; nad < nt_nwavein; nad++)
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)
671 nt_resyncaudio();
672 return (0);
676 /* test dac sync the same way */
677 for (nda = 0; nda < nt_nwaveout; nda++)
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)
685 nt_resyncaudio();
686 return (0);
689 #ifdef MIDI_TIMESTAMP
690 nt_midisync();
691 #endif
692 return (0);
695 /* ------------------- public routines -------------------------- */
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 */
701 int nbuf;
703 nt_realdacblksize = (sys_blocksize ? sys_blocksize : DEFREALDACBLKSIZE);
704 nbuf = sys_advance_samples/nt_realdacblksize;
705 if (nbuf >= MAXBUFFER)
707 fprintf(stderr, "pd: audio buffering maxed out to %d\n",
708 (int)(MAXBUFFER * ((nt_realdacblksize * 1000.)/44100.)));
709 nbuf = MAXBUFFER;
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;
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();
731 void mmio_reportidle(void)
735 #if 0
736 /* list the audio and MIDI device names */
737 void mmio_listdevs(void)
739 UINT wRtn, ndevices;
740 unsigned int i;
742 ndevices = waveInGetNumDevs();
743 for (i = 0; i < ndevices; i++)
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);
753 ndevices = waveOutGetNumDevs();
754 for (i = 0; i < ndevices; i++)
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);
764 #endif
766 void mmio_getdevs(char *indevlist, int *nindevs,
767 char *outdevlist, int *noutdevs, int *canmulti,
768 int maxndev, int devdescsize)
770 int wRtn, ndev, i;
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++)
779 WAVEINCAPS wicap;
780 wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, sizeof(wicap));
781 sprintf(indevlist + i * devdescsize, (wRtn ? "???" : wicap.szPname));
784 ndev = waveOutGetNumDevs();
785 if (ndev > maxndev)
786 ndev = maxndev;
787 *noutdevs = ndev;
788 for (i = 0; i < ndev; i++)
790 WAVEOUTCAPS wocap;
791 wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, sizeof(wocap));
792 sprintf(outdevlist + i * devdescsize, (wRtn ? "???" : wocap.szPname));