aboutsummaryrefslogtreecommitdiff
path: root/pd/src/s_nt.c
diff options
context:
space:
mode:
Diffstat (limited to 'pd/src/s_nt.c')
-rw-r--r--pd/src/s_nt.c1586
1 files changed, 0 insertions, 1586 deletions
diff --git a/pd/src/s_nt.c b/pd/src/s_nt.c
deleted file mode 100644
index 99346e7c..00000000
--- a/pd/src/s_nt.c
+++ /dev/null
@@ -1,1586 +0,0 @@
-/* Copyright (c) 1997-1999 Miller Puckette.
-* For information on usage and redistribution, and for a DISCLAIMER OF ALL
-* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-
-/* modified 2/98 by Winfried Ritsch to deal with up to 4 synchronized
-"wave" devices, which is how ADAT boards appear to the WAVE API. */
-
-#include "m_imp.h"
-#include <stdio.h>
-
-#include <windows.h>
-
-#include <MMSYSTEM.H>
-
-/* ------------------------- audio -------------------------- */
-
-static void nt_close_midiin(void);
-
-static void postflags(void);
-
-#define NAPORTS 16 /* wini hack for multiple ADDA devices */
-#define NT_MAXCH (2 * NAPORTS)
-#define CHANNELS_PER_DEVICE 2
-#define DEFAULTCHANS 2
-#define DEFAULTSRATE 44100
-#define SAMPSIZE 2
-
-#define REALDACBLKSIZE (4 * DACBLKSIZE) /* larger underlying bufsize */
-
-#define MAXBUFFER 100 /* number of buffers in use at maximum advance */
-#define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */
-static int nt_naudiobuffer = DEFBUFFER;
-static int nt_advance_samples;
-
-float sys_dacsr = DEFAULTSRATE;
-
-static int nt_whichapi = API_MMIO;
-static int nt_meters; /* true if we're metering */
-static float nt_inmax; /* max input amplitude */
-static float nt_outmax; /* max output amplitude */
-static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */
-static int nt_blocksize = 0; /* audio I/O block size in sample frames */
-int sys_schedadvance = 20000; /* scheduler advance in microseconds */
-
-typedef struct _sbuf
-{
- HANDLE hData;
- HPSTR lpData; // pointer to waveform data memory
- HANDLE hWaveHdr;
- WAVEHDR *lpWaveHdr; // pointer to header structure
-} t_sbuf;
-
-t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */
-HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */
-static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */
-
-t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */
-HWAVEIN ntsnd_indev[NAPORTS]; /* input device */
-static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */
-int sys_hipriority = 0;
-
-static void nt_waveinerror(char *s, int err)
-{
- char t[256];
- waveInGetErrorText(err, t, 256);
- fprintf(stderr, s, t);
-}
-
-static void nt_waveouterror(char *s, int err)
-{
- char t[256];
- waveOutGetErrorText(err, t, 256);
- fprintf(stderr, s, t);
-}
-
-static void wave_prep(t_sbuf *bp)
-{
- WAVEHDR *wh;
- short *sp;
- int i;
- /*
- * Allocate and lock memory for the waveform data. The memory
- * for waveform data must be globally allocated with
- * GMEM_MOVEABLE and GMEM_SHARE flags.
- */
-
- if (!(bp->hData =
- GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
- (DWORD) (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE))))
- printf("alloc 1 failed\n");
-
- if (!(bp->lpData =
- (HPSTR) GlobalLock(bp->hData)))
- printf("lock 1 failed\n");
-
- /* Allocate and lock memory for the header. */
-
- if (!(bp->hWaveHdr =
- GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR))))
- printf("alloc 2 failed\n");
-
- if (!(wh = bp->lpWaveHdr =
- (WAVEHDR *) GlobalLock(bp->hWaveHdr)))
- printf("lock 2 failed\n");
-
- for (i = CHANNELS_PER_DEVICE * REALDACBLKSIZE,
- sp = (short *)bp->lpData; i--; )
- *sp++ = 0;
-
- wh->lpData = bp->lpData;
- wh->dwBufferLength = (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE);
- wh->dwFlags = 0;
- wh->dwLoops = 0L;
- wh->lpNext = 0;
- wh->reserved = 0;
-}
-
-static int nt_inalloc[NAPORTS], nt_outalloc[NAPORTS];
-static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER;
-
-int mmio_open_audio(void)
-{
- PCMWAVEFORMAT form;
- int i;
- UINT mmresult;
- int nad, nda;
-
- if (sys_verbose)
- post("%d devices in, %d devices out",
- nt_nwavein, nt_nwaveout);
-
- form.wf.wFormatTag = WAVE_FORMAT_PCM;
- form.wf.nChannels = CHANNELS_PER_DEVICE;
- form.wf.nSamplesPerSec = sys_dacsr;
- form.wf.nAvgBytesPerSec = sys_dacsr * (CHANNELS_PER_DEVICE * SAMPSIZE);
- form.wf.nBlockAlign = CHANNELS_PER_DEVICE * SAMPSIZE;
- form.wBitsPerSample = 8 * SAMPSIZE;
-
- for (nad=0; nad < nt_nwavein; nad++)
- {
- /* Open waveform device(s), sucessively numbered, for input */
-
- mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad,
- (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
-
- if (sys_verbose)
- printf("opened adc device %d with return %d\n",
- nt_whichadc+nad,mmresult);
-
- if (mmresult != MMSYSERR_NOERROR)
- {
- nt_waveinerror("waveInOpen: %s\n", mmresult);
- nt_nwavein = nad; /* nt_nwavein = 0 wini */
- }
- else
- {
- if (!nt_inalloc[nad])
- {
- for (i = 0; i < nt_naudiobuffer; i++)
- wave_prep(&ntsnd_invec[nad][i]);
- nt_inalloc[nad] = 1;
- }
- for (i = 0; i < nt_naudiobuffer; i++)
- {
- mmresult = waveInPrepareHeader(ntsnd_indev[nad],
- ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
- if (mmresult != MMSYSERR_NOERROR)
- nt_waveinerror("waveinprepareheader: %s\n", mmresult);
- mmresult = waveInAddBuffer(ntsnd_indev[nad],
- ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
- if (mmresult != MMSYSERR_NOERROR)
- nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
- }
- }
- }
- /* quickly start them all together */
- for(nad=0; nad < nt_nwavein; nad++)
- waveInStart(ntsnd_indev[nad]);
-
- for(nda=0; nda < nt_nwaveout; nda++)
- {
-
- /* Open a waveform device for output in sucessiv device numbering*/
- mmresult = waveOutOpen(&ntsnd_outdev[nda], nt_whichdac + nda,
- (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
-
- if (sys_verbose)
- fprintf(stderr,"opened dac device %d, with return %d\n",
- nt_whichdac +nda, mmresult);
-
- if (mmresult != MMSYSERR_NOERROR)
- {
- fprintf(stderr,"Wave out open device %d + %d\n",nt_whichdac,nda);
- nt_waveouterror("waveOutOpen device: %s\n", mmresult);
- nt_nwaveout = nda;
- }
- else
- {
- if (!(nt_outalloc[nda]))
- {
- for (i = 0; i < nt_naudiobuffer; i++)
- {
- wave_prep(&ntsnd_outvec[nda][i]);
- /* set DONE flag as if we had queued them */
- ntsnd_outvec[nda][i].lpWaveHdr->dwFlags = WHDR_DONE;
- }
- nt_outalloc[nda] = 1;
- }
- }
- }
-
- return (0);
-}
-
-void mmio_close_audio( void)
-{
- int errcode;
- int nda, nad;
- if (sys_verbose)
- post("closing audio...");
-
- for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */
- {
- errcode = waveOutReset(ntsnd_outdev[nda]);
- if (errcode != MMSYSERR_NOERROR)
- printf("error resetting output %d: %d\n", nda, errcode);
- errcode = waveOutClose(ntsnd_outdev[nda]);
- if (errcode != MMSYSERR_NOERROR)
- printf("error closing output %d: %d\n",nda , errcode);
- }
- nt_nwaveout = 0;
-
- for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */
- {
- errcode = waveInReset(ntsnd_indev[nad]);
- if (errcode != MMSYSERR_NOERROR)
- printf("error resetting input: %d\n", errcode);
- errcode = waveInClose(ntsnd_indev[nad]);
- if (errcode != MMSYSERR_NOERROR)
- printf("error closing input: %d\n", errcode);
- }
- nt_nwavein = 0;
-}
-
-
-#define ADCJITTER 10 /* We tolerate X buffers of jitter by default */
-#define DACJITTER 10
-
-static int nt_adcjitterbufsallowed = ADCJITTER;
-static int nt_dacjitterbufsallowed = DACJITTER;
-
- /* ------------- MIDI time stamping from audio clock ------------ */
-
-#ifdef MIDI_TIMESTAMP
-
-static double nt_hibuftime;
-static double initsystime = -1;
-
- /* call this whenever we reset audio */
-static void nt_resetmidisync(void)
-{
- initsystime = clock_getsystime();
- nt_hibuftime = sys_getrealtime();
-}
-
- /* call this whenever we're idled waiting for audio to be ready.
- The routine maintains a high and low water point for the difference
- between real and DAC time. */
-
-static void nt_midisync(void)
-{
- double jittersec, diff;
-
- if (initsystime == -1) nt_resetmidisync();
- jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ?
- nt_dacjitterbufsallowed : nt_adcjitterbufsallowed)
- * REALDACBLKSIZE / sys_getsr();
- diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime);
- if (diff > nt_hibuftime) nt_hibuftime = diff;
- if (diff < nt_hibuftime - jittersec)
- {
- post("jitter excess %d %f", dac, diff);
- nt_resetmidisync();
- }
-}
-
-static double nt_midigettimefor(LARGE_INTEGER timestamp)
-{
- /* this is broken now... used to work when "timestamp" was derived from
- QueryPerformanceCounter() instead of the gates approved
- timeGetSystemTime() call in the MIDI callback routine below. */
- return (nt_tixtotime(timestamp) - nt_hibuftime);
-}
-#endif /* MIDI_TIMESTAMP */
-
-
-static int nt_fill = 0;
-#define WRAPFWD(x) ((x) >= nt_naudiobuffer ? (x) - nt_naudiobuffer: (x))
-#define WRAPBACK(x) ((x) < 0 ? (x) + nt_naudiobuffer: (x))
-#define MAXRESYNC 500
-
-#if 0 /* this is used for debugging */
-static void nt_printaudiostatus(void)
-{
- int nad, nda;
- for (nad = 0; nad < nt_nwavein; nad++)
- {
- int phase = ntsnd_inphase[nad];
- int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
- int firstphasedone = -1, firstphasebusy = -1;
- for (count = 0; count < nt_naudiobuffer; count++)
- {
- int donethis =
- (ntsnd_invec[nad][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
- int donenext =
- (ntsnd_invec[nad][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
- if (donethis && !donenext)
- {
- if (firstphasebusy >= 0) goto multipleadc;
- firstphasebusy = count;
- }
- if (!donethis && donenext)
- {
- if (firstphasedone >= 0) goto multipleadc;
- firstphasedone = count;
- }
- phase2 = phase3;
- phase3 = WRAPFWD(phase2 + 1);
- }
- post("nad %d phase %d busy %d done %d", nad, phase, firstphasebusy,
- firstphasedone);
- continue;
- multipleadc:
- startpost("nad %d phase %d: oops:", nad, phase);
- for (count = 0; count < nt_naudiobuffer; count++)
- {
- char buf[80];
- sprintf(buf, " %d",
- (ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
- poststring(buf);
- }
- endpost();
- }
- for (nda = 0; nda < nt_nwaveout; nda++)
- {
- int phase = ntsnd_outphase[nad];
- int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
- int firstphasedone = -1, firstphasebusy = -1;
- for (count = 0; count < nt_naudiobuffer; count++)
- {
- int donethis =
- (ntsnd_outvec[nda][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
- int donenext =
- (ntsnd_outvec[nda][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
- if (donethis && !donenext)
- {
- if (firstphasebusy >= 0) goto multipledac;
- firstphasebusy = count;
- }
- if (!donethis && donenext)
- {
- if (firstphasedone >= 0) goto multipledac;
- firstphasedone = count;
- }
- phase2 = phase3;
- phase3 = WRAPFWD(phase2 + 1);
- }
- if (firstphasebusy < 0) post("nda %d phase %d all %d",
- nda, phase, (ntsnd_outvec[nad][0].lpWaveHdr->dwFlags & WHDR_DONE));
- else post("nda %d phase %d busy %d done %d", nda, phase, firstphasebusy,
- firstphasedone);
- continue;
- multipledac:
- startpost("nda %d phase %d: oops:", nda, phase);
- for (count = 0; count < nt_naudiobuffer; count++)
- {
- char buf[80];
- sprintf(buf, " %d",
- (ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
- poststring(buf);
- }
- endpost();
- }
-}
-#endif /* 0 */
-
-/* this is a hack to avoid ever resyncing audio pointers in case for whatever
-reason the sync testing below gives false positives. */
-
-static int nt_resync_cancelled;
-
-void nt_noresync( void)
-{
- nt_resync_cancelled = 1;
-}
-
-static void nt_resyncaudio(void)
-{
- UINT mmresult;
- int nad, nda, count;
- if (nt_resync_cancelled)
- return;
- /* for each open input device, eat all buffers which are marked
- ready. The next one will thus be "busy". */
- post("resyncing audio");
- for (nad = 0; nad < nt_nwavein; nad++)
- {
- int phase = ntsnd_inphase[nad];
- for (count = 0; count < MAXRESYNC; count++)
- {
- WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
- if (!(inwavehdr->dwFlags & WHDR_DONE)) break;
- if (inwavehdr->dwFlags & WHDR_PREPARED)
- waveInUnprepareHeader(ntsnd_indev[nad],
- inwavehdr, sizeof(WAVEHDR));
- inwavehdr->dwFlags = 0L;
- waveInPrepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR));
- mmresult = waveInAddBuffer(ntsnd_indev[nad], inwavehdr,
- sizeof(WAVEHDR));
- if (mmresult != MMSYSERR_NOERROR)
- nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
- ntsnd_inphase[nad] = phase = WRAPFWD(phase + 1);
- }
- if (count == MAXRESYNC) post("resync error 1");
- }
- /* Each output buffer which is "ready" is filled with zeros and
- queued. */
- for (nda = 0; nda < nt_nwaveout; nda++)
- {
- int phase = ntsnd_outphase[nda];
- for (count = 0; count < MAXRESYNC; count++)
- {
- WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
- if (!(outwavehdr->dwFlags & WHDR_DONE)) break;
- if (outwavehdr->dwFlags & WHDR_PREPARED)
- waveOutUnprepareHeader(ntsnd_outdev[nda],
- outwavehdr, sizeof(WAVEHDR));
- outwavehdr->dwFlags = 0L;
- memset((char *)(ntsnd_outvec[nda][phase].lpData),
- 0, (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE));
- waveOutPrepareHeader(ntsnd_outdev[nda], outwavehdr,
- sizeof(WAVEHDR));
- mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr,
- sizeof(WAVEHDR));
- if (mmresult != MMSYSERR_NOERROR)
- nt_waveouterror("waveOutAddBuffer: %s\n", mmresult);
- ntsnd_outphase[nda] = phase = WRAPFWD(phase + 1);
- }
- if (count == MAXRESYNC) post("resync error 2");
- }
-
-#ifdef MIDI_TIMESTAMP
- nt_resetmidisync();
-#endif
-
-}
-
-#define LATE 0
-#define RESYNC 1
-#define NOTHING 2
-static int nt_errorcount;
-static int nt_resynccount;
-static double nt_nextreporttime = -1;
-
-void nt_logerror(int which)
-{
-#if 0
- post("error %d %d", count, which);
- if (which < NOTHING) nt_errorcount++;
- if (which == RESYNC) nt_resynccount++;
- if (sys_getrealtime() > nt_nextreporttime)
- {
- post("%d audio I/O error%s", nt_errorcount,
- (nt_errorcount > 1 ? "s" : ""));
- if (nt_resynccount) post("DAC/ADC sync error");
- nt_errorcount = nt_resynccount = 0;
- nt_nextreporttime = sys_getrealtime() - 5;
- }
-#endif
-}
-
-/* system buffer with t_sample types for one tick */
-t_sample *sys_soundout;
-t_sample *sys_soundin;
-float sys_dacsr;
-
-int mmio_send_dacs(void)
-{
- HMMIO hmmio;
- UINT mmresult;
- HANDLE hFormat;
- int i, j;
- short *sp1, *sp2;
- float *fp1, *fp2;
- int nextfill, doxfer = 0;
- int nda, nad;
- if (!nt_nwavein && !nt_nwaveout) return (0);
-
-
- if (nt_meters)
- {
- int i, n;
- float maxsamp;
- for (i = 0, n = 2 * nt_nwavein * DACBLKSIZE, maxsamp = nt_inmax;
- i < n; i++)
- {
- float f = sys_soundin[i];
- if (f > maxsamp) maxsamp = f;
- else if (-f > maxsamp) maxsamp = -f;
- }
- nt_inmax = maxsamp;
- for (i = 0, n = 2 * nt_nwaveout * DACBLKSIZE, maxsamp = nt_outmax;
- i < n; i++)
- {
- float f = sys_soundout[i];
- if (f > maxsamp) maxsamp = f;
- else if (-f > maxsamp) maxsamp = -f;
- }
- nt_outmax = maxsamp;
- }
-
- /* the "fill pointer" nt_fill controls where in the next
- I/O buffers we will write and/or read. If it's zero, we
- first check whether the buffers are marked "done". */
-
- if (!nt_fill)
- {
- for (nad = 0; nad < nt_nwavein; nad++)
- {
- int phase = ntsnd_inphase[nad];
- WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
- if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle;
- }
- for (nda = 0; nda < nt_nwaveout; nda++)
- {
- int phase = ntsnd_outphase[nda];
- WAVEHDR *outwavehdr =
- ntsnd_outvec[nda][phase].lpWaveHdr;
- if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle;
- }
- for (nad = 0; nad < nt_nwavein; nad++)
- {
- int phase = ntsnd_inphase[nad];
- WAVEHDR *inwavehdr =
- ntsnd_invec[nad][phase].lpWaveHdr;
- if (inwavehdr->dwFlags & WHDR_PREPARED)
- waveInUnprepareHeader(ntsnd_indev[nad],
- inwavehdr, sizeof(WAVEHDR));
- }
- for (nda = 0; nda < nt_nwaveout; nda++)
- {
- int phase = ntsnd_outphase[nda];
- WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
- if (outwavehdr->dwFlags & WHDR_PREPARED)
- waveOutUnprepareHeader(ntsnd_outdev[nda],
- outwavehdr, sizeof(WAVEHDR));
- }
- }
-
- /* Convert audio output to fixed-point and put it in the output
- buffer. */
- for (nda = 0, fp1 = sys_soundout; nda < nt_nwaveout; nda++)
- {
- int phase = ntsnd_outphase[nda];
-
- for (i = 0, sp1 = (short *)(ntsnd_outvec[nda][phase].lpData) +
- CHANNELS_PER_DEVICE * nt_fill;
- i < 2; i++, fp1 += DACBLKSIZE, sp1++)
- {
- for (j = 0, fp2 = fp1, sp2 = sp1; j < DACBLKSIZE;
- j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
- {
- int x1 = 32767.f * *fp2;
- if (x1 > 32767) x1 = 32767;
- else if (x1 < -32767) x1 = -32767;
- *sp2 = x1;
- }
- }
- }
- memset(sys_soundout, 0,
- (DACBLKSIZE*sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout);
-
- /* vice versa for the input buffer */
-
- for (nad = 0, fp1 = sys_soundin; nad < nt_nwavein; nad++)
- {
- int phase = ntsnd_inphase[nad];
-
- for (i = 0, sp1 = (short *)(ntsnd_invec[nad][phase].lpData) +
- CHANNELS_PER_DEVICE * nt_fill;
- i < 2; i++, fp1 += DACBLKSIZE, sp1++)
- {
- for (j = 0, fp2 = fp1, sp2 = sp1; j < DACBLKSIZE;
- j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
- {
- *fp2 = ((float)(1./32767.)) * (float)(*sp2);
- }
- }
- }
-
- nt_fill = nt_fill + DACBLKSIZE;
- if (nt_fill == REALDACBLKSIZE)
- {
- nt_fill = 0;
-
- for (nad = 0; nad < nt_nwavein; nad++)
- {
- int phase = ntsnd_inphase[nad];
- HWAVEIN device = ntsnd_indev[nad];
- WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
- waveInPrepareHeader(device, inwavehdr, sizeof(WAVEHDR));
- mmresult = waveInAddBuffer(device, inwavehdr, sizeof(WAVEHDR));
- if (mmresult != MMSYSERR_NOERROR)
- nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
- ntsnd_inphase[nad] = WRAPFWD(phase + 1);
- }
- for (nda = 0; nda < nt_nwaveout; nda++)
- {
- int phase = ntsnd_outphase[nda];
- HWAVEOUT device = ntsnd_outdev[nda];
- WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
- waveOutPrepareHeader(device, outwavehdr, sizeof(WAVEHDR));
- mmresult = waveOutWrite(device, outwavehdr, sizeof(WAVEHDR));
- if (mmresult != MMSYSERR_NOERROR)
- nt_waveouterror("waveOutWrite: %s\n", mmresult);
- ntsnd_outphase[nda] = WRAPFWD(phase + 1);
- }
-
- /* check for DAC underflow or ADC overflow. */
- for (nad = 0; nad < nt_nwavein; nad++)
- {
- int phase = WRAPBACK(ntsnd_inphase[nad] - 2);
- WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
- if (inwavehdr->dwFlags & WHDR_DONE) goto late;
- }
- for (nda = 0; nda < nt_nwaveout; nda++)
- {
- int phase = WRAPBACK(ntsnd_outphase[nda] - 2);
- WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
- if (outwavehdr->dwFlags & WHDR_DONE) goto late;
- }
- }
- return (1);
-
-late:
-
- nt_logerror(LATE);
- nt_resyncaudio();
- return (1);
-
-idle:
-
- /* If more than nt_adcjitterbufsallowed ADC buffers are ready
- on any input device, resynchronize */
-
- for (nad = 0; nad < nt_nwavein; nad++)
- {
- int phase = ntsnd_inphase[nad];
- WAVEHDR *inwavehdr =
- ntsnd_invec[nad]
- [WRAPFWD(phase + nt_adcjitterbufsallowed)].lpWaveHdr;
- if (inwavehdr->dwFlags & WHDR_DONE)
- {
- nt_resyncaudio();
- return (0);
- }
- }
-
- /* test dac sync the same way */
- for (nda = 0; nda < nt_nwaveout; nda++)
- {
- int phase = ntsnd_outphase[nda];
- WAVEHDR *outwavehdr =
- ntsnd_outvec[nda]
- [WRAPFWD(phase + nt_dacjitterbufsallowed)].lpWaveHdr;
- if (outwavehdr->dwFlags & WHDR_DONE)
- {
- nt_resyncaudio();
- return (0);
- }
- }
-#ifdef MIDI_TIMESTAMP
- nt_midisync();
-#endif
- return (0);
-}
-
-
-static void nt_setchsr(int inchannels, int outchannels, int sr)
-{
- int inbytes = inchannels * (DACBLKSIZE*sizeof(float));
- int outbytes = outchannels * (DACBLKSIZE*sizeof(float));
-
- if (nt_nwavein)
- free(sys_soundin);
- if (nt_nwaveout)
- free(sys_soundout);
-
- nt_nwavein = inchannels/CHANNELS_PER_DEVICE;
- nt_nwaveout = outchannels/CHANNELS_PER_DEVICE;
- sys_dacsr = sr;
-
- sys_soundin = (t_float *)malloc(inbytes);
- memset(sys_soundin, 0, inbytes);
-
- sys_soundout = (t_float *)malloc(outbytes);
- memset(sys_soundout, 0, outbytes);
-
- nt_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.);
- if (nt_advance_samples < 3 * DACBLKSIZE)
- nt_advance_samples = 3 * DACBLKSIZE;
-}
-
-/* ------------------------- MIDI output -------------------------- */
-static void nt_midiouterror(char *s, int err)
-{
- char t[256];
- midiOutGetErrorText(err, t, 256);
- fprintf(stderr, s, t);
-}
-
-static HMIDIOUT hMidiOut[MAXMIDIOUTDEV]; /* output device */
-static int nt_nmidiout; /* number of devices */
-
-static void nt_open_midiout(int nmidiout, int *midioutvec)
-{
- UINT result, wRtn;
- int i;
- int dev;
- MIDIOUTCAPS midioutcaps;
- if (nmidiout > MAXMIDIOUTDEV)
- nmidiout = MAXMIDIOUTDEV;
-
- dev = 0;
-
- for (i = 0; i < nmidiout; i++)
- {
- MIDIOUTCAPS mocap;
- result = midiOutOpen(&hMidiOut[dev], midioutvec[i]-1, 0, 0,
- CALLBACK_NULL);
- wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap,
- sizeof(mocap));
- if (result != MMSYSERR_NOERROR)
- {
- fprintf(stderr,"midiOutOpen: %s\n",midioutcaps.szPname);
- nt_midiouterror("midiOutOpen: %s\n", result);
- }
- else
- {
- if (sys_verbose)
- fprintf(stderr,"midiOutOpen: Open %s as Port %d\n",
- midioutcaps.szPname, dev);
- dev++;
- }
- }
- nt_nmidiout = dev;
-}
-
-void sys_putmidimess(int portno, int a, int b, int c)
-{
- DWORD foo;
- MMRESULT res;
- if (portno >= 0 && portno < nt_nmidiout)
- {
- foo = (a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16);
- res = midiOutShortMsg(hMidiOut[portno], foo);
- if (res != MMSYSERR_NOERROR)
- post("MIDI out error %d", res);
- }
-}
-
-void sys_putmidibyte(int portno, int byte)
-{
- MMRESULT res;
- if (portno >= 0 && portno < nt_nmidiout)
- {
- res = midiOutShortMsg(hMidiOut[portno], byte);
- if (res != MMSYSERR_NOERROR)
- post("MIDI out error %d", res);
- }
-}
-
-static void nt_close_midiout(void)
-{
- int i;
- for (i = 0; i < nt_nmidiout; i++)
- {
- midiOutReset(hMidiOut[i]);
- midiOutClose(hMidiOut[i]);
- }
- nt_nmidiout = 0;
-}
-
-/* -------------------------- MIDI input ---------------------------- */
-
-#define INPUT_BUFFER_SIZE 1000 // size of input buffer in events
-
-static void nt_midiinerror(char *s, int err)
-{
- char t[256];
- midiInGetErrorText(err, t, 256);
- fprintf(stderr, s, t);
-}
-
-
-/* Structure to represent a single MIDI event.
- */
-
-#define EVNT_F_ERROR 0x00000001L
-
-typedef struct event_tag
-{
- DWORD fdwEvent;
- DWORD dwDevice;
- LARGE_INTEGER timestamp;
- DWORD data;
-} EVENT;
-typedef EVENT FAR *LPEVENT;
-
-/* Structure to manage the circular input buffer.
- */
-typedef struct circularBuffer_tag
-{
- HANDLE hSelf; /* handle to this structure */
- HANDLE hBuffer; /* buffer handle */
- WORD wError; /* error flags */
- DWORD dwSize; /* buffer size (in EVENTS) */
- DWORD dwCount; /* byte count (in EVENTS) */
- LPEVENT lpStart; /* ptr to start of buffer */
- LPEVENT lpEnd; /* ptr to end of buffer (last byte + 1) */
- LPEVENT lpHead; /* ptr to head (next location to fill) */
- LPEVENT lpTail; /* ptr to tail (next location to empty) */
-} CIRCULARBUFFER;
-typedef CIRCULARBUFFER FAR *LPCIRCULARBUFFER;
-
-
-/* Structure to pass instance data from the application
- to the low-level callback function.
- */
-typedef struct callbackInstance_tag
-{
- HANDLE hSelf;
- DWORD dwDevice;
- LPCIRCULARBUFFER lpBuf;
-} CALLBACKINSTANCEDATA;
-typedef CALLBACKINSTANCEDATA FAR *LPCALLBACKINSTANCEDATA;
-
-/* Function prototypes
- */
-LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData(void);
-void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf);
-
-LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize);
-void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf);
-WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent);
-
-// Callback instance data pointers
-LPCALLBACKINSTANCEDATA lpCallbackInstanceData[MAXMIDIINDEV];
-
-UINT wNumDevices = 0; // Number of MIDI input devices opened
-BOOL bRecordingEnabled = 1; // Enable/disable recording flag
-int nNumBufferLines = 0; // Number of lines in display buffer
-RECT rectScrollClip; // Clipping rectangle for scrolling
-
-LPCIRCULARBUFFER lpInputBuffer; // Input buffer structure
-EVENT incomingEvent; // Incoming MIDI event structure
-
-MIDIINCAPS midiInCaps[MAXMIDIINDEV]; // Device capabilities structures
-HMIDIIN hMidiIn[MAXMIDIINDEV]; // MIDI input device handles
-
-
-/* AllocCallbackInstanceData - Allocates a CALLBACKINSTANCEDATA
- * structure. This structure is used to pass information to the
- * low-level callback function, each time it receives a message.
- *
- * Because this structure is accessed by the low-level callback
- * function, it must be allocated using GlobalAlloc() with the
- * GMEM_SHARE and GMEM_MOVEABLE flags and page-locked with
- * GlobalPageLock().
- *
- * Params: void
- *
- * Return: A pointer to the allocated CALLBACKINSTANCE data structure.
- */
-LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData(void)
-{
- HANDLE hMem;
- LPCALLBACKINSTANCEDATA lpBuf;
-
- /* Allocate and lock global memory.
- */
- hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE,
- (DWORD)sizeof(CALLBACKINSTANCEDATA));
- if(hMem == NULL)
- return NULL;
-
- lpBuf = (LPCALLBACKINSTANCEDATA)GlobalLock(hMem);
- if(lpBuf == NULL){
- GlobalFree(hMem);
- return NULL;
- }
-
- /* Page lock the memory.
- */
- //GlobalPageLock((HGLOBAL)HIWORD(lpBuf));
-
- /* Save the handle.
- */
- lpBuf->hSelf = hMem;
-
- return lpBuf;
-}
-
-/* FreeCallbackInstanceData - Frees the given CALLBACKINSTANCEDATA structure.
- *
- * Params: lpBuf - Points to the CALLBACKINSTANCEDATA structure to be freed.
- *
- * Return: void
- */
-void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf)
-{
- HANDLE hMem;
-
- /* Save the handle until we're through here.
- */
- hMem = lpBuf->hSelf;
-
- /* Free the structure.
- */
- //GlobalPageUnlock((HGLOBAL)HIWORD(lpBuf));
- GlobalUnlock(hMem);
- GlobalFree(hMem);
-}
-
-
-/*
- * AllocCircularBuffer - Allocates memory for a CIRCULARBUFFER structure
- * and a buffer of the specified size. Each memory block is allocated
- * with GlobalAlloc() using GMEM_SHARE and GMEM_MOVEABLE flags, locked
- * with GlobalLock(), and page-locked with GlobalPageLock().
- *
- * Params: dwSize - The size of the buffer, in events.
- *
- * Return: A pointer to a CIRCULARBUFFER structure identifying the
- * allocated display buffer. NULL if the buffer could not be allocated.
- */
-
-
-LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize)
-{
- HANDLE hMem;
- LPCIRCULARBUFFER lpBuf;
- LPEVENT lpMem;
-
- /* Allocate and lock a CIRCULARBUFFER structure.
- */
- hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE,
- (DWORD)sizeof(CIRCULARBUFFER));
- if(hMem == NULL)
- return NULL;
-
- lpBuf = (LPCIRCULARBUFFER)GlobalLock(hMem);
- if(lpBuf == NULL)
- {
- GlobalFree(hMem);
- return NULL;
- }
-
- /* Page lock the memory. Global memory blocks accessed by
- * low-level callback functions must be page locked.
- */
-#ifndef _WIN32
- GlobalSmartPageLock((HGLOBAL)HIWORD(lpBuf));
-#endif
-
- /* Save the memory handle.
- */
- lpBuf->hSelf = hMem;
-
- /* Allocate and lock memory for the actual buffer.
- */
- hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, dwSize * sizeof(EVENT));
- if(hMem == NULL)
- {
-#ifndef _WIN32
- GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
-#endif
- GlobalUnlock(lpBuf->hSelf);
- GlobalFree(lpBuf->hSelf);
- return NULL;
- }
-
- lpMem = (LPEVENT)GlobalLock(hMem);
- if(lpMem == NULL)
- {
- GlobalFree(hMem);
-#ifndef _WIN32
- GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
-#endif
- GlobalUnlock(lpBuf->hSelf);
- GlobalFree(lpBuf->hSelf);
- return NULL;
- }
-
- /* Page lock the memory. Global memory blocks accessed by
- * low-level callback functions must be page locked.
- */
-#ifndef _WIN32
- GlobalSmartPageLock((HGLOBAL)HIWORD(lpMem));
-#endif
-
- /* Set up the CIRCULARBUFFER structure.
- */
- lpBuf->hBuffer = hMem;
- lpBuf->wError = 0;
- lpBuf->dwSize = dwSize;
- lpBuf->dwCount = 0L;
- lpBuf->lpStart = lpMem;
- lpBuf->lpEnd = lpMem + dwSize;
- lpBuf->lpTail = lpMem;
- lpBuf->lpHead = lpMem;
-
- return lpBuf;
-}
-
-/* FreeCircularBuffer - Frees the memory for the given CIRCULARBUFFER
- * structure and the memory for the buffer it references.
- *
- * Params: lpBuf - Points to the CIRCULARBUFFER to be freed.
- *
- * Return: void
- */
-void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf)
-{
- HANDLE hMem;
-
- /* Free the buffer itself.
- */
-#ifndef _WIN32
- GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf->lpStart));
-#endif
- GlobalUnlock(lpBuf->hBuffer);
- GlobalFree(lpBuf->hBuffer);
-
- /* Free the CIRCULARBUFFER structure.
- */
- hMem = lpBuf->hSelf;
-#ifndef _WIN32
- GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
-#endif
- GlobalUnlock(hMem);
- GlobalFree(hMem);
-}
-
-/* GetEvent - Gets a MIDI event from the circular input buffer. Events
- * are removed from the buffer. The corresponding PutEvent() function
- * is called by the low-level callback function, so it must reside in
- * the callback DLL. PutEvent() is defined in the CALLBACK.C module.
- *
- * Params: lpBuf - Points to the circular buffer.
- * lpEvent - Points to an EVENT structure that is filled with the
- * retrieved event.
- *
- * Return: Returns non-zero if successful, zero if there are no
- * events to get.
- */
-WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent)
-{
- /* If no event available, return */
- if (!wNumDevices || lpBuf->dwCount <= 0) return (0);
-
- /* Get the event.
- */
- *lpEvent = *lpBuf->lpTail;
-
- /* Decrement the byte count, bump the tail pointer.
- */
- --lpBuf->dwCount;
- ++lpBuf->lpTail;
-
- /* Wrap the tail pointer, if necessary.
- */
- if(lpBuf->lpTail >= lpBuf->lpEnd)
- lpBuf->lpTail = lpBuf->lpStart;
-
- return 1;
-}
-
-/* PutEvent - Puts an EVENT in a CIRCULARBUFFER. If the buffer is full,
- * it sets the wError element of the CIRCULARBUFFER structure
- * to be non-zero.
- *
- * Params: lpBuf - Points to the CIRCULARBUFFER.
- * lpEvent - Points to the EVENT.
- *
- * Return: void
-*/
-
-void FAR PASCAL PutEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent)
-{
- /* If the buffer is full, set an error and return.
- */
- if(lpBuf->dwCount >= lpBuf->dwSize){
- lpBuf->wError = 1;
- return;
- }
-
- /* Put the event in the buffer, bump the head pointer and the byte count.
- */
- *lpBuf->lpHead = *lpEvent;
-
- ++lpBuf->lpHead;
- ++lpBuf->dwCount;
-
- /* Wrap the head pointer, if necessary.
- */
- if(lpBuf->lpHead >= lpBuf->lpEnd)
- lpBuf->lpHead = lpBuf->lpStart;
-}
-
-/* midiInputHandler - Low-level callback function to handle MIDI input.
- * Installed by midiInOpen(). The input handler takes incoming
- * MIDI events and places them in the circular input buffer. It then
- * notifies the application by posting a MM_MIDIINPUT message.
- *
- * This function is accessed at interrupt time, so it should be as
- * fast and efficient as possible. You can't make any
- * Windows calls here, except PostMessage(). The only Multimedia
- * Windows call you can make are timeGetSystemTime(), midiOutShortMsg().
- *
- *
- * Param: hMidiIn - Handle for the associated input device.
- * wMsg - One of the MIM_***** messages.
- * dwInstance - Points to CALLBACKINSTANCEDATA structure.
- * dwParam1 - MIDI data.
- * dwParam2 - Timestamp (in milliseconds)
- *
- * Return: void
- */
-void FAR PASCAL midiInputHandler(
-HMIDIIN hMidiIn,
-WORD wMsg,
-DWORD dwInstance,
-DWORD dwParam1,
-DWORD dwParam2)
-{
- EVENT event;
-
- switch(wMsg)
- {
- case MIM_OPEN:
- break;
-
- /* The only error possible is invalid MIDI data, so just pass
- * the invalid data on so we'll see it.
- */
- case MIM_ERROR:
- case MIM_DATA:
- event.fdwEvent = (wMsg == MIM_ERROR) ? EVNT_F_ERROR : 0;
- event.dwDevice = ((LPCALLBACKINSTANCEDATA)dwInstance)->dwDevice;
- event.data = dwParam1;
-#ifdef MIDI_TIMESTAMP
- event.timestamp = timeGetSystemTime();
-#endif
- /* Put the MIDI event in the circular input buffer.
- */
-
- PutEvent(((LPCALLBACKINSTANCEDATA)dwInstance)->lpBuf,
- (LPEVENT) &event);
-
- break;
-
- default:
- break;
- }
-}
-
-void nt_open_midiin(int nmidiin, int *midiinvec)
-{
- UINT wRtn;
- char szErrorText[256];
- unsigned int i;
- unsigned int ndev = 0;
- /* Allocate a circular buffer for low-level MIDI input. This buffer
- * is filled by the low-level callback function and emptied by the
- * application.
- */
- lpInputBuffer = AllocCircularBuffer((DWORD)(INPUT_BUFFER_SIZE));
- if (lpInputBuffer == NULL)
- {
- printf("Not enough memory available for input buffer.\n");
- return;
- }
-
- /* Open all MIDI input devices after allocating and setting up
- * instance data for each device. The instance data is used to
- * pass buffer management information between the application and
- * the low-level callback function. It also includes a device ID,
- * a handle to the MIDI Mapper, and a handle to the application's
- * display window, so the callback can notify the window when input
- * data is available. A single callback function is used to service
- * all opened input devices.
- */
- for (i=0; (i<(unsigned)nmidiin) && (i<MAXMIDIINDEV); i++)
- {
- if ((lpCallbackInstanceData[ndev] = AllocCallbackInstanceData()) == NULL)
- {
- printf("Not enough memory available.\n");
- FreeCircularBuffer(lpInputBuffer);
- return;
- }
- lpCallbackInstanceData[i]->dwDevice = i;
- lpCallbackInstanceData[i]->lpBuf = lpInputBuffer;
-
- wRtn = midiInOpen((LPHMIDIIN)&hMidiIn[ndev],
- midiinvec[i] - 1,
- (DWORD)midiInputHandler,
- (DWORD)lpCallbackInstanceData[ndev],
- CALLBACK_FUNCTION);
- if (wRtn)
- {
- FreeCallbackInstanceData(lpCallbackInstanceData[ndev]);
- nt_midiinerror("midiInOpen: %s\n", wRtn);
- }
- else ndev++;
- }
-
- /* Start MIDI input.
- */
- for (i=0; i<ndev; i++)
- {
- if (hMidiIn[i])
- midiInStart(hMidiIn[i]);
- }
- wNumDevices = ndev;
-}
-
-static void nt_close_midiin(void)
-{
- unsigned int i;
- /* Stop, reset, close MIDI input. Free callback instance data.
- */
-
- for (i=0; (i<wNumDevices) && (i<MAXMIDIINDEV); i++)
- {
- if (hMidiIn[i])
- {
- if (sys_verbose)
- post("closing MIDI input %d...", i);
- midiInStop(hMidiIn[i]);
- midiInReset(hMidiIn[i]);
- midiInClose(hMidiIn[i]);
- FreeCallbackInstanceData(lpCallbackInstanceData[i]);
- }
- }
-
- /* Free input buffer.
- */
- if (lpInputBuffer)
- FreeCircularBuffer(lpInputBuffer);
-
- if (sys_verbose)
- post("...done");
- wNumDevices = 0;
-}
-
-void inmidi_noteon(int portno, int channel, int pitch, int velo);
-void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
-void inmidi_programchange(int portno, int channel, int value);
-void inmidi_pitchbend(int portno, int channel, int value);
-void inmidi_aftertouch(int portno, int channel, int value);
-void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
-void inmidi_realtimein(int portno, int rtmsg);
-
-void sys_poll_midi(void)
-{
- static EVENT nt_nextevent;
- static int nt_isnextevent;
- static double nt_nexteventtime;
-
- while (1)
- {
- if (!nt_isnextevent)
- {
- if (!GetEvent(lpInputBuffer, &nt_nextevent)) break;
- nt_isnextevent = 1;
-#ifdef MIDI_TIMESTAMP
- nt_nexteventtime = nt_midigettimefor(&foo.timestamp);
-#endif
- }
-#ifdef MIDI_TIMESTAMP
- if (0.001 * clock_gettimesince(initsystime) >= nt_nexteventtime)
-#endif
- {
- int msgtype = ((nt_nextevent.data & 0xf0) >> 4) - 8;
- int commandbyte = nt_nextevent.data & 0xff;
- int byte1 = (nt_nextevent.data >> 8) & 0xff;
- int byte2 = (nt_nextevent.data >> 16) & 0xff;
- int portno = nt_nextevent.dwDevice;
- switch (msgtype)
- {
- case 0:
- case 1:
- case 2:
- case 3:
- case 6:
- sys_midibytein(portno, commandbyte);
- sys_midibytein(portno, byte1);
- sys_midibytein(portno, byte2);
- break;
- case 4:
- case 5:
- sys_midibytein(portno, commandbyte);
- sys_midibytein(portno, byte1);
- break;
- case 7:
- sys_midibytein(portno, commandbyte);
- break;
- }
- nt_isnextevent = 0;
- }
- }
-}
-
-/* ------------------- public routines -------------------------- */
-
-void sys_open_audio(int naudioindev, int *audioindev,
- int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
- int nchoutdev, int *choutdev, int rate) /* IOhannes */
-{
- int inchans, outchans;
- if (nchindev < 0)
- inchans = (nchindev < 1 ? -1 : chindev[0]);
- else
- {
- int i = nchindev;
- int *l = chindev;
- inchans = 0;
- while (i--)
- inchans += *l++;
- }
- if (nchoutdev<0)
- outchans = (nchoutdev < 1 ? -1 : choutdev[0]);
- else
- {
- int i = nchoutdev;
- int *l = choutdev;
- outchans = 0;
- while (i--)
- outchans += *l++;
- }
- if (inchans < 0)
- inchans = DEFAULTCHANS;
- if (outchans < 0)
- outchans = DEFAULTCHANS;
- if (inchans & 1)
- {
- post("input channels rounded up to even number");
- inchans += 1;
- }
- if (outchans & 1)
- {
- post("output channels rounded up to even number");
- outchans += 1;
- }
- if (inchans > NT_MAXCH)
- inchans = NT_MAXCH;
- if (outchans > NT_MAXCH)
- outchans = NT_MAXCH;
- if (sys_verbose)
- post("channels in %d, out %d", inchans, outchans);
- if (rate < 1)
- rate = DEFAULTSRATE;
- nt_setchsr(inchans, outchans, rate);
- if (nt_whichapi == API_PORTAUDIO)
- {
- int blocksize = (nt_blocksize ? nt_blocksize : 256);
- if (blocksize != (1 << ilog2(blocksize)))
- post("warning: blocksize adjusted to power of 2: %d",
- (blocksize = (1 << ilog2(blocksize))));
- pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout,
- blocksize, nt_advance_samples/blocksize,
- (naudioindev < 1 ? -1 : audioindev[0]),
- (naudiooutdev < 1 ? -1 : audiooutdev[0]));
- }
- else
- {
- nt_nwavein = inchans / 2;
- nt_nwaveout = outchans / 2;
- nt_whichdac = (naudiooutdev < 1 ? (nt_nwaveout > 1 ? 0 : -1) : audiooutdev[0] - 1);
- nt_whichadc = (naudioindev < 1 ? (nt_nwavein > 1 ? 0 : -1) : audioindev[0] - 1);
- if (naudiooutdev > 1 || naudioindev > 1)
- post("separate audio device choice not supported; using sequential devices.");
- if (nt_blocksize)
- post("warning: blocksize not settable for MMIO, just ASIO");
- mmio_open_audio();
- }
-}
-
-void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec)
-{
- if (nmidiout)
- nt_open_midiout(nmidiout, midioutvec);
- if (nmidiin)
- {
- post(
- "midi input enabled; warning, don't close the DOS window directly!");
- nt_open_midiin(nmidiin, midiinvec);
- }
- else post("not using MIDI input (use 'pd -midiindev 1' to override)");
-}
-
-float sys_getsr(void)
-{
- return (sys_dacsr);
-}
-
-int sys_get_inchannels(void)
-{
- return (2 * nt_nwavein);
-}
-
-int sys_get_outchannels(void)
-{
- return (2 * nt_nwaveout);
-}
-
-void sys_audiobuf(int n)
-{
- /* set the size, in msec, of the audio FIFO. It's incorrect to
- calculate this on the basis of 44100 sample rate; really, the
- work should have been done in nt_setchsr(). */
- int nbuf = n * (44100./(REALDACBLKSIZE * 1000.));
- if (nbuf >= MAXBUFFER)
- {
- fprintf(stderr, "pd: audio buffering maxed out to %d\n",
- (int)(MAXBUFFER * ((REALDACBLKSIZE * 1000.)/44100.)));
- nbuf = MAXBUFFER;
- }
- else if (nbuf < 4) nbuf = 4;
- fprintf(stderr, "%d audio buffers\n", nbuf);
- nt_naudiobuffer = nbuf;
- if (nt_adcjitterbufsallowed > nbuf - 2)
- nt_adcjitterbufsallowed = nbuf - 2;
- if (nt_dacjitterbufsallowed > nbuf - 2)
- nt_dacjitterbufsallowed = nbuf - 2;
- sys_schedadvance = 1000 * n;
-}
-
-void sys_getmeters(float *inmax, float *outmax)
-{
- if (inmax)
- {
- nt_meters = 1;
- *inmax = nt_inmax;
- *outmax = nt_outmax;
- }
- else
- nt_meters = 0;
- nt_inmax = nt_outmax = 0;
-}
-
-void sys_reportidle(void)
-{
-}
-
-int sys_send_dacs(void)
-{
- if (nt_whichapi == API_PORTAUDIO)
- return (pa_send_dacs());
- else return (mmio_send_dacs());
-}
-
-void sys_close_audio( void)
-{
- if (nt_whichapi == API_PORTAUDIO)
- pa_close_audio();
- else mmio_close_audio();
-}
-
-void sys_close_midi( void)
-{
- nt_close_midiin();
- nt_close_midiout();
-}
-
-void sys_setblocksize(int n)
-{
- if (n < 1)
- n = 1;
- nt_blocksize = n;
-}
-
-/* ----------- public routines which are only defined for MSW/NT ---------- */
-
-/* select between MMIO and ASIO audio APIs */
-void nt_set_sound_api(int which)
-{
- nt_whichapi = which;
- if (sys_verbose)
- post("nt_whichapi %d", nt_whichapi);
-}
-
-/* list the audio and MIDI device names */
-void sys_listdevs(void)
-{
- UINT wRtn, ndevices;
- unsigned int i;
-
- /* for MIDI and audio in and out, get the number of devices.
- Then get the capabilities of each device and print its description. */
-
- ndevices = midiInGetNumDevs();
- for (i = 0; i < ndevices; i++)
- {
- MIDIINCAPS micap;
- wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) &micap,
- sizeof(micap));
- if (wRtn) nt_midiinerror("midiInGetDevCaps: %s\n", wRtn);
- else fprintf(stderr,
- "MIDI input device #%d: %s\n", i+1, micap.szPname);
- }
-
- ndevices = midiOutGetNumDevs();
- for (i = 0; i < ndevices; i++)
- {
- MIDIOUTCAPS mocap;
- wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap,
- sizeof(mocap));
- if (wRtn) nt_midiouterror("midiOutGetDevCaps: %s\n", wRtn);
- else fprintf(stderr,
- "MIDI output device #%d: %s\n", i+1, mocap.szPname);
- }
-
- if (nt_whichapi == API_PORTAUDIO)
- {
- pa_listdevs();
- return;
- }
- ndevices = waveInGetNumDevs();
- for (i = 0; i < ndevices; i++)
- {
- WAVEINCAPS wicap;
- wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap,
- sizeof(wicap));
- if (wRtn) nt_waveinerror("waveInGetDevCaps: %s\n", wRtn);
- else fprintf(stderr,
- "audio input device #%d: %s\n", i+1, wicap.szPname);
- }
-
- ndevices = waveOutGetNumDevs();
- for (i = 0; i < ndevices; i++)
- {
- WAVEOUTCAPS wocap;
- wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap,
- sizeof(wocap));
- if (wRtn) nt_waveouterror("waveOutGetDevCaps: %s\n", wRtn);
- else fprintf(stderr,
- "audio output device #%d: %s\n", i+1, wocap.szPname);
- }
-}
-
-void nt_soundindev(int which)
-{
- nt_whichadc = which - 1;
-}
-
-void nt_soundoutdev(int which)
-{
- nt_whichdac = which - 1;
-}
-
-void glob_audio(void *dummy, t_floatarg fadc, t_floatarg fdac)
-{
- int adc = fadc, dac = fdac;
- if (!dac && !adc)
- post("%d channels in, %d channels out",
- 2 * nt_nwavein, 2 * nt_nwaveout);
- else
- {
- sys_close_audio();
- sys_open_audio(1, 0, 1, 0, /* dummy parameters */
- 1, &adc, 1, &dac, sys_dacsr);
- }
-}
-