星空网 > 软件开发 > 操作系统

WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)

刚好最近接触了一些DirectSound,就写了一个小程序练练手,可以用来添加播放基本的wav和mp3音频文件的播放器。界面只是简单的GDI,dxsdk只使用了DirectSound8相关的接口。



WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)images/loading.gif' data-original="http://images0.cnblogs.com/blog2015/707063/201508/111819168179111.png" />




DirectSound的使用步骤很简单
  • 首先你要创建一个DirectSound8设备对象
1 HRESULT DirectSoundCreate8(2      LPCGUID lpcGuidDevice,3     LPDIRECTSOUND8 * ppDS8,4      LPUNKNOWN pUnkOuter5 )

  当然要确保已安装了DXSDK,并在工程中设置了相关路径,包含dsound.lib。

lpcGuidDevice是声音设备对象GUID的地址,设置为NULL,表示默认设备;
ppDS8是返回的IDirectSound8接口指针,接下来就通过它来调用相关接口了;
pUnkOuter必须设置为NULL。

 

  • 接下来是设置协作级别
1 HRESULT SetCooperativeLevel(2      HWND hwnd,3      DWORD dwLevel4 )


hwnd是应用程序窗口句柄;
dwLevel是请求的协作级别,可选的值包括
DSSCL_NORMAL:正常级别,其他程序可共享设备;
DSSCL_PRIORITY:优先级别,设备为当前程序独占;
DSSCL_EXCLUSIVE:对于DX8.0及之后的版本,具有和DSSCL_PRIORITY相同的效果;
DSSCL_WRITEPRIMARY:当前程序具有主缓冲区的写权限,同时副缓冲区不能进行播放。


  • 接下来就可以创建缓冲区了
1 HRESULT CreateSoundBuffer(2      LPCDSBUFFERDESC pcDSBufferDesc,3     LPDIRECTSOUNDBUFFER * ppDSBuffer,4      LPUNKNOWN pUnkOuter5 )


pcDSBufferDesc是一个DSBUFFERDESC结构的指针,用来描述要创建的声音缓冲区的地址;
ppDSBuffer是返回的IDirectSoundBuffer接口对象的指针;
pUnkOuter必须设置为NULL。

其中DSBUFFERDESC定义如下

1 typedef struct DSBUFFERDESC {2   DWORD dwSize;3   DWORD dwFlags;4   DWORD dwBufferBytes;5   DWORD dwReserved;6   LPWAVEFORMATEX lpwfxFormat;7   GUID guid3DAlgorithm;8 } DSBUFFERDESC;


dwSize:结构的大小,用字节表示;
dwFlags:指定缓冲区的功能标志,常用的有DSBCAPS_GLOBALFOCUS(缓冲区为全局)、DSBCAPS_CTRLVOLUME(缓冲区具有音量控制功能)、DSBCAPS_CTRLPOSITIONNOTIFY(缓冲区具有位置通知功能)等。
dwBufferBytes:将要创建的缓冲区大小;
dwReserved:保留参数,必须为0;
lpwfxFormat:指向一个WAVEFORMATEX结构的指针,该结构用来指定缓冲区的波形格式。


  • 然后是创建副缓冲区
通过使用IDirectSoundBuffer的QueryInterface方法,GUID设置为IID_IDirectSoundBuffer8,得到一个IDirectSoundBuffer8接口对象,用来控制播放等。

1 IDirectSoundBuffer8* m_pBuffer8 = NULL;2 ppDSBuffer->QueryInterface( IID_IDirectSoundBuffer8, (void**)&m_pBuffer8 );


到这里创建m_pBuffer8成功的话,就可以调用Play(),Stop()的方法控制基本的播放了。



  • 创建缓冲区通知对象
为了更好的控制缓冲区播放,我们还可以创建缓冲区通知对象,通过IDirectSoundBuffer8的QueryInterface方法,GUID设置为IID_IDirectSoundNotify,得到一个IDirectSoundNotify8接口对象。

1 IDirectSoundNotify8* pNotify = NULL;2 m_pBuffer8->QueryInterface( IID_IDirectSoundNotify,(void**)&pNotify );



接口获取成功后,就可以设置通知位置了,也就是说当缓冲区播放到相应位置时,系统就会触发对应的事件,可用来填充新的数据。

1 HRESULT SetNotificationPositions(2      DWORD dwPositionNotifies,3      LPCDSBPOSITIONNOTIFY pcPositionNotifies4 )


dwPositionNotifies:DSBPOSITIONNOTIFY结构的数量;
pcPositionNotifies:指向DSBPOSITIONNOTIFY结构的指针。


其中DSBPOSITIONNOTIFY结构如下

1 typedef struct DSBPOSITIONNOTIFY {2   DWORD dwOffset;3   HANDLE hEventNotify;4 } DSBPOSITIONNOTIFY;


dwOffset:触发位置,即缓冲区开始起的偏移量;
hEventNotify:触发事件句柄。

  • 填充缓冲区
另外,在填充缓冲区的操作,必须在IDirectSoundBuffer8的lock和unlock方法之间进行:

1 HRESULT Lock(2      DWORD dwOffset,3      DWORD dwBytes,4     LPVOID * ppvAudioPtr1,5      LPDWORD pdwAudioBytes1,6     LPVOID * ppvAudioPtr2,7      LPDWORD pdwAudioBytes2,8      DWORD dwFlags9 )


dwOffset:要锁定的缓冲区起始位置,即从缓冲区首地址起的偏移量,用字节表示;
dwBytes:希望锁定的缓冲区内存大小,用字节表示;
ppvAudioPtr1:返回指向该锁定缓冲区的第一部分指针;
pdwAudioBytes1:ppvAudioPtr1指向地址的大小;
ppvAudioPtr2:返回指向该锁定缓冲区的第二部分指针,如果传入NULL,则该锁定区域全部返回到ppvAudioPtr1;
pdwAudioBytes2:ppvAudioPtr2指向地址的大小,如果ppvAudioPtr2传入NULL,该值则应传入0;
dwFlags:修改锁定事件的标志,一般不使用设为0。

1 HRESULT Unlock(2      LPVOID pvAudioPtr1,3      DWORD dwAudioBytes1,4      LPVOID pvAudioPtr2,5      DWORD dwAudioBytes26 )


填充完锁定缓冲区内存后,用来取消该锁定区域,参数可以参看lock中的介绍。

至此,IDirectSound8中主要用到的接口就这些了。


  • WAVEFORMATEX结构
使用DirectSound播放PCM的重点就在于解析相应的音频文件格式获取相应信息,来填充WAVEFORMATEX结构。


1 typedef struct tWAVEFORMATEX {2   WORD wFormatTag;3   WORD nChannels;4   DWORD nSamplesPerSec;5   DWORD nAvgBytesPerSec;6   WORD nBlockAlign;7   WORD wBitsPerSample;8   WORD cbSize;9 } WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX;


下面详细介绍一下此结构:
wFormatTag:波形音频格式类型,在这里都设置为WAVE_FORMAT_PCM;
nChannels:音频声道数;
nSamplesPerSec:采样率;
nAvgBytesPerSec:平均传输率,如果音频格式设置为WAVE_FORMAT_PCM,该值则必须等于nSamplesPerSec和nBlockAlign的乘积;
nBlockAlign:以字节为单位的块对齐,是wFormatTag对应的最小原子单位,如果是WAVE_FORMAT_PCM,该值必须等于nChannels和wBitsPerSample的乘积除以8;
wBitsPerSample:每次采样的比特数,即量化位数;
cbSize:需要附加的额外信息大小,以字节为单位,这里设置为0。

关于DirectSound相关的内容就介绍到这里,接下来就该考虑怎么将wav和mp3文件信息解析并填充WAVEFORMATEX结构了。

  • WAV音频文件格式的解析


1、解析wav文件,这就需要稍微了解一下基本的wav文件格式,wav文件相应的非数据信息存储在文件头部分,常见的几种文件头格式: 

8KHz采样、16比特量化的线性PCM语音信号的WAV文件头格式表(共44字节)

偏移地址

字节数

数据类型

内容

文件头定义为

00H

4

Char

"RIFF"

char riff_id[4]="RIFF"

04H

4

long int

文件总长-8

 long int size0=文总长-8

08H

8

Char

"WAVEfmt "

char wave_fmt[8]

10H

4

long int

10 00 00 00H(PCM)

long int size1=0x10

14H

2

Int

01 00H

int fmttag=0x01

16H

2

Int

Int

channel=1 或2

18H

4

long int 

采样率

long int samplespersec

1CH

long int 

每秒播放字节数

long int bytepersec

20H 

int 

采样一次占字节数 

int blockalign=声道数*量化数/8

22H 

int 

量化数 

int bitpersamples=8或16

24H 

Char

"data" 

char data_id="data"

28H

4

long int

采样数据字节数

long int size2=文长-44

2CH

 

 

 

到文尾 char 采样数据

                   

8KHz采样、8比特A律量化的PCM语音信号的WAV文件头格式表(共58字节)

偏移地址

字节数

数据类型

内容

文件头定义为

00H

4

char 

"RIFF" 

char riff_id[4]="RIFF"

04H 

long int 

文件总长-8 

long int size0=文总长-8

08H 

char 

"WAVEfmt " 

char wave_fmt[8]

10H 

long int 

12000000H(ALAW) 

long int size1=0x12

14H 

int 

06 00H 

int fmttag=0x06

16H 

Int

声道数

int channel=1 或2

18H 

long int

采样率 

long int samplespersec

1CH 

long int

每秒播放字节数 

long int bytepersec

20H 

int 

采样一次占字节数

int blockalign=0x01

22H 

long int 

量化数 

long int bitpersamples=8

26H 

char 

"fact" 

char wave_fact="fact"

2AH 

char 

0400000000530700H定 

char temp

32H 

char 

"data" 

char wave_data="data"

36H 

long int 

采样数据字节数 

lont int size2=文长-58





只要构建字节对应的结构,然后从wav文件起始位置读取相应长度到结构即可,例如

 1 struct WAVE_HEADER          //44bytes 2 { 3   char  riff_sig[4]; 4   long  waveform_chunk_size; 5   char  wave_sig[4]; 6   char  format_sig[4]; 7   long  format_chunk_size; 8   short  format_tag; 9   short  channels;10   long  sample_rate;11   long  bytes_per_sec;12   short  block_align;13   short  bits_per_sample;14   char  data_sig[4];15   long  data_size;16 };17 18 19 struct WAVE_HEADER_FACT        //58bytes20 {21   char  riff_sig[4];22   long  waveform_chunk_size;23   char  wave_sig[4];24   char  format_sig[4];25   long  format_chunk_size;26   short  format_tag;27   short  channels;28   long  sample_rate;29   long  bytes_per_sec;30   short  block_align;31   short  bits_per_sample;32   short  bits_per_sample2;33   char  fact_sig[4];34   short  fact_size;35   short  fact_size2;36   char  fact_data[4];37   char  data_sig[4];38   long  data_size;39 };


这里构建了两种类型的wav格式头,从文件中读取信息到结构,然后直接赋值给WAVEFORMATEX即可

1 WAVEFORMATEX  wave_format;2 WAVE_HEADER    wave_header;3 fread( &wave_header, 1, sizeof(WAVE_HEADER), fp);4 wave_format.wFormatTag   = WAVE_FORMAT_PCM;5 wave_format.nChannels    = wave_header.channels;6 wave_format.nSamplesPerSec = wave_header.sample_rate;7 wave_format.wBitsPerSample = wave_header.bits_per_sample;8 wave_format.nBlockAlign   = wave_header.bits_per_sample / 8 * wave_header.channels;9 wave_format.nAvgBytesPerSec = wave_header.sample_rate * wave_format.nBlockAlign;

  • mp3音频文件格式的解析

2、解析mp3文件选择使用了libmpg123库中提供的方法,mpg123解码器是全部开源的,可以在http://www.mpg123.de/ 下载获得。


在编译libmpg123的过程中可能会遇到若干问题,这里大致罗列一下,进入ports\MSVC++选择对应的vs版本工程,这里选择了2010版。

由于工程中在预链接事件中使用了yasm汇编器,所以需要下载配置yasm到vs工程中,在http://yasm.tortall.net/Download.html 有32位和64位系统对应的vs2010版本。
下载后解压,根据readme文档添加配置:将yasm.exe放置vs主目录bin中;将yasm.props、yasm.targets、yasm.
选择Debug_X86或Release_x86配置,编译中可能会提示link无法打开输入文件xxx.o,将附加依赖和预链接命令中的.o全部替换为.obj。
将生成的libmpg123.lib添加到工程中,并将ports\MSVC++下的mpg123.h也引入到自己的工程中,接下来就可以使用libmpg123相关的方法来解析mp3文件了。


首先需要创建一个mpg123_handle句柄指针,过程如下

1 mpg123_handle* m_mpghandle = NULL;2 int ret = MPG123_OK;3 if( (ret = mpg123_init()) != MPG123_OK || (m_mpghandle = mpg123_new(NULL, &ret)) == NULL )4   return -1;


之后打开mp3文件并获取相关信息

1 long rate;    //频率2 int channels;  //声道数3 int encoding;  //编码格式4 if( mpg123_open(m_mpghandle, "youfile.mp3") != MPG123_OK || mpg123_getformat(m_mpghandle, &rate, &channels, &encoding) != MPG123_OK )5   return -1;


通过判断encoding来设置量化数,并赋值WAVEFORMATEX结构,代码如下

 1 WAVEFORMATEX  wave_format; 2 int    perbits = 16;  //量化数 3 if((encoding & MPG123_ENC_16) == MPG123_ENC_16) 4   perbits = 16; 5 else if((encoding & MPG123_ENC_32) == MPG123_ENC_32) 6   perbits = 32; 7 else 8   perbits = 8; 9 10 wave_format.wFormatTag   = WAVE_FORMAT_PCM;11 wave_format.nChannels    = channels;12 wave_format.nSamplesPerSec = rate;13 wave_format.wBitsPerSample = perbits;14 wave_format.nBlockAlign   = perbits / 8 * channels;15 wave_format.nAvgBytesPerSec = rate * perbits / 8 * channels;




另外再说一下如何获取mp3文件的时长和比特率,mp3文件是由帧所构成的,想要知道播放时长,就可以通过总帧数 * 每一帧的时长来推算获得。
总帧数可通过mpg123_tellframe获取,而每一帧时长 = 每一帧的采样个数 * 每一采样的时长 = 每一帧的采样个数 * (1/每一帧的采样频率),
而无论哪种编码的mp3文件每一帧的采样个数都是1152,所以计算时长代码如下:

1 long  frameNum;2 long  fileTime;3 mpg123_seek( m_mpghandle, 0, SEEK_END );4 frameNum = mpg123_tellframe( m_mpghandle ); //获取总帧数5 fTime = (long)( frameNum * 1152/ rate );


而计算比特率,需要区别编码格式,如果是CBR,则比特率是固定的;
如果是VBR,由于比特率不固定,所以只能大概取一个平均比特率,计算公式为 平均比特率 = 文件大小(字节)*8 / 总时长 /1000,计算比特率代码如下:

 1 mpg123_frameinfo mpginfo; 2 int bitrate; 3 long filesize; 4 FILE* tmpfp = NULL; 5 if( mpg123_info( m_mpghandle, &mpginfo) != MPG123_OK ) 6   return -1; 7 if(mpginfo.layer != 3) 8   return -1; 9 if( mpginfo.vbr == MPG123_CBR )10   bitrate = mpginfo.bitrate;11 else if( mpginfo.vbr == MPG123_VBR )12 {13   fopen_s( &tmpfp, "youfile.mp3", "rb" );14   fseek( tmpfp, 0, SEEK_END );15   filesize = ftell( tmpfp );16   fcolse( tmpfp );17   tmpfp = NULL;18   bitrate = (filesize * 8)/(fTime*1000);19 }


以下是全部代码:

D3DPlayer.h
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)
 1 #ifndef  __D3D_PLAYER__ 2 #define  __D3D_PLAYER__ 3  4  5 #include "resource.h" 6  7 #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } 8 #define SAFE_DELETE(p) { if(p) {delete (p); (p)=NULL; } } 9 10 #endif

D3DPlayer.h


D3DPlayer.cpp
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)
 1 #include "stdafx.h" 2 #include "D3DPlayer.h" 3 #include "D3DSound.h" 4  5 #define MAX_LOADSTRING    100 6 #define WS_MYPLAYERWINDOW  (WS_OVERLAPPED   | \ 7               WS_CAPTION    | \ 8               WS_SYSMENU    | \ 9               WS_MINIMIZEBOX  | \ 10                WS_MAXIMIZEBOX) 11 #define MYWINWIDTH      700 12 #define MYWINHEIGHT      300 13  14 HINSTANCE hInst;                // 当前实例 15 TCHAR szTitle[MAX_LOADSTRING];          // 标题栏文本 16 TCHAR szWindowClass[MAX_LOADSTRING];      // 主窗口类名 17 extern myD3DSound*  g_pmySound; 18  19 BOOL        PreTranslateMessage(LPMSG pMsg); 20 ATOM        MyRegisterClass(HINSTANCE hInstance); 21 BOOL        InitInstance(HINSTANCE, int); 22 LRESULT CALLBACK  WndProc(HWND, UINT, WPARAM, LPARAM); 23 INT_PTR CALLBACK  About(HWND, UINT, WPARAM, LPARAM); 24  25 int APIENTRY _tWinMain(HINSTANCE hInstance, 26            HINSTANCE hPrevInstance, 27            LPTSTR  lpCmdLine, 28           int    nCmdShow) 29 { 30   UNREFERENCED_PARAMETER(hPrevInstance); 31   UNREFERENCED_PARAMETER(lpCmdLine); 32  33   MSG msg; 34   HACCEL hAccelTable; 35  36   myD3DSound* pDXSound = new myD3DSound; 37   LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 38   LoadString(hInstance, IDC_D3DPLAYER, szWindowClass, MAX_LOADSTRING); 39   MyRegisterClass(hInstance); 40  41   if (!InitInstance (hInstance, nCmdShow)) 42   { 43     return FALSE; 44   } 45  46   hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_D3DPLAYER)); 47  48   while (GetMessage(&msg, NULL, 0, 0)) 49   { 50     if(!PreTranslateMessage(&msg)) 51     {   52       if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 53       { 54         TranslateMessage(&msg); 55         DispatchMessage(&msg); 56       } 57     } 58   } 59    60   SAFE_DELETE(g_pmySound); 61   return (int) msg.wParam; 62 } 63  64 ATOM MyRegisterClass(HINSTANCE hInstance) 65 { 66   WNDCLASSEX wcex; 67  68   wcex.cbSize = sizeof(WNDCLASSEX); 69  70   wcex.style      = CS_HREDRAW | CS_VREDRAW; 71   wcex.lpfnWndProc  = WndProc; 72   wcex.cbClsExtra    = 0; 73   wcex.cbWndExtra    = 0; 74   wcex.hInstance    = hInstance; 75   wcex.hIcon      = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYPLAYER)); 76   wcex.hCursor    = LoadCursor(NULL, IDC_ARROW); 77   wcex.hbrBackground  = (HBRUSH)( COLOR_WINDOW - 1 ); 78   wcex.lpszMenuName  = MAKEINTRESOURCE(IDC_D3DPLAYER); 79   wcex.lpszClassName  = szWindowClass; 80   wcex.hIconSm    = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_MYSMALL)); 81  82   return RegisterClassEx(&wcex); 83 } 84  85 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 86 { 87   HWND hWnd; 88  int iWidth; 89  int iHeight; 90  hInst = hInstance; // 将实例句柄存储在全局变量中 91  iWidth=GetSystemMetrics(SM_CXSCREEN); 92  iHeight=GetSystemMetrics(SM_CYSCREEN); 93  94  hWnd = CreateWindow(szWindowClass, szTitle, WS_MYPLAYERWINDOW, (iWidth-MYWINWIDTH)/2,  95    (iHeight-MYWINHEIGHT)/2, MYWINWIDTH, MYWINHEIGHT, NULL, NULL, hInstance, NULL); 96  97  if (!hWnd) 98   { 99    return FALSE;100   }101  //102  g_pmySound->myInit( hWnd );103 104   ShowWindow(hWnd, nCmdShow);105   UpdateWindow(hWnd);106 107  return TRUE;108 }109 110 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)111 {112   int wmId, wmEvent;113   PAINTSTRUCT ps;114   HDC hdc;115   RECT rect;116   LRESULT res;117   UINT CtrlId;118   DRAWITEMSTRUCT *dis;119   HFONT hfont;120   NMHDR *pNMHDR;121 122   switch (message)123   {124     case WM_NOTIFY:125     {126       pNMHDR = (LPNMHDR)lParam;127       switch( pNMHDR->code )128       {129       case NM_DBLCLK:130         {131           if( pNMHDR->idFrom == IDB_SONGLIST )132           {133             int i = SendMessage(g_pmySound->m_listview, LVM_GETNEXTITEM, -1, LVNI_SELECTED);134             NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;135             if(pNMListView && pNMListView->iItem >= 0 && pNMListView->iItem < g_pmySound->mySongNum() )136             {  137               g_pmySound->mySetPlayInfo(pNMListView,TRUE);138               g_pmySound->myPlay();139               GetClientRect( hWnd, &rect );140               InvalidateRect(hWnd,&rect,TRUE);141             }142           }143         }break;144       case NM_CLICK:145         {146           if( pNMHDR->idFrom == IDB_SONGLIST )147           {148             SendMessage(g_pmySound->m_listview, LVM_GETNEXTITEM, -1, LVNI_SELECTED);149             NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;150             if(pNMListView && pNMListView->iItem >= 0 && pNMListView->iItem < g_pmySound->mySongNum() )151             {  152               g_pmySound->mySetPlayInfo(pNMListView,FALSE);153               LVITEM vitem;154               LVITEM* pvitem;155               HANDLE hProcess;156               DWORD PID;157               GetWindowThreadProcessId(hWnd, &PID);158               hProcess=OpenProcess(PROCESS_ALL_ACCESS,false,PID);159               vitem.iItem = pNMListView->iItem;160               vitem.state = LVIS_SELECTED|LVIS_FOCUSED;161               vitem.stateMask = LVIS_SELECTED|LVIS_FOCUSED;162               pvitem=(LVITEM*)VirtualAllocEx(hProcess, NULL, sizeof(LVITEM),MEM_COMMIT, PAGE_READWRITE);163               WriteProcessMemory(hProcess, pvitem, &vitem, sizeof(LVITEM), NULL);164               SendMessage(g_pmySound->m_listview, LVM_SETITEMSTATE, (WPARAM)pNMListView->iItem, (LPARAM)pvitem);165               GetClientRect( hWnd, &rect );166               InvalidateRect(hWnd,&rect,TRUE);167             168             }169           }170           else if( pNMHDR->idFrom == 12 )171           {172             int i = 0;173           }174         }break;175       default:176         break;177       }178       break;179     }180     case WM_COMMAND:181     {182       wmId  = LOWORD(wParam);183       wmEvent = HIWORD(wParam);184       // 分析菜单选择:185       switch (wmId)186       {187       case IDM_ABOUT:188         DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);189         break;190       case IDM_EXIT:191         res = MessageBox( hWnd, TEXT("是否关闭"), TEXT("退出"), MB_YESNO );192         if( res == IDYES )193         {194           DestroyWindow( hWnd );195         }196         break;197       case IDB_OPEN:198         g_pmySound->myOpenFile();199         GetClientRect( hWnd, &rect );200         InvalidateRect(hWnd,&rect,TRUE);201         break;202       case IDB_CLOSE:203         g_pmySound->myCloseFile();204         GetClientRect( hWnd, &rect );205         InvalidateRect(hWnd,&rect,TRUE);206         break;207       case IDB_PLAY:208         g_pmySound->myPlay();209         GetClientRect( hWnd, &rect );210         InvalidateRect(hWnd,&rect,TRUE);211         break;212       case IDB_STOP:213         g_pmySound->myStop();214         GetClientRect( hWnd, &rect );215         InvalidateRect(hWnd,&rect,TRUE);216         break;217       case IDB_PAUSE:218         g_pmySound->myPause();219         break;220       default:221         return DefWindowProc(hWnd, message, wParam, lParam);222       }223       break;224     }225     case WM_PAINT:226     {227       hdc = BeginPaint(hWnd, &ps);228       // TODO: 在此添加任意绘图代码...229       EndPaint(hWnd, &ps);230       break;231     }232     case WM_DRAWITEM:233     {234       CtrlId = (UINT)wParam;235       dis = (LPDRAWITEMSTRUCT)lParam;236       int lw,lh,fw,fh,len;  //ctrl width,ctrl height,font w,font h,font size237       WCHAR txt[MAX_PATH];238       lw=(dis->rcItem.right)-(dis->rcItem.left);239       lh=(dis->rcItem.bottom)-(dis->rcItem.top);240       fh=lh;241       len=GetWindowText(dis->hwndItem,txt,MAX_PATH);242       txt[len] = 0;243       fw=lw/(len+1);244       if( IDB_SONGTEXT == CtrlId || IDB_PLAYING == CtrlId )245       {246         fh = 16;247         fw = 8;248       }249       else if( IDB_SONGINFO == CtrlId )250       {251         fw = 7;252       }253       else if( IDB_SONGTIME == CtrlId || IDB_TIMESHOW == CtrlId )254       {255         fh = 14;256         fw = 7;257       }258       hfont=CreateFont( fh, fw, 0, 0, 500, FALSE, FALSE, FALSE, 259         GB2312_CHARSET, OUT_DEFAULT_PRECIS,260         CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, 261         DEFAULT_PITCH, TEXT("宋体") );262 263       switch( CtrlId )264       {265       case IDB_PLAYING:266       case IDB_SONGTEXT:267         {268           hfont = (HFONT)SelectObject( dis->hDC, hfont );269           SetBkMode( dis->hDC, TRANSPARENT );270           SetTextColor( dis->hDC, RGB(0,0,0) );271           TextOut( dis->hDC, 0, 0, txt,len+1 );272           hfont = (HFONT)SelectObject(dis->hDC, hfont );273           DeleteObject(hfont);274         }break;275       case IDB_TIMESHOW:276         {277           SetTimer( hWnd, 200, 1000, NULL );278           hfont = (HFONT)SelectObject( dis->hDC, hfont );279           SetBkMode( dis->hDC, TRANSPARENT );280           SetTextColor( dis->hDC, RGB(0,0,0) );281           TextOut( dis->hDC, 0, 0, txt,len+1 );282           hfont = (HFONT)SelectObject(dis->hDC, hfont );283           DeleteObject(hfont);284         }break;285       case IDB_SONGINFO:286         {287           hfont = (HFONT)SelectObject( dis->hDC, hfont );288           SetBkMode( dis->hDC, TRANSPARENT );289           SetTextColor( dis->hDC, RGB(0,0,0) );290           TextOut( dis->hDC, 0, 0, txt,len+1 );291           hfont = (HFONT)SelectObject(dis->hDC, hfont );292           DeleteObject(hfont);293         }break;294       case IDB_SONGTIME:295         {296           hfont = (HFONT)SelectObject( dis->hDC, hfont );297           SetBkMode( dis->hDC, TRANSPARENT );298           SetTextColor( dis->hDC, RGB(0,0,0) );299           TextOut( dis->hDC, 0, 0, txt,len+1 );300           hfont = (HFONT)SelectObject(dis->hDC, hfont );301           DeleteObject(hfont);302           //GetClientRect( hWnd, &rect );303           //InvalidateRect(hWnd,&rect,TRUE);304         }break;305       }306       break;307     }308     case WM_DESTROY:309     {  PostQuitMessage(0);310       break;311     }312     case WM_CREATE:313     {314       g_pmySound->myCreateWin(hWnd);315       g_pmySound->myInitList();316       break;317     }318     case WM_SIZE:319     {320       g_pmySound->myChangeSize( hWnd );321       break;322     }323     case WM_TIMER:324     {325       GetClientRect( hWnd, &rect );326       InvalidateRect(hWnd,&rect,TRUE);327       SYSTEMTIME time;328       if( wParam == 200 )329       {      330         if( ! g_pmySound->isPlay() )331         {332           GetLocalTime( &time );333           g_pmySound->mySetTimer( time );334           SetWindowText( g_pmySound->m_timeshow, g_pmySound->myGetTimer() );335         }336       }337       break;338     }339     case WM_CLOSE:340     {341       res = MessageBox( hWnd, TEXT("是否关闭"), TEXT("退出"), MB_YESNO );342       if( res == IDYES )343       {344         DestroyWindow( hWnd );345       }346       break;347     }348     case WM_INITDIALOG:349     {350       break;351     }  352     case WM_HSCROLL:353     {354       //no use355       break;356     }357     case WM_LBUTTONUP:358     {359       //no use360       break;361     }362     default:363       return DefWindowProc(hWnd, message, wParam, lParam);364   }365   return 0;366 }367 368 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)369 {370   UNREFERENCED_PARAMETER(lParam);371   switch (message)372   {373   case WM_INITDIALOG:374     return (INT_PTR)TRUE;375 376   case WM_COMMAND:377     if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)378     {379       EndDialog(hDlg, LOWORD(wParam));380       return (INT_PTR)TRUE;381     }382     break;383   }384   return (INT_PTR)FALSE;385 }386 387 388 BOOL PreTranslateMessage(LPMSG pMsg)389 {390   if( pMsg->message == WM_LBUTTONUP )391   {392     if( (HWND)pMsg->hwnd == g_pmySound->m_scrollbar )393     {394       g_pmySound->mySetScrollPos( TRUE, 0 );395       //return TRUE;396     }397     else if( (HWND)pMsg->hwnd == g_pmySound->m_volumebar )398     {399       g_pmySound->mySetVolumePos( TRUE, 0 );400       //return TRUE;401     }402     else403     {404       return FALSE;405     }406   }407   return FALSE;408 }

D3DPlayer.cpp


D3DSound.h
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)
 1 #ifndef  __D3D_SOUND__ 2 #define  __D3D_SOUND__ 3  4 #include "D3DPlayer.h" 5 #include "stdafx.h" 6 #include "mpg123.h" 7  8 #define MAX_AUDIO_BUF    4 9 #define BUFFERNOTIFYSIZE  192000 10 #define IDB_OPEN      1001 11 #define IDB_CLOSE      1002 12 #define IDB_PLAY      1003 13 #define IDB_PAUSE      1004 14 #define IDB_STOP      1005 15 #define IDB_PLAYING      2001 16 #define IDB_TIMESHOW    2002 17 #define IDB_SONGINFO    2003 18 #define IDB_SONGTEXT    2004 19 #define IDB_SONGTIME    2005 20 #define IDB_SONGLIST    2006 21  22 struct WAVE_HEADER          //44bytes 23 { 24   char  riff_sig[4]; 25   long  waveform_chunk_size; 26   char  wave_sig[4]; 27   char  format_sig[4]; 28   long  format_chunk_size; 29   short  format_tag; 30   short  channels; 31   long  sample_rate; 32   long  bytes_per_sec; 33   short  block_align; 34   short  bits_per_sample; 35   char  data_sig[4]; 36   long  data_size; 37 }; 38  39 struct WAVE_HEADER_FACT        //58bytes 40 { 41   char  riff_sig[4]; 42   long  waveform_chunk_size; 43   char  wave_sig[4]; 44   char  format_sig[4]; 45   long  format_chunk_size; 46   short  format_tag; 47   short  channels; 48   long  sample_rate; 49   long  bytes_per_sec; 50   short  block_align; 51   short  bits_per_sample; 52   short  bits_per_sample2; 53   char  fact_sig[4];       54   short  fact_size;       55   short  fact_size2; 56   char  fact_data[4]; 57   char  data_sig[4]; 58   long  data_size; 59 }; 60  61 struct myListMember  62 { 63   int    m_idx; 64   WCHAR  m_name[100]; 65   WCHAR  m_time[10]; 66   WCHAR  m_type[10]; 67   WCHAR  m_bits[20]; 68   WCHAR  m_path[MAX_PATH]; 69 }; 70  71 static DWORD ThreadNotifyEvent( LPVOID thread_data ); 72 static DWORD ThreadNotifyEvent2( LPVOID thread_data ); 73 static DWORD ThreadNotifyEvent3( LPVOID thread_data ); 74 void ChartoWCHAR( const char*, WCHAR* ); 75 void WCHARtoChar( const WCHAR*, char* ); 76  77 class myD3DSound 78 { 79 private: 80   OPENFILENAME opfn; 81   bool  isPlaying; 82   DWORD  m_ds_dwBuffSize;  //dxsound缓冲区大小 83   HANDLE  m_hThread;      //控制buffer 84   DWORD  m_thread_id; 85   HANDLE  m_hThread2;      //滚动条显示 86   DWORD  m_thread_id2; 87   HANDLE  m_hThread3;      //剩余时间显示 88   DWORD  m_thread_id3; 89   FILE* m_fp; 90   mpg123_handle* m_mpghandle; 91   DWORD  m_dwPlayPos; 92   WCHAR m_wstrTime[60]; 93   WCHAR m_wSongTime[30];    //总时长 94   WCHAR m_wSongLeave[30];    //剩余时长 95   typedef std::vector<myListMember> MY_SONG_LIST; 96   MY_SONG_LIST m_list; 97   WCHAR m_wSongPath[MAX_PATH];    //正在播放歌曲 98   WCHAR m_wSongName[MAX_PATH]; 99   WCHAR m_wSongPathPre[MAX_PATH];    //单击选中歌曲100   WCHAR m_wSongNamePre[MAX_PATH];101   102   bool  m_bmpg;103   bool  m_factwav;104 public:105   HWND m_father;106   //button107   HWND m_openbtn;108   HWND m_closebtn;109   HWND m_playbtn;110   HWND m_pausebtn;111   HWND m_stopbtn;112   //static113   HWND m_txtplaying;114   HWND m_songtxt;115   HWND m_songinfo;116   HWND m_timeshow;117   HWND m_songtime;118   //119   HWND m_scrollbar;120   HWND m_volumebar;121   HWND m_listview;122 123   LPDIRECTSOUND8      m_pDirectSound;124 125   //playing file info126   LPDIRECTSOUNDBUFFER8  m_pBuffer8;127   HANDLE m_hEvents[MAX_AUDIO_BUF];128 #ifdef __MAX_BUFFER__129   DWORD  m_ds_dwFileSize;  //文件大小130 #endif131   DWORD  m_ds_dwFileTime;  //文件时长(s)132   DWORD  m_ds_dwFilebps;    //文件传输率133   DWORD  m_ds_dwPos;      //文件偏移量134   DWORD  m_ds_dwLeave;    //文件剩余量135   int    m_iScrollPos;    //进度条位置136   int    m_iVolumePos;    //音量条位置137 138   enum eFAIL_CODE{139     EFAIL_NOFILE = 1,140     EFAIL_NOTSUPPORT,141     EFAIL_PCMBUFFERERR,142     EFAIL_MPGBUFFERERR,143     EFAIL_OPENFILEERR,144     EFAIL_FORMATERR,145   };146 147 private:148   int mySetSoundType();149   int myGetWAVFormat( DWORD* dwSize, DWORD* dwCycle, FILE* fp, WAVEFORMATEX** wfx );150   int myGetMP3Format( char* filestr, DWORD* dwSize, DWORD* dwCycle, int* bitrate, WAVEFORMATEX** wfx, bool isClose = TRUE );151   HRESULT myCreatePCMBuffer( WAVEFORMATEX* wfx, DWORD* dwBuffSize );152   HRESULT myCreateMPGBuffer( WAVEFORMATEX* wfx, DWORD* dwBuffSize );153   void myUpdateList();154   void myCleanBuffer();155   void cleanup();    //clear mpg123 handle156 public:157   myD3DSound();158   ~myD3DSound();159   HRESULT myInit( HWND );160   void myCreateWin( HWND );161   void myChangeSize( HWND );162   void mySetList( WCHAR* );163   void myInitList();164   void mySetPlayInfo( NM_LISTVIEW* pNMListView, bool DBClick );165   void mySetTimer( SYSTEMTIME );166   bool myReadBuffer( long lock_pos, long lock_size );167   bool myReadMPGBuffer( long lock_pos, long lock_size );168   void mySetScrollPos( bool isUp, DWORD dPos );169   void mySetVolumePos( bool isUp, DWORD dPos );170 171   //button172   void myOpenFile();173   void myCloseFile();174   int myPlay();175   int myStop();176   int myPause();177 178   int mySongNum();179   WCHAR* myGetTimer();180   bool isPlay(){ return isPlaying; }181   void SetPlaying( bool flags ){ isPlaying = flags; }182   int GetBufferValue( FILE** fp, mpg123_handle** mpghandle, DWORD* BuffSize );183   bool IsMPG3(){return m_bmpg;}184 };185 186 187 #endif

D3DSound.h


D3DSound.cpp
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)
  1 #include "D3DSound.h"  2   3 const WCHAR* g_cwErrorMsg[7] = {  4   TEXT(""),  5   TEXT("Pelase choose a file!"),  6   TEXT("Only supports .mp3 and .wav file!"),  7   TEXT("Create PCM buffer fail!"),  8   TEXT("Create MPG buffer fail!"),  9   TEXT("Cannot play the file!"), 10   TEXT("File format error!")  11 }; 12 WCHAR* g_cwSongList[6] = { 13   TEXT("序号"), 14   TEXT("名称"), 15   TEXT("持续时间"), 16   TEXT("扩展名"), 17   TEXT("比特率"), 18   TEXT("文件路径") 19 }; 20  21  22  23 myD3DSound*  g_pmySound = NULL; 24  25  26 /////////////////////// 27 //public function 28 /////////////////////// 29  30 HRESULT myD3DSound::myInit( HWND hWnd ) 31 { 32   m_father = hWnd; 33   if( FAILED( DirectSoundCreate8(NULL, &m_pDirectSound, NULL) ) ) 34     return E_FAIL; 35  36   if( FAILED( m_pDirectSound->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ) ) ) 37     return E_FAIL; 38    39   return S_OK; 40 } 41  42 myD3DSound::myD3DSound(): 43 m_pDirectSound(NULL), 44 m_pBuffer8(NULL), 45 m_father(NULL), 46 m_openbtn(NULL), 47 m_closebtn(NULL), 48 m_playbtn(NULL), 49 m_pausebtn(NULL), 50 m_stopbtn(NULL), 51 m_txtplaying(NULL), 52 m_songtxt(NULL), 53 m_timeshow(NULL), 54 m_songinfo(NULL), 55 m_songtime(NULL), 56 m_scrollbar(NULL), 57 m_volumebar(NULL), 58 m_listview(NULL), 59 m_fp(NULL), 60 isPlaying(FALSE), 61 m_bmpg(FALSE), 62 m_factwav(FALSE), 63 m_hThread(NULL), 64 m_hThread2(NULL), 65 m_mpghandle(NULL) 66 { 67  68   m_ds_dwBuffSize = 0; 69 #ifdef __MAX_BUFFER__ 70   m_ds_dwFileSize = 0; 71 #endif 72   m_ds_dwFileTime = 0; 73   m_ds_dwFilebps = 0; 74   m_ds_dwPos = 0; 75   m_ds_dwLeave = 0; 76   m_iScrollPos = 0; 77   m_iVolumePos = 50; 78  79   m_thread_id = 0; 80   m_dwPlayPos = 0; 81   ZeroMemory(&opfn, sizeof(OPENFILENAME)); 82   memset( m_wstrTime, 0, sizeof(m_wstrTime) ); 83   memset( m_wSongTime, 0, sizeof(m_wSongTime) ); 84   memset( m_wSongLeave, 0, sizeof(m_wSongLeave) ); 85   memset( m_wSongPath, 0, sizeof(m_wSongPath) ); 86   memset( m_wSongName, 0, sizeof(m_wSongName) ); 87   memset( m_wSongPathPre, 0, sizeof(m_wSongPathPre) ); 88   memset( m_wSongNamePre, 0, sizeof(m_wSongNamePre) ); 89   m_list.clear(); 90   g_pmySound = this; 91 } 92  93 myD3DSound::~myD3DSound() 94 { 95   SAFE_RELEASE(m_pBuffer8); 96   SAFE_RELEASE(m_pDirectSound); 97   ZeroMemory(&opfn, sizeof(OPENFILENAME)); 98   memset( m_wstrTime, 0, sizeof(m_wstrTime) ); 99   memset( m_wSongTime, 0, sizeof(m_wSongTime) ); 100   memset( m_wSongLeave, 0, sizeof(m_wSongLeave) ); 101   memset( m_wSongPath, 0, sizeof(m_wSongPath) ); 102   memset( m_wSongName, 0, sizeof(m_wSongName) ); 103   memset( m_wSongPathPre, 0, sizeof(m_wSongPathPre) ); 104   memset( m_wSongNamePre, 0, sizeof(m_wSongNamePre) ); 105   if( m_fp ) 106   { 107     fclose( m_fp ); 108     m_fp = NULL; 109   } 110   m_list.clear(); 111   cleanup(); 112 } 113  114  115  116 void myD3DSound::myCreateWin( HWND hWnd ) 117 { 118   RECT dynamic_rc; 119   RECT button_rc; 120   RECT static_rc; 121   RECT list_rc; 122   GetClientRect( hWnd, &dynamic_rc ); 123   LONG Width  = dynamic_rc.right - dynamic_rc.left; 124   LONG Height = dynamic_rc.bottom - dynamic_rc.top; 125  126   button_rc.left = 15; 127   button_rc.top = 15; 128   m_openbtn = CreateWindow( TEXT("BUTTON"), TEXT("Add"),WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 129     button_rc.left, button_rc.top, 50, 20, hWnd, (HMENU)IDB_OPEN, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 130  131   button_rc.left += 60; 132   m_closebtn = CreateWindow( TEXT("BUTTON"), TEXT("Del"),WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 133     button_rc.left, button_rc.top, 50, 20, hWnd, (HMENU)IDB_CLOSE, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 134  135   button_rc.left += 60; 136   m_playbtn = CreateWindow( TEXT("BUTTON"), TEXT("Play"),WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 137     button_rc.left, button_rc.top, 50, 20, hWnd, (HMENU)IDB_PLAY, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 138  139   button_rc.left += 60; 140   m_pausebtn = CreateWindow( TEXT("BUTTON"), TEXT("Pause"),WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 141     button_rc.left, button_rc.top, 50, 20, hWnd, (HMENU)IDB_PAUSE, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 142  143   button_rc.left += 60; 144   m_stopbtn = CreateWindow( TEXT("BUTTON"), TEXT("Stop"),WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 145     button_rc.left, button_rc.top, 50, 20, hWnd, (HMENU)IDB_STOP, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 146    147   button_rc.left += 60; 148   m_scrollbar = CreateWindow( TRACKBAR_CLASS, TEXT(""), WS_VISIBLE|WS_CHILD|WS_BORDER|TBS_HORZ|TBS_TOOLTIPS, 149     button_rc.left, button_rc.top, 275, 20, hWnd, (HMENU)12, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 150   //static 151   static_rc.left = 15; 152   static_rc.top = 50; 153   m_txtplaying = CreateWindow(TEXT("STATIC"), TEXT("playing now:"), WS_VISIBLE|WS_CHILD|SS_CENTER|SS_OWNERDRAW, 154     static_rc.left, static_rc.top, 90, 20, hWnd, (HMENU)IDB_PLAYING, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 155  156   static_rc.left += ( 90 + 10 ); 157   m_songtxt = CreateWindow( TEXT("STATIC"), TEXT("无文件"), WS_VISIBLE|WS_CHILD|WS_BORDER|SS_LEFT|SS_OWNERDRAW, 158     static_rc.left, static_rc.top, 560, 20, hWnd, (HMENU)IDB_SONGTEXT, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 159  160   static_rc.left = 15; 161   static_rc.top = Height - 5 - 16; 162   m_songinfo = CreateWindow( TEXT("STATIC"), TEXT("请选择wav文件进行播放。"), WS_VISIBLE|WS_CHILD|SS_CENTER|WS_BORDER|SS_OWNERDRAW, 163     static_rc.left, static_rc.top, 350, 16, hWnd, (HMENU)IDB_SONGINFO, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 164  165   static_rc.left += (350 + 10); 166   m_songtime = CreateWindow( TEXT("STATIC"), TEXT("00:00 / 00:00"), WS_VISIBLE|WS_CHILD|SS_CENTER|WS_BORDER|SS_OWNERDRAW, 167     static_rc.left, static_rc.top, 140, 16, hWnd, (HMENU)IDB_SONGTIME, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 168  169   static_rc.left = Width - 15 - 150; 170   m_timeshow = CreateWindow( TEXT("STATIC"), TEXT(""), WS_VISIBLE|WS_CHILD|SS_CENTER|SS_OWNERDRAW, 171     static_rc.left, static_rc.top, 150, 16, hWnd, (HMENU)IDB_TIMESHOW, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 172  173   static_rc.left = Width - 90; 174   static_rc.top = 15; 175   m_volumebar = CreateWindow( TRACKBAR_CLASS, TEXT(""), WS_VISIBLE|WS_CHILD|WS_BORDER|TBS_HORZ|TBS_TOOLTIPS, 176     static_rc.left, static_rc.top, 80, 20, hWnd, (HMENU)13, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 177   SendMessage( m_volumebar, TBM_SETPOS, TRUE, (LPARAM)50 ); 178  179   list_rc.left = 30; 180   list_rc.top = 80; 181   m_listview = CreateWindowEx( LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT, WC_LISTVIEW, TEXT(""),  182     WS_VISIBLE|WS_CHILD|WS_BORDER|WS_VSCROLL|WS_HSCROLL|LVS_REPORT|LVS_SHOWSELALWAYS|LVS_SINGLESEL,  183     list_rc.left, list_rc.top, 640, 145, hWnd, (HMENU)IDB_SONGLIST, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL ); 184 } 185  186  187  188 void myD3DSound::myChangeSize( HWND hWnd ) 189 { 190   RECT dynamic_rc; 191   GetClientRect( hWnd, &dynamic_rc ); 192   LONG Width  = dynamic_rc.right - dynamic_rc.left; 193   LONG Height = dynamic_rc.bottom - dynamic_rc.top; 194    195   MoveWindow( m_songinfo, 15, Height - 5 - 16, 350, 16, TRUE ); 196  197   MoveWindow( m_songtime, 15 + 350 + 10, Height - 5 - 16, 140, 16, TRUE ); 198    199   MoveWindow( m_timeshow, Width - 15 - 150, Height - 5 - 16, 150, 16, TRUE ); 200  201   MoveWindow( m_songtxt, 115, 50, Width - 115 - 15, 20, TRUE ); 202  203   MoveWindow( m_scrollbar, 315, 15, Width - 315 - 15 - 90, 20, TRUE ); 204  205   MoveWindow(  m_volumebar, Width - 90, 15, 80, 20, TRUE ); 206  207   MoveWindow( m_listview, 30, 80, Width - 60, Height - 80 - 10 - 21, TRUE ); 208    209 } 210  211  212 void myD3DSound::mySetList( WCHAR* wcFilename ) 213 { 214   myListMember tmplist; 215   //m_path 216   StrCpyW( tmplist.m_path, wcFilename ); 217   //m_name 218   char  cName[100]; 219   char  tmpstr[MAX_PATH]; 220   memset(cName,0,100); 221   memset(tmpstr,0,MAX_PATH); 222  223   WCHARtoChar( wcFilename, tmpstr ); 224   int len = strlen(tmpstr); 225   char* p = &tmpstr[len]; 226   int len_name = 0; 227   bool isname = 0;  228   bool bk = 0; 229   while( !bk ) 230   { 231     if( !isname && (*p == '.') ) 232     { 233       isname = true; 234       p--; 235       continue; 236     } 237     if( isname ) 238     { 239       if(*p == '\\' ) 240       { 241         bk = true; 242         p++; 243         continue; 244       } 245       len_name++; 246     } 247     p--; 248   } 249   memcpy( cName, p, len_name ); 250   ChartoWCHAR( cName, tmplist.m_name ); 251  252   //type 253   LPWSTR  lwType; 254   char  ctmpType[5]; 255   char  cType[4]; 256   lwType = PathFindExtension( wcFilename ); 257   WCHARtoChar( lwType, ctmpType); 258   sprintf_s( cType, "%s", ctmpType+1); 259   ChartoWCHAR( cType, tmplist.m_type ); 260  261   if( StrCmpW( lwType, TEXT(".wav") ) == 0 || StrCmpW( lwType, TEXT(".WAV") ) == 0 ) 262   { 263     //m_bits 264     FILE* tmpfp = NULL; 265     char  cBits[20]; 266     DWORD  tmpSize; 267     DWORD  tmpCycle; 268     WAVEFORMATEX* pwfx = NULL; 269     memset(cBits,0,20); 270     if( fopen_s( &tmpfp, tmpstr, "rb" ) == 0 ) 271     { 272       myGetWAVFormat( &tmpSize, &tmpCycle, tmpfp, &pwfx ); 273       if(pwfx != NULL) 274       { 275         sprintf_s( cBits, 20, "%d kbps", (pwfx->wBitsPerSample * pwfx->nChannels * pwfx->nSamplesPerSec)/1000 ); 276       } 277       fclose(tmpfp); 278     } 279     ChartoWCHAR( cBits, tmplist.m_bits ); 280     //time 281     char cTime[10]; 282     memset(cTime,0,10); 283     sprintf_s( cTime, "%02d:%02d", tmpCycle/60, tmpCycle%60 ); 284     ChartoWCHAR( cTime, tmplist.m_time ); 285   } 286   else if( StrCmpW( lwType, TEXT(".mp3") ) == 0 || StrCmpW( lwType, TEXT(".MP3") ) == 0 ) 287   { 288     char  cBits[20]; 289     int    bits; 290     DWORD  tmpSize; 291     DWORD  tmpCycle; 292     FILE* tmpfp = NULL; 293     WAVEFORMATEX* pwfx = NULL; 294     memset(cBits,0,20); 295     if( myGetMP3Format( tmpstr, &tmpSize, &tmpCycle, &bits, &pwfx ) == 0 ) 296     { 297       sprintf_s( cBits, 20, "%d kbps", bits); 298     } 299     ChartoWCHAR( cBits, tmplist.m_bits ); 300     //time 301     char cTime[10]; 302     memset(cTime,0,10); 303     sprintf_s( cTime, "%02d:%02d", tmpCycle/60, tmpCycle%60 ); 304     ChartoWCHAR( cTime, tmplist.m_time ); 305   } 306  307   m_list.push_back( tmplist ); 308  309   myUpdateList(); 310 } 311  312  313  314 void myD3DSound::myUpdateList() 315 { 316   ListView_DeleteAllItems(m_listview);  317  318   int iSize = m_list.size(); 319   LVITEM vitem; 320   vitem.mask = LVIF_TEXT; 321   for( int i = 0; i< iSize; i++ ) 322   { 323     char  cIdx[100]; 324     WCHAR  wIdx[100]; 325     memset(cIdx,0,100); 326     memset(wIdx,0,100); 327  328     vitem.iItem = i; 329     m_list[i].m_idx = i+1;  330     sprintf_s( cIdx, "%d", i+1 ); 331     ChartoWCHAR( cIdx, wIdx ); 332     vitem.pszText = wIdx; 333     vitem.iSubItem = 0;  334     ListView_InsertItem(m_listview, &vitem); 335    336     vitem.iSubItem = 1;  337     vitem.pszText = m_list[i].m_name;  338     ListView_SetItem( m_listview, &vitem);   339     vitem.iSubItem = 2;  340     vitem.pszText = m_list[i].m_time;  341     ListView_SetItem(m_listview, &vitem);  342     vitem.iSubItem = 3;  343     vitem.pszText = m_list[i].m_type;  344     ListView_SetItem(m_listview, &vitem);  345     vitem.iSubItem = 4;  346     vitem.pszText = m_list[i].m_bits;  347     ListView_SetItem(m_listview, &vitem);  348     vitem.iSubItem = 5;  349     vitem.pszText = m_list[i].m_path;  350     ListView_SetItem(m_listview, &vitem);  351   } 352 } 353  354  355  356 int myD3DSound::mySongNum() 357 { 358   return m_list.size(); 359 } 360  361  362  363 void myD3DSound::myInitList() 364 { 365   LVCOLUMN vcl; 366   vcl.mask = LVCF_SUBITEM | LVCF_WIDTH | LVCF_TEXT | LVCF_FMT; 367   vcl.fmt = LVCFMT_LEFT; 368   for( int i = 0; i < 6; i++ ) 369   { 370     vcl.pszText = g_cwSongList[i]; 371     vcl.cx = 80; 372     if( i == 5 ) 373       vcl.cx = 800; 374     vcl.iSubItem = i; 375     ListView_InsertColumn( m_listview, i, &vcl );  376   } 377 } 378  379  380  381 void myD3DSound::mySetTimer( SYSTEMTIME time ) 382 { 383   char strtime[60]; 384   memset( strtime, 0, 60 ); 385   sprintf_s(strtime,"%04d-%02d-%02d %02d:%02d:%02d", 386     time.wYear,time.wMonth,time.wDay,time.wHour,time.wMinute,time.wSecond); 387   ChartoWCHAR(strtime,m_wstrTime); 388 } 389  390  391  392 WCHAR* myD3DSound::myGetTimer() 393 { 394   return m_wstrTime; 395 } 396  397  398  399 void myD3DSound::mySetScrollPos( bool isUp, DWORD dPos ) 400 { 401   if(isUp) 402   { 403     int iPos; 404     iPos = SendMessage( m_scrollbar, TBM_GETPOS, 0, 0 ); 405     if( g_pmySound->isPlay() && g_pmySound->m_ds_dwFileSize <= DSBSIZE_MAX ) 406     { 407       DWORD dNewPos; 408       dNewPos = iPos * (g_pmySound->m_ds_dwFileSize / 100);  409       g_pmySound->m_pBuffer8->SetCurrentPosition( dNewPos ); 410       g_pmySound->m_pBuffer8->Play(0, 0, DSBPLAY_LOOPING); 411     } 412     else 413     { 414       iPos = SendMessage( m_scrollbar, TBM_SETPOS, TRUE, (LPARAM)0 ); 415     } 416      417   } 418   else 419   { 420  421   } 422 } 423  424  425  426  427 void myD3DSound::mySetVolumePos( bool isUp, DWORD dPos ) 428 { 429   LONG vol = 0; 430   double dbValue; 431   int iPos; 432   if( isUp && m_pBuffer8 != NULL ) 433   { 434     iPos = SendMessage( m_volumebar, TBM_GETPOS, 0, 0 ); 435     if( iPos > 0 && iPos <= 100 ) 436     { 437       dbValue = 20.0f * log10( (double)(iPos / 100.0f) );  438       vol = (LONG)(dbValue * 100.0f);  439     } 440     else if( iPos == 0 ) 441     { 442       vol = DSBVOLUME_MIN; 443     } 444     else 445     { 446       vol = DSBVOLUME_MAX; 447     } 448     m_pBuffer8->SetVolume( vol ); 449   } 450 } 451  452  453  454  455 void myD3DSound::myOpenFile() 456 { 457   WCHAR strFilename[MAX_PATH];  458   ZeroMemory(&opfn, sizeof(OPENFILENAME)); 459  460   opfn.lStructSize = sizeof(OPENFILENAME);                //结构体大小 461   opfn.lpstrFilter = L"所有文件\0*.*\0wav文件\0*.wav\0MP3文件\0*.mp3\0";  //过滤器 462   opfn.nFilterIndex = 1;                          //过滤索引 463   opfn.lpstrFile = strFilename;                      //文件名的缓冲,不需要初始化则必须为null 464   opfn.lpstrFile[0] = '\0';  465   opfn.nMaxFile = sizeof(strFilename); 466   opfn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;  467  468   if( GetOpenFileName(&opfn) )  469   { 470     mySetList(strFilename); 471   } 472 } 473  474 void myD3DSound::myCloseFile() 475 { 476   ZeroMemory(&opfn, sizeof(OPENFILENAME)); 477   if( StrCmpW(m_wSongPath, m_wSongPathPre) == 0 ) 478   { 479     SetWindowText(m_songtxt, TEXT("")); 480     myStop(); 481     if( m_fp ) 482     { 483       fclose( m_fp ); 484       m_fp = NULL; 485     } 486   } 487   MY_SONG_LIST::iterator Songit; 488   for( Songit = m_list.begin(); Songit != m_list.end(); Songit++ ) 489   { 490     if( StrCmpW(Songit->m_path, m_wSongPathPre) == 0 ) 491     { 492       m_list.erase( Songit ); 493       memset( m_wSongPathPre, 0, MAX_PATH ); 494       memset( m_wSongPath, 0, MAX_PATH ); 495       myUpdateList(); 496       return; 497     } 498   } 499    500 } 501  502  503  504 void myD3DSound::mySetPlayInfo( NM_LISTVIEW* pNMListView, bool DBClick ) 505 { 506   if( DBClick ) 507   { 508     if( StrCmpW(m_list[pNMListView->iItem].m_path, m_wSongPath) ) 509     {//双击新歌则停止当前播放 510       myStop(); 511     } 512     StrCpyW( m_wSongPath, m_list[pNMListView->iItem].m_path ); 513     StrCpyW( m_wSongName, m_list[pNMListView->iItem].m_name ); 514     StrCpyW( m_wSongPathPre, m_list[pNMListView->iItem].m_path ); 515     StrCpyW( m_wSongNamePre, m_list[pNMListView->iItem].m_name ); 516   } 517   else 518   {//单击 519     StrCpyW( m_wSongPathPre, m_list[pNMListView->iItem].m_path ); 520     StrCpyW( m_wSongNamePre, m_list[pNMListView->iItem].m_name ); 521     if( ! isPlay() ) 522     { 523       StrCpyW( m_wSongPath, m_list[pNMListView->iItem].m_path ); 524       StrCpyW( m_wSongName, m_list[pNMListView->iItem].m_name ); 525     } 526   } 527 } 528  529  530  531 int myD3DSound::myPlay() 532 { 533   if( isPlay() ) 534   { 535     if( StrCmpW( m_wSongPath, m_wSongPathPre ) ) 536     { 537       myStop(); 538       StrCpyW( m_wSongName, m_wSongNamePre ); 539       StrCpyW( m_wSongPath, m_wSongPathPre ); 540     } 541     else 542     { 543       return 0; 544     } 545   } 546   if( m_pBuffer8 == NULL ) 547   { 548     int res = 0; 549     res = mySetSoundType(); 550     if( res != 0 ) 551     { 552       MessageBox( m_father, g_cwErrorMsg[res], TEXT("ERROR"), MB_OK ); 553       return 0; 554     } 555     //create notification thread 556     m_hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ThreadNotifyEvent, NULL, 0, &m_thread_id ); 557     m_hThread2 = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ThreadNotifyEvent2, NULL, 0, &m_thread_id2 ); 558     m_hThread3 = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ThreadNotifyEvent3, NULL, 0, &m_thread_id3 ); 559     SetWindowText( m_songtxt, m_wSongName ); 560   } 561   SetPlaying( TRUE ); 562   mySetVolumePos(TRUE,0); 563   m_pBuffer8->SetCurrentPosition( m_dwPlayPos ); 564   m_pBuffer8->Play(0, 0, DSBPLAY_LOOPING); 565   return 0; 566 } 567  568  569  570 int myD3DSound::myStop() 571 { 572   myCleanBuffer(); 573   if( isPlay() ) 574   { 575     CloseHandle( m_hEvents[0] ); 576  577     if( m_hThread != NULL ) 578     { 579       TerminateThread( m_hThread, 0 ); 580       CloseHandle( m_hThread ); 581     } 582   } 583   if( IsMPG3() ) 584   { 585     cleanup(); 586   } 587   SetWindowText( m_songinfo, TEXT("请选择wav文件进行播放。") ); 588   StrCpyW( m_wSongName, TEXT("")); 589   StrCpyW( m_wSongPath, TEXT("")); 590   SetWindowText( m_songtxt, m_wSongName ); 591   SendMessage( g_pmySound->m_scrollbar, TBM_SETPOS, TRUE, (LPARAM)0 ); 592   SetWindowText( g_pmySound->m_songtime, TEXT("00:00 / 00:00") ); 593   return 0; 594 } 595  596  597  598 int myD3DSound::myPause() 599 { 600   if( m_pBuffer8 == NULL ) 601     return -1; 602   if( isPlay() ) 603   { 604     m_pBuffer8->GetCurrentPosition( &m_dwPlayPos, NULL ); 605     SetPlaying( FALSE ); 606     m_pBuffer8->Stop(); 607   } 608   else 609   { 610     SetPlaying( TRUE ); 611     m_pBuffer8->SetCurrentPosition( m_dwPlayPos ); 612     m_pBuffer8->Play(0, 0, DSBPLAY_LOOPING); 613   } 614   return 0; 615 } 616  617  618  619 int myD3DSound::GetBufferValue( FILE** fp, mpg123_handle** mpghandle, DWORD* BuffSize ) 620 { 621   *fp = m_fp; 622   *mpghandle = m_mpghandle; 623   *BuffSize = m_ds_dwBuffSize; 624   return 0; 625 } 626  627  628 /////////////////////// 629 //private 630 /////////////////////// 631  632 int myD3DSound::mySetSoundType() 633 { 634   WCHAR cNameStr[MAX_PATH]; 635   LPWSTR lpNameType; 636   char cType[4]; 637   char cTmpStr[5]; 638   memset( cNameStr, 0, MAX_PATH ); 639   memset( cType, 0, 4 ); 640   memset( cTmpStr, 0, 5 ); 641  642   StrCpyW( cNameStr, m_wSongPath ); 643  644   if( cNameStr[0] == '\0' ) 645   { 646     return EFAIL_NOFILE; 647   } 648   lpNameType = PathFindExtension( cNameStr ); 649  650   WCHARtoChar( lpNameType, cTmpStr); 651   sprintf_s( cType, "%s", cTmpStr+1); 652   if( StrCmpW( lpNameType, TEXT(".mp3") ) == 0 || StrCmpW( lpNameType, TEXT(".MP3") ) == 0 ) 653   { 654     DWORD dwSize;    //stream size 655     DWORD dwCycle; 656     DWORD dwBuffSize; 657     int bitrate; 658     WAVEFORMATEX wfx; 659     WAVEFORMATEX* pTmpWfx = NULL; 660     char filepath[MAX_PATH]; 661     memset( filepath, 0, MAX_PATH ); 662     WCHARtoChar( cNameStr, filepath ); 663     if( myGetMP3Format( filepath, &dwSize, &dwCycle, &bitrate, &pTmpWfx, FALSE ) != 0 ) 664     { 665       return EFAIL_FORMATERR; 666     } 667     m_ds_dwFileSize = dwSize; 668  669     m_ds_dwFileTime = dwCycle; 670     m_ds_dwFilebps = pTmpWfx->nAvgBytesPerSec; 671     m_ds_dwPos    = 0;    //offset position 672     m_ds_dwLeave  = dwSize;  //leave data size 673     wfx.wFormatTag    = pTmpWfx->wFormatTag; 674     wfx.nChannels    = pTmpWfx->nChannels; 675     wfx.nSamplesPerSec = pTmpWfx->nSamplesPerSec; 676     wfx.wBitsPerSample = pTmpWfx->wBitsPerSample; 677     wfx.nBlockAlign   = pTmpWfx->nBlockAlign; 678     wfx.nAvgBytesPerSec = pTmpWfx->nAvgBytesPerSec; 679     pTmpWfx = NULL; 680     if( FAILED( myCreateMPGBuffer( &wfx, &dwBuffSize ) ) ) 681     { 682       return EFAIL_MPGBUFFERERR; 683     } 684     m_ds_dwBuffSize = dwBuffSize; 685     //song info 686     WCHAR  wcStr_info[100]; 687     char  cStr_info[100];   688     char  cStr_type[5]; 689     memset( wcStr_info,0,100 ); 690     memset( cStr_info,0,100 ); 691     memset( cStr_type,0,5 ); 692     WCHARtoChar( lpNameType, cStr_type ); 693     sprintf_s( cStr_info, "%s | %d kbps | %d Hz", cStr_type+1, bitrate, wfx.nSamplesPerSec); 694     ChartoWCHAR( cStr_info, wcStr_info ); 695     SetWindowText( m_songinfo, wcStr_info ); 696     m_bmpg = TRUE; 697   } 698  699   else if( StrCmpW( lpNameType, TEXT(".wav") ) == 0 || StrCmpW( lpNameType, TEXT(".WAV") ) == 0 ) 700   { 701     WAVEFORMATEX wfx; 702     DWORD dwSize;      //声音文件总大小 703     DWORD dwCycle; 704  705     DWORD dwBuffSize;    //创建的缓冲区总大小 706     int inum=WideCharToMultiByte(CP_ACP,0,cNameStr,-1,NULL,0,NULL,0); 707     char* cfilename = NULL; 708     cfilename = (char*)malloc( inum * sizeof(char) ); 709     if( cfilename == NULL ) 710       free(cfilename); 711     memset( cfilename, 0, inum * sizeof(char) ); 712     WideCharToMultiByte(CP_ACP,0,cNameStr,-1,cfilename,inum,NULL,0);  713  714     if( fopen_s( &m_fp, cfilename, "rb" ) ) 715     { 716       return EFAIL_OPENFILEERR; 717     } 718     WAVEFORMATEX* pTmpWfx = NULL; 719     myGetWAVFormat( &dwSize, &dwCycle, m_fp, &pTmpWfx ); 720  721     if( pTmpWfx == NULL ) 722     { 723       return EFAIL_FORMATERR; 724     } 725     m_ds_dwFileSize = dwSize; 726  727     m_ds_dwFileTime = dwCycle; 728     m_ds_dwFilebps = pTmpWfx->nAvgBytesPerSec; 729     if(m_factwav) 730       m_ds_dwPos = sizeof(WAVE_HEADER_FACT);  //offset position 731     else 732       m_ds_dwPos = sizeof(WAVE_HEADER); 733  734     m_ds_dwLeave = dwSize;        //leave data size 735     wfx.wFormatTag    = pTmpWfx->wFormatTag; 736     wfx.nChannels    = pTmpWfx->nChannels; 737     wfx.nSamplesPerSec = pTmpWfx->nSamplesPerSec; 738     wfx.wBitsPerSample = pTmpWfx->wBitsPerSample; 739     wfx.nBlockAlign   = pTmpWfx->nBlockAlign; 740     wfx.nAvgBytesPerSec = pTmpWfx->nAvgBytesPerSec; 741     pTmpWfx = NULL; 742     if( FAILED( myCreatePCMBuffer( &wfx, &dwBuffSize ) ) ) 743     { 744       return EFAIL_PCMBUFFERERR; 745     } 746     m_ds_dwBuffSize = dwBuffSize;  //返回缓冲区大小 747     //songinfo 748     WCHAR  wcStr_info[100];  //output info 749     char  cStr_info[100];   750     char  cStr_type[5]; 751     memset( wcStr_info,0,100 ); 752     memset( cStr_info,0,100 ); 753     memset( cStr_type,0,5 ); 754     WCHARtoChar( lpNameType, cStr_type ); 755     sprintf_s( cStr_info, "%s | %d kbps | %d Hz", cStr_type+1,  756       (wfx.wBitsPerSample * wfx.nChannels * wfx.nSamplesPerSec)/1000, wfx.nSamplesPerSec);  //类型|比特率|频率 757     ChartoWCHAR( cStr_info, wcStr_info ); 758     SetWindowText( m_songinfo, wcStr_info ); 759     m_bmpg = FALSE; 760   } 761   else 762   { 763     return EFAIL_NOTSUPPORT; 764   } 765  766    767   return 0; 768  769 } 770  771  772  773 int myD3DSound::myGetWAVFormat( DWORD* dwSize, DWORD* dwCycle, FILE* fp, WAVEFORMATEX** wfx ) 774 { 775   WAVE_HEADER      wave_header; 776   WAVE_HEADER_FACT  wave_header2; 777 #ifndef _DEBUG 778   volatile WAVEFORMATEX  wave_format; 779 #else 780   WAVEFORMATEX  wave_format; 781 #endif 782   char fact[4]; 783   fseek( fp, 38, SEEK_SET ); 784   fread( fact, 1, 4, fp ); 785   fseek( fp, 0, SEEK_SET ); 786   if( memcmp(fact,"fact",4) == 0 ) 787   { 788     fread( &wave_header2, 1, sizeof(WAVE_HEADER_FACT), fp); 789     m_factwav = TRUE; 790     if(memcmp(wave_header2.riff_sig, "RIFF", 4) ||  791       memcmp(wave_header2.wave_sig, "WAVE", 4) || 792       memcmp(wave_header2.format_sig, "fmt ", 4) ) 793     { 794       return -1; 795     } 796     wave_format.wFormatTag   = WAVE_FORMAT_PCM; 797     wave_format.nChannels    = wave_header2.channels; 798     wave_format.nSamplesPerSec = wave_header2.sample_rate; 799     wave_format.wBitsPerSample = wave_header2.bits_per_sample; 800     wave_format.nBlockAlign   = wave_header2.bits_per_sample / 8 * wave_header2.channels; 801     wave_format.nAvgBytesPerSec = wave_header2.sample_rate * wave_format.nBlockAlign; 802     *dwSize = wave_header2.data_size; 803     *dwCycle = wave_header2.data_size / wave_format.nAvgBytesPerSec; 804   } 805   else 806   { 807     fread( &wave_header, 1, sizeof(WAVE_HEADER), fp); 808     m_factwav = FALSE; 809     if(memcmp(wave_header.riff_sig, "RIFF", 4) ||  810       memcmp(wave_header.wave_sig, "WAVE", 4) || 811       memcmp(wave_header.format_sig, "fmt ", 4) ) 812     { 813       return -1; 814     } 815     wave_format.wFormatTag   = WAVE_FORMAT_PCM; 816     wave_format.nChannels    = wave_header.channels; 817     wave_format.nSamplesPerSec = wave_header.sample_rate; 818     wave_format.wBitsPerSample = wave_header.bits_per_sample; 819     wave_format.nBlockAlign   = wave_header.bits_per_sample / 8 * wave_header.channels; 820     wave_format.nAvgBytesPerSec = wave_header.sample_rate * wave_format.nBlockAlign; 821     *dwSize = wave_header.data_size; 822     *dwCycle = wave_header.data_size / wave_format.nAvgBytesPerSec; 823   } 824  825   *wfx = (WAVEFORMATEX*)&wave_format; 826   return 0; 827 } 828  829  830  831  832 int myD3DSound::myGetMP3Format( char* filestr, DWORD* dwSize, DWORD* dwCycle, int* bitrate, WAVEFORMATEX** wfx, bool isClose ) 833 { 834   int    ret = MPG123_OK; 835   int    channels = 0;  //声道 836   int    encoding = 0;  //编码格式 837   long  rate = 0;    //频率 838   int    perbits = 16;  //bits per second 839   long  fTime = 0; 840   long  fSize = 0; 841   int    simpleNum = 1152; 842   long  frameNum; 843   //long  streamSize; 844   long  streamSize1; 845   long  streamSize2; 846   long  streamSize3; 847   FILE*  tmpfp = NULL; 848 #ifndef _DEBUG 849   volatile WAVEFORMATEX  wave_format; 850 #else 851   WAVEFORMATEX  wave_format; 852 #endif 853   mpg123_frameinfo mpginfo; 854  855   cleanup(); 856  857   ret = mpg123_init(); 858   if(ret != MPG123_OK || ( m_mpghandle = mpg123_new(NULL, &ret) ) == NULL) 859    { 860      cleanup(); 861     return -1; 862    } 863   if( mpg123_open(m_mpghandle, filestr) != MPG123_OK || mpg123_getformat(m_mpghandle, &rate, &channels, &encoding) != MPG123_OK ) 864    { 865      cleanup(); 866     return -1; 867    } 868  869   if((encoding & MPG123_ENC_16) == MPG123_ENC_16) 870     perbits = 16; 871   else if((encoding & MPG123_ENC_32) == MPG123_ENC_32) 872     perbits = 32; 873   else 874     perbits = 8; 875  876   //wfx 877   wave_format.wFormatTag   = WAVE_FORMAT_PCM; 878   wave_format.nChannels    = channels; 879   wave_format.nSamplesPerSec = rate; 880   wave_format.wBitsPerSample = perbits; 881   wave_format.nBlockAlign   = perbits / 8 * channels; 882   wave_format.nAvgBytesPerSec = rate * perbits / 8 * channels; 883   *wfx = (WAVEFORMATEX*)&wave_format; 884  885   mpg123_seek( m_mpghandle, 0, SEEK_END ); 886   frameNum = mpg123_tellframe( m_mpghandle ); 887   //总帧数法:Total_Time = Total_Frame_Number * (Sample_Number * (1 / Frame_Sample_Rate)) 888   fTime = (long)( frameNum * simpleNum / rate ); 889  890   //time and buffer size 891   *dwCycle = fTime; 892   //data size = ftime * nAvgBytesPerSec = (frameNum*simpleNum/rate)*(rate*perbits/8*channels) 893   *dwSize = frameNum * simpleNum * perbits * channels / 8; 894  895   if( mpg123_info( m_mpghandle, &mpginfo) != MPG123_OK ) 896    { 897      cleanup(); 898     return -1; 899    } 900   if(mpginfo.layer != 3) 901   { 902     cleanup(); 903     return -1; 904   } 905  906   //bit rate 907   if( mpginfo.vbr == MPG123_CBR ) 908   { 909     *bitrate = mpginfo.bitrate; 910   } 911   else if( mpginfo.vbr == MPG123_VBR ) 912   { 913     if( fopen_s( &tmpfp, filestr, "rb" ) == 0 ) 914     { 915       fseek( tmpfp, 0, SEEK_END ); 916       fSize = ftell( tmpfp );    //文件大小 917       fclose( tmpfp ); 918       tmpfp = NULL; 919       *bitrate = (fSize * 8)/(fTime*1000);  //(kbits/s) : filesize(bytes)*8(bits)/filetime(s)/1000 920       //平均比特率 = 文件大小/总时间/1000 921     } 922   } 923   if(isClose) 924   { 925     cleanup(); 926   } 927   return 0; 928 } 929  930  931  932  933 HRESULT myD3DSound::myCreatePCMBuffer( WAVEFORMATEX* wfx, DWORD* dwBuffSize ) 934 { 935   DSBUFFERDESC dsbd; 936   WAVEFORMATEX wave; 937   IDirectSound8* lpDS8; 938   LPDIRECTSOUNDBUFFER    pTmpBuffer; 939  940   LPDIRECTSOUNDNOTIFY8  pNotify; 941  942   DSBPOSITIONNOTIFY    dspNotify; 943  944   DSCAPS caps; 945  946   if( m_pDirectSound == NULL ) 947     return E_FAIL; 948  949   lpDS8 = m_pDirectSound; 950   ZeroMemory(&dsbd, sizeof(dsbd)); 951  952   wave.wFormatTag = WAVE_FORMAT_PCM; 953   if( wfx ) 954   { 955     wave.nChannels = wfx->nChannels;      //音频文件的通道数量 956     wave.nSamplesPerSec = wfx->nSamplesPerSec;  //采样频率 957     wave.wBitsPerSample = wfx->wBitsPerSample;  //每次采样样本的大小 958   } 959   else 960   { 961     wave.nChannels = 2;             962     wave.nSamplesPerSec = 44100; 963     wave.wBitsPerSample = 16; 964   } 965   wave.nBlockAlign = wave.nChannels * wave.wBitsPerSample / 8; 966   wave.nAvgBytesPerSec = wave.nSamplesPerSec * wave.nBlockAlign; 967   wave.cbSize = 0; 968  969   dsbd.dwSize = sizeof(dsbd);  970   dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY; 971  972   if( m_ds_dwFileSize > DSBSIZE_MAX ) 973     dsbd.dwBufferBytes = DSBSIZE_MAX; 974   else 975     dsbd.dwBufferBytes = m_ds_dwFileSize; 976  977  978   *dwBuffSize = dsbd.dwBufferBytes;    //返回缓冲区大小 979   dsbd.lpwfxFormat = &wave; 980  981   caps.dwSize = sizeof(DSCAPS); 982   if( SUCCEEDED( lpDS8->GetCaps(&caps) ) ) 983   { 984     if( caps.dwMaxHwMixingStreamingBuffers > 0 ) 985       dsbd.dwFlags |= DSBCAPS_LOCDEFER; 986     else 987       dsbd.dwFlags |= DSBCAPS_STATIC; 988   } 989  990   if( FAILED( lpDS8->CreateSoundBuffer( &dsbd, &pTmpBuffer, NULL ) ) ) 991     return E_FAIL; 992  993   if( FAILED( pTmpBuffer->QueryInterface( IID_IDirectSoundBuffer8, (void**)&m_pBuffer8 ) ) ) 994     return E_FAIL; 995   pTmpBuffer->Release(); 996  997  998  999   if( FAILED( m_pBuffer8->QueryInterface( IID_IDirectSoundNotify,(void**)&pNotify ) ) )1000     return E_FAIL;1001 1002   dspNotify.dwOffset = dsbd.dwBufferBytes - 1;1003   m_hEvents[0] = CreateEvent(NULL,FALSE,FALSE,NULL); 1004   dspNotify.hEventNotify = m_hEvents[0];1005   pNotify->SetNotificationPositions( 1, &dspNotify);1006   pNotify->Release();  1007 1008   fseek( m_fp, m_ds_dwPos, SEEK_SET );1009   if( myReadBuffer( 0, dsbd.dwBufferBytes ) )1010   {1011     m_ds_dwPos    += dsbd.dwBufferBytes;1012     //if(m_ds_dwFileSize <= DSBSIZE_MAX), this m_ds_dwLeave will be 01013     m_ds_dwLeave  -= dsbd.dwBufferBytes;1014 1015     return S_OK;1016   }1017   else1018     return E_FAIL;1019 1020 }1021 1022 1023 1024 1025 HRESULT myD3DSound::myCreateMPGBuffer( WAVEFORMATEX* wfx, DWORD* dwBuffSize )1026 {1027   DSBUFFERDESC dsbd;1028   WAVEFORMATEX wave;1029   IDirectSound8* lpDS8;1030   LPDIRECTSOUNDBUFFER    pTmpBuffer;1031 1032   LPDIRECTSOUNDNOTIFY8  pNotify;1033 1034   DSBPOSITIONNOTIFY    dspNotify;1035 1036 1037   DSCAPS caps;1038 1039   if( m_pDirectSound == NULL )1040     return E_FAIL;1041 1042   lpDS8 = m_pDirectSound;1043   ZeroMemory(&dsbd, sizeof(dsbd));1044 1045   wave.wFormatTag = WAVE_FORMAT_PCM;1046   if( wfx )1047   {1048     wave.nChannels = wfx->nChannels;1049     wave.nSamplesPerSec = wfx->nSamplesPerSec;1050     wave.wBitsPerSample = wfx->wBitsPerSample;1051   }1052   else1053   {1054     wave.nChannels = 2;            1055     wave.nSamplesPerSec = 44100;1056     wave.wBitsPerSample = 16;1057   }1058   wave.nBlockAlign = wave.nChannels * wave.wBitsPerSample / 8;1059   wave.nAvgBytesPerSec = wave.nSamplesPerSec * wave.nBlockAlign;1060   wave.cbSize = 0;1061 1062   dsbd.dwSize = sizeof(dsbd); 1063   dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY;1064 1065   if( m_ds_dwFileSize > DSBSIZE_MAX )1066     dsbd.dwBufferBytes = DSBSIZE_MAX;1067   else1068     dsbd.dwBufferBytes = m_ds_dwFileSize;1069 1070   *dwBuffSize = dsbd.dwBufferBytes;    //返回缓冲区大小1071   dsbd.lpwfxFormat = &wave;1072 1073   caps.dwSize = sizeof(DSCAPS);1074   if( SUCCEEDED( lpDS8->GetCaps(&caps) ) )1075   {1076     if( caps.dwMaxHwMixingStreamingBuffers > 0 )1077       dsbd.dwFlags |= DSBCAPS_LOCDEFER;1078     else1079       dsbd.dwFlags |= DSBCAPS_STATIC;1080   }1081 1082   if( FAILED( lpDS8->CreateSoundBuffer( &dsbd, &pTmpBuffer, NULL ) ) )1083     return E_FAIL;1084 1085   if( FAILED( pTmpBuffer->QueryInterface( IID_IDirectSoundBuffer8, (void**)&m_pBuffer8 ) ) )1086     return E_FAIL;1087   pTmpBuffer->Release();1088 1089 1090   if( FAILED( m_pBuffer8->QueryInterface( IID_IDirectSoundNotify,(void**)&pNotify ) ) )1091     return E_FAIL;1092 1093   dspNotify.dwOffset = dsbd.dwBufferBytes - 1;1094   m_hEvents[0] = CreateEvent(NULL,FALSE,FALSE,NULL); 1095   dspNotify.hEventNotify = m_hEvents[0];1096   pNotify->SetNotificationPositions( 1, &dspNotify);1097   pNotify->Release();  1098 1099   if( m_mpghandle == NULL )1100   {1101     return E_FAIL;1102   }1103   mpg123_seek( m_mpghandle, 0, SEEK_SET );1104 1105   if( myReadMPGBuffer( 0, dsbd.dwBufferBytes ) )1106   {1107     m_ds_dwPos    += dsbd.dwBufferBytes;1108     //if(m_ds_dwFileSize <= DSBSIZE_MAX), this m_ds_dwLeave will be 01109     m_ds_dwLeave  -= dsbd.dwBufferBytes;1110 1111     return S_OK;1112   }1113   else1114     return E_FAIL;1115 }1116 1117 1118 1119 1120 bool myD3DSound::myReadBuffer( long lock_pos, long lock_size )1121 {1122   if( m_pBuffer8 == NULL || m_fp == NULL )1123     return 0;1124 1125   LPVOID buf = NULL; 1126   DWORD buf_len = 0;1127   if( SUCCEEDED( m_pBuffer8->Lock(lock_pos, lock_size, &buf, &buf_len, NULL, NULL, 0 ) ) )1128   {1129     fread( buf, 1, buf_len, m_fp );1130     m_pBuffer8->Unlock( buf, buf_len, NULL, 0 );1131   }1132   return 1;1133 }1134 1135 1136 1137 bool myD3DSound::myReadMPGBuffer( long lock_pos, long lock_size )1138 {1139   if( m_pBuffer8 == NULL || m_mpghandle == NULL )1140     return 0;1141 1142   LPVOID buf = NULL; 1143   DWORD buf_len = 0;1144   unsigned char* _buffer;1145   size_t outsize;1146   _buffer = (unsigned char*)malloc( lock_size * sizeof(unsigned char) );1147   if( SUCCEEDED( m_pBuffer8->Lock(lock_pos, lock_size, &buf, &buf_len, NULL, NULL, 0 ) ) )1148   {1149     mpg123_read( m_mpghandle, _buffer, lock_size, &outsize);1150      memcpy(buf, _buffer, outsize);1151     m_pBuffer8->Unlock( buf, buf_len, NULL, 0 );1152   }1153   return 1;1154 }1155 1156 1157 1158 1159 void myD3DSound::myCleanBuffer()1160 {1161   if( m_pBuffer8 )1162   {1163     m_pBuffer8->Stop();1164   }1165   SetPlaying( FALSE );1166   m_ds_dwPos = 0;1167   m_ds_dwLeave = 0;1168   m_ds_dwBuffSize =0;1169   m_dwPlayPos = 0;1170   SAFE_RELEASE( m_pBuffer8 );1171 #ifdef __MAX_BUFFER__1172   m_ds_dwFileSize = 0;1173 #endif1174   m_ds_dwFileTime = 0;1175   m_ds_dwFilebps = 0;1176   m_iScrollPos = 0;1177 1178 }1179 1180 void myD3DSound::cleanup()1181 {1182   if( m_mpghandle != NULL )1183   {1184     mpg123_close(m_mpghandle);1185     mpg123_delete(m_mpghandle);1186     m_mpghandle = NULL;1187     mpg123_exit();1188   }1189 }1190 1191 ///////////////////////1192 //global function1193 ///////////////////////1194 1195 1196 DWORD ThreadNotifyEvent( LPVOID thread_data )1197 {1198   DWORD res_msg = 0;1199   DWORD dwBuffsize = 0;1200   FILE* fp = NULL;1201   mpg123_handle* mpghandle = NULL;1202   if( g_pmySound == NULL )1203     return 0;1204 1205   g_pmySound->GetBufferValue( &fp, &mpghandle, &dwBuffsize );1206   if( (!g_pmySound->IsMPG3() && fp == NULL) || dwBuffsize == 0 || (g_pmySound->IsMPG3() && mpghandle == 0) )1207     return 0;1208   while( 1 )1209   {1210     res_msg = WaitForSingleObject( g_pmySound->m_hEvents[0], INFINITE ); 1211 1212     if( res_msg == WAIT_OBJECT_0 )1213     {1214       //update buffer1215       if( g_pmySound->m_ds_dwLeave == 0 )1216       {1217         g_pmySound->myStop();1218         ExitThread( 0 );1219       }1220       if( g_pmySound->IsMPG3() )1221       {1222         mpg123_seek( mpghandle, g_pmySound->m_ds_dwPos, SEEK_SET );1223         if( g_pmySound->m_ds_dwLeave <= dwBuffsize )1224         {1225           g_pmySound->myReadMPGBuffer( 0, g_pmySound->m_ds_dwLeave );1226           g_pmySound->m_ds_dwLeave = 0;1227         }1228         else1229         {1230           g_pmySound->myReadMPGBuffer( 0, dwBuffsize );1231           g_pmySound->m_ds_dwPos    += dwBuffsize;1232           g_pmySound->m_ds_dwLeave  -= dwBuffsize;1233         }1234       }1235       else1236       {1237         fseek(fp, g_pmySound->m_ds_dwPos, SEEK_SET);1238         if( g_pmySound->m_ds_dwLeave <= dwBuffsize )1239         {1240           g_pmySound->myReadBuffer( 0, g_pmySound->m_ds_dwLeave );1241           g_pmySound->m_ds_dwLeave = 0;1242         }1243         else1244         {1245           g_pmySound->myReadBuffer( 0, dwBuffsize );1246           g_pmySound->m_ds_dwPos    += dwBuffsize;1247           g_pmySound->m_ds_dwLeave  -= dwBuffsize;1248         }1249       }1250     } 1251   }1252   return 0;1253 }1254 1255 1256 DWORD ThreadNotifyEvent2( LPVOID thread_data )1257 {1258   DWORD d_FileSize = g_pmySound->m_ds_dwFileSize;1259   if( d_FileSize <= DSBSIZE_MAX )1260   {1261     DWORD  d_PosFile;1262     int    icut = 1;1263     while( 1 )1264     {1265       //update slider1266       if( g_pmySound->m_pBuffer8 == NULL )1267       {1268         SendMessage( g_pmySound->m_scrollbar, TBM_SETPOS, TRUE, (LPARAM)0 );1269         ExitThread(0);1270       }1271       if( FAILED( g_pmySound->m_pBuffer8->GetCurrentPosition( &d_PosFile, NULL ) ) )1272       {1273         SendMessage( g_pmySound->m_scrollbar, TBM_SETPOS, TRUE, (LPARAM)0 );1274         ExitThread(0);1275       }1276       if( d_PosFile >= (d_FileSize/100)* icut )1277       {1278         SendMessage( g_pmySound->m_scrollbar, TBM_SETPOS, TRUE, (LPARAM)icut );1279         icut++;1280       }1281       if( icut >= 100 )1282       {1283         ExitThread(0);1284       }1285     }1286   }1287   return 0;1288 }1289 1290 DWORD ThreadNotifyEvent3( LPVOID thread_data )1291 {1292   DWORD  d_FileTime = g_pmySound->m_ds_dwFileTime;1293   DWORD  d_Filebps = g_pmySound->m_ds_dwFilebps;    //每秒传输字节1294   char  ctmpTime[20];1295   WCHAR  wtmpTime[20];1296   RECT rect;1297   memset(ctmpTime,0,20 );1298   memset(wtmpTime,0,20 );1299   DWORD  d_Nowtime = 0;1300   sprintf_s( ctmpTime, "%02d:%02d / %02d:%02d", d_Nowtime/60, d_Nowtime%60, d_FileTime/60, d_FileTime%60 );1301   ChartoWCHAR( ctmpTime, wtmpTime );1302   SetWindowText( g_pmySound->m_songtime, wtmpTime );1303   while(1)1304   {1305     DWORD  d_PosFile;1306     SYSTEMTIME time;1307     memset(ctmpTime,0,20 );1308     memset(wtmpTime,0,20 );1309     if( g_pmySound->m_pBuffer8 == NULL )1310     {1311       SetWindowText( g_pmySound->m_songtime, TEXT("00:00 / 00:00") );1312       ExitThread(0);1313     }1314     if( FAILED( g_pmySound->m_pBuffer8->GetCurrentPosition( &d_PosFile, NULL ) ) )1315     {1316       SetWindowText( g_pmySound->m_songtime, TEXT("00:00 / 00:00") );1317       ExitThread(0);1318     }1319     if( d_PosFile >= d_Filebps *(d_Nowtime+1) )1320     {1321       d_Nowtime++;1322       sprintf_s( ctmpTime, "%02d:%02d / %02d:%02d", d_Nowtime/60, d_Nowtime%60, d_FileTime/60, d_FileTime%60 );1323       ChartoWCHAR( ctmpTime, wtmpTime );1324       SetWindowText( g_pmySound->m_songtime, wtmpTime );1325       GetLocalTime( &time );1326       g_pmySound->mySetTimer( time );1327       SetWindowText( g_pmySound->m_timeshow, g_pmySound->myGetTimer() );1328       GetClientRect( g_pmySound->m_father, &rect );1329       InvalidateRect(g_pmySound->m_father,&rect,TRUE);1330     }1331     if( d_Nowtime == d_FileTime )1332     {1333       ExitThread(0);1334     }1335   }1336 }1337 1338 void ChartoWCHAR( const char* dsc, WCHAR* dst)1339 {1340   int len_c;1341   len_c = MultiByteToWideChar( CP_ACP,0,dsc,-1,NULL,0 );1342   MultiByteToWideChar( CP_ACP,0,dsc,-1,dst,len_c );1343 }1344 void WCHARtoChar( const WCHAR* dsc, char* dst )1345 {1346   int len_w;1347   len_w = WideCharToMultiByte(CP_ACP,0,dsc,-1,NULL,0,NULL,0);1348   WideCharToMultiByte(CP_ACP,0,dsc,-1,dst,len_w,NULL,0);1349 1350 }

D3DSound.cpp
 

 




原标题:WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)

关键词:win

win
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

德国VAT税号查询最全面的网站汇总:https://www.kjdsnews.com/a/1387983.html
德国VAT税号查询最佳网站推荐:https://www.kjdsnews.com/a/1387984.html
干掉Anker,月售百万美金!3C卖家有多野?:https://www.kjdsnews.com/a/1387985.html
德国VAT税号申请指南一步一步搞定:https://www.kjdsnews.com/a/1387986.html
德国VAT税号申请指南:https://www.kjdsnews.com/a/1387987.html
德国VAT税号注销流程及注意事项:https://www.kjdsnews.com/a/1387988.html
在古巴做游轮 古巴旅游项目:https://www.vstour.cn/a/363194.html
西藏旅游攻略自驾游需要多少天 去西藏旅游自驾游要多久时间:https://www.vstour.cn/a/363195.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流