标签:
刚好最近接触了一些DirectSound,就写了一个小程序练练手,可以用来添加播放基本的wav和mp3音频文件的播放器。界面只是简单的GDI,dxsdk只使用了DirectSound8相关的接口。
DirectSound的使用步骤很简单
1 HRESULT DirectSoundCreate8( 2 LPCGUID lpcGuidDevice, 3 LPDIRECTSOUND8 * ppDS8, 4 LPUNKNOWN pUnkOuter 5 )
当然要确保已安装了DXSDK,并在工程中设置了相关路径,包含dsound.lib。
lpcGuidDevice是声音设备对象GUID的地址,设置为NULL,表示默认设备;
ppDS8是返回的IDirectSound8接口指针,接下来就通过它来调用相关接口了;
pUnkOuter必须设置为NULL。
1 HRESULT SetCooperativeLevel( 2 HWND hwnd, 3 DWORD dwLevel 4 )
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 pUnkOuter 5 )
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 pcPositionNotifies 4 )
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 dwFlags 9 )
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 dwAudioBytes2 6 )
填充完锁定缓冲区内存后,用来取消该锁定区域,参数可以参看lock中的介绍。
至此,IDirectSound8中主要用到的接口就这些了。
使用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结构了。
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 |
4 |
long int |
每秒播放字节数 |
long int bytepersec |
20H |
2 |
int |
采样一次占字节数 |
int blockalign=声道数*量化数/8 |
22H |
2 |
int |
量化数 |
int bitpersamples=8或16 |
24H |
4 |
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 |
4 |
long int |
文件总长-8 |
long int size0=文总长-8 |
08H |
8 |
char |
"WAVEfmt " |
char wave_fmt[8] |
10H |
4 |
long int |
12000000H(ALAW) |
long int size1=0x12 |
14H |
2 |
int |
06 00H |
int fmttag=0x06 |
16H |
2 |
Int |
声道数 |
int channel=1 或2 |
18H |
4 |
long int |
采样率 |
long int samplespersec |
1CH |
4 |
long int |
每秒播放字节数 |
long int bytepersec |
20H |
2 |
int |
采样一次占字节数 |
int blockalign=0x01 |
22H |
4 |
long int |
量化数 |
long int bitpersamples=8 |
26H |
4 |
char |
"fact" |
char wave_fact="fact" |
2AH |
8 |
char |
0400000000530700H定 |
char temp |
32H |
4 |
char |
"data" |
char wave_data="data" |
36H |
4 |
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 //58bytes 20 { 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;
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.xml三个规则文件添加至MSBuild\Microsoft.Cpp\v4.0\BuildCustomizations目录中。
选择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 if( fopen_s( &tmpfp, "youfile.mp3", "rb" ) == 0 ) 14 { 15 fseek( tmpfp, 0, SEEK_END ); 16 filesize = ftell( tmpfp ); 17 fclose( tmpfp ); 18 tmpfp = NULL; 19 bitrate = (filesize * 8)/(fTime*1000); 20 } 21 }
以下是全部代码:
D3DPlayer.h
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.cpp
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 size 237 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 use 355 break; 356 } 357 case WM_LBUTTONUP: 358 { 359 //no use 360 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 else 403 { 404 return FALSE; 405 } 406 } 407 return FALSE; 408 }
D3DSound.h
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 //button 107 HWND m_openbtn; 108 HWND m_closebtn; 109 HWND m_playbtn; 110 HWND m_pausebtn; 111 HWND m_stopbtn; 112 //static 113 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 info 126 LPDIRECTSOUNDBUFFER8 m_pBuffer8; 127 HANDLE m_hEvents[MAX_AUDIO_BUF]; 128 #ifdef __MAX_BUFFER__ 129 DWORD m_ds_dwFileSize; //文件大小 130 #endif 131 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 handle 156 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 //button 172 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.cpp
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 0 1013 m_ds_dwLeave -= dsbd.dwBufferBytes; 1014 1015 return S_OK; 1016 } 1017 else 1018 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 else 1053 { 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 else 1068 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 else 1079 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 0 1109 m_ds_dwLeave -= dsbd.dwBufferBytes; 1110 1111 return S_OK; 1112 } 1113 else 1114 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 #endif 1174 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 function 1193 /////////////////////// 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 buffer 1215 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 else 1229 { 1230 g_pmySound->myReadMPGBuffer( 0, dwBuffsize ); 1231 g_pmySound->m_ds_dwPos += dwBuffsize; 1232 g_pmySound->m_ds_dwLeave -= dwBuffsize; 1233 } 1234 } 1235 else 1236 { 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 else 1244 { 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 slider 1266 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 }
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)
标签:
原文地址:http://www.cnblogs.com/gpsupergp/p/4720219.html