' Program to edit spike events const chUnit%:=1; const BAKacclour% := 10; const BAKrejclour% := 5; var memchEvent%,memchInstantRate%,memchForWaveMark%; var chUnitEvent%; var vh%:=0,hWave1%, avwin%; ' pointers for windows var WaveMarkDataPoint%,WaveMarkPreTrig%; var ScreenWidth:=1; ' screen size, used for centring display ' in Next, Previous, Advance, Back var TrigLevel:=-0.5; var MinimumTimeBetweenTriggers:=0.7; 'in ms var kIF%:=0; var hcINC:=0.033333333333333; var wave1n%:=1; var wave2n%:=0; ' used in OPEN: NoS imported var wave2X[10000000]; var wave2Y[10000000]; var wave1chancounter%:=0; var maxnos := 250; ' max # spikes in display window var wave1sTlist[256]; var wave1channr%:=1; var displwave1channr%:=1; var UnitSamplingInterval; var Overlapsetting:=0; 'var TrigMode%:=8; var SpikesTlist[256]; ' filled in UpdateSpkDisplay; used in ' Highlight, Wave1Next, Wave1Prev, Delete var pointer001%:=1; ' limits for spike highlighting var pointer255%:=250; ' could be a constant var pointermid%:=0; ' pointer for highlighting spikes 'var pointerlast%:=0; var HighlightChanNum%:=256; var NumberOfSpike%:=0, NrEventAdded%:=0; var BAKon := 0; var KeepCursorCenter%:=0; var prelude := 10; var AverFromHere := 0; var ReDisp% := 0; var AveData[250]; ' average spike waveform, hopefully long enough ArrConst(wave1sTlist[],-1); ArrConst(SpikesTlist[],-1); ToolbarClear(); ToolbarText("S P I K E E D I T O R"); 'This avoids flickering DoToolbar(); proc DoToolbar() ToolbarSet(1,"Quit",Quit%); 'Set up toolbar buttons ToolbarSet(2,"Open", Open%); ToolbarSet(3,"&Delete", Delete%); ToolbarEnable(3,0); ToolbarSet(4,"&Add", Add%); ToolbarEnable(4,0); ToolbarSet(5,"&Save",SavNAdv%); ToolbarEnable(5,0); ToolbarSet(6,"redisplay",UpdateSpkDisplay%); ToolbarEnable(6,0); ToolbarSet(7,"clear",AllSpikeDeleted%); ToolbarEnable(7,0); 'ToolbarSet(8,"Set trigger",Trig%); ToolbarSet(8,"&Take",TakeOne%); ToolbarEnable(8,0); ToolbarSet(9,"Tab:Adv|0x09",Advance%); ToolbarEnable(9,0); ToolbarSet(13,"BkSp:Back|0x08",Back%); ToolbarEnable(13,0); 'ToolbarSet(10,"&Window",Taketoo%); 'ToolbarEnable(10,0); ToolbarSet(11,"Show IF",InsFreq%); ToolbarEnable(11,0); ToolbarSet(12,"Settings",SetInt%); 'ToolbarSet(13,"hcUP|0x26",hcUP%); 'ToolbarSet(14,"hcDOWN|0x28",hcDOWN%); ToolbarSet(14,"&Locate Spike",locaSpk%); ToolbarEnable(14,0); 'ToolbarSet(15,"&Check IF",MaxIF%); 'ToolbarEnable(15,0); ToolbarSet(16,"&Next",Wave1Next%); ToolbarEnable(16,0); ToolbarSet(17,"&Back",Wave1Prev%); ToolbarEnable(17,0); ToolbarSet(18,"Keep Cursor Centered",CtrCsr%); Toolbar("S P I K E E D I T O R", 1023); end; func CtrCsr%() KeepCursorCenter%:=1; ToolbarSet(18,"Don't Keep Cursor Centered",NoCtrCsr%); return 1; end; func NoCtrCsr%() KeepCursorCenter%:=0; ToolbarSet(18,"Keep Cursor Centered",CtrCsr%); return 1; end; func AllSpikeDeleted%() var mmm%,nnn%; for nnn%:=0 to Len(SpikesTlist[])-1 do if SpikesTlist[nnn%]<>-1 then mmm%:=mmm%+1;endif; Next; NrEventAdded%:=MemDeleteTime(memchEvent%,3,XLow(),XHigh()); ' clear spikes in window NumberOfSpike%:=NumberOfSpike% - NrEventAdded%; ' update total number of spikes MemDeleteTime(memchForWaveMark%,3,XLow(),XHigh()); ' clear spike times MemDeleteTime(memchInstantRate%,3,XLow(),XHigh()); ' clear inst freqency View(hWave1%); ' clear spike window for nnn%:=1 to 256 do ' or BAK window XYDelete(nnn%); Next; View(vh%); return 1; end; func HowManySpikesDisplayed%() var nnn%,mmm%,msgw$; for nnn%:=pointer001% to pointer255% do if SpikesTlist[nnn%] <> -1 then mmm%:=mmm%+1; endif; Next; View(hWave1%);msgw$:=Str$(mmm%) + " last accepted spikes shown. Total # spike that has been accepted is " + Str$(NumberOfSpike%);WindowTitle$(msgw$);View(vh%); return mmm%; end; func FindItem%(Data[],theValue,deltavalue) ' output is the index of the array ' put very small value as Delta var nnn%; for nnn%:=0 to Len(Data[])-1 do if (Data[nnn%] >= (theValue-deltavalue)) and (Data[nnn%] <= (theValue+deltavalue)) then return nnn%; endif; Next; return -1; 'not found end; func UpdateSpkDisplay%(); var sT,sT2,lsT,eT,tempsT,nn%,loopstrt%,NrEvents%; var WaveData[WaveMarkDataPoint%+prelude],WaveDataX[WaveMarkDataPoint%+prelude]; for nn%:=0 to WaveMarkDataPoint%+prelude-1 do WaveDataX[nn%]:=nn% * UnitSamplingInterval; ' time points for spike display next; sT:=XHigh(); ArrConst(SpikesTlist[],-1); ' init with -1 View(hWave1%); ' clear spike window for nn%:=1 to 256 do ' or BAK window XYDelete(nn%); Next; View(vh%); ' seach in trace window NrEvents% := Count(memchForWaveMark%,XLow(),XHigh()); if NrEvents% > 0 then ' total number of spikes, updated in takeall if NrEvents% >= maxnos then ' set start of loop loopstrt% := maxnos; else loopstrt% := NrEvents%; endif nn% := 0; tempsT := sT; ' remember sT while nn% < loopstrt% do sT:=LastTime(memchForWaveMark%,sT); ' search backward for spike if sT < XLow() then loopstrt% := nn%; ' number of spikes on display nn% := 255; ' break the loop endif; nn% := nn% + 1; ' update index wend; sT := tempsT; ' restore sT if NumberOfSpike% > 0 then View(hWave1%); XYSetChan(254,0,0,1,14);XYDrawMode(254,2,4); ' set up average XYAddData(254,WaveDataX[],AveData[]); endif; for nn%:=loopstrt% to 1 step -1 do View(vh%); lsT := sT; ' remember time of last spike sT:=LastTime(memchForWaveMark%,sT); ' search backward for spike sT2:=LastTime(memchEvent%,lsT); ' search for accepted spike SpikesTlist[nn%]:=sT; ' fill list of start times eT:=sT + ((WaveMarkDataPoint%-1)*UnitSamplingInterval); ' calculate end of spike ChanData(chUnit%,WaveData[],sT-(prelude*UnitSamplingInterval),eT); ' copy spike into display array View(hWave1%); XYSetChan(nn%,0,0,1);XYDrawMode(nn%,2,0); XYAddData(nn%,WaveDataX[],WaveData[]); ' add to spike or BAK display Optimise(-1); if BAKon then if sT = sT2 then ' spike in both WaveMark channels XYColour(nn%,BAKacclour%); else XYColour(nn%,BAKrejclour%); ' rejected spike endif; endif; Next; pointer001%:=1; pointer255%:=loopstrt%; ' set to number of spikes, last spike pointermid%:=loopstrt%; else pointer001%:=1; ' no spikes pointer255%:=maxnos; pointermid%:=0; endif; View(vh%); return 1; end; func HighLight%(whichone%) var WaveData[WaveMarkDataPoint%+prelude],WaveDataX[WaveMarkDataPoint%+prelude],nnn%; for nnn%:=0 to WaveMarkDataPoint%+prelude-1 do WaveDataX[nnn%]:=nnn% * UnitSamplingInterval; next; ' set highlight to last spike View(vh%); Cursor(0,SpikesTlist[whichone%]); ' collect spike from unit channel ChanData(chUnit%,WaveData[],SpikesTlist[pointermid%]-(prelude*UnitSamplingInterval),SpikesTlist[pointermid%]+((WaveMarkDataPoint%-1)*UnitSamplingInterval)); View(hWave1%); XYDelete(HighlightChanNum%); ' clear old highlighted spike if BAKon and isonreject%(SpikesTlist[whichone%]) then XYAddData(HighlightChanNum%,WaveDataX[],WaveData[]);XYColour(HighlightChanNum%,18); else XYAddData(HighlightChanNum%,WaveDataX[],WaveData[]);XYColour(HighlightChanNum%,16); endif; View(vh%); return 1; end func Wave1Next%() var Cursor0Time; if pointermid% >= pointer255% then return 1; endif var tempx[WaveMarkDataPoint%+prelude],tempy[WaveMarkDataPoint%+prelude]; while 1 do if (pointermid% >= pointer255%) and (pointermid% <= pointer001%) then return 1; endif pointermid%:=pointermid%+1; if pointermid% > pointer255% then pointermid%:=pointer255%;endif; 'can't be larger that pointer255% if spikesTlist[pointermid%] <> -1 then 'Debug ' printlog("%d, %d, %d \n",pointer001%,pointer255%,pointermid%); View(vh%); Cursor(0,spikesTlist[pointermid%]); Cursor0Time:=Cursor(0); if KeepCursorCenter%=1 then if (spikesTlist[pointermid%]+(ScreenWidth/2) <= MaxTime()) then XRange(spikesTlist[pointermid%]-(ScreenWidth/2),spikesTlist[pointermid%]+(ScreenWidth/2)); else XRange(MaxTime()-ScreenWidth,MaxTime()); endif; endif; View(hWave1%); XYGetData(pointermid%-pointer001%+1,tempx[],tempy[]); XYDelete(HighlightChanNum%); XYAddData(HighlightChanNum%,tempx[],tempy[]);XYColour(HighlightChanNum%,16); if isonreject%(Cursor0Time) then ' change colour if BAK rejected XYColour(HighlightChanNum%,18); endif; View(vh%); return 1; else pointermid%:=pointermid%-1; return 1; endif; wend; 'View(vh%); 'return 1; end; func Wave1Prev%() var Cursor0Time; if pointermid% <= pointer001% then return 1; endif var tempx[WaveMarkDataPoint%+prelude],tempy[WaveMarkDataPoint%+prelude]; while 1 do if (pointermid% >= pointer255%) and (pointermid% <= pointer001%) then return 1; endif pointermid%:=pointermid%-1;if pointermid% < pointer001% then pointermid%:=pointer001%;endif; 'can't be smaller that pointer001% if spikesTlist[pointermid%] <> -1 then 'Debug ' printlog("%d, %d, %d \n",pointer001%,pointer255%,pointermid%); View(vh%); Cursor(0,spikesTlist[pointermid%]); Cursor0Time:=Cursor(0); if KeepCursorCenter%=1 then if (spikesTlist[pointermid%] <= (XLow()+(ScreenWidth/2))) then if (spikesTlist[pointermid%]-(ScreenWidth/2) >= 0) then XRange(spikesTlist[pointermid%]-(ScreenWidth/2),spikesTlist[pointermid%]+(ScreenWidth/2)); else XRange(0, ScreenWidth); endif; endif; endif; View(hWave1%); XYGetData(pointermid%-pointer001%+1,tempx[],tempy[]); XYDelete(HighlightChanNum%); XYAddData(HighlightChanNum%,tempx[],tempy[]);XYColour(HighlightChanNum%,16); if isonreject%(Cursor0Time) then ' change colour if BAK rejected XYColour(HighlightChanNum%,18); endif; View(vh%); return 1; else pointermid%:=pointermid%+1; return 1; endif; wend; 'View(vh%); 'return 1; end; func MaxIF%() var tView%; tView% := View(); View(vh%); Optimise(memchInstantRate%); ' Maximize instant freq channel View(tView%); return 1; end; func OverLapSet%() Overlapsetting:= 0.001 * Input("Enter length of overlap region for advance and back (ms)",Overlapsetting*1000,0,50); return 1; end; func hcUP%() TrigLevel := HCursor(1); TrigLevel := TrigLevel + hcINC; HCursor(1,TrigLevel); return 1; end; func hcDOWN%() TrigLevel := HCursor(1); TrigLevel := TrigLevel - hcINC; HCursor(1,TrigLevel); return 1; end; func SetInt%() var ok%, oBAK; 'MinimumTimeBetweenTriggers:=Input("Enter minimum time between 2 triggers (ms)",MinimumTimeBetweenTriggers,0.1,100); 'Overlapsetting:= 0.001 * Input("Enter length of overlap region for advance and back (ms)",Overlapsetting*1000,0,50); 'ScreenWidth:=Input("Enter new screen width in second",ScreenWidth,0.001,1000); ' setting minimum time between triggers, amount of overlap, Screen width DlgCreate("SpikeEditor settings",0,0,60); DlgReal(1, "Enter minimum time between 2 triggers (ms)",0.1,100,40,2); DlgInteger(2, "Length of overlap region for advance (ms)",0,50,40,4); Overlapsetting := Overlapsetting * 1000; DlgReal(3, "Enter new screen width in second",.1,100,40,6); DlgReal(4, "Length of prelude in millisecond",10,100,40,8); DlgReal(5, "Average from here",0,10000,40,10); DlgCheck(6, "Re-examine analysed spikes",00,12); DlgCheck(7, "Use BAK window",40,12); oBAK := BAKon; ' remember state of BAK flag ok% := dlgshow(MinimumTimeBetweenTriggers,Overlapsetting,ScreenWidth,prelude,AverFromHere,ReDisp%,BAKon); Overlapsetting := Overlapsetting * 0.001; ' convert to ms if vh% > 0 then XRange(XLow(),XLow()+ScreenWidth); endif; if hWave1% > 0 then ' switch in the middle of analysis View(hWave1%); if BAKon and not oBAK then HCursorNew(2,TrigLevel); ' set up pointers in spike window HCursorNew(3,TrigLevel); CursorNew(UnitSamplingInterval*prelude,1); endif; if not BAKon and oBAK then CursorDelete(1); ' remove all the cursors HCursorDelete(1); HCursorDelete(2); endif; View(vh%); endif; return 1; end; func TakeOne%() ' BAKon ' flag for spike highlight, ' used in Advance, UpdateSpkDisplay, Add, locaSpk if BAKon then TakeAll%(1); else TakeAll%(0); endif; return 1; end; func TakeToo%() BAKon := 1; ' set flag for spike highlight ' used in Advance, UpdateSpkDisplay, Add, locaSpk TakeAll%(1); return 1; end; func TakeAll%(BAKflag) var eT,sT,junk,code%[4],TM%,pp$,data[WaveMarkDataPoint%],TStep,nn%; var NoWEventAdded%; var windinx%, windelay, winup, winlow; View(vh%); ArrConst(wave1sTlist[],-1); wave1chancounter%:=0; wave1channr%:=1;displwave1channr%:=1; wave1n%:=1; code%[0]:=4; TStep:=BinSize(chUnit%); TrigLevel:=HCursor(1); if TrigLevel < 0 then TM%:=3; ' falling through trigger level else TM%:=2; ' rising through trigger level endif; NrEventAdded%:=MemDeleteTime(memchEvent%,3,XLow(),XHigh()); ' clear spikes in window NumberOfSpike%:=NumberOfSpike% - NrEventAdded%; ' update total number of spikes MemDeleteTime(memchForWaveMark%,3,XLow(),XHigh()); ' clear spike times MemDeleteTime(memchInstantRate%,3,XLow(),XHigh()); ' clear inst freqency ' find time of spikes NrEventAdded%:=MemImport(memchForWaveMark%,chUnit%,XLow(),XHigh(),TM%,MinimumTimeBetweenTriggers/1000,TrigLevel); if NrEventAdded% > 0 then sT:=XLow(); if BAKflag then View(hWave1%); windelay := Cursor(1); ' fetch spike window settings winup := HCursor(1); winlow := Hcursor(2); if winup < winlow then ' swap levels junk := winup; winup := winlow; winlow := junk; endif; View(vh%); NoWEventAdded% := 0; ' counter for accepted spikes windinx% := windelay / UnitSamplingInterval - prelude; if windinx% < 0 then ' check index overflow windinx% := 0; endif; if windinx% > Len(data[]) then windinx% := Len(data[])-1; endif; for nn%:=1 to NrEventAdded% do sT:=NextTime(memchForWaveMark%,sT); ' fetch time of trigger ' sT:=NextTime(memchForWaveMark%,sT)-(prelude*UnitSamplingInterval); ' fetch time of trigger eT:=sT + ((WaveMarkDataPoint%-1)*TStep); ChanData(chUnit%,data[],sT,eT); ' fetch spike if data[windinx%] < winup and data[windinx%] > winlow then NoWEventAdded% := NoWEventAdded% + 1; MemSetItem(memchEvent%,0,sT,code%[],data[]); ' deposit spike into buffer MemSetItem(memchInstantRate%,0,sT); ' deposit spike for inst freq display endif; Next; UpdateSpkDisplay%(); ' window discriminator NumberOfSpike%:=NumberOfSpike% + NoWEventAdded%; ' update total number of spikes else ' no BAK window for nn%:=1 to NrEventAdded% do sT:=NextTime(memchForWaveMark%,sT); ' fetch time of trigger eT:=sT + ((WaveMarkDataPoint%-1)*TStep); ChanData(chUnit%,data[],sT,eT); ' fetch spike MemSetItem(memchEvent%,0,sT,code%[],data[]); ' deposit spike into buffer MemSetItem(memchInstantRate%,0,sT); ' deposit spike for inst freq display Next; UpdateSpkDisplay%(); NumberOfSpike%:=NumberOfSpike% + NrEventAdded%; ' update total number of spikes endif; HighLight%(pointermid%); HowManySpikesDisplayed%(); 'Debug ' printlog("%d, %d, %d \n",pointer001%,pointer255%,pointermid%); DrawMode(memchInstantRate%,2,1); DrawMode(memchInstantRate%,7,3);' recompute instant freq endif; pp$:=Str$(NrEventAdded%)+" spikes was added."; ToolbarText(pp$); ToolbarEnable(16,1); ToolbarEnable(17,1); return 1; end; func Open%() var WavemarkNrPoint%, tempChan%, channellist%[64], nnn%, unitsplrate%, splmsg$; var chan10check%:=0; var mmm%:=0; var ua, uo; vh% := FileOpen("",0,1); if vh% < 0 then Message("Error opening file, halt..."); halt; else View(vh%); FrontView(vh%); WindowVisible(1);Window(0,0,75,100); ' position traces on the left XRange(0,ScreenWidth); CursorVisible(-1,0); Cursor(0,0.0001);CursorVisible(0,1);CursorLabelPos(0,100);CursorLabel(0,0); endif; UnitSamplingInterval := BinSize(chUnit%); ' check whether channel 30 exists 'BOB ChanList(channellist%[]); for nnn%:=1 to channellist%[0] do if channellist%[nnn%] = 30 then chan10check% := 1; endif; next; if chan10check% = 1 then Message("Channel #30 exists");'BOB chUnitEvent%:=30; 'BOB DrawMode(chUnitEvent%,2); ' draw tics else Message("Channel #30 for storing spike wavemark does not exist, you are creating one now"); 'BOB unitsplrate% := 1/UnitSamplingInterval; splmsg$ := Print$("How many points do you need to capture from the action potential (%d samples/s)?",unitsplrate%); WavemarkNrPoint% := Input(splmsg$,70,10,2000); tempChan% := MemChan(6,WavemarkNrPoint%,BinSize(chUnit%),0); chUnitEvent%:=30; 'BOB MemSave(tempChan%,chUnitEvent%,6,1); DrawMode(chUnitEvent%,2); ' draw tics ChanDelete(tempChan%); endif; ChanHide(-1); ChanShow(1,chUnitEvent%); ' display units and spike markers ChanTitle$(chUnitEvent%,"Saved Events"); WaveMarkDataPoint%:=MarkInfo(chUnitEvent%,WaveMarkPreTrig%); ViewColour(0,1); ' grey background ChanShow(4); ' select horizontal target ChanColour(4,1,7); ' black target ChanShow(2); ' select horizontal gaze ChanShow(3); ' select vertical eye ChanColour(3,1,11); ' Set channel colour ChanColour(1,1,39); ' unit light ChanSelect(2,1); ChanOrder(4,1,-3); ' overlay Heye(Ch2) on target(Ch4) ChanOrder(4,0,-3); ChanSelect(2,0); ChanSelect(3,1); ChanOrder(2,0,-3); ' overlay H & Veye YAxisLock(4,1,0); ' Set group y axis lock Optimise(4); ChanSelect(3,0); ' release Chan 3 ' create deletable memory channel memchEvent%:=MemChan(6,WaveMarkDataPoint%,BinSize(chUnitEvent%),WaveMarkPreTrig%);ChanScale(memchEvent%,ChanScale(1)); uo := YHigh(1); ' transfer unit axis ua := Ylow(1); YRange(401,ua,uo); wave2n% := MemImport(memchEvent%,chUnitEvent%,0,MaxTime(chUnit%)); 'copy spikes to deletable channel ChanShow(memchEvent%); ChanTitle$(memchEvent%,"Deletable"); ChanSelect(401,1); ChanOrder(1,0,-3); ' Overlay WaveMarks and Units ChanSelect(1,1); ChanSelect(401,0); ChanOrder(401,0,-3); ' WaveMark in front YAxisLock(401,1,0); ' Set group y axis lock memchForWaveMark%:=MemChan(3);ChanHide(memchForWaveMark%); MemImport(memchForWaveMark%,chUnitEvent%,0,MaxTime(chUnit%)); 'copy spikes to second buffer ' Create instant frequency channel memchInstantRate% := MemChan(3,0,BinSize(1)); ' 103 MemImport(memchInstantRate%,chUnitEvent%,0,MaxTime(chUnit%)); DrawMode(memchInstantRate%,7,3); ' plot as frequency, dot size 3 ChanTitle$(memchInstantRate%,"Instant Freq"); ChanUnits$(memchInstantRate%,"Hz"); YRange(memchInstantRate%,0,800); hWave1%:=FileNew(12,1);View(hWave1%);FrontView(hWave1%);Window(75,0,100,50); ViewColour(0,3); ' grey back ground WindowTitle$("ACCEPTED Action Potential, 255 spike max"); 'prepare all 256 channels for nnn%:=1 to 256 do ' create 256 display channels for spikes XYSetChan(0,0,0,1); Next; 'last channel for highlight is 256: drawn with data points, as solid line, width 2, joined XYDrawMode(HighlightChanNum%,2,0);XYDrawMode(HighlightChanNum%,3,0);XYDrawMode(HighlightChanNum%,4,2); XYJoin(HighlightChanNum%,1); XYDelete(HighlightChanNum%); XRange(0,UnitSamplingInterval*(WaveMarkDataPoint%+prelude)); XYDrawMode(0,5,0); ' keep axis fixed View(vh%);FrontView(vh%); uo := YHigh(1); ' transfer unit axis ua := Ylow(1); View(hWave1%); if BAKon then XRange(0,(UnitSamplingInterval*(WaveMarkDataPoint%+prelude))/2); ' magnify x range YRange(0,ua,uo); HCursorNew(2,TrigLevel); ' define spike window marker HCursorNew(3,TrigLevel); CursorNew(UnitSamplingInterval*prelude,1); endif; View(vh%); AverFromHere := MaxTime(chUnitEvent%); DoAverg%(); if wave2n% > 0 then var WaveX[WaveMarkDataPoint%+prelude],sT,eT,msgw$,lastloc; var kk%:=0; View(vh%); ' select data window sT:=0; for nnn%:= 0 to WaveMarkDataPoint%+prelude-1 do WaveX[nnn%]:=nnn% * UnitSamplingInterval; next; while sT >= 0 do ' collect all previously saved spikes sT:=NextTime(chUnitEvent%,sT); eT:=sT + ((WaveMarkDataPoint%-1)*UnitSamplingInterval); if sT > 0 then kk%:=kk%+1; lastloc:=sT; endif; wend; View(vh%); ' bring to last accepted spike XRange(lastloc-0.5*ScreenWidth,lastloc+0.5*ScreenWidth); Optimise(4); Cursor(0,(XLow()+XHigh())/2); ' put cursor 0 at the center ToolbarEnable(16,1); ' next and previous button ToolbarEnable(17,1); endif; NumberOfSpike%:=wave2n%; UpdateSpkDisplay%(); HighLight%(pointermid%); HowManySpikesDisplayed%(); HCursorDelete(-1); ' make a new trigger level HCursorNew(401,TrigLevel); HCursorLabel(0,1); ' no label CursorActive(0,14,memchEvent%,0,"","",0,0,0); ToolbarEnable(2,0); ' disable open function ToolbarEnable(3,1); ' delete spikes at cursor 0 ToolbarEnable(4,1); ' add spikes at cursor 0 ToolbarEnable(5,1); ' save spikes from memory channel ToolbarEnable(6,1); ' retake window ToolbarEnable(7,1); ' clear spikes ToolbarEnable(8,1); ' take all ToolbarEnable(9,1); ' advance ToolbarEnable(11,1); ' show IFR 'ToolbarEnable(10,1); ' enable BAK window 'ToolbarEnable(15,1); ' enable IF check ToolbarEnable(13,1); ' enable Backspace ToolbarEnable(14,1); ' enable locate spike InsFreq%(); ' turn on instant frequency return 1; end; func locaSpk%() ' locate spike in spike window var goto%, ii%, nowat%, windinx%, windelay, winup, winlow, junk; var oldcur, oldhcur1, oldhcur2, ua, uo, xa, xo; var tempx[WaveMarkDataPoint%+prelude],tempy[WaveMarkDataPoint%+prelude]; nowat% := pointermid%; ' remember current cusor position View(hWave1%); xa := XLow(); ' save X and Y axis settings xo := XHigh(); ua :=YLow(0); uo :=YHigh(0); if BAKon then oldcur := Cursor(1); ' fetch spike window settings oldhcur1 := HCursor(1); oldhcur2 := Hcursor(2); Cursor(1,UnitSamplingInterval*prelude); ' restore spike window settings HCursor(1,TrigLevel); Hcursor(2,TrigLevel); else HCursorNew(2,TrigLevel); ' set up pointers in spike window HCursorNew(3,TrigLevel); CursorNew(UnitSamplingInterval*prelude,1); endif; goto%:=Interact("use cursors to pinpoint spike .. then hit GO",1023,0,"&Go"); windelay := Cursor(1); ' fetch spike window settings winup := HCursor(1); winlow := Hcursor(2); if winup < winlow then ' swap levels junk := winup; winup := winlow; winlow := junk; endif; windinx% := windelay / UnitSamplingInterval; if windinx% < 0 then ' check index overflow windinx% := 0; endif; if windinx% > Len(tempy[]) then windinx% := Len(tempy[])-1; endif; goto%:=pointermid%; ' remember current highlight position ii% := pointer001%-1; while ii% < pointer255% do ii% := ii% + 1; if spikesTlist[ii%] <> -1 then XYGetData(ii%,tempx[],tempy[]); if tempy[windinx%] < winup and tempy[windinx%] > winlow then goto% := ii%; ' found a matching spike endif; endif; wend; if goto% <> -1 then pointermid% := goto%; ' new cursor position else pointermid% := nowat%; ' restore cursor to old position endif; if BAKon then Cursor(1,oldcur); ' restore spike window settings HCursor(1,oldhcur1); Hcursor(2,oldhcur2); else CursorDelete(1); ' remove all the cursors HCursorDelete(1); HCursorDelete(2); endif; YRange(0,ua,uo); ' restore window XRange(xa,xo); HighLight%(pointermid%); return 1; end; func Delete%() var Cursor0Time,NewCursor0Time,NrDeletedItem%,pointerlocal%,whereinXY%, tempmid%; var StringCursor0Time$, StringNrDeletedItem$, StringToolbar$; Cursor0Time:=Cursor(0); NrDeletedItem%:=MemDeleteTime(memchEvent%,0,Cursor0Time,0.001); ' delete marker if NrDeletedItem%<=0 then Message("Nothing deleted??"); return 1; endif; if not BAKon then NrDeletedItem%:=MemDeleteTime(memchForWaveMark%,0,Cursor0Time,0.001); ' delete second level marker endif; ' recompute instant freq MemDeleteTime(memchInstantRate%,0,Cursor0Time,0.001);DrawMode(memchInstantRate%,2,1);DrawMode(memchInstantRate%,7,3); StringCursor0Time$:=Str$(Cursor0Time,12,6); StringNrDeletedItem$:=Str$(NrDeletedItem%); StringToolbar$:=StringNrDeletedItem$+" spike was deleted at time: "+StringCursor0Time$; ToolbarText(StringToolbar$); pointerlocal%:=FindItem%(SpikesTlist[],Cursor0Time,0.00001); ' index in display, not found = -1 if pointerlocal% <> -1 then ' yes NumberofSpike%:=NumberOfSpike%-1; ' update total number of spikes if pointerlocal% > 1 then NewCursor0Time:=SpikesTlist[pointerlocal%-1]; else if SpikesTlist[2] <> -1 then NewCursor0Time:=SpikesTlist[2]; else NewCursor0Time:=0; endif;endif; if NewCursor0Time <> 0 then tempmid%:=FindItem%(SpikesTlist[],NewCursor0Time,0.00001); endif; 'debug ' printlog("%d, %d, %d \n",pointer001%,pointer255%,pointermid%); UpdateSpkDisplay%(); ' also update list of spikes times pointermid% := tempmid%; HighLight%(pointermid%); HowManySpikesDisplayed%(); Cursor(0,NewCursor0Time); else ' the deleted spike is not in the wave 1 display NumberofSpike%:=NumberOfSpike%-1; endif; return 1 end; func Add%() var nn%, bt%, cur1t,pp$,data[WaveMarkDataPoint%],TStep,eT,code%[4], TrigMode%; var idxaddedspk%, goon%, addmore%, Cursor0Time, sT, oTrig, uxa, uxo; 'code%[0]:=2; ' 4:red 2:green 1:blue if BAKon then Cursor0Time:=Cursor(0); if isonreject%(Cursor0Time) then code%[0]:=4; sT:=Cursor0Time; ' set time of trigger TStep:=BinSize(chUnit%); eT:=sT + ((WaveMarkDataPoint%-1)*TStep); ChanData(chUnit%,data[],sT,eT); ' fetch spike MemSetItem(memchEvent%,0,sT,code%[],data[]); ' deposit spike into buffer MemSetItem(memchInstantRate%,0,sT); ' deposit spike for inst freq display DrawMode(memchInstantRate%,2,1); DrawMode(memchInstantRate%,7,3);' recompute instant freq nn%:=FindItem%(SpikesTlist[],Cursor0Time,0.00001); ' index in display, no found = -1 if nn% > 0 then View(hWave1%); XYColour(nn%,BAKacclour%); ' change colour in BAK display XYColour(HighlightChanNum%,16); View(vh%); endif; return 1; endif; endif; TStep:=BinSize(chUnit%); goon% := 1; ' flag for while loop oTrig := HCursor(1); ' remember trigger level uxa := XLow(); uxo := XHigh(); ' remember screen setting while goon% do goon%:=Interact("zoom in/out and pan; then set trigger",1023,0,"&Done","Set n &Go"); goon% := goon%-1; if goon% then TrigLevel:=HCursor(1); if TrigLevel < 0 then TrigMode%:=8; else TrigMode%:=7; endif; FrontView(vh%); CursorActive(0,TrigMode%,1,0,"","",TrigLevel,0,0); Cursor(0,(XLow()+XHigh())/2.0); addmore% := 1; ' control loop to add spikes while addmore% do bt%:=Interact("Place Cursor 0 on spike",1023,0,"&Add(RED)","Add&1(BLUE)","Add&2(GREEN)","fetch cursor","&Cancel or set up again","&Done"); if bt% < 4 then if bt%=1 then ' set wavemark code code%[0]:=4; endif; if bt%=2 then code%[0]:=1; endif; if bt%=3 then code%[0]:=2; endif; cur1t:=Cursor(0); if nooverlap%(cur1t) then eT:=cur1t + ((WaveMarkDataPoint%-1)*TStep); ChanData(1,data[],cur1t,eT); ' fetch spike from unit channel MemSetItem(memchEvent%,0,cur1t,code%[],data[]); MemSetItem(memchForWaveMark%,0,cur1t,code%[],data[]); ' deposit wavemark in second temp buffer 'fix instant rate MemSetItem(memchInstantRate%,0,cur1t); DrawMode(memchInstantRate%,2,1); DrawMode(memchInstantRate%,7,3); ' recompute instant freq pp$:="One spike was placed at time: " + Str$(cur1t,12,6); ToolbarText(pp$); NumberOfSpike%:=NumberOfSpike%+1; else Message("Spike already defined??"); endif; else if bt% = 4 then ' just fetch cursor Cursor(0,(XLow()+XHigh())/2.0); else addmore% := 0; ' exit add spike loop if bt% = 6 then ' done goon% := 0; ' exit both loops endif; endif; endif; ' if bt% < 4 etc.. wend; ' loop adding spikes endif; ' if goon wend; ' loop set up horiz cursor HCursor(1,oTrig); ' restore trigger level XRange(uxa,uxo); ' restore X axis UpdateSpkDisplay%(); ' tidy spike and BAK display HighLight%(pointermid%); HowManySpikesDisplayed%(); 'return cursor 0 mode to before function call CursorActive(0,14,memchEvent%,0,"","",0,0,0); return 1; end; func nooverlap%(tstime) var wobble, dada%, NrDeletedItem%; wobble := MinimumTimeBetweenTriggers/2000; dada%:=FindItem%(SpikesTlist[],tstime,wobble); ' index in display, not found = -1 if dada% = -1 then return 1; else if BAKon then if isonreject%(SpikesTlist[dada%]) then ' with BAK window check whether spike triggered NrDeletedItem%:=MemDeleteTime(memchForWaveMark%,0,tstime,0.001); ' delete second level marker return 1; endif; endif; return 0; endif; end; func SavNAdv%() ' accept spikes and take next window var sT; Save%(); View(vh%); sT := XHigh(); if NextTime(chUnitEvent%,sT) < 0 then Advance%(); ' no more spikes, capture more endif; return 1; end; func Save%() 'ClrchSavut%(); ' save only spikes in window ChanDelete(chUnitEvent%); MemSave(memchEvent%,chUnitEvent%,0); ChanShow(chUnitEvent%); DrawMode(chUnitEvent%,2); ' draw tics ChanTitle$(chUnitEvent%,"Saved Events"); DoAverg%(); ' Plot saved wavemarks var WaveX[WaveMarkDataPoint%+prelude],sT,eT,nnn%,msgw$; var kk%:=0; View(vh%); sT:=0; for nnn%:= 0 to WaveMarkDataPoint%+prelude-1 do WaveX[nnn%]:=nnn% * UnitSamplingInterval; next; while sT >= 0 do sT:=NextTime(chUnitEvent%,sT); eT:=sT + ((WaveMarkDataPoint%-1)*UnitSamplingInterval); if sT > 0 then kk%:=kk%+1; endif; wend; View(vh%); '======================= return 1; end; func DoAverg%() var sT, eT, nn%, nnn%; var WaveData[WaveMarkDataPoint%+prelude]; ArrConst(AveData[],0); ' clear average buffer sT := AverFromHere; View(vh%); ' seach in trace window sT := NextTime(chUnitEvent%,sT); nnn% := 0; ' number of spikes 'while sT > 0 do ' average all saved spikes while sT > 0 and sT < XHigh() do ' average up to current window eT:=sT + ((WaveMarkDataPoint%-1)*UnitSamplingInterval); ' calculate end of spike ChanData(chUnit%,WaveData[],sT-(prelude*UnitSamplingInterval),eT); ' fetch spike ArrAdd(AveData[],WaveData[]); ' accumulate spikes nnn% := nnn% + 1; ' count spikes sT := NextTime(chUnitEvent%,sT); ' find next spike wend; if nnn% > 0 then ArrDiv(AveData[],nnn%); ' calculate average endif; return 1; end; func isonreject%(Cursor0T) var sT, MarkT, onreject%:=0, currV%; currV% := View(); ' deposit current view View(vh%); ' check if cursor 0 on reject spike sT := Cursor0T - MinimumTimeBetweenTriggers/1000; MarkT := NextTime(memchForWaveMark%,sT); if MarkT = Cursor0T then onreject% := 1; ' cursor sitting on BAK spike endif; sT := NextTime(memchEvent%,sT); if sT = Cursor0T then ' check whether sitting on reject spike onreject% := 0; ' cursor sitting accepted spike, do manual add endif; View(currV%); ' restore view return onreject%; end; func ClrchSavut%() var sT, tempChan%, WaveMarkDataPoint%, tView%; tView% := View(); View(vh%); ' remember current view sT := XLow(); ' left hand margin of window sT := NextTime(chUnitEvent%,sT); if sT < 0 or sT > XHigh() then ChanSave(memchEvent%,chUnitEvent%,0,XLow(),XHigh()); ' copy spikes in window else WaveMarkDataPoint%:=MarkInfo(chUnitEvent%,WaveMarkPreTrig%); ' create temporary channel tempChan%:=MemChan(6,WaveMarkDataPoint%,BinSize(chUnitEvent%),WaveMarkPreTrig%); ChanScale(tempChan%,ChanScale(1)); MemImport(tempChan%,chUnitEvent%,0,MaxTime(chUnit%)); 'copy spikes to deletable channel MemDeleteTime(tempChan%,3,XLow(),XHigh()); ' clear spikes in save buffer ChanSave(memchEvent%,tempChan%,0,XLow(),XHigh()); ' copy spikes in window ChanDelete(chUnitEvent%); MemSave(tempChan%,chUnitEvent%,0); ChanShow(chUnitEvent%); DrawMode(chUnitEvent%,2); ' draw tics ChanTitle$(chUnitEvent%,"Saved Events"); ChanDelete(tempChan%); endif; View(tView%); ' restore view return 1; end; func Quit%() FileClose(-1,-1); halt; end; func Fetch%() Cursor(0,(XLow()+XHigh())/2); ' put cursor 0 at the center CursorVisible(0,1); return 1; end; func ScreenRes%() var sT; ScreenWidth:=Input("Enter new screen width in second",ScreenWidth,0.001,1000); XRange(XLow(),XLow()+ScreenWidth); if CursorExists(1) then Cursor(1,XLow()); ' set cursor to left side of screen else CursorNew(XLow(),1); endif; sT := XLow(); sT:=NextTime(memchForWaveMark%,sT); ' check for spikes return 1; end; func Advanco%() var dotake%, sT; View(vh%); sT := XHigh(); if NextTime(chUnitEvent%,sT) < 0 then dotake% := 1; ' no more spikes, capture more else dotake% := 0; ' there are spikes, just advance endif; XRange(XHigh()-Overlapsetting,XHigh()+ScreenWidth-Overlapsetting); '20 ms hysterisis Cursor(0,(XLow()+XHigh())/2); ' put cursor 0 at the center Optimise(4); if dotake% then if BAKon then TakeToo%(); ' take spikes in new window, with BAK discriminator else TakeOne%(); ' take spikes in new window endif; endif; return 1; end; func Advance%() XRange(XHigh()-Overlapsetting,XHigh()+ScreenWidth-Overlapsetting); '20 ms hysterisis Cursor(0,(XLow()+XHigh())/2); ' put cursor 0 at the center Optimise(4); if ReDisp% then ' flag set in Settings UpdateSpkDisplay%(); ' redisplay previously analysed spikes else if BAKon then TakeToo%(); ' take spikes in new window, with BAK discriminator else TakeOne%(); ' take spikes in new window endif; endif return 1; end; func Back%() XRange(XLow()-ScreenWidth+Overlapsetting,XLow()+Overlapsetting); '20 ms hysterisis Cursor(0,(XLow()+XHigh())/2); ' put cursor 0 at the center Optimise(4); if ReDisp% then ' flag set in Settings UpdateSpkDisplay%(); ' redisplay previously analysed spikes endif; return 1; end; func InsFreq%() if kIF%=0 then ChanShow(memchInstantRate%); kIF%:=1; ToolbarSet(11,"Hide IF",InsFreq%); else ChanHide(memchInstantRate%); kIF%:=0; ToolbarSet(11,"Show IF",InsFreq%); endif; return 1; end; func FindSamplingRate%(St,chn%) var t1,t2; t1:=NextTime(chn%,St); t2:=NextTime(chn%,t1); return round(1/(t2-t1)); end; func FindSamplingInterval(St,chn%) var t1,t2; t1:=NextTime(chn%,St); t2:=NextTime(chn%,t1); return t2-t1; end;