diff options
author | Thomas Grill <xovo@users.sourceforge.net> | 2003-09-23 00:21:28 +0000 |
---|---|---|
committer | Thomas Grill <xovo@users.sourceforge.net> | 2003-09-23 00:21:28 +0000 |
commit | 64fdb009695828b788fce074135b20a5e52c5fc4 (patch) | |
tree | a05144197dd339721b6d4a3a0927f7596e8872b6 /pd/src/s_nt.c | |
parent | a30193fcd726552364de74984b200be2c30723e7 (diff) |
imported version 0.37-0
svn path=/trunk/; revision=1016
Diffstat (limited to 'pd/src/s_nt.c')
-rw-r--r-- | pd/src/s_nt.c | 1586 |
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); - } -} - |