Page 1 of 1

ProcedureC?

Posted: Sat Nov 22, 2014 4:23 pm
by soerenkj
With Windows 7 Pro and PureBasic 5.31 the following steps are causing my application to crash:

1. Save the code below into a folder together with a short stereo sample named 'test.wav' and the Csound library dll (download and run Setup_Csound6_6.03.2.exe from http://sourceforge.net/projects/csound/ ... sound6.03/).

2. Run the code and press the space bar quickly a number of times (usually less than 40).

Code: Select all

OpenLibrary(0, "csound64.dll")

PrototypeC.l ftype1()
PrototypeC.i ftype2(*p1)
PrototypeC.i ftype3(*p1, s.p-ascii)
PrototypeC.i ftype4(*p1, *p2)

Global csoundCreate.ftype1                     = GetFunction(0, "csoundCreate")
Global csoundSetOption.ftype3                  = GetFunction(0, "csoundSetOption")
Global csoundCompileOrc.ftype3                 = GetFunction(0, "csoundCompileOrc")
Global csoundStart.ftype2                      = GetFunction(0, "csoundStart")
Global csoundStop.ftype2                       = GetFunction(0, "csoundStop")
Global csoundReset.ftype2                      = GetFunction(0, "csoundReset")
Global csoundDestroy.ftype2                    = GetFunction(0, "csoundDestroy")
Global csoundPerform.ftype2                    = GetFunction(0, "csoundPerform")
Global csoundPerformKsmps.ftype2               = GetFunction(0, "csoundPerformKsmps")
Global csoundInputMessage.ftype3               = GetFunction(0, "csoundInputMessage")
Global csoundInputMessage2.ftype4              = GetFunction(0, "csoundInputMessage")
Global csoundRewindScore.ftype2                = GetFunction(0, "csoundRewindScore")
Global csoundSetOutputChannelCallback.ftype4   = GetFunction(0, "csoundSetOutputChannelCallback")

ProcedureC InstrumentCallback(csound.l, channelname.l, value.l, type.l) ;if defined as InstrumentCallback() (with no parameters) the application does not crash
  Debug PeekL(csound)
  ;if a debug print statement is put here the application does not crash
EndProcedure

Procedure CsoundThread(*csound)
  csoundPerform(*csound)
EndProcedure

Procedure CheckKey(*csound)
  Static isOn
  If KeyboardPushed(#PB_Key_Space)
    If Not isOn
      isOn = #True
      csoundInputMessage(*csound, "i 1 0 0.2")
    EndIf
  Else
    If isOn
      isOn = #False
    EndIf
  EndIf
EndProcedure

Procedure InitCsound()
  *csound = csoundCreate()
  csoundSetOption(*csound, "-odac")
  csoundSetOutputChannelCallback(*csound, @InstrumentCallback()) ;if the callback is not registered the application does not crash
  
  ;create a csound 'instrument' which will call our callback every time it is first activated (at 'init time') to play a stereo sample which is loaded into 'ftable' number 1
  csoundCompileOrc(*csound, "sr=44100" + Chr(10) +
                            "ksmps=10" + Chr(10) +
                            "nchnls=2" + Chr(10) +
                            "0dbfs=1" + Chr(10) +
                            "instr 1" + Chr(10) +
                            "  kVal init 1" + Chr(10) +
                            "  if kVal > 1 then" + Chr(10) +
                            "    outvalue " + Chr(34) + "x" + Chr(34) + ", 1" + Chr(10) +
                            "    kVal = 0" + Chr(10) +
                            "  endif" + Chr(10) +
                            "  aL, aR loscil 1, 1, 1, 1" + Chr(10) +
                            "  outs aL, aR" + Chr(10) +
                            "endin")

  csoundStart(*csound)
  CreateThread(@CsoundThread(), *csound)
  ProcedureReturn *csound
EndProcedure

InitSprite()
InitKeyboard()
OpenWindow(0, 0, 0, 600, 500, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, 1, 1)

*csound = InitCsound()

csoundInputMessage(*csound, "f 1 0 0 1 " + Chr(34) + "test.wav" + Chr(34) + " 0 0 0")

Repeat
  Repeat
    event = WindowEvent()
    
    Select event
      Case #PB_Event_CloseWindow
        End
    EndSelect
  Until event = 0
  
  FlipBuffers()
  ExamineKeyboard()
  
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  CheckKey(*csound)
  ;if using only one CheckKey(*csound) call the application does not crash
  
ForEver

Re: ProcedureC?

Posted: Sat Nov 22, 2014 7:34 pm
by IdeasVacuum
Why do you have more than one CheckKey(*csound)?

Re: ProcedureC?

Posted: Sat Nov 22, 2014 10:05 pm
by soerenkj
If there is only one call to CheckKey the application does not crash. The code here emulates a 'real' situation where I would have to check several different keys, one at a time.

Re: ProcedureC?

Posted: Sun Nov 23, 2014 1:40 am
by IdeasVacuum
It would seem that the only function in that CheckKey() procedure that could cause the crash is csoundInputMessage(). Perhaps there is a limitation as to how many times it can be called? Perhaps it should be freed after use?

Re: ProcedureC?

Posted: Sun Nov 23, 2014 11:05 am
by soerenkj
More calls to CheckKey actually does not imply more calls to csoundInputMessage, check the logic. Also, the crashes only happen if the callback is also defined.
NB. I have communicated with the Csound developers and they seem confident that the error is not caused by Csound..

Are you able to recreate this problem?

Re: ProcedureC?

Posted: Sun Nov 23, 2014 1:21 pm
by Mistrel
I wonder if this is related to my bug report:
http://purebasic.fr/english/viewtopic.php?f=4&t=61027

In my case, an application is calling a function in my plugin much like your callback. I've checked and double-checked that it's using stdcall and not cdecl, so it should work fine.

In your case, are you certain that cdecl is the right convention?

Re: ProcedureC?

Posted: Sun Nov 23, 2014 10:29 pm
by soerenkj
Yes it looks similar. Interesting. I don't really know about cdecl and stdecl, but I know that if I use 'Procedure' instead of 'ProcedureC' nothing at all works..

Re: ProcedureC?

Posted: Sun Nov 23, 2014 10:34 pm
by skywalk

Code: Select all

; CALLING CONVENTIONS:
;   __cdecl     = Default calling convention for C and C++ programs. 
;               + Allows functions with variable number of arguments.
;               - Creates larger executables.
;   __stdcall   = Win32 API functions.
;               - Functions cannot have variable number of arguments.
;   __fastcall  = Attempts arguments in registers instead of stack. Default PB x64 convention.
;               + Theoretically means faster calls.
;   Thiscall    = Default calling convention for C++ member functions.
;               - No functions with variable number of arguments.