Windows下声音的输出

因为要搞一些声音处理的算法,本来在matlab下调试,虽然matlab很强大,但是要完全按照自己的意志去仿真一些东西的时候还是有点问题,不是matlab办不到,主要是找不到一些合适的模块,或者写一个S-functuon太麻烦了,还是在自己用程序实现比较实际,而且算法也可以比较快的移植到DSP上面。

Widnows下声音输入输出有一系列的API函数,我这里给出的例子是读取一个Wav文件,然后输出到声卡,不要看小看这段看像根本没有的代码,他是声音处理的基本输入输出函数,在这之上,你可以加上IIR,FIR滤波,频谱分析等等。如果你像我一样想偷懒,拿来就用,可以下载Wave_effec的VC程序,在VC6下通过。 注意Wave文件缺省是c:\test.wav. 只能是48K,16bit,单通道的Wave文件

本来我是一个Frame一个frame这样来处理,不过不知道是什么原因,windows播放的时候会断断续续,所以一次处理完才输出。

在processing函数中,可以加上你想要的任意处理。


void Processing( char * p,  char *q,unsigned long n)
{
	short *in,*out;
	unsigned int i;


	in=(short *)p;out=(short *)q;

	for(i=0;i<n/2;i++)
	{
	//	fprintf(wavform,"%d\n",*in );
		*out++=(short) (*in++) ;	
	}
}

在我的程序中有一个wav_form的文件,是用来写数据到一个文件中,到matlab中分析用的,你可以不用它。如果你想用它,下面的函数可能对你有用,wavread,wavwrite,wavplay,load(用来load 数据到matlab中)

主程序如下



void CALLBACK 
  waveOutProc( HWAVEOUT hwo,      
               UINT uMsg,         
               DWORD dwInstance,  
               DWORD dwParam1,    
               DWORD dwParam2     )
{
   
   printf( "Get a waveOutProc uMsg = %d\n", uMsg );
    if (uMsg == WOM_DONE) 
   { 
		PostThreadMessage( CurThreadID, WM_QUIT , 11, 22 ); // WM_QUIT
  
   }
   return ;
}


int main(int argc, char* argv[])
{
HWAVEOUT phwo;

    CurThreadID = GetCurrentThreadId( ); // 取得当前线程的 ID (标识号)

//fp=fopen(argv[1] ,"rb");
fp=fopen("c:\\test.wav" ,"rb");
wavform=fopen("wav_form.dat","wt");


if(fp==NULL || wavform ==NULL)
{
    printf("Can not find file\n");
    return 0;
    }

fseek(fp,0x14,SEEK_SET);
fread(&waveformat,sizeof(waveformat),1,fp);

printf("This porgram is only for 1 channel 16bit Wave file!\n");
printf("wFormatTag: %d\n",waveformat.wFormatTag );
printf("Channel: %d\n",waveformat.nChannels );
printf("nSamplesPerSec: %d\n",waveformat.nSamplesPerSec );
printf("nAvgBytesPerSec: %d\n",waveformat.nAvgBytesPerSec );
printf("nBlockAlign: %d\n",waveformat.nBlockAlign  );
printf("wBitsPerSample: %d\n",waveformat.wBitsPerSample  );
printf("cbSize: %d\n",waveformat.cbSize );

fseek(fp,0x28,SEEK_SET);
fread(&filesize,4,1,fp);
printf("WAVE Data Size: %d\n",filesize);

/*
waveformat.wFormatTag=WAVE_FORMAT_PCM;
waveformat.nChannels=1;
waveformat.nSamplesPerSec=0; //8000;
waveformat.nAvgBytesPerSec=0; //8000;
waveformat.nBlockAlign=0; //1;
waveformat.wBitsPerSample=0; //8; //指定录音格式
waveformat.cbSize=0;
*/

if (waveOutGetNumDevs())
{
  ;//  printf("有可以使用的 WaveOut 通道\n");
    }
 else
 {
    printf("没有可以使用的 waveOut 通道\n");
    return 0;
     }
                                                                   

 int res=waveOutOpen( &phwo, WAVE_MAPPER, &waveformat,(DWORD)waveOutProc , NULL, CALLBACK_FUNCTION ); //打开录音设备

 if ( res == MMSYSERR_NOERROR )
 {
   ;//printf("打开 waveOut 成功\n");  // 验证创建是否成功
   }
 else
 {
    printf("打开 waveOut 失败,Error_Code = %d\n", res );
    }


  m_pWaveHdr1.lpData = (char *)GlobalLock( GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE, datasize) );
  m_pWaveHdr2.lpData = (char *)GlobalLock( GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE, filesize) );

  memset(m_pWaveHdr1.lpData, 0, datasize );
  memset(m_pWaveHdr2.lpData, 0, datasize );

  char *prt=m_pWaveHdr2.lpData;

// 读入磁盘数据
  fseek(fp,46,SEEK_SET);
  unsigned int frame=0;

  buf_id=1;
  buf_count=1;

  for(int i=0;i < filesize / datasize;i++)
  {
	  fread(m_pWaveHdr1.lpData, datasize, 1, fp);
	  buf_count++;		

	  Processing(m_pWaveHdr1.lpData,prt,datasize);
	  prt+=datasize;
	
  }
  
  printf("processing frame done\n");



  m_pWaveHdr1.dwBufferLength = datasize;
  m_pWaveHdr1.dwBytesRecorded = 0;
  m_pWaveHdr1.dwUser = 0;
  m_pWaveHdr1.dwFlags = 0;
  m_pWaveHdr1.dwLoops = 0;

  m_pWaveHdr2.dwBufferLength = filesize;
  m_pWaveHdr2.dwBytesRecorded = 0;
  m_pWaveHdr2.dwUser = 0;
  m_pWaveHdr2.dwFlags = 0;
  m_pWaveHdr2.dwLoops = 0;


  UINT resPrepare = 0;
  resPrepare =  waveOutPrepareHeader( phwo, &m_pWaveHdr2, sizeof(WAVEHDR) );


 if ( resPrepare == MMSYSERR_NOERROR)
	{
    ;//printf("准备放音用头文件成功");
	}
  else
  {
    printf( "不能开辟放音头文件,Error_Code = %d\n", resPrepare );
	return 0;
    }

 if (waveOutPause(phwo) )
   ;///printf("无法 Pause");
 else
   ;//printf("成功 Pause");

 if ( waveOutWrite( phwo, &m_pWaveHdr2, sizeof(WAVEHDR) ) )
    ;// printf("开始写入放音数据失败");
   else
   ;//printf("开始写入放音数据成功");

  if ( waveOutRestart(phwo) )
    ;//printf(" 非法 Resume");
  else
    ;//printf(" Resume 到 Playback");

 
    PostThreadMessage( CurThreadID, WM_USER , 11, 22 ); // WM_QUIT
   // 进入消息循环
  MSG msg;
  while(1)
  {
    if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    { 
		printf( "Get The uMsg =%d\n", msg.message );
		if (msg.message == WM_QUIT) 
			break;
	}
    else
	{ 
		;//printf("没有取到消息");
		WaitMessage();
	}
  } // end while

 
 if ( waveOutPause(phwo) )
	 ;//printf("无法 Pause");
 else
	;//printf("成功 Pause");


 if ( waveOutReset(phwo) )
	 ;//printf("不能 Reset"); 
 else 
	 ;//printf("成功 Reset");

// resPrepare =  waveOutUnprepareHeader( phwo, &m_pWaveHdr1, sizeof(WAVEHDR) );
 resPrepare =  waveOutUnprepareHeader( phwo, &m_pWaveHdr2, sizeof(WAVEHDR) );

 if ( resPrepare == MMSYSERR_NOERROR) 
	 ;//printf("释放放音用头文件成功");
  else 
	 printf( "不能释放放音头文件,Error_Code =%d", resPrepare );


  if ( m_pWaveHdr1.lpData )
    if ( GlobalFree(GlobalHandle( m_pWaveHdr1.lpData )) ) 
		printf("Global Free 失败");
	else 
		;//		printf("Global Free 成功");

if ( m_pWaveHdr2.lpData )
    if ( GlobalFree(GlobalHandle( m_pWaveHdr2.lpData )) ) 
		printf("Global Free 失败");
	else 
		;//printf("Global Free 成功");


 if (res == MMSYSERR_NOERROR )  //关闭录音设备
 if (waveOutClose(phwo)==MMSYSERR_NOERROR)
	printf("正常关闭放音设备");
 else 
	 printf("非正常关闭放音设备");

 
	fclose(wavform);
	fclose(fp);
	return 0;
}

我的程序主要改自csdn上的某位作者的程序,在此感谢他(她)。

home"> Home / Index 雁过留声