2010-11-05 11 views
8

Escribo una aplicación de escritura básica en C# y quería que el programa hiciera sonidos de máquina de escribir mientras escribía. He enganchado el evento KeyPress en mi RichTextBox a una función que usa un SoundPlayer para reproducir un archivo wav corto cada vez que se presiona una tecla, sin embargo, después de un tiempo noté que mi computadora se ralentizaba y comprobaba mis procesos, audiodlg .exe estaba usando 5 GIGABYTES de RAM.SoundPlayer provocando pérdidas de memoria?

El código que estoy usando es el siguiente:

Me inicializar el SoundPlayer como una variable global en el programa se inicia con

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

Luego, en el evento KeyPress simplemente me llamo

sp.Play(); 

¿Alguien sabe qué está causando el uso de la memoria pesada? El archivo dura menos de un segundo, por lo que no debería obstruirlo demasiado.

+0

Si comenta 'sp.Play();' ¿nota que su memoria ya no crece a 5 Gb? Si aún lo hace, hay algo más que está mal con tu código. – JLWarlow

+0

Actualice sus controladores de audio. –

+0

Sí, definitivamente. Le asigné una tecla para no hacer nada, y otra para hacer el ruido. Mantener presionada la tecla "no hacer nada" no modifica el uso de la memoria de audiodg.exe. Si mantiene presionada la tecla "reproducir ruido", se disparará rápidamente. Entonces no se cae si lo dejo por varios minutos. –

Respuesta

5

no utilice SoundPlayer - utilizar la API waveOut... lugar:

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

SoundPlayer es más como un juguete que un producto componente preparado para ion, aunque estoy seguro de que el interno de MS que lo escribió tenía buenas intenciones. :)

Actualización: Si utiliza la muestra vinculada y se familiariza con el código, verá lo que probablemente sea incorrecto con la implementación SoundPlayer. La reproducción de audio con las funciones waveOut... implica dos búferes en memoria: uno pequeño para el encabezado y un búfer potencialmente grande que contiene los datos de muestra reales. El artículo de la revisión que vinculó menciona la pérdida de unos pocos cientos de bytes cada vez que se llama Play, lo que significa que el código probablemente esté instanciando un nuevo encabezado cada vez y luego no se deshaga de él correctamente. (Esto está asumiendo SoundPlayer envuelve la API waveOut... - No sé si este es el caso o no)

Los programadores dan por sentada la máxima "no reinventar la rueda". Bueno, a veces la rueda necesita reinventarse desesperadamente.

+0

A fecha de 2014/09/17 el enlace está roto. –

+1

No se pudo encontrar el código fuente original, así que agregué otro (posiblemente mejor) enlace. – Sire

0

Pruebe usar el método Load del reproductor de sonido para cargar el sonido, y luego invoque reproducir. Play usa un segundo hilo para cargar (si no está cargado) y reproduce el archivo.

Tal vez el constructor no carga el archivo inicialmente (lo que creo que es bastante posible), asocia al reproductor con el nombre del archivo de sonido.

+0

Acabo de intentarlo y la memoria sigue aumentando cuando se reproduce el sonido. Estoy ejecutando Load() en el inicializador de mi ventana, así que definitivamente está sucediendo. –

2

Podría ser un error en el SoundPlayer.

Pruebe este artículo en code project, tal vez le dará algunas pistas.

+0

Probé la implementación del artículo, que tampoco funcionó. Me temo. –

0

He hecho con this sample. WWFM (también conocido como "Worked Well For Me") Intenta buscar errores en tu código (que, estoy casi seguro, es lo suficientemente puro) u otro archivo de sonido

+0

Todavía se rompió para mí.Debe haber algo mal con mi computadora. –

+0

Intente actualizar sus controladores de sonido, .NET y/o reinstale Windows (como la manera más extrema). Debería ayudar =) – shybovycha

0

Prueba a eliminar el SoundPlayer después de reproducir el sonido. .. recolector de basura Si todavía consume memoria adicional, algo realmente desagradable está ocurriendo y que debe ejecutar las pruebas en otro equipo

+0

Todavía no funciona para mí, intentaré probar en mi computadora personal, a ver si también lo hace. –

0

He utilizado la función PlaySound dentro de la API Win32 antes de hacer algo similar. Aunque esto no está en el mismo idioma que está utilizando, a continuación se muestra un ejemplo de un programa que va a jugar 'mahnamahna.wav' en cada golpe de teclado 100a. (Sí, fue bastante divertido)

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 

lo anterior no funcionará sin la DLL siguiente (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 
0

esto no es estrictamente hablando una respuesta, así que no voy a confirmar esto como la respuesta aceptada a mi pregunta, pero es una solución para aquellos que han tenido los mismos problemas (y también confirma que no es culpa de mi sistema)

Decidí implementar el sonido usando la biblioteca AudioPlayback de ManagedDirectX, que es tan fácil de usar como SoundPlayer, pero ha resuelto mi problema con éxito.

Para aquellos que quieren saber, el código es simple:

1) añadir una referencia a la DLL audioplayback.

2) Crear un objeto de audio (I llamado a la mía sonido), lo convierten en una variable en el formulario para que pueda referirse a ella de nuevo, utilizar el constructor para establecer el nombre del archivo que debe jugar

3) Reproducir el archivo con sonido.Jugar();

4) Si usted necesita para reproducir el archivo de nuevo, utilice la siguiente línea:

sound.SeekCurrentPosition(0, SeekPositionFlags.AbsolutePositioning); 

Es bastante rápido, y bastante buena. Habrá problemas de memoria si necesita muchos efectos de sonido diferentes, porque todos estarán constantemente en la memoria, pero si necesita un sonido para jugar mucho, este lo hará sin aumentar su Audiodlg.exe

0

Usted debe tratar de usar()

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

al proceso de acabado sp.Play() memoria de regreso a sus automáticos del sistema.

+1

¿Cómo está usando más memoria mi sistema? Quiero crearlo al principio, usarlo tanto como lo desee y luego eliminarlo, en lugar de crearlo y destruirlo cada vez que se ejecuta (que es mucho) –

+0

Lo siento, olvidé intentar usar el sonido para escribir. – Hutchibang

Cuestiones relacionadas