WinRTC中的简单音频混频器代码

编者:李国帅

qq:9611153 微信lgs9611153

时间:2005-11-1 

背景原因:

多年前曾做过sip客户端,测试过几个软件,其中包含有音频的简单混音,有兴趣可以看一下。

做法仅仅把音频相加。

代码:

/
#include "resource.h"    // main symbols
#include "windows.h"
#include "mmsystem.h"

#ifdef WIN32
#define WAVDATA  BYTE
#else
#define WAVDATA  BYTE _huge
#define WAVEFORMATEX PCMWAVEFORMAT 
#endif
#ifdef WIN32
#define WAV16DATA   WORD
#else
#define WAV16DATA   WORD _huge
#endif

class MWAVE
{
private:
	BOOL       OpenFlage;
	DWORD      DataSize;
	HGLOBAL    hData;
	WAVDATA*   lpData;
	PCMWAVEFORMAT    pFormat;
	WAVEHDR    WaveHead;
	HWAVEOUT      hWaveOut;
public:
	MWAVE(){memset(this,0,sizeof(MWAVE));};
	~MWAVE(){Close();};
	int Open(char*);    //打开一个WAV文件
	int Play(HWND);     //播放一个WAV文件
	int Add(char*);     //往正在播放的WAV设备中添加WAV 文件
	int Stop();   //停止播放
	int Close();     //关闭设备
};

#include "stdafx.h"
#include "wavemix.h"
#include "wavemixDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

///
// wavemix Class
//

int MWAVE::Open(char* name)
{
	HMMIO 			hMmio;
	MMCKINFO pinfo;
	MMCKINFO cinfo;
//	if(hMmio)Close();

	//打开WAV文件,返回一个HMMIO句柄
	hMmio=mmioOpen(name,NULL,MMIO_READ);
	if(!hMmio)return FALSE;
	OpenFlage=1;

	//查找父块"wave";
	pinfo.fccType=mmioFOURCC('W','A','V','E');
	if(mmioDescend(hMmio,&pinfo,NULL,MMIO_FINDRIFF))goto FALSE_END;

	//查找子块"fmt"  parent"riff";
	cinfo.ckid=mmioFOURCC('f','m','t',' ');
	if(mmioDescend(hMmio,&cinfo,&pinfo,MMIO_FINDCHUNK))
goto FALSE_END;

	mmioRead(hMmio,(LPSTR)&pFormat,sizeof(PCMWAVEFORMAT));//cinfo.cksize);
	if(pFormat.wf.wFormatTag!=WAVE_FORMAT_PCM)
goto FALSE_END;

	//跳入块"FMT"
	mmioAscend(hMmio,&cinfo,0);

	//查找数据块
	cinfo.ckid=mmioFOURCC('d','a','t','a');
	if(mmioDescend(hMmio,&cinfo,&pinfo,MMIO_FINDCHUNK))
         goto FALSE_END;
	DataSize=cinfo.cksize;

	//读取数据
	hData=GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, DataSize);
	lpData=(WAVDATA*)GlobalLock(hData);
	if( !hData || !lpData ) goto FALSE_END;
	if(mmioRead(hMmio,(HPSTR)lpData,DataSize)!=(LRESULT)DataSize)
         goto FALSE_END;

	//close and return
	mmioClose(hMmio,MMIO_FHOPEN);
	return TRUE;

FALSE_END:
	if(hMmio)mmioClose(hMmio,MMIO_FHOPEN);
	if(lpData)LocalUnlock(hData);
	if(hData)GlobalFree(hData);
	memset(this,0,sizeof(MWAVE));
	return 0;
}

int MWAVE::Play(HWND hP)
{
	if(!OpenFlage)return FALSE;

	//检测系统播放功能
	if(waveOutOpen(NULL,WAVE_MAPPER,
                   (WAVEFORMATEX*)&pFormat,NULL,
                    NULL,WAVE_FORMAT_QUERY))
        return Close();

	if(waveOutOpen(&hWaveOut,WAVE_MAPPER,
              ( WAVEFORMATEX*)&pFormat,(DWORD)hP,
                             0,CALLBACK_WINDOW))
        return Close();

	WaveHead.lpData=(LPSTR)lpData;
	WaveHead.dwBufferLength=DataSize;
	WaveHead.dwFlags=0L;
	WaveHead.dwLoops=0L;

	往WAV设备中添加数据
if(waveOutPrepareHeader(hWaveOut,&WaveHead,
     sizeof(WAVEHDR)))
       return Close();

	if(waveOutWrite(hWaveOut,&WaveHead,sizeof(WAVEHDR)))
       return Close();

	return TRUE;
}

//#define min(a, b)  (((a) < (b)) ? (a) : (b))

int MWAVE::Add(char* name)
{
	register int x;
	if(!OpenFlage)return Open(name);

	MWAVE wav;
	if(!wav.Open(name))return FALSE;

	MMTIME time;
	//获得WAV文件当前播放位置
time.wType=TIME_BYTES;
	if(waveOutGetPosition(hWaveOut,&time,sizeof(MMTIME)))
		time.u.cb=0;
	DWORD start=((time.u.cb>>1)<<1);
	DWORD end=min(DataSize_start,wav.DataSize);//混音长度

	register WAVDATA* lpd=lpData+start;
	for(register DWORD i=0;i<end;i++)
		{
//将两组WAV文件数据相加,并检测数据大小是否合法,如果//数据大小越界,则分别取最大值和最小值
x=(((*(lpd+i))+(*(wav.lpData+i))))_128;
			if(x<0)x=0;
			if(x>255)x=255;
			*(lpd+i)=(BYTE)(x);
		}

	return TRUE;
}

int MWAVE::Stop()
{return !waveOutReset(hWaveOut);}

int MWAVE::Close()
{
	if(hWaveOut)
		{
			waveOutReset(hWaveOut);
			waveOutClose(hWaveOut);
			waveOutUnprepareHeader(hWaveOut,&WaveHead, sizeof(WAVEHDR));
		}
	if(lpData)LocalUnlock(hData);
	if(hData)GlobalFree(hData);
	memset(this,0,sizeof(MWAVE));
	return 0;
}

混合器中:

这是程序中的混音设置,计算方法没什么特别;

 


int
PCMMixer::TransformAudioSamples(std::vector<std::pair<AudioSample *, AudioSource *> > &dataIn, AudioSample **ppAudioSample)
{
	tracer.tracef(DET, "TransformAudioSamples\n");
	int result = 0;
	AudioSample *outSample = NULL;
	AudioSample *inSample  = NULL;
	std::vector<std::pair<AudioSample *, AudioSource *>  > data;

	// create a new input vector with only the non-null valid audio samples passed in the input
	for (int i=0; i<dataIn.size(); i++)
	{
		if (dataIn[i].first)
		{
			data.push_back(std::make_pair(dataIn[i].first, dataIn[i].second));
		}
	}

	// make inSample the first (if any) non-null audioSample in the vector. it is used later for audio format stuff

	if (data.size() == 1)//一路输入
	{
		inSample = data[0].first;
		outSample = inSample;
		inSample->AddRef(this);
	}
	else if (data.size() > 1)//多路输入
	{
		// create new audio sample
		inSample = data[0].first;
		result = AudioSampleManager::GetInstance()->GetAudioSample(&outSample, this);
		WAVEFORMATEX sampleFormat;
		inSample->GetFormat(&sampleFormat);
		outSample->SetFormat(sampleFormat);
		short *dataOut = (short *)(outSample->Data());//输入第一路

		// find out how many need to be mixed
		int maxInputSize(0);
		int maxSilenceDuration(0);
		for (int i=0; i< data.size(); i++)
		{
			int sampleDataSize = (data[i].first)->DataSize();
			if (sampleDataSize > maxInputSize)//获得最大数据量
			{
				maxInputSize = sampleDataSize;
			}
			else if (sampleDataSize == 0)//最大静音时间
			{
				maxSilenceDuration = max(maxSilenceDuration, (data[i].first)->GetSilenceDuration());
			}
		}
		outSample->SetSilenceDuration(maxSilenceDuration);	// in case all are silence packets
		int samplesToMix = (outSample->BufferSize() > maxInputSize ? maxInputSize : outSample->BufferSize()) / 2;
		//要混合的样本数量
		// mix samples
		for (i=0; i<samplesToMix; i++)
		{
			double total = 0;

			// first add the samples
			for (int j=0; j<data.size(); j++)
			{
				AudioSample *audioSample = data[j].first;//获得第j路输入的数据
				short *dataIn = (short *)(audioSample->Data());//数据值
				if (audioSample->DataSize() >= (i+1) * 2)		// sample #0 means datasize has to be = (0+1) * 2
				{//第j路样本的数据大小,必须在以混合的音频的后面,不能搅乱前面的部分。
					//输出总大小为samplesToMix * 2
					total += dataIn[i];//把各路音频值相加
				}
			}
			
			// limit the volume
			if (total > 32767.0)
			{
				total = 32767.0;
			}
			else if (total < -32768.0)
			{
				total = -32768.0;
			}

			dataOut[i] = (short)total;
		}
		outSample->SetDataSize(samplesToMix * 2);//设置输出大小为要混合的样本数*2
		tracer.tracef(DET, "TransformAudioSamples : outSample->DataSize = %d\n", samplesToMix * 2);
	}
	*ppAudioSample = outSample;
	tracer.tracef(DET, "~TransformAudioSamples\n");
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微澜-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值