8

我正在用 C# 编写一个基本的写作应用程序,我想让程序在你打字时发出打字机的声音。我已经将我的 RichTextBox 上的 KeyPress 事件连接到一个函数,该函数使用 SoundPlayer 在每次按下一个键时播放一个短的 wav 文件,但是我注意到一段时间后我的计算机慢到爬行并检查我的进程,audiodlg .exe 使用了 5 GB 的 RAM。

我正在使用的代码如下:

我在程序开始时将 SoundPlayer 初始化为全局变量

SoundPlayer sp = new SoundPlayer("typewriter.wav")

然后在 KeyPress 事件中,我只需调用

sp.Play();

有谁知道是什么导致大量内存使用?该文件的长度不到一秒钟,因此它不应该过多地阻塞它。

4

8 回答 8

6

不要使用SoundPlayer- 改用waveOut...API:

http://www.codeproject.com/Articles/4889/A-full-duplex-audio-player-in-C-using-the-waveIn-w

SoundPlayer它更像是一个玩具,而不是一个生产就绪的组件,尽管我确信编写它的 MS 实习生是好意的。:)

更新: 如果您使用链接的示例并熟悉代码,您将看到SoundPlayer实现可能有什么问题。使用这些函数播放音频waveOut...涉及两个内存缓冲区:一个用于标题的小缓冲区,另一个可能比包含实际样本数据的大缓冲区。您链接到的修补程序文章提到每次调用几百字节的泄漏Play,这意味着代码可能每次都实例化一个新的标头,然后没有正确处理它。(这是假设SoundPlayer包装了waveOut...API - 我不知道是否是这种情况)

程序员认为“不要重新发明轮子”是理所当然的。好吧,有时轮子迫切需要重新发明。

于 2011-01-29T17:50:23.297 回答
2

这可能是 SoundPlayer 中的错误。

试试这篇关于代码项目的文章,也许它会给你一些提示。

于 2010-11-05T16:48:25.760 回答
0

这不是严格意义上的答案,所以我不会确认这是对我的问题的公认答案,但对于遇到同样问题的人来说,这是一个解决方案(并且也确认这不是我的系统有问题)

我决定使用 ManagedDirectX 的 AudioPlayback 库来实现声音,它与 SoundPlayer 一样易于使用,但成功地解决了我的问题。

对于那些想知道的人,代码很简单:

1) 添加对音频播放 dll 的引用。

2)创建一个音频对象(我命名为我的声音),使其成为表单上的变量,以便您可以再次引用它,使用构造函数设置它应该播放的文件名

3) 使用 sound.Play() 播放文件;

4)如果您需要再次播放文件,请使用以下行:

sound.SeekCurrentPosition(0, SeekPositionFlags.AbsolutePositioning);

它相当快,而且相当好。如果您需要很多不同的音效,就会出现内存问题,因为它们都会一直存在于内存中,但是如果您需要一种声音来播放很多声音,那么这个声音就可以做到,而不会使您的 Audiodlg.exe 膨胀

于 2011-02-01T23:17:02.607 回答
0

尝试使用Load声音播放器的方法加载声音,然后调用play。Play 使用第二个线程加载(如果尚未加载)并播放文件。

也许构造函数最初并没有加载文件(我认为这很有可能),它将播放器与声音文件名相关联。

于 2010-11-05T16:33:47.593 回答
0

我已经完成了这个示例。WWFM(又名“为我工作得好”)。尝试在您的代码(我几乎可以肯定,它足够纯净)或其他声音文件中搜索错误。

于 2011-01-25T12:15:58.387 回答
0

播放声音后尝试处理 SoundPlayer。然后运行垃圾收集器。如果它仍然消耗额外的内存,那么确实发生了一些令人讨厌的事情,您应该在另一台计算机上运行测试。

于 2011-01-26T14:01:07.550 回答
0

我之前在 Win32 API 中使用过PlaySound函数来做类似的事情。尽管这与您使用的语言不同,但下面是一个程序示例,该程序将在每 100 次击键时播放“mahnamahna.wav”。(是的,这很有趣)

 format PE GUI 4.0
entry start

;Mahna Mahna.

include 'win32a.inc'

include 'helper.asm'

section '.idata' import data readable writeable

    library kernel32,'KERNEL32.DLL',\
            user32,'USER32.DLL',\
            hook,'HOOK.DLL',\
            winmm,'WINMM.DLL'

    import  hook,\
            SetKeyPressedHandler,'SetKeyPressedHandler'

    import winmm,\
            PlaySound,'PlaySound'

    include 'api\kernel32.inc'
    include 'api\user32.inc'

section '.data' data readable writeable

    szWavFile db "mahnamahna.wav",0

    ;String saying what the dll is called.
    szDllName db "HOOK.DLL",0

    ;Name of the function in the dll for the keyboard procedure
    szf_KeyboardProc db "KeyboardProc",0

    ;handle to the dll
    hDll dd ?
    ;handle to the keyboard procedure
    hKeyboardProc dd ?
    ;handle to the hook
    hHook dd ?

    kInput KBINPUT

    keyCount dd 0x0 ;

    ;msg for the message pump
    msg MSG


section '.text' code readable executable

    start:

        ;Load the DLL into memory.
        invoke LoadLibraryA,szDllName
        cmp eax,0x0
        je exit
        mov [hDll],eax


        invoke GetProcAddress,[hDll],szf_KeyboardProc
        cmp eax,0x0
        je freeLibrary
        mov [hKeyboardProc],eax

        invoke SetKeyPressedHandler,KeyPressedHandler

    hook:
        invoke SetWindowsHookEx,WH_KEYBOARD_LL,[hKeyboardProc],[hDll],0x0
        cmp eax,0x0
        je freeLibrary
        mov [hHook],eax

    msg_loop:
        invoke  GetMessage,msg,NULL,0,0
        cmp eax,1
        jb  unhook
        jne msg_loop
        invoke  TranslateMessage,msg
        invoke  DispatchMessage,msg
    jmp msg_loop



    proc KeyPressedHandler code,wparam,lparam

        ;Move the VK Code of the key they pressed into al.
        xor eax,eax
        mov eax,[lparam]
        mov cx,word [eax]

        cmp [wparam],WM_KEYDOWN
        je .ProcessKeyDown
        cmp [wparam],WM_KEYUP
        je .ProcessKeyUp

        .ProcessKeyDown:

            ret ;No need to go any further - we only process characters on key up
        .ProcessKeyUp:
            mov edx,[keyCount]
            inc edx

            cmp cx,VK_F12
            je unhook

            ;Hotkeys.
            ;F12 - Quit.
            cmp edx,0x64
            jne .done
            call MahnaMahna
            xor edx,edx
            .done:
            mov [keyCount],edx
        ret
    endp

    proc MahnaMahna
        invoke PlaySound,szWavFile,0x0,0x20000
        ret
    endp

    unhook:
        invoke UnhookWindowsHookEx,[hHook]

    freeLibrary:
        invoke FreeLibrary,[hDll]
    exit: 
        invoke ExitProcess,0

如果没有以下dll(hook.dll),上述内容将无法工作

 format PE GUI 4.0 DLL
entry _DllMain

include 'win32a.inc'

section '.data' data readable writeable
    hKeyPressedHandler dd 0x0
section '.text' code readable executable

proc _DllMain hinstDLL,fdwReason,lpvReserved
    mov eax,TRUE
    ret
endp

    proc SetKeyPressedHandler hProc
        mov eax,[hProc]
        mov [hKeyPressedHandler],eax
        ret
    endp

    proc KeyboardProc code,wparam,lparam
        cmp [code],0x0
        jl CallNextHook

        cmp [hKeyPressedHandler],0x0;Make sure our event handler is set.
        je CallNextHook

        ;Call our handler.
        invoke hKeyPressedHandler,[code],[wparam],[lparam]

        CallNextHook:
            invoke CallNextHookEx,0x0,[code],[wparam],[lparam]
            ret
    endp

section '.idata' import data readable writeable

    library kernel32,'KERNEL32.DLL',\
            user32,'USER32.DLL'

    include 'api\kernel32.inc'
    include 'api\user32.inc'

section '.edata' export data readable
    export 'hook.DLL',\
        KeyboardProc,'KeyboardProc',\
        SetKeyPressedHandler,'SetKeyPressedHandler'

section '.reloc' fixups data discardable
于 2011-01-30T00:30:07.317 回答
0

你应该尝试使用()

using(SoundPlayer sp = new SoundPlayer("typewriter.wav")) {
   sp.Play();
}

当进程完成 sp.Play() 内存返回到您的系统自动。

于 2011-11-12T09:48:15.480 回答