I'm writing a pattern system for a tracker, but something's not right with some of my pointer management ... could someone take a look at this please? I commented everything to give you an idea of what I'm trying to do - briefly explained:
"StepStruct" is the structure type for one step, i.e. one note + effect command + whatever else I decide to put in there ... for now, it's just one byte named "value", just for testing.
An ordinary array of "PatternStruct" structures is created to hold up to #MaxPatterns number of patterns. Each "PatternStruct" in this array contains a pointer to the "StepStruct" items of each pattern, and the number of rows (NumRows) - the number of channels is global for all patterns ("NumTracks") ...
When a pattern is initialized, memory is allocated for SizeOf(StepStruct) * number of tracks * number of rows.
The problem seems to be the SetNumTracks procedure, which is supposed to convert all the patterns in memory to a new number of tracks - something goes wrong here, as you can tell from the readout. Comment out the call to SetNumTracks, and it works fine - but that's not necessarily because the rest is correct, the StepPtr procedure could very well return bad pointers, or not return them the correct way, I don't know - I get very confused with all these pointers ...
anyway, here's the code...
Code: Select all
; Pattern Data Include
#BaseMemoryID.l = 1
#MaxPatterns.l = 256 ; max. possible number of patterns
NumTracks.l = 8 ; global number of tracks (for all patterns)
Structure StepStruct
Value.b
EndStructure
Structure PatternStruct
*DataPtr.l ; pointer to the memory area that contains StepStruct's
NumRows.l ; number of rows in this pattern
EndStructure
Dim Patterns.PatternStruct(#MaxPatterns) ; the last pattern is reserved for
Procedure InitPatternEx(aPatNum.l, aNumRows.l, aNumTracks.l)
; Allocate the required amount of memory for the StepStruct's of a pattern,
; using a given number of tracks, rather than the global NumTracks
Global Patterns, StepStruct
AllocateMemory(#BaseMemoryID+1+aPatNum, SizeOf(StepStruct)*NumRows*aNumTracks, 0)
Patterns(aPatNum)\DataPtr = MemoryID()
Patterns(aPatNum)\NumRows = aNumRows
EndProcedure
Procedure InitPattern(aPatNum.l, aNumRows.l)
; Allocate the required amount of memory for the StepStruct's of a pattern,
; using the global number of tracks (NumTracks)
Global NumTracks
InitPatternEx(aPatNum, aNumRows, NumTracks)
EndProcedure
Procedure.l StepPtr(aPatNum.l, aTrack.l, aRow.l)
; Calculates and returns a pointer to a specific StepStruct within a pattern
Global Patterns, StepStruct, NumTracks
Offset.l = SizeOf(StepStruct)*(aRow*NumTracks+aTrack)
ProcedureReturn Patterns(aPatNum)\DataPtr + Offset
EndProcedure
Procedure.l StepPtrEx(aPatNum.l, aTrack.l, aRow.l, aNumTracks.l)
; Calculates and returns a pointer to a specific StepStruct within a pattern,
; using a specified number of tracks for calculation, rather than the global NumTracks
Global Patterns, StepStruct
Offset.l = SizeOf(StepStruct)*(aRow*aNumTracks+aTrack)
ProcedureReturn Patterns(aPatNum)\DataPtr + Offset
EndProcedure
Procedure SetNumTracks(NewNumTracks.l)
; Change the number of tracks in all patterns
Global Patterns, StepStruct, NumTracks
DefType.StepStruct *src, *dst
For PatNum = 0 To #MaxPatterns-1
If Patterns(PatNum)\DataPtr 0
; create temporary work pattern with same number of rows as original pattern
InitPattern(#MaxPatterns, Patterns(PatNum)\NumRows)
; copy original pattern into temporary work pattern
CopyMemory(@Patterns(PatNum)\DataPtr, @Patterns(#MaxPatterns)\DataPtr, SizeOf(StepStruct) * Patterns(PatNum)\NumRows * NumTracks)
; resize original pattern
InitPatternEx(PatNum, Patterns(PatNum)\NumRows, NewNumTracks)
; copy each step manually from temporary pattern into original pattern
If NewNumTracks>NumTracks
LastTrack = NumTracks-1
Else ; If NewNumTracks
by the way, I'm very confused by the help files - the word "MemoryID" seems to be used both about memory handles and actual pointers! very confusing ... like in AllocateMemory, for example, you have to supply a "MemoryID" which is a memory handle (i.e. a number of your own choice, by which you will identify the memory block) - but at the same time, the function MemoryID() returns NOT a "MemoryID" as in the previous definition, but a POINTER to the ACTUAL memory block ... am I the only one who finds this really, really confusing?? :)