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

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

4

long int

每秒播放字节数

long int bytepersec

20H

2

int

采样一次占字节数

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

22H

2

int

量化数

int bitpersamples=8或16

24H

4

Char

"data"

char data_id="data"

28H

4

long int

采样数据字节数

long int size2=文长-44

2CH

到文尾 char 采样数据

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

偏移地址

字节数

数据类型

内容

文件头定义为

00H

4

char

"RIFF"

char riff_id[4]="RIFF"

04H

4

long int

文件总长-8

long int size0=文总长-8

08H

8

char

"WAVEfmt "

char wave_fmt[8]

10H

4

long int

12000000H(ALAW)

long int size1=0x12

14H

2

int

06 00H

int fmttag=0x06

16H

2

Int

声道数

int channel=1 或2

18H

4

long int

采样率

long int samplespersec

1CH

4

long int

每秒播放字节数

long int bytepersec

20H

2

int

采样一次占字节数

int blockalign=0x01

22H

4

long int

量化数

long int bitpersamples=8

26H

4

char

"fact"

char wave_fact="fact"

2AH

8

char

0400000000530700H定

char temp

32H

4

char

"data"

char wave_data="data"

36H

4

long int

采样数据字节数

lont int size2=文长-58


只要构建字节对应的结构,然后从wav文件起始位置读取相应长度到结构即可,例如
 1 struct WAVE_HEADER                    //44bytes
 2 {
 3     char    riff_sig[4];
 4     long    waveform_chunk_size;
 5     char    wave_sig[4];
 6     char    format_sig[4];
 7     long    format_chunk_size;
 8     short   format_tag;
 9     short   channels;
10     long    sample_rate;
11     long    bytes_per_sec;
12     short   block_align;
13     short   bits_per_sample;
14     char    data_sig[4];
15     long    data_size;
16 };
17
18
19 struct WAVE_HEADER_FACT                //58bytes
20 {
21     char    riff_sig[4];
22     long    waveform_chunk_size;
23     char    wave_sig[4];
24     char    format_sig[4];
25     long    format_chunk_size;
26     short   format_tag;
27     short   channels;
28     long    sample_rate;
29     long    bytes_per_sec;
30     short   block_align;
31     short   bits_per_sample;
32     short    bits_per_sample2;
33     char    fact_sig[4];
34     short    fact_size;
35     short    fact_size2;
36     char    fact_data[4];
37     char    data_sig[4];
38     long    data_size;
39 };

这里构建了两种类型的wav格式头,从文件中读取信息到结构,然后直接赋值给WAVEFORMATEX即可
1 WAVEFORMATEX    wave_format;
2 WAVE_HEADER        wave_header;
3 fread( &wave_header, 1, sizeof(WAVE_HEADER), fp);
4 wave_format.wFormatTag      = WAVE_FORMAT_PCM;
5 wave_format.nChannels       = wave_header.channels;
6 wave_format.nSamplesPerSec  = wave_header.sample_rate;
7 wave_format.wBitsPerSample  = wave_header.bits_per_sample;
8 wave_format.nBlockAlign     = wave_header.bits_per_sample / 8 * wave_header.channels;
9 wave_format.nAvgBytesPerSec = wave_header.sample_rate * wave_format.nBlockAlign;

  • 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

 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     | \
  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

  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

   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

 

转载于:https://www.cnblogs.com/gpsupergp/p/4720219.html

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

  1. Android media ---- 1.7.ffmpeg 简单音频播放器

    哎,喜欢偷懒,这边直接抄袭下雷神的代码.雷神是个值得敬佩的程序员. vs代码下载链接: https://pan.baidu.com/s/1c2dIuYk 密码:ld4b /* *最简单的基于FFmpe ...

  2. Java实现简单在线播放器——支持优酷和土豆

    今天本来是打算继续写"Java新浪微博客户端开发"的,也实现了"系统托盘","点击查看大图"的功能,写到一半,想起上篇博文中有CSDN有一网 ...

  3. 简单音频播放器java代码_Java实现简易音乐播放器

    //此程序实现mid.wav格式音频文件的播放 //暂时只实现了单曲播放功能 //选项>其它功能会后继添加 //Version 1.0 // @author Zha_yongchun // Em ...

  4. 音视频开发(三十八):ExoPlayer 音频播放器实践

    通过上一篇的学习实践,我们了解了ExoPlayer的优缺点以及基本用法,今天我们进入ExoPlayer的音频播放实践,我们来一起实现一个简单的音频播放器. 目录 媒体播放框架MediaSession ...

  5. HTML,js自制MP3音频播放器

    HTML,js自制音频播放器 示意图 演示效果 MP3音频播放器 文件结构 HTML代码 <!DOCTYPE html> <html><head><meta ...

  6. 使用LM386的简单Arduino音频播放器和放大器

    原文地址:https://circuitdigest.com/microcontroller-projects/arduino-audio-music-player 使用LM386的简单Arduino ...

  7. 最简单的基于FFMPEG+SDL的音频播放器:拆分-解码器和播放器

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

  8. 最简单的基于FFMPEG+SDL的音频播放器 拆分-解码器和播放器

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

  9. 安卓java音乐播放器下一曲_Android实现简单音乐播放器(MediaPlayer)

    Android实现简单音乐播放器(MediaPlayer),供大家参考,具体内容如下 开发工具:Andorid Studio 1.3 运行环境:Android 4.4 KitKat 工程内容 实现一个 ...

最新文章

  1. python实现冒泡排序完整算法_Python实现冒泡排序算法的完整实例
  2. Sublime text3中配置Github
  3. VC++实现任务管理器功能
  4. 命令流水帐之二:配置Server环境LAMP
  5. (译) JSON-RPC 2.0 规范(中文版)
  6. 软件测试个人心得总结
  7. if...elif...else...fi和case...esac的脚本条件判断式
  8. 视频下载比想象中容易
  9. Onvif开发之代码框架生成篇
  10. 一个命令让redis服务端所有信息无所遁形~(收藏吃灰系列)
  11. Rust笔记1 rust基本概念
  12. FPGA基础知识之主要的FPGA生产厂商介绍
  13. VB.NET的数据库基础编程[zz]
  14. PAT 乙级A1025 适合当算法入门练习题做
  15. 03-jenkins集成环境配置
  16. Unbuntu22.04安装教程以及Unbuntu下C++环境的配置
  17. 李彦宏“泼水门”:舆论的狂欢,还是魏则西的葬歌?
  18. ASP VBSCRIPT VBA RSA 公钥加密 私钥解密 私钥签名 公钥验签
  19. heic是什么格式?如何转成JPG格式?
  20. 语音质量评价和可懂度评价

热门文章

  1. TCP/IP Socket 服务器对接
  2. Eclipse在官网下载页面打不开
  3. 埃氏筛法求素数(C语言)
  4. 如何用计算机测试交易系统,一种自动售票机交易功能的测试系统和方法与流程...
  5. shiro权限管理实例
  6. 纯CSS3写的10个不同的酷炫图片遮罩层效果
  7. 新媒体短视频运营哪些内容
  8. linux内核编程,实现内核之间的调用
  9. python清空屏幕
  10. 接口隔离原则-快速理解