📄 mixer.c
字号:
#define __OS_SOURCE_FILE__
#include "kernel.h"
#define MAX_CHANNEL 8
NU_DRIVER *g_drv;
MIXERSOURCE *g_channel[MAX_CHANNEL];
WAVEHDR g_hdrWave1, g_hdrWave2;
char *g_audiobuffer1, *g_audiobuffer2;
void (*MixerDoAudioBuffer)(WAVEHDR *hdr);
BOOL MixerOpenSource(char *szFileName, MIXERSOURCE *source, DWORD dwFlags)
{
MMCKINFO mmckinfoParent;
MMCKINFO mmckinfoSubchunk;
HMEDIAFILE *hmf;
DWORD dwDataSize;
if (szFileName == NULL || source == NULL)
return FALSE;
source->dwFlags = 0;
// open media file
hmf = MediaFileOpen(szFileName, NULL, MMIO_READ);
if (hmf == NULL)
return FALSE;
// search "WAVE" chunk
mmckinfoParent.fccType = MediaFileStrToFourCC("WAVE", 0);
if (MediaFileDescend(hmf, &mmckinfoParent, NULL, MMIO_FINDRIFF) != MMSYSERR_NOERROR){
MediaFileClose(hmf, 0);
return FALSE;
}
// search "data" chunk
mmckinfoSubchunk.ckid = MediaFileStrToFourCC("data", 0);
if (MediaFileDescend(hmf, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK) != MMSYSERR_NOERROR){
MediaFileClose(hmf, 0);
return FALSE;
}
dwDataSize = mmckinfoSubchunk.cksize;
if (dwFlags == MIXERFLAG_MEMORY){
// allocate data buffer
source->buffer = MemAlloc(dwDataSize);
if (source->buffer == NULL){
MediaFileClose(hmf, 0);
return FALSE;
}
// read data
if(MediaFileRead(hmf, source->buffer, dwDataSize) != (int)dwDataSize){
free(source->buffer);
MediaFileClose(hmf, 0);
return FALSE;
}
// completed
MediaFileClose(hmf, 0);
source->size = dwDataSize;
source->pos = 0;
source->dwFlags = MIXERFLAG_MEMORY|MIXERFLAG_OPENED;
return TRUE;
} else {
// file mode
source->size = dwDataSize;
source->pos = 0;
source->start_pos = MediaFileSeek(hmf, 0, SEEK_CUR);
source->hmf = hmf;
source->dwFlags = MIXERFLAG_FILE|MIXERFLAG_OPENED;
return TRUE;
}
}
BOOL MixerCloseSource(MIXERSOURCE *source)
{
if (source == NULL)
return FALSE;
if (source->dwFlags&MIXERFLAG_OPENED){
switch(source->dwFlags&MIXERFLAG_TYPEMASK){
case MIXERFLAG_FILE:
if (source->hmf)
MediaFileClose(source->hmf, 0);
break;
case MIXERFLAG_MEMORY:
if (source->buffer)
MemFree(source->buffer);
break;
default:
return FALSE;
}
source->dwFlags = 0;
return TRUE;
}
return FALSE;
}
BOOL MixerInitChannels(int nChannels)
{
int i;
if (nChannels > MAX_CHANNEL)
return FALSE;
for(i=0; i<MAX_CHANNEL; i++){
g_channel[i] = 0;
}
return TRUE;
}
BOOL MixerSetupChannel(int nChannel, MIXERSOURCE *source, DWORD dwFlags)
{
if (source == NULL || ((source->dwFlags&MIXERFLAG_OPENED)==0))
return FALSE;
if (nChannel >= MAX_CHANNEL)
return FALSE;
switch(dwFlags&MIXERFLAG_SETMASK){
case MIXERFLAG_SET:
break;
case MIXERFLAG_SETWHENSILENCE:
if (g_channel[nChannel] != NULL)
return FALSE;
break;
case MIXERFLAG_SETWHENDIFF:
if (g_channel[nChannel] == source)
return FALSE;
break;
}
g_channel[nChannel] = source;
source->pos = 0;
if ((source->dwFlags&MIXERFLAG_TYPEMASK) == MIXERFLAG_FILE){
MediaFileSeek(source->hmf, source->start_pos, SEEK_SET);
}
if (dwFlags & MIXERFLAG_LOOP){
source->dwFlags |= MIXERFLAG_LOOP;
}
return TRUE;
}
BOOL MixerClearChannel(int nChannel)
{
g_channel[nChannel] = NULL;
return TRUE;
}
void __MixerCallback(WAVEHDR *pwh, DWORD dwUser)
{
NU_DRIVER_REQUEST request;
NU_DRIVER *drv;
drv = (NU_DRIVER *)dwUser;
if (pwh == &g_hdrWave1 || pwh == &g_hdrWave2){
MixerDoAudioBuffer(pwh);
request.nu_function = NU_OUTPUT;
pwh->dwFlags = 0;
pwh->dwLoops = 0;
request.nu_supplemental_ptr = (VOID *)pwh;
NU_Request_Driver(drv, &request);
}
}
BOOL MixerOpenDriver(WAVEFORMATEX *pFormat, DWORD dwBufSize)
{
NU_DRIVER_REQUEST request;
AUDIODS_OPEN open;
// 初始化音频驱动程序
g_drv = GetIODriverFromName("AUDIO");
if (g_drv == NULL)
return FALSE;
// 打开音频驱动
request.nu_function = NU_ASSIGN;
open.dwAudioCommand = AUDIO_PLAY;
open.pwfx = pFormat;
open.dwCallback = (VOID*)__MixerCallback;
open.dwCallbackInstance = (DWORD)g_drv;
open.fdwOpen = 0;
request.nu_supplemental_ptr = (VOID *)&open;
NU_Request_Driver(g_drv, &request);
if (request.nu_status != MMSYSERR_NOERROR)
{
g_drv = NULL;
return FALSE;
}
// allocate audio buffer
g_audiobuffer1 = MemAlloc(dwBufSize);
if (g_audiobuffer1 == NULL){
g_drv = NULL;
return FALSE;
}
g_audiobuffer2 = MemAlloc(dwBufSize);
if (g_audiobuffer2 == NULL){
g_drv = NULL;
free(g_audiobuffer1);
return FALSE;
}
// initialize buffer header
g_hdrWave1.lpData = g_audiobuffer1;
g_hdrWave1.dwBufferLength = dwBufSize;
g_hdrWave1.dwFlags = 0;
g_hdrWave1.dwLoops = 0;
g_hdrWave2.lpData = g_audiobuffer2;
g_hdrWave2.dwBufferLength = dwBufSize;
g_hdrWave2.dwFlags = 0;
g_hdrWave2.dwLoops = 0;
if (pFormat->wBitsPerSample != 8){
MixerDoAudioBuffer = MixerDoAudioBuffer16;
} else {
MixerDoAudioBuffer = MixerDoAudioBuffer8;
}
return TRUE;
}
BOOL MixerCloseDriver()
{
NU_DRIVER_REQUEST request;
if (!g_drv){
return FALSE;
}
request.nu_function = NU_RELEASE;
NU_Request_Driver(g_drv, &request);
if (request.nu_status != MMSYSERR_NOERROR)
return FALSE;
if (g_audiobuffer1 != NULL){
MemFree(g_audiobuffer1);
g_audiobuffer1 = NULL;
}
if (g_audiobuffer2 != NULL){
MemFree(g_audiobuffer2);
g_audiobuffer2 = NULL;
}
return TRUE;
}
BOOL MixerStartPlay()
{
NU_DRIVER_REQUEST request;
if (!g_drv)
return FALSE;
MixerDoAudioBuffer(&g_hdrWave1);
MixerDoAudioBuffer(&g_hdrWave2);
request.nu_function = NU_OUTPUT;
request.nu_supplemental_ptr = (VOID *)&g_hdrWave1;
NU_Request_Driver(g_drv, &request);
request.nu_supplemental_ptr = (VOID *)&g_hdrWave2;
NU_Request_Driver(g_drv, &request);
request.nu_function = NU_STATUS;
request.nu_supplemental_ptr = (VOID *)"play";
NU_Request_Driver(g_drv, &request);
return TRUE;
}
BOOL MixerStopPlay()
{
NU_DRIVER_REQUEST request;
if (!g_drv)
return FALSE;
request.nu_function = NU_STATUS;
request.nu_supplemental_ptr = (VOID *)"stop";
NU_Request_Driver(g_drv, &request);
return TRUE;
}
void MixerDoAudioBuffer8(WAVEHDR *hdr)
{
int i;
unsigned char *src, *dst;
DWORD tocopy, rest, count;
register signed short sample;
if (!hdr){
// if not specified buffer
if (g_hdrWave1.dwFlags & WHDR_DONE){
hdr = &g_hdrWave1;
} else if (g_hdrWave2.dwFlags & WHDR_DONE){
hdr = &g_hdrWave2;
} else {
// no buffer need to mix
return;
}
}
// clear target buffer
memset(hdr->lpData, 0x80, hdr->dwBufferLength);
// mix loop
for(i=0; i<MAX_CHANNEL; i++){
// check if channel is empty
if (g_channel[i] == NULL)
continue;
rest = hdr->dwBufferLength;
dst = (unsigned char *)hdr->lpData;
while(rest){
// calc first section mix
tocopy = g_channel[i]->size - g_channel[i]->pos;
if (tocopy >= rest){
// enough data to mix
count = rest;
rest = 0;
} else if (tocopy > 0){
// not enough data
count = tocopy;
rest -= tocopy;
} else if (tocopy == 0){
// reach buffer end
if (g_channel[i]->dwFlags & MIXERFLAG_LOOP){
// restart buffer
g_channel[i]->pos = 0;
continue;
} else {
// end mix
rest = 0;
continue;
}
} else {
// error, end mix
rest = 0;
continue;
}
// perform first section mix
src = (unsigned char *)(g_channel[i]->buffer + g_channel[i]->pos);
g_channel[i]->pos += count;
while(count-->0){
sample = *dst + *src;
sample -= 0x80;
if (sample > 0xFF){
sample = 0xFF;
} else if (sample < 0){
sample = 0;
}
*dst = (unsigned char)sample;
dst++;
src++;
}
}
}
}
void MixerDoAudioBuffer16(WAVEHDR *hdr)
{
int i;
signed short *src, *dst;
DWORD tocopy, rest, count;
register signed long sample;
if (!hdr){
// if not specified buffer
if (g_hdrWave1.dwFlags & WHDR_DONE){
hdr = &g_hdrWave1;
} else if (g_hdrWave2.dwFlags & WHDR_DONE){
hdr = &g_hdrWave2;
} else {
// no buffer need to mix
return;
}
}
// clear target buffer
memset(hdr->lpData, 0, hdr->dwBufferLength);
// mix loop
for(i=0; i<MAX_CHANNEL; i++){
// check if channel is empty
if (g_channel[i] == NULL)
continue;
rest = hdr->dwBufferLength;
dst = (signed short *)hdr->lpData;
while(rest){
// calc first section mix
tocopy = g_channel[i]->size - g_channel[i]->pos;
if (tocopy >= rest){
// enough data to mix
count = rest;
rest = 0;
} else if (tocopy > 0){
// not enough data
count = tocopy;
rest -= tocopy;
} else if (tocopy == 0){
// reach buffer end
if (g_channel[i]->dwFlags & MIXERFLAG_LOOP){
// restart buffer
g_channel[i]->pos = 0;
continue;
} else {
// end mix
rest = 0;
continue;
}
} else {
// error, end mix
rest = 0;
continue;
}
// perform first section mix
src = (signed short *)(g_channel[i]->buffer + g_channel[i]->pos);
g_channel[i]->pos += count;
count /= 2;
while(count-->0){
sample = *dst + *src;
if (sample > 32767){
sample = 32767;
} else if (sample < -32768){
sample = -32768;
}
*dst = (signed short)sample;
dst++;
src++;
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -