⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mixer.c

📁 好记星的控件,包括button,list,对文件操作
💻 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 + -