= A sample experiment in VB.net = == Download == The example is here attachment:ExperimentTemplate.zip This is an attention monitoring experiment. It may be used in the scanner, or out of the scanner, with a simple switch of a parameter. It contains a colleciton of modules (starting Exp...) that contain functions that should be generally useful for many experiments. This program is provided as an illustration only. You should always check your code carefully. == Program components == === ExpSettings === General experimental settings. Most useful is probably {{{ Public FullScreen As Boolean = True }}} By default, the experiment acquires the whole screen, to give accurate timing, and prevent other programs from being displayed. However, this can be irritating when debugging, so set this to False when programming. === ExpDisp === Contains various subroutines to help you use DirectX for display. ===== Initialize() ===== Sets up screen, in full screen or windowed mode. Make sure the number of colours (third argument in {{{ DXDevice.SetDisplayMode(ES.ScreenWidth, ES.ScreenHeight, 32, 0, False) }}} is set to the same as the colour depth that windows was started in, if you use .FROMARGB anywhere to convert RGB values to colours. ===== ClearScreen ===== Clears the screen ===== DrawFixation ===== Draws a fixation cross ===== FlipSurface ===== To ensure that graphics are displayed tidily, drawing is done on an "off screen surface" (the 'back-buffer') and then flipped to the display. This command flips the display. If in fullscreen mode, a DirectX flip command is used, which will be executed by the graphics card, and give high performance. In the testing windowed mode, a copy command is used to emulate the action of the flip. === ExpTimingAndReponses === Various routines for getting accurate timing, synchronising with the scanner (if used), checking button boxes and the keyboard. Set USESCANNER and USEBUTTONBOX to True to use the software on the scanner or mimic machines. === ExpTrial & AttentionTrial === The !ExpTrial class that represents a single trial, storing the parameters of the trial. This class would usually be used as a base for your own class, which more fully implements the particular experiment in question. Here, this is done in !AttentionTrial, which inherits !ExpTrial, but extends the "Run" method to display an attention monitoring trial. !AttentionTrial contains code useful for drawing images. Firstly, one needs to create a graphics object to draw on the back-buffer (!DXSurfBack): {{{ Dim dc As System.IntPtr dc = ED.DXSurfBack.GetDc() Dim g As Graphics g = Graphics.FromHdcInternal(dc) }}} ED is defined above as the experimental display through a line at the start of the Run() subroutine: {{{ ED = ParentTrialList.ExperimentalDisplay }}} Then, we can draw lines by instantiating a pen object {{{ Dim mypen As New Pen(Color.FromArgb(255, gr, gr, gr)) }}} and draw a line: {{{ g.DrawLine(mypen, cx + xt1, ED.MidY + yt1, cx + xt2, ED.MidY + yt2) }}} This command has five arguments: (!PenObject, x1, y1, x2, y2); the two pairs of 'x,y' values are the beginning and end points of drawing. Additionally, we can draw images: {{{ g.DrawImage(ParentTrialList.b(istarget, Int(ang1 / 2 / Math.PI * ParentTrialList.numbitmap)), cx - rad, ED.MidY - rad) }}} This command has three arguments separated by commas: (!ImageObject, X-Location, Y-Location). It is useful to create the image object beforehand, for instance in !AttentionTrialList (see below). === ExpTrialList & AttentionTrialList === !ExpTrialList stores a list of trials, and knows how to randomize it (or individual parameters), run all of the trials, and dump various things to the output file. !AttentionTrialList is a specific implementation for this experiment, that also prepares the grating stimuli. Nevertheless, the example code of !AttentionTrialList contains several snippets useful for various experiments: Useful code for loading bitmaps is comprised of code necessary to find the files on disk: {{{ Function getstimdir() Return (Application.StartupPath & "\stim") End Function Function getfn(ByVal k, ByVal j) As String Return (getstimdir() & "\grating_" & k & "_" & j & ".bmp") End Function }}} These two functions specify the path to the various images necessary for the experiment. Using variables (here 'k' and 'j') to define the specific file (e.g. 'grating_1_2.bmp') allows concise description of each image. Additionally, initial loading of all the necessary images before the experiment can aid performance: {{{ ReDim b(1, numbitmap) For k As Integer = 0 To 1 For j As Integer = 0 To numbitmap b(k, j) = New Bitmap(getfn(k, j)) Next Next }}} Here, 'b(k, j)' becomes a stored image that can be recalled in the experimental trial through the draw subroutine used in !AttentionTrial (see above). === frmStart === This is the main form. The code behind the "Start" button actually runs the experiment. This code contains the definitions of the trials: {{{ Dim NUMCONDS = 4 Dim NUMSUBBLOCKS = 12 Dim ATTENDLIST() = {0, 3, 12, 15} }}} Modify these definitions to describe the design of your experiment. You may choose to represent each condition by a number of definitions (e.g. a trial may be defined by CONGRUENCY, SOA, DELAY and PRIMEPRESENCE). Then a list of trials is created: {{{ TL = New AttentionTrialList(NUMCONDS * NUMSUBBLOCKS, txtOutputFilename.Text, txtSubjectCode.Text) }}} Here, you have three arguments: (!NewNumTrials, !NewOutputFilename, !NewSubjectCode); dictate the value of the first argument in relation to the definitions described above. Finally, the list is populated by the different parameters relevant to each experimental trial, again dependent on the definitions above: {{{ For i = 0 To NUMSUBBLOCKS - 1 For j = 0 To NUMCONDS - 1 TL.TrialList(ind).AddParameter("Subblock", i) TL.TrialList(ind).AddParameter("MonitorDur", ((MAXBLOCKDUR - MINBLOCKDUR) * i / (NUMSUBBLOCKS - 1.0)) + MINBLOCKDUR) TL.TrialList(ind).AddParameter("AttendTo", ATTENDLIST(j)) ind = ind + 1 Next Next }}} This nested function ensures all trials are created different. Expand/modify this depending on the structuring of your trials. Then the trials are randomized with either or both of two commands: {{{ TL.RandomizeTrialOrderSingleParameter("MonitorDur") TL.RandomizeTrialOrder(True) }}} The first one randomizes a single parameter of the given name independently of the others (change as appropriate) and the second randomises the order of all trials either preserving (argument set to 'True') or not ('False') the Subblocks (see above). Lastly, before running the experiment we need to initialise the devices necessary for our experiment, such as our keyboard: {{{ TL.ET.InitKeyboard(ExpStimulusForm) }}} Finally, we run our experiment {{{ TL.RunAllTrials() }}} and terminate the display afterwards. {{{ ED.Terminate() }}} === Alternative drawing method for AttentionTrial === A different method for drawing onto the back-buffer can be useful when high performance is needed, but complex line drawing capabilities are not. ===== Images ===== To display an image with this method, we first need to create surfaces onto which to lay the images by placing the following code in the !AttentionTrialList class: {{{ Public DXSurfPicture(,,) As Microsoft.DirectX.DirectDraw.Surface Public DXPictureDevice As New Microsoft.DirectX.DirectDraw.Device Public DXPictureDesc As New Microsoft.DirectX.DirectDraw.SurfaceDescription }}} Then we need to lay the images onto the surfaces, using the Device and !SurfaceDescription above (similar to the method of preparing bitmaps): {{{ DXPictureDevice.SetCooperativeLevel(ExpStimulusForm, Microsoft.DirectX.DirectDraw.CooperativeLevelFlags.Normal) DXPictureDesc.Clear() ReDim DXSurfPicture(1, numbitmap) For k As Integer = 0 To 1 For j As Integer = 0 To numbitmap DXSurfPicture(j, k) = New Microsoft.DirectX.DirectDraw.Surface(getfn(j, k), DXPictureDesc, DXPictureDevice) Next Next }}} Finally, we can use the surfaces to draw on the back-buffer, within the !AttentionTrial: {{{ ED.DXSurfBack.DrawFast(cx - rad, ED.MidY - rad, ParentTrialList.DXSurfPicture(istarget, Int(ang1 / 2 / Math.PI * ParentTrialList.numbitmap)), Microsoft.DirectX.DirectDraw.DrawFastFlags.DoNotWait) }}} This command has four arguments: (X-Location, Y-Location, !SurfaceDrawn, !DrawFastFlags) ===== Letter stings ===== Firstly, we need a font object to be created in, say, the !AttentionTrialList: {{{ Public myFont As New Font("arial", 150, FontStyle.Bold, GraphicsUnit.Pixel) }}} This object has two to four arguments: (!FontType, !StimulusSize [, !FontStyle, !SizeUnit]). Then, we may create one instance of this object in the !AttentionTrial: {{{ ED.DXSurfBack.FontHandle = ParentTrialList.myFont.ToHfont }}} Finally, we may draw the letters: {{{ ED.DXSurfBack.ForeColor = Color.Black ED.DXSurfBack.DrawText(x(i), y(i), Mid(Stimuli, i + 1, 1), False) }}} The first line dictates the colour of objects drawn on the back-buffer and the second line draws a text using the following arguments: (X-Location, Y-Location, !LetterString, !drawAtLastPosition). ===== Avoiding conflict ===== To ensure all has been drawn before the back-buffer is flipped onto the screen, the following code can be placed before the flip command (see above): {{{ Do While Not ED.DXSurfBack.IsDrawDone Application.DoEvents() Loop }}} == Author & Acknowledgements == Page and example program created by Rhodri Cusack. Thanks to Daniel Mitchell & Alejandro Vicente-Grabovetsky who contributed parts to this code.