I added another opcode, so there's another patch. This patch does everything the previous patch did, plus the new pitch shift opcode. You can download it here:
http://www.mediafire.com/?sharekey=db15991d3853f45abda4076e811714c8e04e75f6e8ebb871Setting the Pitch ShiftThere is an existing opcode D8 that will set the pitch shift. The pitch shift is added to the note value to get a final note value. For example, if you have a note 4C (an A), and your pitch shift is set to 01, the sound engine will do a 4C+01, giving you 4D (a B).
The D8 opcode takes one operand (the pitch shift value) and is usually found in channel headers. Most channels set it to 00, meaning no change in pitch. It's not a terribly useful opcode.
Adjusting the Pitch ShiftAdjusting the pitch shift on the fly however is very useful. So I made a new opcode to allow you to add or subtract from the pitch shift value.
The new opcode is D2. It takes one operand, which is added to the pitch shift. How is this useful? Let's look at the first chord arpeggio of the classic FF intro song. It's a major/9 arpeggio that spans five octaves. It goes something like this:
(Octave 1)A B C# E (Oc2)A B C# E (Oc3)A B C# E (Oc4)A B C# E (Oc5)A (Oc4)E C# B A (Oc3)E C# B A (Oc2)E C# B A (Oc1)E C# B.
If we were to write it out manually for the FF7 sound engine, we'd get something like this:
01 4C 4E 4F 53 58 5A 5C 5F 64 66 68 6B 70 72 74 77 7C 77 74 72 70 6B 68 66 64 5F 5C 5A 58 53 4F 4E
That's 33 bytes. And this is only one chord. The FF intro song has a few more, so we'd exceed 100 bytes just for one channel!
Luckily, with the new D2 opcode, we can take advantage of the arpeggio pattern and turn the above data into something like this:
01
4C 4E 4F 53 D2 0C CE 04 21 00
4C 47 44 42 D2 F4 CE 04 2B 00
That's 21 bytes, or 2/3 the size!
Let's look at what is happening:
1) First we play the phrase 4C 4E 4F 53.
2) Then we encounter the D2 opcode, which tells the sound engine to adjust the pitch by #$0C. #$0C is hex for 12. There are 12 notes on the music scale, so adding 12 to the pitch will raise it an octave.
3) After the D2 opcode, we encounter the CE opcode, which is our loop opcode. It sends us back to the beginning.
4) We find our phrase again 4C 4E 4F 53, but this time #$0C will be added to them, effectively turning them into 58 5A 5C 5F.
5) We encounter D2 0C again. This will add #$0C AGAIN (it stacks), so now our pitch adjustment is +#$18, or two octaves higher.
6) Loop again (+#$24), and again (+#$30) for a total of 4 times. At the end of our loop we will be 4 octaves higher than we started.
7) Next we get to the descending phrase: 4C 47 44 42. But remember, we are still four octaves higher, so these will actually turn into 7C 77 74 72 for the first playthrough.
8 ) We encounter the D2 opcode. This time we add #$F4 to our pitch adjustment. WTF? #$F4? Yes. Adding #$F4 is actually like subtracting #$0C. Since #$FF is the highest number on an 8-bit machine, the addition will loop around to #$00 and then count up and fall #$0C short of the previous value. We throw away the carry. Maybe this table will help make it clear:
00 00 adding 00 is the same as subtracting 00
FF -01 adding FF is the same as subtracting 01
FE -02 adding FE is the same as subtracting 02, etc
FD -03
FC -04
FB -05
FA -06
F9 -07
F8 -08
F7 -09
F6 -0A
F5 -0B
F4 -0C
etc...
So again, adding #$F4 to our pitch adjustment is essentially subtracting #$0C, which will lower the octave.
9) We loop to the beginning of the descending phrase and repeat 4 times.
Look at this data. It is four chords arpeggiated (A/9, F#m/9, D/9, E/9):
;note length
01
;A/9 Chord
4C 4E 50 53 D2 0C CE 04 21 00
4C 47 44 42 D2 F4 CE 04 2B 00
;F#m/9 chord. I put the D2 F4 in a different place. See explanation below.
49 4B 4C 50 D2 0C CE 04 32 00
D2 F4 55 50 4C 4B CE 04 3C 00
;D/9 chord
51 53 55 58 D2 0C CE 04 46 00
51 4C 49 47 D2 F4 CE 04 50 00
;E/9 chord
D2 02 CF 02 46 00
;song loop
D0
That's 68 bytes. Without opcodes, this same phrase would be 130 bytes. That's almost 50% savings!
The A/9 chord should look familiar, since we already stepped through it above.
Next is the F#m/9 chord. Same concept, different notes.
After the F#m/9 chord, we have the D/9 chord. It looks very similar to the A/9 chord.
Finally, for the E/9 chord, we pitch shift up a step (D2 02) and use the CF loop opcode to replay the D/9 chord, but this time shifted up a step (to E). Doing this saves us 14 bytes. Pretty nice! Notice that we use the CF loop here, not CE. This is because we have a CE loop nested inside our bigger CF loop.
Normally we'd want to zero our pitch shift out and put a D2 FE after our E/9 chord to cancel out the D2 02, but since we are at the end of the channel data we don't have to. The D0 song loop opcode rereads the header, and our header will have a D8 00 in it. I introduced the D8 opcode at the beginning of this post. It sets the pitch shift. The channel header's D8 00 will reset our pitch shift to 0 for us! Sweet!
PreludeHere is data for the FF intro song (but in the key of C). I used the triangle channel as the main instrument for its soft sound, and I used the delay effect trick again. Please look at the song header, as I have the channels in a nonstandard order (square1 and noise both point to the dead rests at the end). You can
paste this data in at 0x1B8DD and hear it as the new intro song. It could still use some work, but I think it's an improvement over the crappy 1-chord version in the Chinese original.

And about half the size too!
FF
00 9D00
01 8100
02 0E00
03 9D00
FF
CC C8 C7 FF C4 6B DB 07000000 DE 0A D8 0C
01
4F 51 53 56 D2 0C CE 04 1E 00
4F 4A 47 45 D2 F4 CE 04 28 00
4C 4E 4F 53 D2 0C CE 04 32 00
4C 47 43 42 D2 F4 CE 04 3C 00 CF 02 1E 00
4C 4F 54 56 D2 0C CE 04 4A 00
D2 F4 58 56 54 4F CE 04 54 00
D2 02 CF 02 4A 00
D2 FE
4B 4F 52 56 D2 0C CE 04 66 00
4B 4A 46 43 D2 F4 CE 04 70 00
D2 02 CF 02 66 00
D0
CC FE C7 FF C4 04 DB 07000000 CD 0301 DE 0A D8 00
DF CE 1D 00 02 C9 CE 02 93 00
00 C9 C9 D0
PatchIf you missed it above, here is the patch:
http://www.mediafire.com/?sharekey=db15991d3853f45abda4076e811714c8e04e75f6e8ebb871And if you missed the little lesson on looping/branching, you can read that post
here.