Apr 12, 2015 at 3:48 PM
Senior Member

"This is the greatest handgun ever made! You have to ask yourself, do I feel lucky?"
Join Date: Aug 2, 2014
Location: inactivity.
Posts: 117
(Note: This probably won't be updated further, if you need a decent reference see PiyoPiyoJ's gabien.music package)
I've worked out most of the PiyoPiyo file format.
Enough that a player can be written, at least.
So I figured I should post it here, since it's useful for those that want to use PiyoPiyo outside Ikachan.
Note that "int32-le" is a 32-bit Little Endian integer.
First 4 bytes are "PMD" followed by 0x80(q3hardcore says that the 0x80 byte is a "writable" flag).
The next 4 bytes are an int32-le for position in file of Track 1 data.
The next 4 bytes are an int32-le for the "music wait"(milliseconds per frame)
The next 4 bytes are an int32-le for the "loop start".
The next 4 bytes are an int32-le for the "loop end".
The next 4 bytes are an int32-le for the amount of 4-byte records per track.
Track Header Data(20 bytes followed by 256 bytes, then 64 bytes):
The first byte is the "Octave" field
The second byte is the "Icon" field.
The next 2 bytes are unknown.
The next 4 bytes are an int32-le for the "Length" field(time envelope is spread over, assume to be 11025==1 second)
The next 4 bytes are an int32-le for the "Volume" field.
The next 8 bytes are unknown.
The next 0x100 bytes are the waveform(8-bit, signed. The sample rate is handled, for me at least, by changing the sample rate entered into the calculation below.)
The next 0x40 bytes are the envelope(also 8-bit, also apparently unsigned)
(This repeats 3 times, track P doesn't have this data)
Finally, there's an int32-le for Track P's volume.
That's the end of the header.
Then, at the offset mentioned, the track data begins.
The track data is not interleaved-it's Track 1 followed by Track 2 followed by Track 3 followed by Track P.
All the tracks are made of 4-byte records.
The 4-byte records are:
First 3 bytes are a bitfield(lowest bit/first byte is lowest pitch),
last byte is the Pan.(0 for no change, else 1 to 7)
The amount of these records per track is in the header.
The calculation you need to turn the note position and octave into the relative pitch is:
First, pos must be 0-based, with higher pitches being higher values.
Then add the octave * 12 to pos.
Run it through this:
double relativePitch=8363d*Math.pow(2.0d,pos/12.0d)/sample_rate;
And you have the relative pitch(where 1.0d is to play at normal speed,2.0d is to play at double speed,0.5d is to play at half speed, you get the idea)!
(Thanks to liborganya, which is where I got that calculation from)
As for the volume, it's weird, and I only have guesswork for now.
If you want more detail, just look in the last thing I uploaded with a PiyoPiyo decoder in it.
You'll probably see these put to uselater today done.
--gamemanj
I've worked out most of the PiyoPiyo file format.
Enough that a player can be written, at least.
So I figured I should post it here, since it's useful for those that want to use PiyoPiyo outside Ikachan.
Note that "int32-le" is a 32-bit Little Endian integer.
First 4 bytes are "PMD" followed by 0x80(q3hardcore says that the 0x80 byte is a "writable" flag).
The next 4 bytes are an int32-le for position in file of Track 1 data.
The next 4 bytes are an int32-le for the "music wait"(milliseconds per frame)
The next 4 bytes are an int32-le for the "loop start".
The next 4 bytes are an int32-le for the "loop end".
The next 4 bytes are an int32-le for the amount of 4-byte records per track.
Track Header Data(20 bytes followed by 256 bytes, then 64 bytes):
The first byte is the "Octave" field
The second byte is the "Icon" field.
The next 2 bytes are unknown.
The next 4 bytes are an int32-le for the "Length" field(time envelope is spread over, assume to be 11025==1 second)
The next 4 bytes are an int32-le for the "Volume" field.
The next 8 bytes are unknown.
The next 0x100 bytes are the waveform(8-bit, signed. The sample rate is handled, for me at least, by changing the sample rate entered into the calculation below.)
The next 0x40 bytes are the envelope(also 8-bit, also apparently unsigned)
(This repeats 3 times, track P doesn't have this data)
Finally, there's an int32-le for Track P's volume.
That's the end of the header.
Then, at the offset mentioned, the track data begins.
The track data is not interleaved-it's Track 1 followed by Track 2 followed by Track 3 followed by Track P.
All the tracks are made of 4-byte records.
The 4-byte records are:
First 3 bytes are a bitfield(lowest bit/first byte is lowest pitch),
last byte is the Pan.(0 for no change, else 1 to 7)
The amount of these records per track is in the header.
The calculation you need to turn the note position and octave into the relative pitch is:
First, pos must be 0-based, with higher pitches being higher values.
Then add the octave * 12 to pos.
Run it through this:
double relativePitch=8363d*Math.pow(2.0d,pos/12.0d)/sample_rate;
And you have the relative pitch(where 1.0d is to play at normal speed,2.0d is to play at double speed,0.5d is to play at half speed, you get the idea)!
(Thanks to liborganya, which is where I got that calculation from)
As for the volume, it's weird, and I only have guesswork for now.
If you want more detail, just look in the last thing I uploaded with a PiyoPiyo decoder in it.
You'll probably see these put to use
--gamemanj