deciphering .ptcop file format

Dec 17, 2011 at 3:21 AM
In my body, in my head
Forum Moderator
"Life begins and ends with Nu."
Join Date: Aug 28, 2009
Location: The Purple Zone
Posts: 5998
Okay so I doubt I'll get much feedback on this but anyway, I'm working on deciphering the file format of songs produced with pxtone (*.ptcop) for reasons unknown. Here are my findings thusfar.

Code:
PTCOP FILE FORMAT

Generally speaking, the format seems to follow the pattern of
Block Name [0x8]
Block Size [0x4]
- Block data

Blocks marked with <!> should never be missing,
but all other blocks are optional
It is currently unknown if the ordering of the blocks matters,
but blocks here are listed according to order of appearance in sample files.

//***********************************************************

0x00 : File header "PTCOLLAGE-071119"
0x10 : Unknown int (0x00000392)

"MasterV5" block <!>
0x0[0x2] Unknown data
0x2[0x1] Beat
0x3[0x2] Unknown data
0x5[0x2] Beat Tempo
0x7[0x4] "Repeat" location (meas * beat * 0x1E0?)
0xB[0x4] "Last" location

"Event V5" block
-This block contains both note signal events and effect events
-If there are no events, field contains a single null int
-If there are events, block data contains the following:
0x0[0x4] number of events
0x4[0x?] event data

Events have the following format
	Position indicator: a variable-length number

	98 02 is
	(02-01)x80 +98

	80 8E 02 is
	(((02-01)*80)+8e-01)*80+80

	0x6000 = 80 C0 01

	Unit ID: A char indicating which unit this event applies to

	Event ID: a byte indicating which type of event it is
		0x1 - Play Instrument (duration)
		0x2 - Note pitch change(new note)
		0x3 - Pan(volume) (new pan)
		0x4 - Velocity
		0x5 - Volume (new volume)
		0x6 - Key Porta (length)
		0x7 -
		0x8 -
		0x9 -
		0xA -
		0xB -
		0xC - Voice No (new voice)
		0xD - Group No (new group)
		0xE - Key Correct (key correct value)
		0xF - Pan(Time) (new pan?)
	
	Event Value: A variable-length number of the same format used
	for the position indicator that specifies the value being
	changed by the event. for example, the event value
	of a Volume event is the new volume of the unit.

"textNAME" block <!>
ASCII string containing the name of the song (not null-terminated)

"textCOMM" block
ASCII string containing song comments (not null-terminated)

"effeDELA" block
Unknown data

"effeOVER" block
Unknown data

"matePCM\20" block
0x00[0x3] Unknown data (padding?)
0x03[0x1] Basic Key field
0x04[0x4] Voice flags
	0x01 - Loop
	0x02 - Smooth
	0x04 - Beat Fit
0x08[0x2] number of channels (mono or stereo)
0x0A[0x2] bitrate (8, 16 or 32 bits)
0x0C[0x4] sample rate (Hz)
0x10[0x4] key correct (32Bit float?)
0x14[0x4] number of samples
0x18[0x?] sample frames - size of (bitrate/8 * nSample)

"matePTV\20"
0x00[0x0C] Unknown data
0x0C[0x08] "PTVOICE-"
0x14[0x0A] Unknown data (doesn't match .ptvoice file)
0x18[0x1A] Unknown data (matches .ptvoice file)
	--note: .ptvoice file is 2 bytes larger (?)

"matePTN\20"
Unknown data

"mateOGGV"
Unknown and really damn big data even for a smidgey little sample

"assiWOIC" block - comes after every "mateXXXX" block
0x0[0x04] Voice number
0x4[0x10] Voice name. If less than 0x10 in len, will be null-terminated

"num UNIT" block <!>
-A single integer denoting the number of units in use by this song

"assiUNIT" block
-one for each unit
0x0[0x04] Unit number
0x4[0x10] Unit name. If less than 0x10 in len, will be null-terminated

"pxtonend" block <!>
-zero size, denotes end of file
//************************************************************************
sample code
if (i <= 7){ //not drams
ptEventVec.add(new PtcopEvent(trackEventArray[j].resourcePos,
woicAssign,
2,
0x3F00 + trackEventArray[j].noteVal * 0x100));
ptEventVec.add(new PtcopEvent(trackEventArray[j].resourcePos,
woicAssign,
1,
(trackEventArray[j].noteLen) * 0x78));
}
else{ //probably drams?
int orgPitch = 80 - trackEventArray[j].noteVal;
int ptPitch;

ptPitch = 0x7200 - orgPitch*orgPitch*2125/1000;
ptEventVec.add(new PtcopEvent(trackEventArray[j].resourcePos,
woicAssign,
2,
ptPitch));

//System.out.print(trackEventArray[j].noteVal);
ptEventVec.add(new PtcopEvent(trackEventArray[j].resourcePos,
woicAssign,
1,
(trackEventArray[j].noteLen + OrgPtcopConvApp.comboVal) * 0x78));
}

If any kind soul feels like contributing to my knowledge of yet-unknown fields, that would be much appreciated. It's really nice of Pixel to lay out his file format so cleanly and self-descriptively, it makes things much easier to figure out.
 
Dec 17, 2011 at 4:45 AM
Been here way too long...
"Life begins and ends with Nu."
Join Date: Jan 4, 2008
Location: Lingerie, but also, like, fancy curtains
Posts: 3054
Obviously I won't be able to say much of anything useful, but thank you for posting this.
It is always good to document the unknown.
 
Dec 17, 2011 at 2:57 PM
graters gonna grate
"Heavy swords for sale. Suitable for most RPG Protagonists. Apply now!"
Join Date: Jul 2, 2008
Location: &
Posts: 1886
Age: 31
Would it be good for me to post my documentation of the *.org format in this thread? I never actually posted a straight-up description of the file format; only the Java code for how to interpret/play it.

edit: nvm, I'll just post it in the "orgs in Java" thread. I was actually planning on posting some more semi-relevant stuff in that thread anyway in the near future.
 
Dec 17, 2011 at 3:46 PM
In my body, in my head
Forum Moderator
"Life begins and ends with Nu."
Join Date: Aug 28, 2009
Location: The Purple Zone
Posts: 5998
Yeah, post it somewhere at least. It might also be very useful for some vaguely unspecified reason.
 
Dec 17, 2011 at 4:15 PM
Been here way too long...
"Life begins and ends with Nu."
Join Date: Jan 4, 2008
Location: Lingerie, but also, like, fancy curtains
Posts: 3054
If you're going to make an .org -> .ptcop converter, why don't you just say so?
 
Dec 17, 2011 at 4:20 PM
In my body, in my head
Forum Moderator
"Life begins and ends with Nu."
Join Date: Aug 28, 2009
Location: The Purple Zone
Posts: 5998
because maybe I will give up and I don't want people to get their hopes too high?

Anyway, updates with more info on "Event V5"
 
Aug 11, 2012 at 8:57 PM
graters gonna grate
"Heavy swords for sale. Suitable for most RPG Protagonists. Apply now!"
Join Date: Jul 2, 2008
Location: &
Posts: 1886
Age: 31
It seems that your description of the general block structure (name followed by size followed by content) is not correct all of the time. For a blank song, the Event V5 block is exactly as long as it claims to be. But for a song with two notes in it, the block is one byte shorter than it claims to be, and for a full blown song I tested, it's about 44kb shorter than it claims to be. Wat do?

edit: also, it's pxtonend not pxtonend

edit: oic, it's IPBoard's fault, not yours

what I meant was, it's pxtonend not pxtonend where bold indicates capitalization.
 
Aug 11, 2012 at 9:05 PM
In my body, in my head
Forum Moderator
"Life begins and ends with Nu."
Join Date: Aug 28, 2009
Location: The Purple Zone
Posts: 5998
Code:
pxtonend
pxtonend
???????

@eventV5, really? I don't remember this, but I didn't really feel like counting bytes for all the blocks every single time - I'll try to look into it if I find the time.
 
Top