📄 wavepdd.c
字号:
/*
* Copyright (C) NEC Electronics Inc. 1997-1999.
*
* File: Wavepdd.c
*
* VRC4173 WaveDev PDD
*/
#include <windows.h>
#include <types.h>
#include <memory.h>
#include <excpt.h>
#include <wavepdd.h>
#include <waveddsi.h>
//#include <nkintr.h>
//#include <oalintr.h>
#include <wavedbg.h>
#include <drvlib.h>
#include <vrc4173.h>
//#include "eagle.h"
static int SampleRate[2];
static void (*GetBuf)(PWAVEHDR pwh, ULONG page, ULONG nSamples);
static void (*FillBuf)(PWAVEHDR pwh, ULONG page, ULONG nSamples);
static ULONG physDMAbase[2];
static PBYTE dma_page[2][2];
static BOOL AIUactive[2];
static ULONG v_nVolume; // used for GETVOLUME and SETVOLUME
static LONG Volume; // real volume
static BOOL v_fMoreData[2];
static ULONG v_nNextPage[2];
static BOOL InPowerHandler = FALSE;
static BOOL initialized = FALSE;
#define SAMPLERATE_MAXDIFF 1000 // Maximum allow sampling rate difference for output
#define AUDIO_SILENCE_REC 0x0800
#define AUDIO_SILENCE_PLAY 0x0200
#define AUDIO_DMA_PAGE_SIZE 1024
//
// function prototypes
static void AIU_ClockEnable(WAPI_INOUT apidir);
static void AIU_ClockDisable(WAPI_INOUT apidir);
static MMRESULT Aud_GetDevCaps(WAPI_INOUT apidir, PWAVEOUTCAPS pCaps, UINT wSize);
static MMRESULT Aud_Open(WAPI_INOUT apidir, LPWAVEFORMATEX lpFormat, BOOL fQueryFormatOnly);
static MMRESULT Aud_Close(WAPI_INOUT apidir);
static void AudIn_GetBufferM8(PWAVEHDR pwh, ULONG page, ULONG nSamples);
static void AudIn_GetBufferS8(PWAVEHDR pwh, ULONG page, ULONG nSamples);
static void AudIn_GetBufferM16(PWAVEHDR pwh, ULONG page, ULONG nSamples);
static void AudIn_GetBufferS16(PWAVEHDR pwh, ULONG page, ULONG nSamples);
static void AudIn_Start(PWAVEHDR pwh);
static void AudIn_Continue(PWAVEHDR pwh);
static void AudIn_Stop(PWAVEHDR pwh);
static void AudIn_Standby(void);
static void AudOut_FillBufferM8(PWAVEHDR pwh, ULONG page, ULONG nSamples);
static void AudOut_FillBufferS8(PWAVEHDR pwh, ULONG page, ULONG nSamples);
static void AudOut_FillBufferM16(PWAVEHDR pwh, ULONG page, ULONG nSamples);
static void AudOut_FillBufferS16(PWAVEHDR pwh, ULONG page, ULONG nSamples);
static void AudOut_Start(PWAVEHDR pwh);
static void AudOut_Continue(PWAVEHDR pwh);
static void AudOut_EndOfData(void);
static void AudOut_Stop(void);
static void AudOut_Standby(void);
AUDIO_STATE PDD_AudioGetInterruptType(VOID);
DWORD PDD_AudioMessage(UINT uMsg, DWORD dwParam1, DWORD dwParam2);
BOOL PDD_AudioInitialize(DWORD dwIndex);
VOID PDD_AudioDeinitialize(VOID);
VOID PDD_AudioPowerHandler(BOOL power_down);
MMRESULT PDD_WaveProc(WAPI_INOUT apidir, DWORD dwCode, DWORD dwParam1, DWORD dwParam2);
extern DWORD gIntrAudio; //= SYSINTR_AUDIO;
//
// AIU common routines
static void
AIU_ClockEnable(WAPI_INOUT apidir)
{
AIUactive[apidir] = TRUE;
InterlockedAndOr16((volatile UINT16 *)(pVRC4173+CMU73CLKMSK), 0xFFFF, MSKAIU);
}
static void
AIU_ClockDisable(WAPI_INOUT apidir)
{
AIUactive[apidir] = FALSE;
if (!(AIUactive[WAPI_IN] || AIUactive[WAPI_OUT])) {
InterlockedAndOr16((volatile UINT16 *)(pVRC4173+CMU73CLKMSK), ~MSKAIU, 0);
}
}
//
// DDSI in/out common subroutines
static MMRESULT
Aud_GetDevCaps(WAPI_INOUT apidir, PWAVEOUTCAPS pCaps, UINT wSize)
{
if (pCaps) {
//
// Fill in the DevCaps here.
//
pCaps->wMid = MM_MICROSOFT;
if (apidir == WAPI_IN) {
pCaps->wPid = 23; // MM_MSFT_GENERIC_WAVEIN
} else {
pCaps->wPid = 24; // MM_MSFT_GENERIC_WAVEOUT
pCaps->dwSupport = WAVECAPS_VOLUME;
}
pCaps->vDriverVersion = 0x0001;
wsprintf (pCaps->szPname, TEXT("VRC4173 Audio (%hs)"), __DATE__);
pCaps->dwFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 |
WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16 |
WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16 |
WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16 |
WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16 |
WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16;
pCaps->wChannels = 2;
}
return MMSYSERR_NOERROR;
}
static MMRESULT
Aud_Open(WAPI_INOUT apidir, LPWAVEFORMATEX lpFormat, BOOL fQueryFormatOnly)
{
int s, maxdiff;
//
// Allow PCM, mono or stereo, 8 or 16 bit at 11k, 22k or 44kHz
//
if ((lpFormat->wFormatTag != WAVE_FORMAT_PCM) ||
(lpFormat->nChannels != 1 &&
lpFormat->nChannels != 2) ||
(lpFormat->wBitsPerSample != 8 &&
lpFormat->wBitsPerSample != 16)) {
return WAVERR_BADFORMAT;
}
s = lpFormat->nSamplesPerSec;
// allow inaccure sampling rate on wave output
maxdiff = (apidir == WAPI_OUT) ? SAMPLERATE_MAXDIFF : 0;
if (s>=(8000-maxdiff) && s<=(8000+maxdiff)) {
s = 8000;
} else if (s>=(11025-maxdiff) && s<=(11025+maxdiff)) {
s = 11025;
} else if (s>=(22050-maxdiff) && s<=(22050+maxdiff)) {
s = 22050;
} else if (s>=(44100-maxdiff) && s<=(44100+maxdiff)) {
s = 44100;
} else {
return WAVERR_BADFORMAT;
}
if (fQueryFormatOnly) {
return MMSYSERR_NOERROR;
}
// real open request
// BUGBUG: block open only on recording. not block on playing.
if (apidir == WAPI_IN && AIUactive[apidir]) {
return MMSYSERR_ALLOCATED;
}
SampleRate[apidir] = s;
if (apidir == WAPI_IN) {
if (lpFormat->wBitsPerSample == 8) {
if (lpFormat->nChannels == 1) {
GetBuf = AudIn_GetBufferM8;
} else {
GetBuf = AudIn_GetBufferS8;
}
} else {
if (lpFormat->nChannels == 1) {
GetBuf = AudIn_GetBufferM16;
} else {
GetBuf = AudIn_GetBufferS16;
}
}
} else {
if (lpFormat->wBitsPerSample == 8) {
if (lpFormat->nChannels == 1) {
FillBuf = AudOut_FillBufferM8;
} else {
FillBuf = AudOut_FillBufferS8;
}
} else {
if (lpFormat->nChannels == 1) {
FillBuf = AudOut_FillBufferM16;
} else {
FillBuf = AudOut_FillBufferS16;
}
}
}
return MMSYSERR_NOERROR;
}
static MMRESULT
Aud_Close(WAPI_INOUT apidir)
{
// do nothing...
return MMSYSERR_NOERROR;
}
//
// Wave input private routines
static void
AudIn_GetBufferM8(PWAVEHDR pwh, ULONG page, ULONG nSamples)
{
ULONG a;
SAMPLE_8_MONO *pm8;
volatile UINT16 *pbuf;
if (pwh == NULL) {
return;
}
pbuf = (volatile UINT16 *)dma_page[WAPI_IN][page];
pm8 = (SAMPLE_8_MONO *)(pwh->lpData + pwh->dwBytesRecorded);
for (a=0; a<nSamples; a++) {
if (pwh->dwBytesRecorded >= pwh->dwBufferLength) {
pwh = pwh->lpNext;
if (pwh == NULL)
break;
pm8 = (SAMPLE_8_MONO *)(pwh->lpData + pwh->dwBytesRecorded);
}
pm8->sample = (BYTE)(pbuf[a] >> 4);
pm8++;
pwh->dwBytesRecorded++;
}
}
static void
AudIn_GetBufferS8(PWAVEHDR pwh, ULONG page, ULONG nSamples)
{
ULONG a;
LONG sample;
SAMPLE_8_STEREO *ps8;
volatile UINT16 *pbuf;
if (pwh == NULL) {
return;
}
pbuf = (volatile UINT16 *)dma_page[WAPI_IN][page];
ps8 = (SAMPLE_8_STEREO *)(pwh->lpData + pwh->dwBytesRecorded);
for (a=0; a<nSamples; a++) {
if (pwh->dwBytesRecorded >= pwh->dwBufferLength) {
pwh = pwh->lpNext;
if (pwh == NULL)
break;
ps8 = (SAMPLE_8_STEREO *)(pwh->lpData + pwh->dwBytesRecorded);
}
sample = pbuf[a] >> 4;
ps8->sample_left = (BYTE)sample;
ps8->sample_right = (BYTE)sample;
ps8++;
pwh->dwBytesRecorded += 2;
}
}
static void
AudIn_GetBufferM16(PWAVEHDR pwh, ULONG page, ULONG nSamples)
{
ULONG a;
SAMPLE_16_MONO *pm16;
volatile UINT16 *pbuf;
if (pwh == NULL) {
return;
}
pbuf = (volatile UINT16 *)dma_page[WAPI_IN][page];
pm16 = (SAMPLE_16_MONO *)(pwh->lpData + pwh->dwBytesRecorded);
for (a=0; a<nSamples; a++) {
if (pwh->dwBytesRecorded >= pwh->dwBufferLength) {
pwh = pwh->lpNext;
if (pwh == NULL)
break;
pm16 = (SAMPLE_16_MONO *)(pwh->lpData + pwh->dwBytesRecorded);
}
pm16->sample = (INT16)((pbuf[a] << 4) - 32768);
pm16++;
pwh->dwBytesRecorded += 2;
}
}
static void
AudIn_GetBufferS16(PWAVEHDR pwh, ULONG page, ULONG nSamples)
{
ULONG a;
LONG sample;
SAMPLE_16_STEREO *ps16;
volatile UINT16 *pbuf;
if (pwh == NULL) {
return;
}
pbuf = (volatile UINT16 *)dma_page[WAPI_IN][page];
ps16 = (SAMPLE_16_STEREO *)(pwh->lpData + pwh->dwBytesRecorded);
for (a=0; a<nSamples; a++) {
if (pwh->dwBytesRecorded >= pwh->dwBufferLength) {
pwh = pwh->lpNext;
if (pwh == NULL)
break;
ps16 = (SAMPLE_16_STEREO *)(pwh->lpData + pwh->dwBytesRecorded);
}
sample = (pbuf[a] << 4) - 32768;
ps16->sample_left = (INT16)sample;
ps16->sample_right = (INT16)sample;
ps16++;
pwh->dwBytesRecorded += 4;
}
}
static void
AudIn_Start(PWAVEHDR pwh)
{
v_fMoreData[WAPI_IN] = TRUE; // we expect to have more data coming...
v_nNextPage[WAPI_IN] = 0;
// setup input DMA address
REG32(pVRC4173+AIUIBALREG) = physDMAbase[WAPI_IN];
REG32(pVRC4173+AIUIALREG) = physDMAbase[WAPI_IN];
// enable input DMA
InterlockedAndOr16((volatile UINT16 *)(pVRC4173+DMA73MSKREG), 0xFFFF, DMAMSKAIN);
// enable AIU Tclock
AIU_ClockEnable(WAPI_IN);
// set input sampling rate
switch (SampleRate[WAPI_IN]) {
case 8000:
REG16(pVRC4173+AIUMCNVRREG) = CNVR_8K;
break;
case 11025:
REG16(pVRC4173+AIUMCNVRREG) = CNVR_11K;
break;
case 22050:
REG16(pVRC4173+AIUMCNVRREG) = CNVR_22K;
break;
case 44100:
REG16(pVRC4173+AIUMCNVRREG) = CNVR_44K;
break;
default:
RETAILMSG(1, (TEXT("AudIn_Start: bad sampling rate\r\n")));
}
// A/D Vref power on
REG16(pVRC4173+AIUMCNTREG) = ADENAIU; // MSTOPEN=0, ADENAIU=1
RtcWait(1); // wait for Vref stable
// clear input interrupts
REG16(pVRC4173+AIUINTREG) = AIUINTMIDLE | AIUINTM | AIUINTMEND;
// activate AIU input
InterlockedAndOr16((volatile UINT16 *)(pVRC4173+AIUSEQREG), 0xFFFF, AIUMEN);
}
// prepare next input DMA buffer
static void
AudIn_Continue(PWAVEHDR pwh)
{
// get data from DMA buffer
(*GetBuf)(pwh, v_nNextPage[WAPI_IN], AUDIO_DMA_PAGE_SIZE/2);
// flip page
v_nNextPage[WAPI_IN] ^= 1;
}
// stop input immediately
static void
AudIn_Stop(PWAVEHDR pwh)
{
ULONG nSamples;
// Stop recording
v_fMoreData[WAPI_IN] = FALSE;
AudIn_Standby();
// Get partial samples in DMA buffer
nSamples = (REG32(pVRC4173+AIUIALREG) & (AUDIO_DMA_PAGE_SIZE-1)) / 2;
(*GetBuf)(pwh, v_nNextPage[WAPI_IN], nSamples);
}
// power down AIU input
static void
AudIn_Standby(void)
{
// disable AIU input
InterlockedAndOr16((volatile UINT16 *)(pVRC4173+AIUSEQREG), ~AIUMEN, 0);
// clear input interrupts
REG16(pVRC4173+AIUINTREG) = AIUINTMIDLE | AIUINTM | AIUINTMEND;
// A/D Vref power off
REG16(pVRC4173+AIUMCNTREG) = 0; // MSTOPEN=0, ADENAIU=0
// disable input DMA
InterlockedAndOr16((volatile UINT16 *)(pVRC4173+DMA73MSKREG), ~DMAMSKAIN, 0);
AIU_ClockDisable(WAPI_IN);
}
//
// Wave output private routines
static void
AudOut_FillBufferM8(PWAVEHDR pwh, ULONG page, ULONG nSamples)
{
ULONG a;
LONG sample;
SAMPLE_8_MONO *pm8;
volatile UINT16 *pbuf;
if (pwh == NULL) {
return;
}
pbuf = (volatile UINT16 *)dma_page[WAPI_OUT][page];
pm8 = (SAMPLE_8_MONO *)(pwh->lpData + pwh->dwBytesRecorded);
for (a=0; a<nSamples; a++) {
if (pwh->dwBytesRecorded >= pwh->dwBufferLength) {
pwh = pwh->lpNext;
if (pwh == NULL)
break;
pm8 = (SAMPLE_8_MONO *)(pwh->lpData + pwh->dwBytesRecorded);
}
sample = ((((LONG)pm8->sample) - 128) * Volume) >> 14;
pbuf[a] = (UINT16)(sample + AUDIO_SILENCE_PLAY);
pm8++;
pwh->dwBytesRecorded++;
}
// fill rest space
while (a < nSamples) {
pbuf[a++] = AUDIO_SILENCE_PLAY;
}
}
static void
AudOut_FillBufferS8(PWAVEHDR pwh, ULONG page, ULONG nSamples)
{
ULONG a;
LONG sample;
SAMPLE_8_STEREO *ps8;
volatile UINT16 *pbuf;
if (pwh == NULL) {
return;
}
pbuf = (volatile UINT16 *)dma_page[WAPI_OUT][page];
ps8 = (SAMPLE_8_STEREO *)(pwh->lpData + pwh->dwBytesRecorded);
for (a=0; a<nSamples; a++) {
if (pwh->dwBytesRecorded >= pwh->dwBufferLength) {
pwh = pwh->lpNext;
if (pwh == NULL)
break;
ps8 = (SAMPLE_8_STEREO *)(pwh->lpData + pwh->dwBytesRecorded);
}
sample = ((LONG)ps8->sample_left) + ((LONG)ps8->sample_right) - 256;
sample = (sample*Volume) >> 15;
pbuf[a] = (UINT16)(sample + AUDIO_SILENCE_PLAY);
ps8++;
pwh->dwBytesRecorded += 2;
}
// fill rest space
while (a < nSamples) {
pbuf[a++] = AUDIO_SILENCE_PLAY;
}
}
static void
AudOut_FillBufferM16(PWAVEHDR pwh, ULONG page, ULONG nSamples)
{
ULONG a;
LONG sample;
SAMPLE_16_MONO *pm16;
volatile UINT16 *pbuf;
if (pwh == NULL) {
return;
}
pbuf = (volatile UINT16 *)dma_page[WAPI_OUT][page];
pm16 = (SAMPLE_16_MONO *)(pwh->lpData + pwh->dwBytesRecorded);
for (a=0; a<nSamples; a++) {
if (pwh->dwBytesRecorded >= pwh->dwBufferLength) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -