WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)「建议收藏」

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

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

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



WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)「建议收藏」





DirectSound的使用步骤很简单
  • 首先你要创建一个DirectSound8设备对象
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中主要用到的接口就这些了。


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


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


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

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

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

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

偏移地址

字节数

数据类型

内容

文件头定义为

00H

4

Char

“RIFF”

char riff_id[4]=”RIFF”

04H

4

long int

文件总长-8

 long int size0=文总长-8

08H

8

Char

“WAVEfmt “

char wave_fmt[8]

10H

4

long int

10 00 00 00H(PCM)

long int size1=0x10

14H

2

Int

01 00H

int fmttag=0x01

16H

2

Int

Int

channel=1 或2

18H

4

long int 

采样率

long int samplespersec

1CH

long int 

每秒播放字节数

long int bytepersec

20H 

int 

采样一次占字节数 

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

22H 

int 

量化数 

int bitpersamples=8或16

24H 

Char

“data” 

char data_id=”data”

28H

4

long int

采样数据字节数

long int size2=文长-44

2CH

 

 

 

到文尾 char 采样数据

                   

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

偏移地址

字节数

数据类型

内容

文件头定义为

00H

4

char 

“RIFF” 

char riff_id[4]=”RIFF”

04H 

long int 

文件总长-8 

long int size0=文总长-8

08H 

char 

“WAVEfmt ” 

char wave_fmt[8]

10H 

long int 

12000000H(ALAW) 

long int size1=0x12

14H 

int 

06 00H 

int fmttag=0x06

16H 

Int

声道数

int channel=1 或2

18H 

long int

采样率 

long int samplespersec

1CH 

long int

每秒播放字节数 

long int bytepersec

20H 

int 

采样一次占字节数

int blockalign=0x01

22H 

long int 

量化数 

long int bitpersamples=8

26H 

char 

“fact” 

char wave_fact=”fact”

2AH 

char 

0400000000530700H定 

char temp

32H 

char 

“data” 

char wave_data=”data”

36H 

long int 

采样数据字节数 

lont int size2=文长-58





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

 1 struct WAVE_HEADER                    //44bytes
 2 {
 3     char    riff_sig[4];
 4     long    waveform_chunk_size;
 5     char    wave_sig[4];
 6     char    format_sig[4];
 7     long    format_chunk_size;
 8     short   format_tag;
 9     short   channels;
10     long    sample_rate;
11     long    bytes_per_sec;
12     short   block_align;
13     short   bits_per_sample;
14     char    data_sig[4];
15     long    data_size;
16 };
17 
18 
19 struct WAVE_HEADER_FACT                //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;


  • mp3音频文件格式的解析

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


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

由于工程中在预链接事件中使用了yasm汇编器,所以需要下载配置yasm到vs工程中,在http://yasm.tortall.net/Download.html 有32位和64位系统对应的vs2010版本。
下载后解压,根据readme文档添加配置:将yasm.exe放置vs主目录bin中;将yasm.props、yasm.targets、yasm.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 }



将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 {
 8     mpg123_read( m_mpghandle, _buffer, lock_size, &outsize);
 9      memcpy(buf, _buffer, outsize);
10     m_pBuffer8->Unlock( buf, buf_len, NULL, 0 );
11 }


其中lock_pos和lock_size 分别是缓冲区的偏移量和锁定大小。
mpg13_read的第2个参数返回实际读取到的数据指针,第3个参数是希望读取的数据长度,第4个参数返回实际读取的数据长度。


 
以下是全部代码:

D3DPlayer.h
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)「建议收藏」
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)「建议收藏」

 1 #ifndef    __D3D_PLAYER__
 2 #define    __D3D_PLAYER__
 3 
 4 
 5 #include "resource.h"
 6 
 7 #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
 8 #define SAFE_DELETE(p) { if(p) {delete (p); (p)=NULL; } }
 9 
10 #endif

D3DPlayer.h



D3DPlayer.cpp
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)「建议收藏」
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)「建议收藏」

 1 #include "stdafx.h"  2 #include "D3DPlayer.h"  3 #include "D3DSound.h"  4  5 #define MAX_LOADSTRING 100  6 #define WS_MYPLAYERWINDOW (WS_OVERLAPPED | \  7 WS_CAPTION | \  8 WS_SYSMENU | \  9 WS_MINIMIZEBOX | \  10  WS_MAXIMIZEBOX)  11 #define MYWINWIDTH 700  12 #define MYWINHEIGHT 300  13  14 HINSTANCE hInst; // 当前实例  15 TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本  16 TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名  17 extern myD3DSound* g_pmySound;  18  19 BOOL PreTranslateMessage(LPMSG pMsg);  20 ATOM MyRegisterClass(HINSTANCE hInstance);  21 BOOL InitInstance(HINSTANCE, int);  22 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);  23 INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);  24  25 int APIENTRY _tWinMain(HINSTANCE hInstance,  26  HINSTANCE hPrevInstance,  27  LPTSTR lpCmdLine,  28 int nCmdShow)  29 {  30  UNREFERENCED_PARAMETER(hPrevInstance);  31  UNREFERENCED_PARAMETER(lpCmdLine);  32  33  MSG msg;  34  HACCEL hAccelTable;  35  36 myD3DSound* pDXSound = new myD3DSound;  37  LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);  38  LoadString(hInstance, IDC_D3DPLAYER, szWindowClass, MAX_LOADSTRING);  39  MyRegisterClass(hInstance);  40  41 if (!InitInstance (hInstance, nCmdShow))  42  {  43 return FALSE;  44  }  45  46 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_D3DPLAYER));  47  48 while (GetMessage(&msg, NULL, 0, 0))  49  {  50 if(!PreTranslateMessage(&msg))  51  {  52 if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))  53  {  54 TranslateMessage(&msg);  55 DispatchMessage(&msg);  56  }  57  }  58  }  59  60  SAFE_DELETE(g_pmySound);  61 return (int) msg.wParam;  62 }  63  64 ATOM MyRegisterClass(HINSTANCE hInstance)  65 {  66  WNDCLASSEX wcex;  67  68 wcex.cbSize = sizeof(WNDCLASSEX);  69  70 wcex.style = CS_HREDRAW | CS_VREDRAW;  71 wcex.lpfnWndProc = WndProc;  72 wcex.cbClsExtra = 0;  73 wcex.cbWndExtra = 0;  74 wcex.hInstance = hInstance;  75 wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYPLAYER));  76 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);  77 wcex.hbrBackground = (HBRUSH)( COLOR_WINDOW - 1 );  78 wcex.lpszMenuName = MAKEINTRESOURCE(IDC_D3DPLAYER);  79 wcex.lpszClassName = szWindowClass;  80 wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_MYSMALL));  81  82 return RegisterClassEx(&wcex);  83 }  84  85 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)  86 {  87  HWND hWnd;  88 int iWidth;  89 int iHeight;  90 hInst = hInstance; // 将实例句柄存储在全局变量中  91 iWidth=GetSystemMetrics(SM_CXSCREEN);  92 iHeight=GetSystemMetrics(SM_CYSCREEN);  93  94 hWnd = CreateWindow(szWindowClass, szTitle, WS_MYPLAYERWINDOW, (iWidth-MYWINWIDTH)/2,  95 (iHeight-MYWINHEIGHT)/2, MYWINWIDTH, MYWINHEIGHT, NULL, NULL, hInstance, NULL);  96  97 if (!hWnd)  98  {  99 return FALSE; 100  } 101 // 102 g_pmySound->myInit( hWnd ); 103 104  ShowWindow(hWnd, nCmdShow); 105  UpdateWindow(hWnd); 106 107 return TRUE; 108 } 109 110 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 111 { 112 int wmId, wmEvent; 113  PAINTSTRUCT ps; 114  HDC hdc; 115  RECT rect; 116  LRESULT res; 117  UINT CtrlId; 118 DRAWITEMSTRUCT *dis; 119  HFONT hfont; 120 NMHDR *pNMHDR; 121 122 switch (message) 123  { 124 case WM_NOTIFY: 125  { 126 pNMHDR = (LPNMHDR)lParam; 127 switch( pNMHDR->code ) 128  { 129 case NM_DBLCLK: 130  { 131 if( pNMHDR->idFrom == IDB_SONGLIST ) 132  { 133 int i = SendMessage(g_pmySound->m_listview, LVM_GETNEXTITEM, -1, LVNI_SELECTED); 134 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; 135 if(pNMListView && pNMListView->iItem >= 0 && pNMListView->iItem < g_pmySound->mySongNum() ) 136  { 137 g_pmySound->mySetPlayInfo(pNMListView,TRUE); 138 g_pmySound->myPlay(); 139 GetClientRect( hWnd, &rect ); 140 InvalidateRect(hWnd,&rect,TRUE); 141  } 142  } 143 }break; 144 case NM_CLICK: 145  { 146 if( pNMHDR->idFrom == IDB_SONGLIST ) 147  { 148 SendMessage(g_pmySound->m_listview, LVM_GETNEXTITEM, -1, LVNI_SELECTED); 149 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; 150 if(pNMListView && pNMListView->iItem >= 0 && pNMListView->iItem < g_pmySound->mySongNum() ) 151  { 152 g_pmySound->mySetPlayInfo(pNMListView,FALSE); 153  LVITEM vitem; 154 LVITEM* pvitem; 155  HANDLE hProcess; 156  DWORD PID; 157 GetWindowThreadProcessId(hWnd, &PID); 158 hProcess=OpenProcess(PROCESS_ALL_ACCESS,false,PID); 159 vitem.iItem = pNMListView->iItem; 160 vitem.state = LVIS_SELECTED|LVIS_FOCUSED; 161 vitem.stateMask = LVIS_SELECTED|LVIS_FOCUSED; 162 pvitem=(LVITEM*)VirtualAllocEx(hProcess, NULL, sizeof(LVITEM),MEM_COMMIT, PAGE_READWRITE); 163 WriteProcessMemory(hProcess, pvitem, &vitem, sizeof(LVITEM), NULL); 164 SendMessage(g_pmySound->m_listview, LVM_SETITEMSTATE, (WPARAM)pNMListView->iItem, (LPARAM)pvitem); 165 GetClientRect( hWnd, &rect ); 166 InvalidateRect(hWnd,&rect,TRUE); 167 168  } 169  } 170 else if( pNMHDR->idFrom == 12 ) 171  { 172 int i = 0; 173  } 174 }break; 175 default: 176 break; 177  } 178 break; 179  } 180 case WM_COMMAND: 181  { 182 wmId = LOWORD(wParam); 183 wmEvent = HIWORD(wParam); 184 // 分析菜单选择: 185 switch (wmId) 186  { 187 case IDM_ABOUT: 188  DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 189 break; 190 case IDM_EXIT: 191 res = MessageBox( hWnd, TEXT("是否关闭"), TEXT("退出"), MB_YESNO ); 192 if( res == IDYES ) 193  { 194  DestroyWindow( hWnd ); 195  } 196 break; 197 case IDB_OPEN: 198 g_pmySound->myOpenFile(); 199 GetClientRect( hWnd, &rect ); 200 InvalidateRect(hWnd,&rect,TRUE); 201 break; 202 case IDB_CLOSE: 203 g_pmySound->myCloseFile(); 204 GetClientRect( hWnd, &rect ); 205 InvalidateRect(hWnd,&rect,TRUE); 206 break; 207 case IDB_PLAY: 208 g_pmySound->myPlay(); 209 GetClientRect( hWnd, &rect ); 210 InvalidateRect(hWnd,&rect,TRUE); 211 break; 212 case IDB_STOP: 213 g_pmySound->myStop(); 214 GetClientRect( hWnd, &rect ); 215 InvalidateRect(hWnd,&rect,TRUE); 216 break; 217 case IDB_PAUSE: 218 g_pmySound->myPause(); 219 break; 220 default: 221 return DefWindowProc(hWnd, message, wParam, lParam); 222  } 223 break; 224  } 225 case WM_PAINT: 226  { 227 hdc = BeginPaint(hWnd, &ps); 228 // TODO: 在此添加任意绘图代码... 229 EndPaint(hWnd, &ps); 230 break; 231  } 232 case WM_DRAWITEM: 233  { 234 CtrlId = (UINT)wParam; 235 dis = (LPDRAWITEMSTRUCT)lParam; 236 int lw,lh,fw,fh,len; //ctrl width,ctrl height,font w,font h,font 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 }

D3DPlayer.cpp



D3DSound.h
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)「建议收藏」
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)「建议收藏」

 1 #ifndef __D3D_SOUND__  2 #define __D3D_SOUND__  3  4 #include "D3DPlayer.h"  5 #include "stdafx.h"  6 #include "mpg123.h"  7  8 #define MAX_AUDIO_BUF 4  9 #define BUFFERNOTIFYSIZE 192000  10 #define IDB_OPEN 1001  11 #define IDB_CLOSE 1002  12 #define IDB_PLAY 1003  13 #define IDB_PAUSE 1004  14 #define IDB_STOP 1005  15 #define IDB_PLAYING 2001  16 #define IDB_TIMESHOW 2002  17 #define IDB_SONGINFO 2003  18 #define IDB_SONGTEXT 2004  19 #define IDB_SONGTIME 2005  20 #define IDB_SONGLIST 2006  21  22 struct WAVE_HEADER //44bytes  23 {  24 char riff_sig[4];  25 long waveform_chunk_size;  26 char wave_sig[4];  27 char format_sig[4];  28 long format_chunk_size;  29 short format_tag;  30 short channels;  31 long sample_rate;  32 long bytes_per_sec;  33 short block_align;  34 short bits_per_sample;  35 char data_sig[4];  36 long data_size;  37 };  38  39 struct WAVE_HEADER_FACT //58bytes  40 {  41 char riff_sig[4];  42 long waveform_chunk_size;  43 char wave_sig[4];  44 char format_sig[4];  45 long format_chunk_size;  46 short format_tag;  47 short channels;  48 long sample_rate;  49 long bytes_per_sec;  50 short block_align;  51 short bits_per_sample;  52 short bits_per_sample2;  53 char fact_sig[4];  54 short fact_size;  55 short fact_size2;  56 char fact_data[4];  57 char data_sig[4];  58 long data_size;  59 };  60  61 struct myListMember  62 {  63 int m_idx;  64 WCHAR m_name[100];  65 WCHAR m_time[10];  66 WCHAR m_type[10];  67 WCHAR m_bits[20];  68  WCHAR m_path[MAX_PATH];  69 };  70  71 static DWORD ThreadNotifyEvent( LPVOID thread_data );  72 static DWORD ThreadNotifyEvent2( LPVOID thread_data );  73 static DWORD ThreadNotifyEvent3( LPVOID thread_data );  74 void ChartoWCHAR( const char*, WCHAR* );  75 void WCHARtoChar( const WCHAR*, char* );  76  77 class myD3DSound  78 {  79 private:  80  OPENFILENAME opfn;  81 bool isPlaying;  82 DWORD m_ds_dwBuffSize; //dxsound缓冲区大小  83 HANDLE m_hThread; //控制buffer  84  DWORD m_thread_id;  85 HANDLE m_hThread2; //滚动条显示  86  DWORD m_thread_id2;  87 HANDLE m_hThread3; //剩余时间显示  88  DWORD m_thread_id3;  89 FILE* m_fp;  90 mpg123_handle* m_mpghandle;  91  DWORD m_dwPlayPos;  92 WCHAR m_wstrTime[60];  93 WCHAR m_wSongTime[30]; //总时长  94 WCHAR m_wSongLeave[30]; //剩余时长  95 typedef std::vector<myListMember> MY_SONG_LIST;  96  MY_SONG_LIST m_list;  97 WCHAR m_wSongPath[MAX_PATH]; //正在播放歌曲  98  WCHAR m_wSongName[MAX_PATH];  99 WCHAR m_wSongPathPre[MAX_PATH]; //单击选中歌曲 100  WCHAR m_wSongNamePre[MAX_PATH]; 101 102 bool m_bmpg; 103 bool m_factwav; 104 public: 105  HWND m_father; 106 //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.h



D3DSound.cpp
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)「建议收藏」
WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)「建议收藏」

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

D3DSound.cpp

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/167416.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 列式数据库概述_列式数据库多张表

    列式数据库概述_列式数据库多张表阐述列式数据库的基本定义,现状,以及一些开源数据库的性能比较。

  • chkdsk命令修复磁盘没反应_chkdsk怎么修复c盘

    chkdsk命令修复磁盘没反应_chkdsk怎么修复c盘故障笔记本电脑进不了系统,XP系统的开机进度条一走完蓝屏画面一闪就自己重启了,试了安全模式与最后一次正确配置都是一样的情况,据笔记本的主人说想一键还原也不行(装有GHOST一键还原)。使用PE工具盘启动笔记本,进入“我的电脑”一看,C盘信息全没了,没有已用空间大小,也没有可用空间大小,连C盘大小也没有了,格式变成RAW,但是用工具盘上的DiskGenius却可以看到里面的文件,也可以看到C盘是NT…

    2022年10月27日
  • 中标麒麟操作系统安装教程_中标麒麟内核是centos

    中标麒麟操作系统安装教程_中标麒麟内核是centos为什么80%的码农都做不了架构师?>>>…

  • windows启动、重启nginx

    windows启动、重启nginxwindows中启动、重启nginx命令1.找到nginx的安装目录,在目录上cmd进入黑窗口;2.启动startnginx3.配置文件nginx.conf修改重装载命令nginx-sreload

    2022年10月28日
  • HandlerSocket_handlermapping原理

    HandlerSocket_handlermapping原理HandlerSocket的应用场景:MySQL自身的局限性,很多站点都采用了MySQL+Memcached的经典架构,甚至一些网站放弃MySQL而采用NoSQL产品,比如Redis/MongoDB等。不可否认,在做一些简单查询(尤其是PK查询)的时候,很多NoSQL产品比MySQL要快很多,而且前台网站上的80%以上查询都是简洁的查询业务。MySQL通过HandlerSock…

  • slf4j如何使用_正确刷牙方法图解

    slf4j如何使用_正确刷牙方法图解环境说明Windows101803IDEA2018.2.EAPMaven3.5.2这是正文POM文件&lt;!–https://mvnrepository.com/artifact/org.projectlombok/lombok–&gt;&lt;dependency&gt;&lt;groupId&g…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号