发信人: lzzzl(lzzzl)
整理人: yangcs(2004-10-14 14:22:35), 站内信件
|
支持手工弹和自动演奏了,多线程有小BUG,未处理好
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
include \masm32\include\winmm.inc
include \MASM32\INCLUDE\masm32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\winmm.lib
includelib \MASM32\LIB\masm32.lib
.data
ClassName db "Line5PlayerClass",0
AppName db "五线谱播放播放器 [版本:1.0 作者:周仲俐 2004.02.03]",0
szText db '高低音{j,k,l,s,d,f,^,v} 速度{<-,->} 音符{1,2,3,4,5,6,7}',0h
.data?
hInstance HINSTANCE ? ;程序实例句柄
hdc HDC ? ;midi句柄
midiScale DWORD ? ;音符{1,2,3,4,5,6,7}
midiTone DWORD ? ;音调{s,d,f}={低,中,高}
midiBase DWORD ? ;基调{j,k,l}={低,中,高}
midiFlag BYTE ?
midiPlayFlag BYTE ?
delay DWORD ?
lastmidi DWORD ?
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke WinMain, hInstance,NULL,NULL,SW_SHOWDEFAULT
invoke ExitProcess,eax
; ########################################################################
; 读取文件内容
ReadFileIn proc lpszDiskFile:DWORD
LOCAL hFile :DWORD ;文件句柄
LOCAL hMem$ :DWORD ;BSTR指针
LOCAL ln :DWORD ;文件长度
LOCAL br :DWORD ;实际读取到的字节数
LOCAL brw :DWORD ;实际读取到的字节数
local skipping :DWORD ;是否正在跳过注释
local last :DWORD ;前一字符
local @playf:WORD
local tc :DWORD
local skipnext :DWORD
local txtBuffer[1024]:BYTE
invoke CreateFile,lpszDiskFile,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
mov hFile, eax
invoke GetFileSize,hFile,NULL
mov ln, eax
.if ln > 32767
invoke CloseHandle,hFile
;szText tooBig,"乐谱文件太大,系统无法处理!"
;invoke MessageBox,hWnd,ADDR tooBig,"dd",MB_OK
xor eax, eax
ret
.endif
mov skipping,0
mov last,0
mov skipnext,0h
.while TRUE
invoke ReadFile,hFile,addr brw,1,ADDR br,NULL
and brw,0ffh ;也许不必
.if br==0
.break
.elseif brw==3bh ;";",判断注释是否开始
mov skipping,1
.elseif skipping==1
.if brw==0ah
.elseif brw==0dh
.else
.if last==0ah
mov skipping,0 ;注释行结束
.elseif last==0dh
mov skipping,0
.else
.endif
.endif
.else
.endif
.if skipping==1
.elseif brw==0ah
.elseif brw==0dh
.else
;invoke MessageBox,NULL,addr brw,addr AppName,MB_OK
mov @playf,0h
push brw
pop midiScale
;==================== 基调 =======================
.if midiScale==6ch ;l
mov midiBase,12 ;24,12,0
.elseif midiScale==6bh ;k
mov midiBase,0 ;12,0,-12(默认)
.elseif midiScale==6ah ;j
mov midiBase,-12 ;0,-12,-24
.else
.endif
;==================== 音调 =======================
.if midiScale==60h ;“`”,高,相对+12
add midiTone,12
.elseif midiScale==64h ;中
.elseif midiScale==2eh ;“.”,低,相对-12
add midiTone,-12
.else
.endif
;==================== 全音 =======================
.if midiScale==31h ;1
mov midiScale,3ch ;注意可能又误用于后面的判断
mov @playf,1
.elseif midiScale==32h ;2
mov midiScale,3eh
mov @playf,1
.elseif midiScale==33h ;3
mov midiScale,40h
mov @playf,1
.elseif midiScale==34h ;4
mov midiScale,41h
mov @playf,1
.elseif midiScale==35h ;5
mov midiScale,43h
mov @playf,1
.elseif midiScale==36h ;6
mov midiScale,45h
mov @playf,1
.elseif midiScale==37h ;7
mov midiScale,47h
mov @playf,1
.elseif midiScale==7eh ;“~”,滑音
mov skipnext,1
.else
.endif
;===================== 半音 ======================
.if midiScale==71h ;q
mov midiScale,3dh
mov @playf,1
.elseif midiScale==77h ;w
mov midiScale,3fh
mov @playf,1
.elseif midiScale==65h ;e
mov midiScale,42h
mov @playf,1
.elseif midiScale==72h ;r
mov midiScale,44h
mov @playf,1
.elseif midiScale==74h ;t
mov midiScale,46h
mov @playf,1
.endif
;===================== 发声 ======================
.if @playf==1
mov eax,midiTone
add midiScale,eax ;调整音调
mov cl,8
shl midiScale,cl ;左移一个字节
and midiScale,0ff00h
add midiScale,680090h ;使之成为乐音
mov eax,midiScale
.if skipnext==0
.elseif lastmidi==eax
.else
mov skipnext,0
.endif
.if skipnext==1
mov skipnext,0
.else
invoke midiOutShortMsg,hdc,midiScale
;复位
mov midiPlayFlag,0h
push midiBase
pop midiTone
.endif
invoke GetTickCount ; get a time reference
mov tc, eax
mov edx,delay
add tc, edx;250 ; add 1/4 seconds to the time reference
; ------------------------------------------------
; loop until Tick count catches up with added time
; ------------------------------------------------
@@:
invoke GetTickCount
.if tc > eax
jmp @B
.endif
push midiScale
pop lastmidi
.elseif skipping==1
.elseif brw==2dh
invoke GetTickCount ; get a time reference
mov tc, eax
add tc, 250 ; add 1/4 seconds to the time reference
; ------------------------------------------------
; loop until Tick count catches up with added time
; ------------------------------------------------
@@:
invoke GetTickCount
.if tc > eax
jmp @B
.endif
.endif
.endif
.if skipping==1
.elseif brw==28h
shr delay,1
.elseif brw==29h
shl delay,1
.else
.endif
push brw
pop last
.endw
invoke CloseHandle,hFile
ret
ReadFileIn endp
play proc Param:DWORD
LOCAL clBuffer[128]:BYTE
invoke GetCL,1, ADDR clBuffer
invoke ReadFileIn,ADDR clBuffer
play endp
;入口(主)函数
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX ;(本地)局部变量
LOCAL msg:MSG
LOCAL hwnd:HWND
local x:DWORD
local y:DWORD
local w:DWORD
local h:DWORD
local txtBuffer[1024]:BYTE
;窗口用户界面
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst ;变量->变量,比用mov指令及寄存器简单
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
mov w,420
mov x,800
mov eax,w
sub x,eax
shr x,1
mov h,180
mov y,600
mov eax,h
sub y,eax
shr y,1
invoke RegisterClassEx, addr wc ;地址传递
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,x,\
y,w,h,NULL,NULL,\
hInst,NULL
mov hwnd,eax
INVOKE ShowWindow, hwnd,SW_SHOWNORMAL
INVOKE UpdateWindow, hwnd
;音效设备
invoke midiOutOpen,ADDR hdc,-1,NULL,NULL,NULL
;全局变量
mov midiBase,0h
mov midiTone,0h
mov midiPlayFlag,1h
mov delay,500
;消息循环
.WHILE TRUE
INVOKE GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
;消息处理(回调)函数
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
local @stPs:PAINTSTRUCT ;前缀@何意?
local @stRect:RECT
local @hDc
local @playf:WORD
LOCAL clBuffer[128]:BYTE
local id:DWORD
.IF uMsg==WM_DESTROY
invoke midiOutClose,hdc ;如何句柄无效会怎样?
invoke PostQuitMessage,NULL
.ELSEIF uMsg ==WM_PAINT
invoke BeginPaint,hWnd,addr @stPs
mov @hDc,eax
invoke GetClientRect,hWnd,addr @stRect
invoke DrawText,@hDc,addr szText,-1,\
addr @stRect,\
DT_SINGLELINE or DT_CENTER or DT_VCENTER
invoke EndPaint,hWnd,addr @stPs
.ELSEIF uMsg==WM_CHAR ;好象相当于KeyPress,KeyUp时不产生此事件
push wParam
pop midiScale
;===============ESC键退出================
.if midiScale==WM_DEVMODECHANGE ;1bh(27)
invoke midiOutClose,hdc
invoke PostQuitMessage,NULL
.elseif midiScale==70h ;"p" to play
; start compressing in a thread
invoke CreateThread,NULL,NULL,OFFSET play,NULL,0,ADDR id
invoke CloseHandle,addr id
.else
.ENDIF
mov @playf,0h
push wParam
pop midiScale
;===============ESC键退出================
.if midiScale==WM_DEVMODECHANGE ;1bh(27)
invoke midiOutClose,hdc
invoke PostQuitMessage,NULL
.ENDIF
;==================== 基调 =======================
.if midiScale==6ch ;l
mov midiBase,12 ;24,12,0
.elseif midiScale==6bh ;k
mov midiBase,0 ;12,0,-12(默认)
.elseif midiScale==6ah ;j
mov midiBase,-12 ;0,-12,-24
.else
.endif
;==================== 音调 =======================
;按下高音键后不能松手,一松手系统就恢复为正常音调。低音键类似
.if midiScale==66h ;f(高,相对+12)
push midiBase
pop midiTone
add midiTone,12
.elseif midiScale==64h ;d(中)
push midiBase
pop midiTone
;add midiTone,0
.elseif midiScale==73h ;s(低,相对-12)
push midiBase
pop midiTone
add midiTone,-12
.else
.endif
;==================== 全音 =======================
.if midiScale==31h ;1
mov midiScale,3ch
mov @playf,1
.elseif midiScale==32h ;2
mov midiScale,3eh
mov @playf,1
.elseif midiScale==33h ;3
mov midiScale,40h
mov @playf,1
.elseif midiScale==34h ;4
mov midiScale,41h
mov @playf,1
.elseif midiScale==35h ;5
mov midiScale,43h
mov @playf,1
.elseif midiScale==36h ;6
mov midiScale,45h
mov @playf,1
.elseif midiScale==37h ;7
mov midiScale,47h
mov @playf,1
.endif
;===================== 半音 ======================
.if midiScale==71h ;q
mov midiScale,3dh
mov @playf,1
.elseif midiScale==77h ;w
mov midiScale,3fh
mov @playf,1
.elseif midiScale==65h ;e
mov midiScale,42h
mov @playf,1
.elseif midiScale==72h ;r
mov midiScale,44h
mov @playf,1
.elseif midiScale==74h ;t
mov midiScale,46h
mov @playf,1
.endif
;===================== 发声 ======================
.if @playf==1
mov eax,midiTone
add midiScale,eax ;调整音调
mov cl,8
shl midiScale,cl ;左移一个字节
and midiScale,0ff00h
add midiScale,680090h ;使之成为乐音
.if midiPlayFlag==1h
invoke midiOutShortMsg,hdc,midiScale
;复位
mov midiPlayFlag,0h
.endif
.endif
.ELSEIF uMsg==WM_KEYUP
mov midiPlayFlag,1h
;只要松开高音或低音键,就恢复为正常
.if wParam==46h ;f
push midiBase
pop midiTone
.elseif wParam==53h ;s
push midiBase
pop midiTone
.else
.endif
;用于自动演奏
.if wParam==25h ;<--
shl delay,1
.elseif wParam==26h ;^
add midiBase,12
.elseif wParam==27h ;-->
shr delay,1
.elseif wParam==28h ;V
add midiBase,-12
.else
.endif
.ELSE
;转发不能处理的系统消息
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax ;why not mov eax,0h?
ret
WndProc endp
end start
---- 不想计较得失,却总在计较得失 |
|