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.c795
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
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