Results 1 to 11 of 11

Thread: [RESOLVED] Pls help to debug a piece of subclass code about audio.

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Resolved [RESOLVED] Pls help to debug a piece of subclass code about audio.

    I don't like subclass very much and always avoid it in my program. But the winmm.dll APIs that play wave files must use the callback function, which means that subclass must be used.

    I found a piece of source code on the web, and after clearing some of its bugs, the source code now works. I want to encapsulate this code as a Class, and replace the subclass in this source code with the safe-subclass from TheTrick's clsTrickSound2, so I made a few changes to this source code. After the change, the program doesn't work. I don't know where the problem is.

    The original code (which works fine):
    Code:
    Declare Function CallWindowProc Lib "user32" _
                            Alias "CallWindowProcA" ( _
                            ByVal lpPrevWndFunc As Long, _
                            ByVal hWnd As Long, _
                            ByVal msg As Long, _
                            ByVal wParam As Long, _
                            ByRef lParam As WAVEHDR) As Long
    
    Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByRef wavhdr As WAVEHDR) As Long
        Static dataRemaining As Long
        
        If (uMsg = MM_WOM_DONE) Then
            If (fPlaying = True) Then
            '{
                    dataRemaining = (dataOffset + audioLength - mmioSeek(hmmioIn, 0, SEEK_CUR))
                    If (bufferSize < dataRemaining) Then
                        rc = mmioRead(hmmioIn, wavhdr.lpData, bufferSize)
                    Else
                        rc = mmioRead(hmmioIn, wavhdr.lpData, dataRemaining)
                        fPlaying = False
                    End If
                    
                    wavhdr.dwBufferLength = rc
                    rc = waveOutWrite(hWaveOut, wavhdr, Len(wavhdr))
            '}
            Else
                For i = 1 To NUM_BUFFERS
                    waveOutUnprepareHeader hWaveOut, hdr(i), Len(hdr(i))
                Next
                waveOutClose hWaveOut
            End If
        End If
        
        WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, wavhdr)
    End Function
    My modified code (which doesn't work):
    Code:
    Declare Function CallWindowProc_B Lib "user32" _
                            Alias "CallWindowProcA" ( _
                            ByVal lpPrevWndFunc As Long, _
                            ByVal hWnd As Long, _
                            ByVal msg As Long, _
                            ByVal wParam As Long, _
                            ByVal lParam As Long) As Long
    Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        Static dataRemaining As Long
        Dim tWaveHdr As WAVEHDR
            
        If (uMsg = MM_WOM_DONE) Then
            If (fPlaying = True) Then
            
                    memcpy tWaveHdr, ByVal lParam, Len(tWaveHdr)
                    
                    dataRemaining = (dataOffset + audioLength - mmioSeek(hmmioIn, 0, SEEK_CUR))
                    If (bufferSize < dataRemaining) Then
                        rc = mmioRead(hmmioIn, tWaveHdr.lpData, bufferSize)
                    Else
                        rc = mmioRead(hmmioIn, tWaveHdr.lpData, dataRemaining)
                        fPlaying = False
                    End If
                    
                    tWaveHdr.dwBufferLength = rc
                    rc = waveOutWrite(hWaveOut, tWaveHdr, Len(tWaveHdr))
            Else
                For i = 1 To NUM_BUFFERS
                    waveOutUnprepareHeader hWaveOut, hdr(i), Len(hdr(i))
                Next
                waveOutClose hWaveOut
            End If
        End If
        
        WindowProc = CallWindowProc_B(lpPrevWndProc, hw, uMsg, wParam, lParam)
        
    End Function
    Attached Files Attached Files
    Last edited by dreammanor; Dec 8th, 2017 at 11:47 AM.

  2. #2
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Pls help to debug a piece of subclass code about audio.

    One thing you are not doing...

    The original passed the UDT byRef. And changes are being made to it in the subclass routine. Ok?

    In your modified version, you are making changes only to the copy. Once changes are made, you need to replace the version at lParam with the copy you modified, i.e.,
    memcpy ByVal lParam, tWaveHdr, Len(tWaveHdr)
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  3. #3

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: Pls help to debug a piece of subclass code about audio.

    Hi LaVolpe, thanks for your reply. I don't quite understand what you mean. please read the red words above, or look at the source code of the attachment. Really appreciate any help you can provide.

    Edit:
    Oh, I see, I'll try it now.
    Last edited by dreammanor; Dec 8th, 2017 at 09:40 PM.

  4. #4

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: Pls help to debug a piece of subclass code about audio.

    I modified it as you said, but the program still crashes.

    Code:
    Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        Static dataRemaining As Long
        Dim tWaveHdr As WAVEHDR
            
        If (uMsg = MM_WOM_DONE) Then
            If (fPlaying = True) Then
            
                    memcpy tWaveHdr, ByVal lParam, Len(tWaveHdr)
                    
                    dataRemaining = (dataOffset + audioLength - mmioSeek(hmmioIn, 0, SEEK_CUR))
                    If (bufferSize < dataRemaining) Then
                        rc = mmioRead(hmmioIn, tWaveHdr.lpData, bufferSize)
                    Else
                        rc = mmioRead(hmmioIn, tWaveHdr.lpData, dataRemaining)
                        fPlaying = False
                    End If
                    
                    tWaveHdr.dwBufferLength = rc
                    rc = waveOutWrite(hWaveOut, tWaveHdr, Len(tWaveHdr))
                    
                    memcpy ByVal lParam, tWaveHdr, Len(tWaveHdr)
            Else
                For i = 1 To NUM_BUFFERS
                    waveOutUnprepareHeader hWaveOut, hdr(i), Len(hdr(i))
                Next
                waveOutClose hWaveOut
            End If
        End If
        
        WindowProc = CallWindowProc_B(lpPrevWndProc, hw, uMsg, wParam, lParam)
        
    End Function
    The following code comes from TheTrick's clsTrickSound2, TheTrick didn't replace the lParam with the hdr(didn't use the "memcpy ByVal lParam, hdr, Len (hdr)") . But his program can run normally. I don't know why. (Note: TheTrick uses DefWindowProc instead of CallWindowProc)

    Code:
    Private Function WndProc( _
                     ByVal hwnd As Long, _
                     ByVal Msg As Long, _
                     ByVal wParam As Long, _
                     ByVal lParam As Long) As Long
        Dim idx As Long
        Dim hdr As WAVEHDR
        
        If unavailable Then
        
            Select Case Msg
            Case MM_WIM_DATA
                
                memcpy hdr, ByVal lParam, Len(hdr)
    
                RaiseEvent NewData(hdr.lpData, mSmpCount * mFormat.nBlockAlign)
                
                idx = GetBufferIndex(hdr.lpData)
                
                If idx = -1 Then Exit Function
                
                waveInAddBuffer hWaveIn, Buffers(idx).Header, Len(Buffers(idx).Header)
                
                Exit Function
                
            Case MM_WOM_DONE
                
                If mActive Then
                    
                    memcpy hdr, ByVal lParam, Len(hdr)
        
                    RaiseEvent NewData(hdr.lpData, mSmpCount * mFormat.nBlockAlign)
                    
                    idx = GetBufferIndex(hdr.lpData)
                    
                    If idx = -1 Then Exit Function
                    
                    waveOutWrite hWaveOut, Buffers(idx).Header, Len(Buffers(idx).Header)
                    
                End If
                
                Exit Function
                
            End Select
            
        End If
        
        WndProc = DefWindowProc(hwnd, Msg, wParam, lParam)
        
    End Function
    Last edited by dreammanor; Dec 8th, 2017 at 10:04 PM.

  5. #5
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Pls help to debug a piece of subclass code about audio.

    I modified your sample project just as you did above. Crashes.
    So, first I want you to know that I know little to nothing about those APIs. Just tweaked a couple things, I did get it to work, but required some re-organizing and an API declaration tweak.

    instead of your attempt
    Code:
                    tWaveHdr.dwBufferLength = rc
                    rc = waveOutWrite(hWaveOut, tWaveHdr, Len(tWaveHdr))
                    memcpy ByVal lParam, tWaveHdr, Len(tWaveHdr)
    I did this
    Code:
                    tWaveHdr.dwBufferLength = rc
                    memcpy ByVal lParam, tWaveHdr, Len(tWaveHdr)
                    rc = waveOutWrite(hWaveOut, lParam, Len(tWaveHdr))
    Here is the API declaration I changed
    Code:
    Declare Function waveOutWrite Lib "winmm.dll" (ByVal hWaveOut As Long, ByVal lpWaveOutHdr As Long, ByVal uSize As Long) As Long
    Above said and done. Not sure why you want to fix something that ain't broke
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  6. #6

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: Pls help to debug a piece of subclass code about audio.

    Hi LaVolpe, thank you so much. After I modified the code as you said, the program doesn't crash now. But I feel very strange, why TheTrick's code is normal, and my code is similar to his code and crashes.

    Quote Originally Posted by LaVolpe View Post
    Above said and done. Not sure why you want to fix something that ain't broke
    I need to use TheTrick's clsTrickSound2 to process my wave files, but clsTrickSound2 doesn't have the OpenWaveFile function and can't open wave files directly, it only accepts byte arrays. So I need to analyze the wave file format myself and read the audio data from the wave file into a byte array for clsSound2 to process. In order to deal with large wave files and to play audio smoothly, I also need to use multiple buffer mechanism to fill the byte arrays. These changs or operations are quite easy for an audio expert like TheTrick, but it's very difficult for me because I don't know much about the audio APIs (I just started learning about it for some time). I looked for a piece of source code from the Internet, hoping to be able to merge this source code into TheTrick's clsTrickSound2 class, so I need to rewrite this source code according to the API declarations in the clsTrickSound2.

    I still don't know if I can successfully merge these two pieces of code together. Your help greatly enhances my confidence. Thanks very much.
    Last edited by dreammanor; Dec 9th, 2017 at 03:53 AM.

  7. #7

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: Pls help to debug a piece of subclass code about audio.

    Hi LaVolpe, I'm sorry to disturb you again. Now I changed the Module1.bas to a class and replaced the subclass in it with the safe-subclass from TheTrick's cslTrickSound2. After making these changes, the program crashed when I clicked the Play button on the form.

    Do I need to change all "ByRef wavhdr As WAVEHDR" in all the winmm.dll API declarations to "ByVal lParam As Long"?

    Could you help me find out what is the reason? Really appreciate any help you can provide.
    Attached Files Attached Files

  8. #8
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Pls help to debug a piece of subclass code about audio.

    I don't use that type of ASM subclassing (using the heap). Additionally, no idea even if the ASM is correct or not. Wherever you got that (and it may very well be valid code), suggest you put together a test project as simple as possible to see if you can get subclassing to call back to your class. Just FYI. You don't need to go ASM, thunk-type subclassing. Just use a module

    Edited: Just taking a closer look at the thunk code. This line:
    GetMem4 ByVal vTable + WNDPROCINDEX * 4 + &H1C, lpMeth
    I'm making the assumption that the window procedure in your class must be at a specific position within the class, i.e., 1st, 2nd, 3rd, etc procedure. Additionally, is the window procedure routine suppose to be Public vs. Private? Again, I'd look at the project you got that code from & see what the relationship is between the window procedure in that project with its position in the class.
    Last edited by LaVolpe; Dec 9th, 2017 at 12:01 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  9. #9

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: Pls help to debug a piece of subclass code about audio.

    Here's the link for TheTrick's clsTrickSound2:
    http://www.vbforums.com/showthread.p...ing-with-audio

    I used subclass in my controls 10 years ago. I downloaded a lot of subclass code from PsCode, but I never found an absolutely safe subclass solution, and then I removed all the subclass from my program. Now, I have completely forgotten the subclass knowledge I have ever learned.

    I know Krool, TheTrick, DEXWERX, vbAccelerator and you have adopted different subclass solutions, I don't know which solution is the most suitable for me.

  10. #10
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Pls help to debug a piece of subclass code about audio.

    Here's what I see based on his class.

    1. The WNDPROCINDEX constant has the value 20
    2. The line I mentioned above (GetMem4 ByVal vTable + WNDPROCINDEX * 4 + &H1C, lpMeth) is using a known class offset of &H1C. Offset is 1st public method of a class.
    3. The "Private Function WndProc(...)" routine happens to be the 1st private function after the 20th Public method. Note "method" means: sub, function, property. 20 cannot be coincidence

    So based on the above, I'd say a simple test is

    1. Place all your Public methods at the top of your class, no exceptions. Order doesn't matter but no private methods between your declarations section and any Public method

    2. Add your window procedure routine as the 1st private method after the last Public method

    3. Count how many Public methods you have starting immediately after the declarations section. Change the WNDPROCINDEX to that number. If you add any public methods afterwards, ensure it's above the 1st private method & adjust that constant. Likewise, if you remove any public methods, adjust that number. Never place a new private method above your window procedure routine.

    4. Save and hope for the best?

    note: I wouldn't use any public variables in the declarations section. If needed, make them Public properties; otherwise, your count of Public methods may be off.

    Edited: Don't count Public Event() declarations in the declarations section. In the class, there is one and it appears it is not part of the count.
    Last edited by LaVolpe; Dec 9th, 2017 at 02:29 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  11. #11

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: Pls help to debug a piece of subclass code about audio.

    The reason is exactly what you said, now the program no longer crashes.

    Previously, I had seen some subclasses that require WndProc to be placed in a specific location, but I didn't understand what it meant at that time. Now I finally understand.

    LaVolpe, you helped me a lot, thank you so much.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width