summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/s_audio_mmio.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/s_audio_mmio.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio_mmio.c1588
1 files changed, 1588 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/s_audio_mmio.c b/apps/plugins/pdbox/PDa/src/s_audio_mmio.c
new file mode 100644
index 0000000000..44bbae855b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_audio_mmio.c
@@ -0,0 +1,1588 @@
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
18static void nt_close_midiin(void);
19static void nt_noresync( void);
20
21static 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
29int 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! */
34static int nt_naudiobuffer = DEFBUFFER;
35float sys_dacsr = DEFAULTSRATE;
36
37static int nt_whichapi = API_MMIO;
38static int nt_meters; /* true if we're metering */
39static float nt_inmax; /* max input amplitude */
40static float nt_outmax; /* max output amplitude */
41static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */
42
43typedef 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
51t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */
52HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */
53static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */
54
55t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */
56HWAVEIN ntsnd_indev[NAPORTS]; /* input device */
57static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */
58
59static void nt_waveinerror(char *s, int err)
60{
61 char t[256];
62 waveInGetErrorText(err, t, 256);
63 fprintf(stderr, s, t);
64}
65
66static void nt_waveouterror(char *s, int err)
67{
68 char t[256];
69 waveOutGetErrorText(err, t, 256);
70 fprintf(stderr, s, t);
71}
72
73static 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
118static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER;
119
120int 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
222void 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
256static int nt_adcjitterbufsallowed = ADCJITTER;
257static int nt_dacjitterbufsallowed = DACJITTER;
258
259 /* ------------- MIDI time stamping from audio clock ------------ */
260
261#ifdef MIDI_TIMESTAMP
262
263static double nt_hibuftime;
264static double initsystime = -1;
265
266 /* call this whenever we reset audio */
267static 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
277static 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
294static 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
304static 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 */
310static 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
395reason the sync testing below gives false positives. */
396
397static int nt_resync_cancelled;
398
399static void nt_noresync( void)
400{
401 nt_resync_cancelled = 1;
402}
403
404static 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
468static int nt_errorcount;
469static int nt_resynccount;
470static double nt_nextreporttime = -1;
471
472void 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 */
490t_sample *sys_soundout;
491t_sample *sys_soundin;
492float sys_dacsr;
493
494int 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
652late:
653
654 nt_logerror(LATE);
655 nt_resyncaudio();
656 return (1);
657
658idle:
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
697void 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
731void mmio_reportidle(void)
732{
733}
734
735#if 0
736/* list the audio and MIDI device names */
737void 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
766void 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/* Copyright (c) 1997-1999 Miller Puckette.
796* For information on usage and redistribution, and for a DISCLAIMER OF ALL
797* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
798
799/* modified 2/98 by Winfried Ritsch to deal with up to 4 synchronized
800"wave" devices, which is how ADAT boards appear to the WAVE API. */
801
802#include "m_pd.h"
803#include "s_stuff.h"
804#include <stdio.h>
805
806#include <windows.h>
807
808#include <MMSYSTEM.H>
809
810/* ------------------------- audio -------------------------- */
811
812static void nt_close_midiin(void);
813static void nt_noresync( void);
814
815static void postflags(void);
816
817#define NAPORTS 16 /* wini hack for multiple ADDA devices */
818#define CHANNELS_PER_DEVICE 2
819#define DEFAULTCHANS 2
820#define DEFAULTSRATE 44100
821#define SAMPSIZE 2
822
823int nt_realdacblksize;
824#define DEFREALDACBLKSIZE (4 * DEFDACBLKSIZE) /* larger underlying bufsize */
825
826#define MAXBUFFER 100 /* number of buffers in use at maximum advance */
827#define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */
828static int nt_naudiobuffer = DEFBUFFER;
829float sys_dacsr = DEFAULTSRATE;
830
831static int nt_whichapi = API_MMIO;
832static int nt_meters; /* true if we're metering */
833static float nt_inmax; /* max input amplitude */
834static float nt_outmax; /* max output amplitude */
835static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */
836
837typedef struct _sbuf
838{
839 HANDLE hData;
840 HPSTR lpData; // pointer to waveform data memory
841 HANDLE hWaveHdr;
842 WAVEHDR *lpWaveHdr; // pointer to header structure
843} t_sbuf;
844
845t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */
846HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */
847static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */
848
849t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */
850HWAVEIN ntsnd_indev[NAPORTS]; /* input device */
851static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */
852
853static void nt_waveinerror(char *s, int err)
854{
855 char t[256];
856 waveInGetErrorText(err, t, 256);
857 fprintf(stderr, s, t);
858}
859
860static void nt_waveouterror(char *s, int err)
861{
862 char t[256];
863 waveOutGetErrorText(err, t, 256);
864 fprintf(stderr, s, t);
865}
866
867static void wave_prep(t_sbuf *bp, int setdone)
868{
869 WAVEHDR *wh;
870 short *sp;
871 int i;
872 /*
873 * Allocate and lock memory for the waveform data. The memory
874 * for waveform data must be globally allocated with
875 * GMEM_MOVEABLE and GMEM_SHARE flags.
876 */
877
878 if (!(bp->hData =
879 GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
880 (DWORD) (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize))))
881 printf("alloc 1 failed\n");
882
883 if (!(bp->lpData =
884 (HPSTR) GlobalLock(bp->hData)))
885 printf("lock 1 failed\n");
886
887 /* Allocate and lock memory for the header. */
888
889 if (!(bp->hWaveHdr =
890 GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR))))
891 printf("alloc 2 failed\n");
892
893 if (!(wh = bp->lpWaveHdr =
894 (WAVEHDR *) GlobalLock(bp->hWaveHdr)))
895 printf("lock 2 failed\n");
896
897 for (i = CHANNELS_PER_DEVICE * nt_realdacblksize,
898 sp = (short *)bp->lpData; i--; )
899 *sp++ = 0;
900
901 wh->lpData = bp->lpData;
902 wh->dwBufferLength = (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize);
903 wh->dwFlags = 0;
904 wh->dwLoops = 0L;
905 wh->lpNext = 0;
906 wh->reserved = 0;
907 /* optionally (for writing) set DONE flag as if we had queued them */
908 if (setdone)
909 wh->dwFlags = WHDR_DONE;
910}
911
912static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER;
913
914int mmio_do_open_audio(void)
915{
916 PCMWAVEFORMAT form;
917 int i, j;
918 UINT mmresult;
919 int nad, nda;
920 static int naudioprepped = 0, nindevsprepped = 0, noutdevsprepped = 0;
921 if (sys_verbose)
922 post("%d devices in, %d devices out",
923 nt_nwavein, nt_nwaveout);
924
925 form.wf.wFormatTag = WAVE_FORMAT_PCM;
926 form.wf.nChannels = CHANNELS_PER_DEVICE;
927 form.wf.nSamplesPerSec = sys_dacsr;
928 form.wf.nAvgBytesPerSec = sys_dacsr * (CHANNELS_PER_DEVICE * SAMPSIZE);
929 form.wf.nBlockAlign = CHANNELS_PER_DEVICE * SAMPSIZE;
930 form.wBitsPerSample = 8 * SAMPSIZE;
931
932 if (nt_nwavein <= 1 && nt_nwaveout <= 1)
933 nt_noresync();
934
935 if (nindevsprepped < nt_nwavein)
936 {
937 for (i = nindevsprepped; i < nt_nwavein; i++)
938 for (j = 0; j < naudioprepped; j++)
939 wave_prep(&ntsnd_invec[i][j], 0);
940 nindevsprepped = nt_nwavein;
941 }
942 if (noutdevsprepped < nt_nwaveout)
943 {
944 for (i = noutdevsprepped; i < nt_nwaveout; i++)
945 for (j = 0; j < naudioprepped; j++)
946 wave_prep(&ntsnd_outvec[i][j], 1);
947 noutdevsprepped = nt_nwaveout;
948 }
949 if (naudioprepped < nt_naudiobuffer)
950 {
951 for (j = naudioprepped; j < nt_naudiobuffer; j++)
952 {
953 for (i = 0; i < nt_nwavein; i++)
954 wave_prep(&ntsnd_invec[i][j], 0);
955 for (i = 0; i < nt_nwaveout; i++)
956 wave_prep(&ntsnd_outvec[i][j], 1);
957 }
958 naudioprepped = nt_naudiobuffer;
959 }
960 for (nad=0; nad < nt_nwavein; nad++)
961 {
962 /* Open waveform device(s), sucessively numbered, for input */
963
964 mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad,
965 (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
966
967 if (sys_verbose)
968 printf("opened adc device %d with return %d\n",
969 nt_whichadc+nad,mmresult);
970
971 if (mmresult != MMSYSERR_NOERROR)
972 {
973 nt_waveinerror("waveInOpen: %s\n", mmresult);
974 nt_nwavein = nad; /* nt_nwavein = 0 wini */
975 }
976 else
977 {
978 for (i = 0; i < nt_naudiobuffer; i++)
979 {
980 mmresult = waveInPrepareHeader(ntsnd_indev[nad],
981 ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
982 if (mmresult != MMSYSERR_NOERROR)
983 nt_waveinerror("waveinprepareheader: %s\n", mmresult);
984 mmresult = waveInAddBuffer(ntsnd_indev[nad],
985 ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
986 if (mmresult != MMSYSERR_NOERROR)
987 nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
988 }
989 }
990 }
991 /* quickly start them all together */
992 for (nad = 0; nad < nt_nwavein; nad++)
993 waveInStart(ntsnd_indev[nad]);
994
995 for (nda = 0; nda < nt_nwaveout; nda++)
996 {
997 /* Open a waveform device for output in sucessiv device numbering*/
998 mmresult = waveOutOpen(&ntsnd_outdev[nda], nt_whichdac + nda,
999 (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
1000
1001 if (sys_verbose)
1002 fprintf(stderr,"opened dac device %d, with return %d\n",
1003 nt_whichdac +nda, mmresult);
1004
1005 if (mmresult != MMSYSERR_NOERROR)
1006 {
1007 fprintf(stderr,"Wave out open device %d + %d\n",nt_whichdac,nda);
1008 nt_waveouterror("waveOutOpen device: %s\n", mmresult);
1009 nt_nwaveout = nda;
1010 }
1011 }
1012
1013 return (0);
1014}
1015
1016void mmio_close_audio( void)
1017{
1018 int errcode;
1019 int nda, nad;
1020 if (sys_verbose)
1021 post("closing audio...");
1022
1023 for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */
1024 {
1025 errcode = waveOutReset(ntsnd_outdev[nda]);
1026 if (errcode != MMSYSERR_NOERROR)
1027 printf("error resetting output %d: %d\n", nda, errcode);
1028 errcode = waveOutClose(ntsnd_outdev[nda]);
1029 if (errcode != MMSYSERR_NOERROR)
1030 printf("error closing output %d: %d\n",nda , errcode);
1031 }
1032 nt_nwaveout = 0;
1033
1034 for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */
1035 {
1036 errcode = waveInReset(ntsnd_indev[nad]);
1037 if (errcode != MMSYSERR_NOERROR)
1038 printf("error resetting input: %d\n", errcode);
1039 errcode = waveInClose(ntsnd_indev[nad]);
1040 if (errcode != MMSYSERR_NOERROR)
1041 printf("error closing input: %d\n", errcode);
1042 }
1043 nt_nwavein = 0;
1044}
1045
1046
1047#define ADCJITTER 10 /* We tolerate X buffers of jitter by default */
1048#define DACJITTER 10
1049
1050static int nt_adcjitterbufsallowed = ADCJITTER;
1051static int nt_dacjitterbufsallowed = DACJITTER;
1052
1053 /* ------------- MIDI time stamping from audio clock ------------ */
1054
1055#ifdef MIDI_TIMESTAMP
1056
1057static double nt_hibuftime;
1058static double initsystime = -1;
1059
1060 /* call this whenever we reset audio */
1061static void nt_resetmidisync(void)
1062{
1063 initsystime = clock_getsystime();
1064 nt_hibuftime = sys_getrealtime();
1065}
1066
1067 /* call this whenever we're idled waiting for audio to be ready.
1068 The routine maintains a high and low water point for the difference
1069 between real and DAC time. */
1070
1071static void nt_midisync(void)
1072{
1073 double jittersec, diff;
1074
1075 if (initsystime == -1) nt_resetmidisync();
1076 jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ?
1077 nt_dacjitterbufsallowed : nt_adcjitterbufsallowed)
1078 * nt_realdacblksize / sys_getsr();
1079 diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime);
1080 if (diff > nt_hibuftime) nt_hibuftime = diff;
1081 if (diff < nt_hibuftime - jittersec)
1082 {
1083 post("jitter excess %d %f", dac, diff);
1084 nt_resetmidisync();
1085 }
1086}
1087
1088static double nt_midigettimefor(LARGE_INTEGER timestamp)
1089{
1090 /* this is broken now... used to work when "timestamp" was derived from
1091 QueryPerformanceCounter() instead of the gates approved
1092 timeGetSystemTime() call in the MIDI callback routine below. */
1093 return (nt_tixtotime(timestamp) - nt_hibuftime);
1094}
1095#endif /* MIDI_TIMESTAMP */
1096
1097
1098static int nt_fill = 0;
1099#define WRAPFWD(x) ((x) >= nt_naudiobuffer ? (x) - nt_naudiobuffer: (x))
1100#define WRAPBACK(x) ((x) < 0 ? (x) + nt_naudiobuffer: (x))
1101#define MAXRESYNC 500
1102
1103#if 0 /* this is used for debugging */
1104static void nt_printaudiostatus(void)
1105{
1106 int nad, nda;
1107 for (nad = 0; nad < nt_nwavein; nad++)
1108 {
1109 int phase = ntsnd_inphase[nad];
1110 int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
1111 int firstphasedone = -1, firstphasebusy = -1;
1112 for (count = 0; count < nt_naudiobuffer; count++)
1113 {
1114 int donethis =
1115 (ntsnd_invec[nad][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
1116 int donenext =
1117 (ntsnd_invec[nad][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
1118 if (donethis && !donenext)
1119 {
1120 if (firstphasebusy >= 0) goto multipleadc;
1121 firstphasebusy = count;
1122 }
1123 if (!donethis && donenext)
1124 {
1125 if (firstphasedone >= 0) goto multipleadc;
1126 firstphasedone = count;
1127 }
1128 phase2 = phase3;
1129 phase3 = WRAPFWD(phase2 + 1);
1130 }
1131 post("nad %d phase %d busy %d done %d", nad, phase, firstphasebusy,
1132 firstphasedone);
1133 continue;
1134 multipleadc:
1135 startpost("nad %d phase %d: oops:", nad, phase);
1136 for (count = 0; count < nt_naudiobuffer; count++)
1137 {
1138 char buf[80];
1139 sprintf(buf, " %d",
1140 (ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
1141 poststring(buf);
1142 }
1143 endpost();
1144 }
1145 for (nda = 0; nda < nt_nwaveout; nda++)
1146 {
1147 int phase = ntsnd_outphase[nad];
1148 int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
1149 int firstphasedone = -1, firstphasebusy = -1;
1150 for (count = 0; count < nt_naudiobuffer; count++)
1151 {
1152 int donethis =
1153 (ntsnd_outvec[nda][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
1154 int donenext =
1155 (ntsnd_outvec[nda][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
1156 if (donethis && !donenext)
1157 {
1158 if (firstphasebusy >= 0) goto multipledac;
1159 firstphasebusy = count;
1160 }
1161 if (!donethis && donenext)
1162 {
1163 if (firstphasedone >= 0) goto multipledac;
1164 firstphasedone = count;
1165 }
1166 phase2 = phase3;
1167 phase3 = WRAPFWD(phase2 + 1);
1168 }
1169 if (firstphasebusy < 0) post("nda %d phase %d all %d",
1170 nda, phase, (ntsnd_outvec[nad][0].lpWaveHdr->dwFlags & WHDR_DONE));
1171 else post("nda %d phase %d busy %d done %d", nda, phase, firstphasebusy,
1172 firstphasedone);
1173 continue;
1174 multipledac:
1175 startpost("nda %d phase %d: oops:", nda, phase);
1176 for (count = 0; count < nt_naudiobuffer; count++)
1177 {
1178 char buf[80];
1179 sprintf(buf, " %d",
1180 (ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
1181 poststring(buf);
1182 }
1183 endpost();
1184 }
1185}
1186#endif /* 0 */
1187
1188/* this is a hack to avoid ever resyncing audio pointers in case for whatever
1189reason the sync testing below gives false positives. */
1190
1191static int nt_resync_cancelled;
1192
1193static void nt_noresync( void)
1194{
1195 nt_resync_cancelled = 1;
1196}
1197
1198static void nt_resyncaudio(void)
1199{
1200 UINT mmresult;
1201 int nad, nda, count;
1202 if (nt_resync_cancelled)
1203 return;
1204 /* for each open input device, eat all buffers which are marked
1205 ready. The next one will thus be "busy". */
1206 post("resyncing audio");
1207 for (nad = 0; nad < nt_nwavein; nad++)
1208 {
1209 int phase = ntsnd_inphase[nad];
1210 for (count = 0; count < MAXRESYNC; count++)
1211 {
1212 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
1213 if (!(inwavehdr->dwFlags & WHDR_DONE)) break;
1214 if (inwavehdr->dwFlags & WHDR_PREPARED)
1215 waveInUnprepareHeader(ntsnd_indev[nad],
1216 inwavehdr, sizeof(WAVEHDR));
1217 inwavehdr->dwFlags = 0L;
1218 waveInPrepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR));
1219 mmresult = waveInAddBuffer(ntsnd_indev[nad], inwavehdr,
1220 sizeof(WAVEHDR));
1221 if (mmresult != MMSYSERR_NOERROR)
1222 nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
1223 ntsnd_inphase[nad] = phase = WRAPFWD(phase + 1);
1224 }
1225 if (count == MAXRESYNC) post("resync error 1");
1226 }
1227 /* Each output buffer which is "ready" is filled with zeros and
1228 queued. */
1229 for (nda = 0; nda < nt_nwaveout; nda++)
1230 {
1231 int phase = ntsnd_outphase[nda];
1232 for (count = 0; count < MAXRESYNC; count++)
1233 {
1234 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
1235 if (!(outwavehdr->dwFlags & WHDR_DONE)) break;
1236 if (outwavehdr->dwFlags & WHDR_PREPARED)
1237 waveOutUnprepareHeader(ntsnd_outdev[nda],
1238 outwavehdr, sizeof(WAVEHDR));
1239 outwavehdr->dwFlags = 0L;
1240 memset((char *)(ntsnd_outvec[nda][phase].lpData),
1241 0, (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize));
1242 waveOutPrepareHeader(ntsnd_outdev[nda], outwavehdr,
1243 sizeof(WAVEHDR));
1244 mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr,
1245 sizeof(WAVEHDR));
1246 if (mmresult != MMSYSERR_NOERROR)
1247 nt_waveouterror("waveOutAddBuffer: %s\n", mmresult);
1248 ntsnd_outphase[nda] = phase = WRAPFWD(phase + 1);
1249 }
1250 if (count == MAXRESYNC) post("resync error 2");
1251 }
1252
1253#ifdef MIDI_TIMESTAMP
1254 nt_resetmidisync();
1255#endif
1256
1257}
1258
1259#define LATE 0
1260#define RESYNC 1
1261#define NOTHING 2
1262static int nt_errorcount;
1263static int nt_resynccount;
1264static double nt_nextreporttime = -1;
1265
1266void nt_logerror(int which)
1267{
1268#if 0
1269 post("error %d %d", count, which);
1270 if (which < NOTHING) nt_errorcount++;
1271 if (which == RESYNC) nt_resynccount++;
1272 if (sys_getrealtime() > nt_nextreporttime)
1273 {
1274 post("%d audio I/O error%s", nt_errorcount,
1275 (nt_errorcount > 1 ? "s" : ""));
1276 if (nt_resynccount) post("DAC/ADC sync error");
1277 nt_errorcount = nt_resynccount = 0;
1278 nt_nextreporttime = sys_getrealtime() - 5;
1279 }
1280#endif
1281}
1282
1283/* system buffer with t_sample types for one tick */
1284t_sample *sys_soundout;
1285t_sample *sys_soundin;
1286float sys_dacsr;
1287
1288int mmio_send_dacs(void)
1289{
1290 HMMIO hmmio;
1291 UINT mmresult;
1292 HANDLE hFormat;
1293 int i, j;
1294 short *sp1, *sp2;
1295 float *fp1, *fp2;
1296 int nextfill, doxfer = 0;
1297 int nda, nad;
1298 if (!nt_nwavein && !nt_nwaveout) return (0);
1299
1300
1301 if (nt_meters)
1302 {
1303 int i, n;
1304 float maxsamp;
1305 for (i = 0, n = 2 * nt_nwavein * DEFDACBLKSIZE, maxsamp = nt_inmax;
1306 i < n; i++)
1307 {
1308 float f = sys_soundin[i];
1309 if (f > maxsamp) maxsamp = f;
1310 else if (-f > maxsamp) maxsamp = -f;
1311 }
1312 nt_inmax = maxsamp;
1313 for (i = 0, n = 2 * nt_nwaveout * DEFDACBLKSIZE, maxsamp = nt_outmax;
1314 i < n; i++)
1315 {
1316 float f = sys_soundout[i];
1317 if (f > maxsamp) maxsamp = f;
1318 else if (-f > maxsamp) maxsamp = -f;
1319 }
1320 nt_outmax = maxsamp;
1321 }
1322
1323 /* the "fill pointer" nt_fill controls where in the next
1324 I/O buffers we will write and/or read. If it's zero, we
1325 first check whether the buffers are marked "done". */
1326
1327 if (!nt_fill)
1328 {
1329 for (nad = 0; nad < nt_nwavein; nad++)
1330 {
1331 int phase = ntsnd_inphase[nad];
1332 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
1333 if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle;
1334 }
1335 for (nda = 0; nda < nt_nwaveout; nda++)
1336 {
1337 int phase = ntsnd_outphase[nda];
1338 WAVEHDR *outwavehdr =
1339 ntsnd_outvec[nda][phase].lpWaveHdr;
1340 if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle;
1341 }
1342 for (nad = 0; nad < nt_nwavein; nad++)
1343 {
1344 int phase = ntsnd_inphase[nad];
1345 WAVEHDR *inwavehdr =
1346 ntsnd_invec[nad][phase].lpWaveHdr;
1347 if (inwavehdr->dwFlags & WHDR_PREPARED)
1348 waveInUnprepareHeader(ntsnd_indev[nad],
1349 inwavehdr, sizeof(WAVEHDR));
1350 }
1351 for (nda = 0; nda < nt_nwaveout; nda++)
1352 {
1353 int phase = ntsnd_outphase[nda];
1354 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
1355 if (outwavehdr->dwFlags & WHDR_PREPARED)
1356 waveOutUnprepareHeader(ntsnd_outdev[nda],
1357 outwavehdr, sizeof(WAVEHDR));
1358 }
1359 }
1360
1361 /* Convert audio output to fixed-point and put it in the output
1362 buffer. */
1363 for (nda = 0, fp1 = sys_soundout; nda < nt_nwaveout; nda++)
1364 {
1365 int phase = ntsnd_outphase[nda];
1366
1367 for (i = 0, sp1 = (short *)(ntsnd_outvec[nda][phase].lpData) +
1368 CHANNELS_PER_DEVICE * nt_fill;
1369 i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
1370 {
1371 for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
1372 j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
1373 {
1374 int x1 = 32767.f * *fp2;
1375 if (x1 > 32767) x1 = 32767;
1376 else if (x1 < -32767) x1 = -32767;
1377 *sp2 = x1;
1378 }
1379 }
1380 }
1381 memset(sys_soundout, 0,
1382 (DEFDACBLKSIZE *sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout);
1383
1384 /* vice versa for the input buffer */
1385
1386 for (nad = 0, fp1 = sys_soundin; nad < nt_nwavein; nad++)
1387 {
1388 int phase = ntsnd_inphase[nad];
1389
1390 for (i = 0, sp1 = (short *)(ntsnd_invec[nad][phase].lpData) +
1391 CHANNELS_PER_DEVICE * nt_fill;
1392 i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
1393 {
1394 for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
1395 j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
1396 {
1397 *fp2 = ((float)(1./32767.)) * (float)(*sp2);
1398 }
1399 }
1400 }
1401
1402 nt_fill = nt_fill + DEFDACBLKSIZE;
1403 if (nt_fill == nt_realdacblksize)
1404 {
1405 nt_fill = 0;
1406
1407 for (nad = 0; nad < nt_nwavein; nad++)
1408 {
1409 int phase = ntsnd_inphase[nad];
1410 HWAVEIN device = ntsnd_indev[nad];
1411 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
1412 waveInPrepareHeader(device, inwavehdr, sizeof(WAVEHDR));
1413 mmresult = waveInAddBuffer(device, inwavehdr, sizeof(WAVEHDR));
1414 if (mmresult != MMSYSERR_NOERROR)
1415 nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
1416 ntsnd_inphase[nad] = WRAPFWD(phase + 1);
1417 }
1418 for (nda = 0; nda < nt_nwaveout; nda++)
1419 {
1420 int phase = ntsnd_outphase[nda];
1421 HWAVEOUT device = ntsnd_outdev[nda];
1422 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
1423 waveOutPrepareHeader(device, outwavehdr, sizeof(WAVEHDR));
1424 mmresult = waveOutWrite(device, outwavehdr, sizeof(WAVEHDR));
1425 if (mmresult != MMSYSERR_NOERROR)
1426 nt_waveouterror("waveOutWrite: %s\n", mmresult);
1427 ntsnd_outphase[nda] = WRAPFWD(phase + 1);
1428 }
1429
1430 /* check for DAC underflow or ADC overflow. */
1431 for (nad = 0; nad < nt_nwavein; nad++)
1432 {
1433 int phase = WRAPBACK(ntsnd_inphase[nad] - 2);
1434 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
1435 if (inwavehdr->dwFlags & WHDR_DONE) goto late;
1436 }
1437 for (nda = 0; nda < nt_nwaveout; nda++)
1438 {
1439 int phase = WRAPBACK(ntsnd_outphase[nda] - 2);
1440 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
1441 if (outwavehdr->dwFlags & WHDR_DONE) goto late;
1442 }
1443 }
1444 return (1);
1445
1446late:
1447
1448 nt_logerror(LATE);
1449 nt_resyncaudio();
1450 return (1);
1451
1452idle:
1453
1454 /* If more than nt_adcjitterbufsallowed ADC buffers are ready
1455 on any input device, resynchronize */
1456
1457 for (nad = 0; nad < nt_nwavein; nad++)
1458 {
1459 int phase = ntsnd_inphase[nad];
1460 WAVEHDR *inwavehdr =
1461 ntsnd_invec[nad]
1462 [WRAPFWD(phase + nt_adcjitterbufsallowed)].lpWaveHdr;
1463 if (inwavehdr->dwFlags & WHDR_DONE)
1464 {
1465 nt_resyncaudio();
1466 return (0);
1467 }
1468 }
1469
1470 /* test dac sync the same way */
1471 for (nda = 0; nda < nt_nwaveout; nda++)
1472 {
1473 int phase = ntsnd_outphase[nda];
1474 WAVEHDR *outwavehdr =
1475 ntsnd_outvec[nda]
1476 [WRAPFWD(phase + nt_dacjitterbufsallowed)].lpWaveHdr;
1477 if (outwavehdr->dwFlags & WHDR_DONE)
1478 {
1479 nt_resyncaudio();
1480 return (0);
1481 }
1482 }
1483#ifdef MIDI_TIMESTAMP
1484 nt_midisync();
1485#endif
1486 return (0);
1487}
1488
1489/* ------------------- public routines -------------------------- */
1490
1491void mmio_open_audio(int naudioindev, int *audioindev,
1492 int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
1493 int nchoutdev, int *choutdev, int rate) /* IOhannes */
1494{
1495 int nbuf;
1496
1497 nt_realdacblksize = (sys_blocksize ? sys_blocksize : DEFREALDACBLKSIZE);
1498 nbuf = sys_advance_samples/nt_realdacblksize;
1499 if (nbuf >= MAXBUFFER)
1500 {
1501 fprintf(stderr, "pd: audio buffering maxed out to %d\n",
1502 (int)(MAXBUFFER * ((nt_realdacblksize * 1000.)/44100.)));
1503 nbuf = MAXBUFFER;
1504 }
1505 else if (nbuf < 4) nbuf = 4;
1506 fprintf(stderr, "%d audio buffers\n", nbuf);
1507 nt_naudiobuffer = nbuf;
1508 if (nt_adcjitterbufsallowed > nbuf - 2)
1509 nt_adcjitterbufsallowed = nbuf - 2;
1510 if (nt_dacjitterbufsallowed > nbuf - 2)
1511 nt_dacjitterbufsallowed = nbuf - 2;
1512
1513 nt_nwavein = sys_inchannels / 2;
1514 nt_nwaveout = sys_outchannels / 2;
1515 nt_whichadc = (naudioindev < 1 ?
1516 (nt_nwavein > 1 ? WAVE_MAPPER : -1) : audioindev[0]);
1517 nt_whichdac = (naudiooutdev < 1 ?
1518 (nt_nwaveout > 1 ? WAVE_MAPPER : -1) : audiooutdev[0]);
1519 if (naudiooutdev > 1 || naudioindev > 1)
1520 post("separate audio device choice not supported; using sequential devices.");
1521 mmio_do_open_audio();
1522}
1523
1524
1525void mmio_reportidle(void)
1526{
1527}
1528
1529#if 0
1530/* list the audio and MIDI device names */
1531void mmio_listdevs(void)
1532{
1533 UINT wRtn, ndevices;
1534 unsigned int i;
1535
1536 ndevices = waveInGetNumDevs();
1537 for (i = 0; i < ndevices; i++)
1538 {
1539 WAVEINCAPS wicap;
1540 wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap,
1541 sizeof(wicap));
1542 if (wRtn) nt_waveinerror("waveInGetDevCaps: %s\n", wRtn);
1543 else fprintf(stderr,
1544 "audio input device #%d: %s\n", i+1, wicap.szPname);
1545 }
1546
1547 ndevices = waveOutGetNumDevs();
1548 for (i = 0; i < ndevices; i++)
1549 {
1550 WAVEOUTCAPS wocap;
1551 wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap,
1552 sizeof(wocap));
1553 if (wRtn) nt_waveouterror("waveOutGetDevCaps: %s\n", wRtn);
1554 else fprintf(stderr,
1555 "audio output device #%d: %s\n", i+1, wocap.szPname);
1556 }
1557}
1558#endif
1559
1560void mmio_getdevs(char *indevlist, int *nindevs,
1561 char *outdevlist, int *noutdevs, int *canmulti,
1562 int maxndev, int devdescsize)
1563{
1564 int wRtn, ndev, i;
1565
1566 *canmulti = 2; /* supports multiple devices */
1567 ndev = waveInGetNumDevs();
1568 if (ndev > maxndev)
1569 ndev = maxndev;
1570 *nindevs = ndev;
1571 for (i = 0; i < ndev; i++)
1572 {
1573 WAVEINCAPS wicap;
1574 wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, sizeof(wicap));
1575 sprintf(indevlist + i * devdescsize, (wRtn ? "???" : wicap.szPname));
1576 }
1577
1578 ndev = waveOutGetNumDevs();
1579 if (ndev > maxndev)
1580 ndev = maxndev;
1581 *noutdevs = ndev;
1582 for (i = 0; i < ndev; i++)
1583 {
1584 WAVEOUTCAPS wocap;
1585 wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, sizeof(wocap));
1586 sprintf(outdevlist + i * devdescsize, (wRtn ? "???" : wocap.szPname));
1587 }
1588}