600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)

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

时间:2024-06-26 16:32:06

相关推荐

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

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

DirectSound的使用步骤很简单

首先你要创建一个DirectSound8设备对象

1 HRESULT DirectSoundCreate8(2LPCGUID lpcGuidDevice,3LPDIRECTSOUND8 * ppDS8,4LPUNKNOWN pUnkOuter5 )

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

lpcGuidDevice是声音设备对象GUID的地址,设置为NULL,表示默认设备;

ppDS8是返回的IDirectSound8接口指针,接下来就通过它来调用相关接口了;

pUnkOuter必须设置为NULL。

接下来是设置协作级别

1 HRESULT SetCooperativeLevel(2HWND hwnd,3DWORD dwLevel4 )

hwnd是应用程序窗口句柄;

dwLevel是请求的协作级别,可选的值包括

DSSCL_NORMAL:正常级别,其他程序可共享设备;

DSSCL_PRIORITY:优先级别,设备为当前程序独占;

DSSCL_EXCLUSIVE:对于DX8.0及之后的版本,具有和DSSCL_PRIORITY相同的效果;

DSSCL_WRITEPRIMARY:当前程序具有主缓冲区的写权限,同时副缓冲区不能进行播放。

接下来就可以创建缓冲区了

1 HRESULT CreateSoundBuffer(2LPCDSBUFFERDESC pcDSBufferDesc,3LPDIRECTSOUNDBUFFER * ppDSBuffer,4LPUNKNOWN pUnkOuter5 )

pcDSBufferDesc是一个DSBUFFERDESC结构的指针,用来描述要创建的声音缓冲区的地址;

ppDSBuffer是返回的IDirectSoundBuffer接口对象的指针;

pUnkOuter必须设置为NULL。

其中DSBUFFERDESC定义如下

1 typedef struct DSBUFFERDESC {2DWORD dwSize;3DWORD dwFlags;4DWORD dwBufferBytes;5DWORD dwReserved;6LPWAVEFORMATEX lpwfxFormat;7GUID 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(2DWORD dwPositionNotifies,3LPCDSBPOSITIONNOTIFY pcPositionNotifies4 )

dwPositionNotifies:DSBPOSITIONNOTIFY结构的数量;

pcPositionNotifies:指向DSBPOSITIONNOTIFY结构的指针。

其中DSBPOSITIONNOTIFY结构如下

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

dwOffset:触发位置,即缓冲区开始起的偏移量;

hEventNotify:触发事件句柄。

填充缓冲区

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

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

dwOffset:要锁定的缓冲区起始位置,即从缓冲区首地址起的偏移量,用字节表示;

dwBytes:希望锁定的缓冲区内存大小,用字节表示;

ppvAudioPtr1:返回指向该锁定缓冲区的第一部分指针;

pdwAudioBytes1:ppvAudioPtr1指向地址的大小;

ppvAudioPtr2:返回指向该锁定缓冲区的第二部分指针,如果传入NULL,则该锁定区域全部返回到ppvAudioPtr1;

pdwAudioBytes2:ppvAudioPtr2指向地址的大小,如果ppvAudioPtr2传入NULL,该值则应传入0;

dwFlags:修改锁定事件的标志,一般不使用设为0。

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

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

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

WAVEFORMATEX结构

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

1 typedef struct tWAVEFORMATEX {2WORD wFormatTag;3WORD nChannels;4DWORD nSamplesPerSec;5DWORD nAvgBytesPerSec;6WORD nBlockAlign;7WORD wBitsPerSample;8WORD 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字节)

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

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

1 struct WAVE_HEADER//44bytes 2 { 3char riff_sig[4]; 4long waveform_chunk_size; 5char wave_sig[4]; 6char format_sig[4]; 7long format_chunk_size; 8short format_tag; 9short channels;10long sample_rate;11long bytes_per_sec;12short block_align;13short bits_per_sample;14char data_sig[4];15long data_size;16 };17 18 19 struct WAVE_HEADER_FACT//58bytes20 {21char riff_sig[4];22long waveform_chunk_size;23char wave_sig[4];24char format_sig[4];25long format_chunk_size;26short format_tag;27short channels;28long sample_rate;29long bytes_per_sec;30short block_align;31short bits_per_sample;32short bits_per_sample2;33char fact_sig[4];34short fact_size;35short fact_size2;36char fact_data[4];37char data_sig[4];38long 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版本工程,这里选择了版。

由于工程中在预链接事件中使用了yasm汇编器,所以需要下载配置yasm到vs工程中,在/Download.html 有32位和64位系统对应的vs版本。

下载后解压,根据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 )4return -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 )5return -1;

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

1 WAVEFORMATEX wave_format; 2 int perbits = 16; //量化数 3 if((encoding & MPG123_ENC_16) == MPG123_ENC_16) 4perbits = 16; 5 else if((encoding & MPG123_ENC_32) == MPG123_ENC_32) 6perbits = 32; 7 else 8perbits = 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 ) 6return -1; 7 if(mpginfo.layer != 3) 8return -1; 9 if( mpginfo.vbr == MPG123_CBR )10bitrate = mpginfo.bitrate;11 else if( mpginfo.vbr == MPG123_VBR )12 {13if( 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 }

将mp3文件解析并创建好缓冲区之后,就可以通过mpg123_read方法将文件数据填充至缓冲区了,代码如下

1 void* buf = NULL; 2 DWORD buf_len = 0; 3 unsigned char* _buffer; 4 size_t outsize; 5 _buffer = (unsigned char*)malloc( lock_size * sizeof(unsigned char) ); 6 if( SUCCEEDED( m_pBuffer8->Lock(lock_pos, lock_size, &buf, &buf_len, NULL, NULL, 0 ) ) ) 7 { 8mpg123_read( m_mpghandle, _buffer, lock_size, &outsize); 9memcpy(buf, _buffer, outsize);10m_pBuffer8->Unlock( buf, buf_len, NULL, 0 );11 }

其中lock_pos和lock_size 分别是缓冲区的偏移量和锁定大小。

mpg13_read的第2个参数返回实际读取到的数据指针,第3个参数是希望读取的数据长度,第4个参数返回实际读取的数据长度。

以下是全部代码:

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.h

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| \ 7WS_CAPTION | \ 8WS_SYSMENU | \ 9WS_MINIMIZEBOX | \ 10WS_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 BOOLPreTranslateMessage(LPMSG pMsg); 20 ATOMMyRegisterClass(HINSTANCE hInstance); 21 BOOLInitInstance(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 { 30UNREFERENCED_PARAMETER(hPrevInstance); 31UNREFERENCED_PARAMETER(lpCmdLine); 32 33MSG msg; 34HACCEL hAccelTable; 35 36myD3DSound* pDXSound = new myD3DSound; 37LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 38LoadString(hInstance, IDC_D3DPLAYER, szWindowClass, MAX_LOADSTRING); 39MyRegisterClass(hInstance); 40 41if (!InitInstance (hInstance, nCmdShow)) 42{ 43 return FALSE; 44} 45 46hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_D3DPLAYER)); 47 48while (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} 5960SAFE_DELETE(g_pmySound); 61return (int) msg.wParam; 62 } 63 64 ATOM MyRegisterClass(HINSTANCE hInstance) 65 { 66WNDCLASSEX wcex; 67 68wcex.cbSize = sizeof(WNDCLASSEX); 69 70wcex.style = CS_HREDRAW | CS_VREDRAW; 71wcex.lpfnWndProc = WndProc; 72wcex.cbClsExtra = 0; 73wcex.cbWndExtra = 0; 74wcex.hInstance = hInstance; 75wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYPLAYER)); 76wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 77wcex.hbrBackground = (HBRUSH)( COLOR_WINDOW - 1 ); 78wcex.lpszMenuName = MAKEINTRESOURCE(IDC_D3DPLAYER); 79wcex.lpszClassName = szWindowClass; 80wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_MYSMALL)); 81 82return 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 {112int wmId, wmEvent;113PAINTSTRUCT ps;114HDC hdc;115RECT rect;116LRESULT res;117UINT CtrlId;118DRAWITEMSTRUCT *dis;119HFONT hfont;120NMHDR *pNMHDR;121 122switch (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 {133int i = SendMessage(g_pmySound->m_listview, LVM_GETNEXTITEM, -1, LVNI_SELECTED);134NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;135if(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 {148SendMessage(g_pmySound->m_listview, LVM_GETNEXTITEM, -1, LVNI_SELECTED);149NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;150if(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);167168}169 }170 else if( pNMHDR->idFrom == 12 )171 {172int 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}365return 0;366 }367 368 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)369 {370UNREFERENCED_PARAMETER(lParam);371switch (message)372{373case WM_INITDIALOG:374 return (INT_PTR)TRUE;375 376case 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}384return (INT_PTR)FALSE;385 }386 387 388 BOOL PreTranslateMessage(LPMSG pMsg)389 {390if( 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}407return FALSE;408 }

D3DPlayer.cpp

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 18 #define IDB_SONGTEXT 19 #define IDB_SONGTIME 20 #define IDB_SONGLIST 21 22 struct WAVE_HEADER//44bytes 23 { 24char riff_sig[4]; 25long waveform_chunk_size; 26char wave_sig[4]; 27char format_sig[4]; 28long format_chunk_size; 29short format_tag; 30short channels; 31long sample_rate; 32long bytes_per_sec; 33short block_align; 34short bits_per_sample; 35char data_sig[4]; 36long data_size; 37 }; 38 39 struct WAVE_HEADER_FACT//58bytes 40 { 41char riff_sig[4]; 42long waveform_chunk_size; 43char wave_sig[4]; 44char format_sig[4]; 45long format_chunk_size; 46short format_tag; 47short channels; 48long sample_rate; 49long bytes_per_sec; 50short block_align; 51short bits_per_sample; 52short bits_per_sample2; 53char fact_sig[4]; 54short fact_size; 55short fact_size2; 56char fact_data[4]; 57char data_sig[4]; 58long data_size; 59 }; 60 61 struct myListMember 62 { 63int m_idx; 64WCHAR m_name[100]; 65WCHAR m_time[10]; 66WCHAR m_type[10]; 67WCHAR m_bits[20]; 68WCHAR 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: 80OPENFILENAME opfn; 81bool isPlaying; 82DWORD m_ds_dwBuffSize; //dxsound缓冲区大小 83HANDLE m_hThread; //控制buffer 84DWORD m_thread_id; 85HANDLE m_hThread2; //滚动条显示 86DWORD m_thread_id2; 87HANDLE m_hThread3; //剩余时间显示 88DWORD m_thread_id3; 89FILE* m_fp; 90mpg123_handle* m_mpghandle; 91DWORD m_dwPlayPos; 92WCHAR m_wstrTime[60]; 93WCHAR m_wSongTime[30]; //总时长 94WCHAR m_wSongLeave[30]; //剩余时长 95typedef std::vector<myListMember> MY_SONG_LIST; 96MY_SONG_LIST m_list; 97WCHAR m_wSongPath[MAX_PATH]; //正在播放歌曲 98WCHAR m_wSongName[MAX_PATH]; 99WCHAR m_wSongPathPre[MAX_PATH]; //单击选中歌曲100WCHAR m_wSongNamePre[MAX_PATH];101102bool m_bmpg;103bool m_factwav;104 public:105HWND m_father;106//button107HWND m_openbtn;108HWND m_closebtn;109HWND m_playbtn;110HWND m_pausebtn;111HWND m_stopbtn;112//static113HWND m_txtplaying;114HWND m_songtxt;115HWND m_songinfo;116HWND m_timeshow;117HWND m_songtime;118//119HWND m_scrollbar;120HWND m_volumebar;121HWND m_listview;122 123LPDIRECTSOUND8 m_pDirectSound;124 125//playing file info126LPDIRECTSOUNDBUFFER8 m_pBuffer8;127HANDLE m_hEvents[MAX_AUDIO_BUF];128 #ifdef __MAX_BUFFER__129DWORD m_ds_dwFileSize; //文件大小130 #endif131DWORD m_ds_dwFileTime; //文件时长(s)132DWORD m_ds_dwFilebps; //文件传输率133DWORD m_ds_dwPos; //文件偏移量134DWORD m_ds_dwLeave; //文件剩余量135int m_iScrollPos; //进度条位置136int m_iVolumePos; //音量条位置137 138enum 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:148int mySetSoundType();149int myGetWAVFormat( DWORD* dwSize, DWORD* dwCycle, FILE* fp, WAVEFORMATEX** wfx );150int myGetMP3Format( char* filestr, DWORD* dwSize, DWORD* dwCycle, int* bitrate, WAVEFORMATEX** wfx, bool isClose = TRUE );151HRESULT myCreatePCMBuffer( WAVEFORMATEX* wfx, DWORD* dwBuffSize );152HRESULT myCreateMPGBuffer( WAVEFORMATEX* wfx, DWORD* dwBuffSize );153void myUpdateList();154void myCleanBuffer();155void cleanup(); //clear mpg123 handle156 public:157myD3DSound();158~myD3DSound();159HRESULT myInit( HWND );160void myCreateWin( HWND );161void myChangeSize( HWND );162void mySetList( WCHAR* );163void myInitList();164void mySetPlayInfo( NM_LISTVIEW* pNMListView, bool DBClick );165void mySetTimer( SYSTEMTIME );166bool myReadBuffer( long lock_pos, long lock_size );167bool myReadMPGBuffer( long lock_pos, long lock_size );168void mySetScrollPos( bool isUp, DWORD dPos );169void mySetVolumePos( bool isUp, DWORD dPos );170 171//button172void myOpenFile();173void myCloseFile();174int myPlay();175int myStop();176int myPause();177 178int mySongNum();179WCHAR* myGetTimer();180bool isPlay(){ return isPlaying; }181void SetPlaying( bool flags ){ isPlaying = flags; }182int GetBufferValue( FILE** fp, mpg123_handle** mpghandle, DWORD* BuffSize );183bool IsMPG3(){return m_bmpg;}184 };185 186 187 #endif

D3DSound.h

D3DSound.cpp

1 #include "D3DSound.h" 2 3 const WCHAR* g_cwErrorMsg[7] = { 4TEXT(""), 5TEXT("Pelase choose a file!"), 6TEXT("Only supports .mp3 and .wav file!"), 7TEXT("Create PCM buffer fail!"), 8TEXT("Create MPG buffer fail!"), 9TEXT("Cannot play the file!"), 10TEXT("File format error!") 11 }; 12 WCHAR* g_cwSongList[6] = { 13TEXT("序号"), 14TEXT("名称"), 15TEXT("持续时间"), 16TEXT("扩展名"), 17TEXT("比特率"), 18TEXT("文件路径") 19 }; 20 21 22 23 myD3DSound* g_pmySound = NULL; 24 25 26 /// 27 //public function 28 /// 29 30 HRESULT myD3DSound::myInit( HWND hWnd ) 31 { 32m_father = hWnd; 33if( FAILED( DirectSoundCreate8(NULL, &m_pDirectSound, NULL) ) ) 34 return E_FAIL; 35 36if( FAILED( m_pDirectSound->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ) ) ) 37 return E_FAIL; 38 39return 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 68m_ds_dwBuffSize = 0; 69 #ifdef __MAX_BUFFER__ 70m_ds_dwFileSize = 0; 71 #endif 72m_ds_dwFileTime = 0; 73m_ds_dwFilebps = 0; 74m_ds_dwPos = 0; 75m_ds_dwLeave = 0; 76m_iScrollPos = 0; 77m_iVolumePos = 50; 78 79m_thread_id = 0; 80m_dwPlayPos = 0; 81ZeroMemory(&opfn, sizeof(OPENFILENAME)); 82memset( m_wstrTime, 0, sizeof(m_wstrTime) ); 83memset( m_wSongTime, 0, sizeof(m_wSongTime) ); 84memset( m_wSongLeave, 0, sizeof(m_wSongLeave) ); 85memset( m_wSongPath, 0, sizeof(m_wSongPath) ); 86memset( m_wSongName, 0, sizeof(m_wSongName) ); 87memset( m_wSongPathPre, 0, sizeof(m_wSongPathPre) ); 88memset( m_wSongNamePre, 0, sizeof(m_wSongNamePre) ); 89m_list.clear(); 90g_pmySound = this; 91 } 92 93 myD3DSound::~myD3DSound() 94 { 95SAFE_RELEASE(m_pBuffer8); 96SAFE_RELEASE(m_pDirectSound); 97ZeroMemory(&opfn, sizeof(OPENFILENAME)); 98memset( m_wstrTime, 0, sizeof(m_wstrTime) ); 99memset( m_wSongTime, 0, sizeof(m_wSongTime) ); 100memset( m_wSongLeave, 0, sizeof(m_wSongLeave) ); 101memset( m_wSongPath, 0, sizeof(m_wSongPath) ); 102memset( m_wSongName, 0, sizeof(m_wSongName) ); 103memset( m_wSongPathPre, 0, sizeof(m_wSongPathPre) ); 104memset( m_wSongNamePre, 0, sizeof(m_wSongNamePre) ); 105if( m_fp ) 106{ 107 fclose( m_fp ); 108 m_fp = NULL; 109} 110m_list.clear(); 111cleanup(); 112 } 113 114 115 116 void myD3DSound::myCreateWin( HWND hWnd ) 117 { 118RECT dynamic_rc; 119RECT button_rc; 120RECT static_rc; 121RECT list_rc; 122GetClientRect( hWnd, &dynamic_rc ); 123LONG Width = dynamic_rc.right - dynamic_rc.left; 124LONG Height = dynamic_rc.bottom - dynamic_rc.top; 125 126button_rc.left = 15; 127button_rc.top = 15; 128m_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 131button_rc.left += 60; 132m_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 135button_rc.left += 60; 136m_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 139button_rc.left += 60; 140m_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 143button_rc.left += 60; 144m_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 ); 146147button_rc.left += 60; 148m_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 151static_rc.left = 15; 152static_rc.top = 50; 153m_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 156static_rc.left += ( 90 + 10 ); 157m_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 160static_rc.left = 15; 161static_rc.top = Height - 5 - 16; 162m_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 165static_rc.left += (350 + 10); 166m_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 169static_rc.left = Width - 15 - 150; 170m_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 173static_rc.left = Width - 90; 174static_rc.top = 15; 175m_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 ); 177SendMessage( m_volumebar, TBM_SETPOS, TRUE, (LPARAM)50 ); 178 179list_rc.left = 30; 180list_rc.top = 80; 181m_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 { 190RECT dynamic_rc; 191GetClientRect( hWnd, &dynamic_rc ); 192LONG Width = dynamic_rc.right - dynamic_rc.left; 193LONG Height = dynamic_rc.bottom - dynamic_rc.top; 194195MoveWindow( m_songinfo, 15, Height - 5 - 16, 350, 16, TRUE ); 196 197MoveWindow( m_songtime, 15 + 350 + 10, Height - 5 - 16, 140, 16, TRUE ); 198199MoveWindow( m_timeshow, Width - 15 - 150, Height - 5 - 16, 150, 16, TRUE ); 200 201MoveWindow( m_songtxt, 115, 50, Width - 115 - 15, 20, TRUE ); 202 203MoveWindow( m_scrollbar, 315, 15, Width - 315 - 15 - 90, 20, TRUE ); 204 205MoveWindow( m_volumebar, Width - 90, 15, 80, 20, TRUE ); 206 207MoveWindow( m_listview, 30, 80, Width - 60, Height - 80 - 10 - 21, TRUE ); 208209 } 210 211 212 void myD3DSound::mySetList( WCHAR* wcFilename ) 213 { 214myListMember tmplist; 215//m_path 216StrCpyW( tmplist.m_path, wcFilename ); 217//m_name 218char cName[100]; 219char tmpstr[MAX_PATH]; 220memset(cName,0,100); 221memset(tmpstr,0,MAX_PATH); 222 223WCHARtoChar( wcFilename, tmpstr ); 224int len = strlen(tmpstr); 225char* p = &tmpstr[len]; 226int len_name = 0; 227bool isname = 0; 228bool bk = 0; 229while( !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} 249memcpy( cName, p, len_name ); 250ChartoWCHAR( cName, tmplist.m_name ); 251 252//type 253LPWSTR lwType; 254char ctmpType[5]; 255char cType[4]; 256lwType = PathFindExtension( wcFilename ); 257WCHARtoChar( lwType, ctmpType); 258sprintf_s( cType, "%s", ctmpType+1); 259ChartoWCHAR( cType, tmplist.m_type ); 260 261if( 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} 286else 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 307m_list.push_back( tmplist ); 308 309myUpdateList(); 310 } 311 312 313 314 void myD3DSound::myUpdateList() 315 { 316ListView_DeleteAllItems(m_listview); 317 318int iSize = m_list.size(); 319LVITEM vitem; 320vitem.mask = LVIF_TEXT; 321for( 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); 335336 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 { 358return m_list.size(); 359 } 360 361 362 363 void myD3DSound::myInitList() 364 { 365LVCOLUMN vcl; 366vcl.mask = LVCF_SUBITEM | LVCF_WIDTH | LVCF_TEXT | LVCF_FMT; 367vcl.fmt = LVCFMT_LEFT; 368for( 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 { 383char strtime[60]; 384memset( strtime, 0, 60 ); 385sprintf_s(strtime,"%04d-%02d-%02d %02d:%02d:%02d", 386 time.wYear,time.wMonth,time.wDay,time.wHour,time.wMinute,time.wSecond); 387ChartoWCHAR(strtime,m_wstrTime); 388 } 389 390 391 392 WCHAR* myD3DSound::myGetTimer() 393 { 394return m_wstrTime; 395 } 396 397 398 399 void myD3DSound::mySetScrollPos( bool isUp, DWORD dPos ) 400 { 401if(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 } 416417} 418else 419{ 420 421} 422 } 423 424 425 426 427 void myD3DSound::mySetVolumePos( bool isUp, DWORD dPos ) 428 { 429LONG vol = 0; 430double dbValue; 431int iPos; 432if( 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 { 457WCHAR strFilename[MAX_PATH]; 458ZeroMemory(&opfn, sizeof(OPENFILENAME)); 459 460opfn.lStructSize = sizeof(OPENFILENAME); //结构体大小 461opfn.lpstrFilter = L"所有文件\0*.*\0wav文件\0*.wav\0MP3文件\0*.mp3\0"; //过滤器 462opfn.nFilterIndex = 1; //过滤索引 463opfn.lpstrFile = strFilename; //文件名的缓冲,不需要初始化则必须为null 464opfn.lpstrFile[0] = '\0'; 465opfn.nMaxFile = sizeof(strFilename); 466opfn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; 467 468if( GetOpenFileName(&opfn) ) 469{ 470 mySetList(strFilename); 471} 472 } 473 474 void myD3DSound::myCloseFile() 475 { 476ZeroMemory(&opfn, sizeof(OPENFILENAME)); 477if( 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} 487MY_SONG_LIST::iterator Songit; 488for( 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} 499500 } 501 502 503 504 void myD3DSound::mySetPlayInfo( NM_LISTVIEW* pNMListView, bool DBClick ) 505 { 506if( 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} 517else 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 { 533if( 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} 546if( 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} 561SetPlaying( TRUE ); 562mySetVolumePos(TRUE,0); 563m_pBuffer8->SetCurrentPosition( m_dwPlayPos ); 564m_pBuffer8->Play(0, 0, DSBPLAY_LOOPING); 565return 0; 566 } 567 568 569 570 int myD3DSound::myStop() 571 { 572myCleanBuffer(); 573if( 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} 583if( IsMPG3() ) 584{ 585 cleanup(); 586} 587SetWindowText( m_songinfo, TEXT("请选择wav文件进行播放。") ); 588StrCpyW( m_wSongName, TEXT("")); 589StrCpyW( m_wSongPath, TEXT("")); 590SetWindowText( m_songtxt, m_wSongName ); 591SendMessage( g_pmySound->m_scrollbar, TBM_SETPOS, TRUE, (LPARAM)0 ); 592SetWindowText( g_pmySound->m_songtime, TEXT("00:00 / 00:00") ); 593return 0; 594 } 595 596 597 598 int myD3DSound::myPause() 599 { 600if( m_pBuffer8 == NULL ) 601 return -1; 602if( isPlay() ) 603{ 604 m_pBuffer8->GetCurrentPosition( &m_dwPlayPos, NULL ); 605 SetPlaying( FALSE ); 606 m_pBuffer8->Stop(); 607} 608else 609{ 610 SetPlaying( TRUE ); 611 m_pBuffer8->SetCurrentPosition( m_dwPlayPos ); 612 m_pBuffer8->Play(0, 0, DSBPLAY_LOOPING); 613} 614return 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; 624return 0; 625 } 626 627 628 /// 629 //private 630 /// 631 632 int myD3DSound::mySetSoundType() 633 { 634WCHAR cNameStr[MAX_PATH]; 635LPWSTR lpNameType; 636char cType[4]; 637char cTmpStr[5]; 638memset( cNameStr, 0, MAX_PATH ); 639memset( cType, 0, 4 ); 640memset( cTmpStr, 0, 5 ); 641 642StrCpyW( cNameStr, m_wSongPath ); 643 644if( cNameStr[0] == '\0' ) 645{ 646 return EFAIL_NOFILE; 647} 648lpNameType = PathFindExtension( cNameStr ); 649 650WCHARtoChar( lpNameType, cTmpStr); 651sprintf_s( cType, "%s", cTmpStr+1); 652if( 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 699else 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} 761else 762{ 763 return EFAIL_NOTSUPPORT; 764} 765 766767return 0; 768 769 } 770 771 772 773 int myD3DSound::myGetWAVFormat( DWORD* dwSize, DWORD* dwCycle, FILE* fp, WAVEFORMATEX** wfx ) 774 { 775WAVE_HEADER wave_header; 776WAVE_HEADER_FACT wave_header2; 777 #ifndef _DEBUG 778volatile WAVEFORMATEX wave_format; 779 #else 780WAVEFORMATEX wave_format; 781 #endif 782char fact[4]; 783fseek( fp, 38, SEEK_SET ); 784fread( fact, 1, 4, fp ); 785fseek( fp, 0, SEEK_SET ); 786if( 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} 805else 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; 826return 0; 827 } 828 829 830 831 832 int myD3DSound::myGetMP3Format( char* filestr, DWORD* dwSize, DWORD* dwCycle, int* bitrate, WAVEFORMATEX** wfx, bool isClose ) 833 { 834int ret = MPG123_OK; 835int channels = 0; //声道 836int encoding = 0; //编码格式 837long rate = 0; //频率 838int perbits = 16; //bits per second 839long fTime = 0; 840long fSize = 0; 841int simpleNum = 1152; 842long frameNum; 843//long streamSize; 844long streamSize1; 845long streamSize2; 846long streamSize3; 847FILE* tmpfp = NULL; 848 #ifndef _DEBUG 849volatile WAVEFORMATEX wave_format; 850 #else 851WAVEFORMATEX wave_format; 852 #endif 853mpg123_frameinfo mpginfo; 854 855cleanup(); 856 857ret = mpg123_init(); 858if(ret != MPG123_OK || ( m_mpghandle = mpg123_new(NULL, &ret) ) == NULL) 859{ 860cleanup(); 861return -1; 862} 863if( mpg123_open(m_mpghandle, filestr) != MPG123_OK || mpg123_getformat(m_mpghandle, &rate, &channels, &encoding) != MPG123_OK ) 864{ 865cleanup(); 866return -1; 867} 868 869if((encoding & MPG123_ENC_16) == MPG123_ENC_16) 870perbits = 16; 871else if((encoding & MPG123_ENC_32) == MPG123_ENC_32) 872perbits = 32; 873else 874perbits = 8; 875 876//wfx 877wave_format.wFormatTag= WAVE_FORMAT_PCM; 878wave_format.nChannels = channels; 879wave_format.nSamplesPerSec = rate; 880wave_format.wBitsPerSample = perbits; 881wave_format.nBlockAlign= perbits / 8 * channels; 882wave_format.nAvgBytesPerSec = rate * perbits / 8 * channels; 883*wfx = (WAVEFORMATEX*)&wave_format; 884 885mpg123_seek( m_mpghandle, 0, SEEK_END ); 886frameNum = mpg123_tellframe( m_mpghandle ); 887//总帧数法:Total_Time = Total_Frame_Number * (Sample_Number * (1 / Frame_Sample_Rate)) 888fTime = (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 895if( mpg123_info( m_mpghandle, &mpginfo) != MPG123_OK ) 896{ 897cleanup(); 898return -1; 899} 900if(mpginfo.layer != 3) 901{ 902 cleanup(); 903 return -1; 904} 905 906//bit rate 907if( mpginfo.vbr == MPG123_CBR ) 908{ 909 *bitrate = mpginfo.bitrate; 910} 911else 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} 923if(isClose) 924{ 925 cleanup(); 926} 927return 0; 928 } 929 930 931 932 933 HRESULT myD3DSound::myCreatePCMBuffer( WAVEFORMATEX* wfx, DWORD* dwBuffSize ) 934 { 935DSBUFFERDESC dsbd; 936WAVEFORMATEX wave; 937IDirectSound8* lpDS8; 938LPDIRECTSOUNDBUFFER pTmpBuffer; 939 940LPDIRECTSOUNDNOTIFY8 pNotify; 941 942DSBPOSITIONNOTIFY dspNotify; 943 944DSCAPS caps; 945 946if( m_pDirectSound == NULL ) 947 return E_FAIL; 948 949lpDS8 = m_pDirectSound; 950ZeroMemory(&dsbd, sizeof(dsbd)); 951 952wave.wFormatTag = WAVE_FORMAT_PCM; 953if( wfx ) 954{ 955 wave.nChannels = wfx->nChannels; //音频文件的通道数量 956 wave.nSamplesPerSec = wfx->nSamplesPerSec; //采样频率 957 wave.wBitsPerSample = wfx->wBitsPerSample; //每次采样样本的大小 958} 959else 960{ 961 wave.nChannels = 2;962 wave.nSamplesPerSec = 44100; 963 wave.wBitsPerSample = 16; 964} 965wave.nBlockAlign = wave.nChannels * wave.wBitsPerSample / 8; 966wave.nAvgBytesPerSec = wave.nSamplesPerSec * wave.nBlockAlign; 967wave.cbSize = 0; 968 969dsbd.dwSize = sizeof(dsbd); 970dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY; 971 972if( m_ds_dwFileSize > DSBSIZE_MAX ) 973 dsbd.dwBufferBytes = DSBSIZE_MAX; 974else 975 dsbd.dwBufferBytes = m_ds_dwFileSize; 976 977 978*dwBuffSize = dsbd.dwBufferBytes; //返回缓冲区大小 979dsbd.lpwfxFormat = &wave; 980 981caps.dwSize = sizeof(DSCAPS); 982if( SUCCEEDED( lpDS8->GetCaps(&caps) ) ) 983{ 984 if( caps.dwMaxHwMixingStreamingBuffers > 0 ) 985 dsbd.dwFlags |= DSBCAPS_LOCDEFER; 986 else 987 dsbd.dwFlags |= DSBCAPS_STATIC; 988} 989 990if( FAILED( lpDS8->CreateSoundBuffer( &dsbd, &pTmpBuffer, NULL ) ) ) 991 return E_FAIL; 992 993if( FAILED( pTmpBuffer->QueryInterface( IID_IDirectSoundBuffer8, (void**)&m_pBuffer8 ) ) ) 994 return E_FAIL; 995pTmpBuffer->Release(); 996 997 998 999if( FAILED( m_pBuffer8->QueryInterface( IID_IDirectSoundNotify,(void**)&pNotify ) ) )1000 return E_FAIL;1001 1002dspNotify.dwOffset = dsbd.dwBufferBytes - 1;1003m_hEvents[0] = CreateEvent(NULL,FALSE,FALSE,NULL); 1004dspNotify.hEventNotify = m_hEvents[0];1005pNotify->SetNotificationPositions( 1, &dspNotify);1006pNotify->Release(); 1007 1008fseek( m_fp, m_ds_dwPos, SEEK_SET );1009if( 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}1017else1018 return E_FAIL;1019 1020 }1021 1022 1023 1024 1025 HRESULT myD3DSound::myCreateMPGBuffer( WAVEFORMATEX* wfx, DWORD* dwBuffSize )1026 {1027DSBUFFERDESC dsbd;1028WAVEFORMATEX wave;1029IDirectSound8* lpDS8;1030LPDIRECTSOUNDBUFFER pTmpBuffer;1031 1032LPDIRECTSOUNDNOTIFY8 pNotify;1033 1034DSBPOSITIONNOTIFY dspNotify;1035 1036 1037DSCAPS caps;1038 1039if( m_pDirectSound == NULL )1040 return E_FAIL;1041 1042lpDS8 = m_pDirectSound;1043ZeroMemory(&dsbd, sizeof(dsbd));1044 1045wave.wFormatTag = WAVE_FORMAT_PCM;1046if( wfx )1047{1048 wave.nChannels = wfx->nChannels;1049 wave.nSamplesPerSec = wfx->nSamplesPerSec;1050 wave.wBitsPerSample = wfx->wBitsPerSample;1051}1052else1053{1054 wave.nChannels = 2; 1055 wave.nSamplesPerSec = 44100;1056 wave.wBitsPerSample = 16;1057}1058wave.nBlockAlign = wave.nChannels * wave.wBitsPerSample / 8;1059wave.nAvgBytesPerSec = wave.nSamplesPerSec * wave.nBlockAlign;1060wave.cbSize = 0;1061 1062dsbd.dwSize = sizeof(dsbd); 1063dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY;1064 1065if( m_ds_dwFileSize > DSBSIZE_MAX )1066 dsbd.dwBufferBytes = DSBSIZE_MAX;1067else1068 dsbd.dwBufferBytes = m_ds_dwFileSize;1069 1070*dwBuffSize = dsbd.dwBufferBytes; //返回缓冲区大小1071dsbd.lpwfxFormat = &wave;1072 1073caps.dwSize = sizeof(DSCAPS);1074if( SUCCEEDED( lpDS8->GetCaps(&caps) ) )1075{1076 if( caps.dwMaxHwMixingStreamingBuffers > 0 )1077 dsbd.dwFlags |= DSBCAPS_LOCDEFER;1078 else1079 dsbd.dwFlags |= DSBCAPS_STATIC;1080}1081 1082if( FAILED( lpDS8->CreateSoundBuffer( &dsbd, &pTmpBuffer, NULL ) ) )1083 return E_FAIL;1084 1085if( FAILED( pTmpBuffer->QueryInterface( IID_IDirectSoundBuffer8, (void**)&m_pBuffer8 ) ) )1086 return E_FAIL;1087pTmpBuffer->Release();1088 1089 1090if( FAILED( m_pBuffer8->QueryInterface( IID_IDirectSoundNotify,(void**)&pNotify ) ) )1091 return E_FAIL;1092 1093dspNotify.dwOffset = dsbd.dwBufferBytes - 1;1094m_hEvents[0] = CreateEvent(NULL,FALSE,FALSE,NULL); 1095dspNotify.hEventNotify = m_hEvents[0];1096pNotify->SetNotificationPositions( 1, &dspNotify);1097pNotify->Release(); 1098 1099if( m_mpghandle == NULL )1100{1101 return E_FAIL;1102}1103mpg123_seek( m_mpghandle, 0, SEEK_SET );1104 1105if( 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}1113else1114 return E_FAIL;1115 }1116 1117 1118 1119 1120 bool myD3DSound::myReadBuffer( long lock_pos, long lock_size )1121 {1122if( m_pBuffer8 == NULL || m_fp == NULL )1123 return 0;1124 1125LPVOID buf = NULL; 1126DWORD buf_len = 0;1127if( 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}1132return 1;1133 }1134 1135 1136 1137 bool myD3DSound::myReadMPGBuffer( long lock_pos, long lock_size )1138 {1139if( m_pBuffer8 == NULL || m_mpghandle == NULL )1140 return 0;1141 1142LPVOID buf = NULL; 1143DWORD buf_len = 0;1144unsigned char* _buffer;1145size_t outsize;1146_buffer = (unsigned char*)malloc( lock_size * sizeof(unsigned char) );1147if( SUCCEEDED( m_pBuffer8->Lock(lock_pos, lock_size, &buf, &buf_len, NULL, NULL, 0 ) ) )1148{1149 mpg123_read( m_mpghandle, _buffer, lock_size, &outsize);1150memcpy(buf, _buffer, outsize);1151 m_pBuffer8->Unlock( buf, buf_len, NULL, 0 );1152}1153return 1;1154 }1155 1156 1157 1158 1159 void myD3DSound::myCleanBuffer()1160 {1161if( m_pBuffer8 )1162{1163 m_pBuffer8->Stop();1164}1165SetPlaying( FALSE );1166m_ds_dwPos = 0;1167m_ds_dwLeave = 0;1168m_ds_dwBuffSize =0;1169m_dwPlayPos = 0;1170SAFE_RELEASE( m_pBuffer8 );1171 #ifdef __MAX_BUFFER__1172m_ds_dwFileSize = 0;1173 #endif1174m_ds_dwFileTime = 0;1175m_ds_dwFilebps = 0;1176m_iScrollPos = 0;1177 1178 }1179 1180 void myD3DSound::cleanup()1181 {1182if( 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 {1198DWORD res_msg = 0;1199DWORD dwBuffsize = 0;1200FILE* fp = NULL;1201mpg123_handle* mpghandle = NULL;1202if( g_pmySound == NULL )1203 return 0;1204 1205g_pmySound->GetBufferValue( &fp, &mpghandle, &dwBuffsize );1206if( (!g_pmySound->IsMPG3() && fp == NULL) || dwBuffsize == 0 || (g_pmySound->IsMPG3() && mpghandle == 0) )1207 return 0;1208while( 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}1252return 0;1253 }1254 1255 1256 DWORD ThreadNotifyEvent2( LPVOID thread_data )1257 {1258DWORD d_FileSize = g_pmySound->m_ds_dwFileSize;1259if( 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}1287return 0;1288 }1289 1290 DWORD ThreadNotifyEvent3( LPVOID thread_data )1291 {1292DWORD d_FileTime = g_pmySound->m_ds_dwFileTime;1293DWORD d_Filebps = g_pmySound->m_ds_dwFilebps; //每秒传输字节1294char ctmpTime[20];1295WCHAR wtmpTime[20];1296RECT rect;1297memset(ctmpTime,0,20 );1298memset(wtmpTime,0,20 );1299DWORD d_Nowtime = 0;1300sprintf_s( ctmpTime, "%02d:%02d / %02d:%02d", d_Nowtime/60, d_Nowtime%60, d_FileTime/60, d_FileTime%60 );1301ChartoWCHAR( ctmpTime, wtmpTime );1302SetWindowText( g_pmySound->m_songtime, wtmpTime );1303while(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 {1340int len_c;1341len_c = MultiByteToWideChar( CP_ACP,0,dsc,-1,NULL,0 );1342MultiByteToWideChar( CP_ACP,0,dsc,-1,dst,len_c );1343 }1344 void WCHARtoChar( const WCHAR* dsc, char* dst )1345 {1346int len_w;1347len_w = WideCharToMultiByte(CP_ACP,0,dsc,-1,NULL,0,NULL,0);1348WideCharToMultiByte(CP_ACP,0,dsc,-1,dst,len_w,NULL,0);1349 1350 }

D3DSound.cpp

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。