Difference between revisions of "FF7/PSX/Sound/Opcodes/0xa8aa"

From QhimmWiki
Jump to navigation Jump to search
Qhimm>G
ffrtt>Loveemu
m
 
(5 intermediate revisions by 2 users not shown)
Line 1: Line 1:
== 0xA8, 0xAA, 0xA3 (Channel Volume, Pan, Volume Modifier) ==
== 0xA8, 0xAA, 0xA3 (Channel Volume, Pan, Volume Modifier) ==
0xA8 has one 8-bit parameter, which used in calculation of base channel volume.
0xA8 has one 8-bit parameter, which used in calculation of base channel volume.


Line 6: Line 5:


0xA3 has one 8-bit parameter, which used in calculation of base channel volume.
0xA3 has one 8-bit parameter, which used in calculation of base channel volume.
Understanding of this opcodes isn't that easy, but here is what I have got:


=== Volume Calculation ===
=== Volume Calculation ===


// Compiler optimizer (at least I think so :)) generated following tables to speedup volume calculation for left & right volume.
// m_AKAO_VOLUME_TABLE_L[i] = 32768 - m_AKAO_VOLUME_TABLE_R[i];
 
const uint16_t m_AKAO_VOLUME_TABLE_L[128] = {
const uint16_t m_AKAO_VOLUME_TABLE_L[256] =
  0x7f80, 0x7e80, 0x7d80, 0x7c80, 0x7b80, 0x7a80, 0x7980, 0x7880,
{
  0x7780, 0x7680, 0x7580, 0x7480, 0x7380, 0x7280, 0x7180, 0x7080,
    0x7f80, 0x7e80, 0x7d80, 0x7c80, 0x7b80, 0x7a80, 0x7980, 0x7880,
  0x6f80, 0x6e80, 0x6d80, 0x6c80, 0x6b80, 0x6a80, 0x6980, 0x6880,
    0x7780, 0x7680, 0x7580, 0x7480, 0x7380, 0x7280, 0x7180, 0x7080,
  0x6780, 0x6680, 0x6580, 0x6480, 0x6380, 0x6280, 0x6180, 0x6080,
    0x6f80, 0x6e80, 0x6d80, 0x6c80, 0x6b80, 0x6a80, 0x6980, 0x6880,
  0x5f80, 0x5e80, 0x5d80, 0x5c80, 0x5b80, 0x5a80, 0x5980, 0x5880,
    0x6780, 0x6680, 0x6580, 0x6480, 0x6380, 0x6280, 0x6180, 0x6080,
  0x5780, 0x5680, 0x5580, 0x5480, 0x5380, 0x5280, 0x5180, 0x5080,
    0x5f80, 0x5e80, 0x5d80, 0x5c80, 0x5b80, 0x5a80, 0x5980, 0x5880,
  0x4f80, 0x4e80, 0x4d80, 0x4c80, 0x4b80, 0x4a80, 0x4980, 0x4880,
    0x5780, 0x5680, 0x5580, 0x5480, 0x5380, 0x5280, 0x5180, 0x5080,
  0x4780, 0x4680, 0x4580, 0x4480, 0x4380, 0x4280, 0x4180, 0x4080,
    0x4f80, 0x4e80, 0x4d80, 0x4c80, 0x4b80, 0x4a80, 0x4980, 0x4880,
  0x3f80, 0x3e80, 0x3d80, 0x3c80, 0x3b80, 0x3a80, 0x3980, 0x3880,
    0x4780, 0x4680, 0x4580, 0x4480, 0x4380, 0x4280, 0x4180, 0x4080,
  0x3780, 0x3680, 0x3580, 0x3480, 0x3380, 0x3280, 0x3180, 0x3080,
    0x3f80, 0x3e80, 0x3d80, 0x3c80, 0x3b80, 0x3a80, 0x3980, 0x3880,
  0x2f80, 0x2e80, 0x2d80, 0x2c80, 0x2b80, 0x2a80, 0x2980, 0x2880,
    0x3780, 0x3680, 0x3580, 0x3480, 0x3380, 0x3280, 0x3180, 0x3080,
  0x2780, 0x2680, 0x2580, 0x2480, 0x2380, 0x2280, 0x2180, 0x2080,
    0x2f80, 0x2e80, 0x2d80, 0x2c80, 0x2b80, 0x2a80, 0x2980, 0x2880,
  0x1f80, 0x1e80, 0x1d80, 0x1c80, 0x1b80, 0x1a80, 0x1980, 0x1880,
    0x2780, 0x2680, 0x2580, 0x2480, 0x2380, 0x2280, 0x2180, 0x2080,
  0x1780, 0x1680, 0x1580, 0x1480, 0x1380, 0x1280, 0x1180, 0x1080,
    0x1f80, 0x1e80, 0x1d80, 0x1c80, 0x1b80, 0x1a80, 0x1980, 0x1880,
  0x0f80, 0x0e80, 0x0d80, 0x0c80, 0x0b80, 0x0a80, 0x0980, 0x0880,
    0x1780, 0x1680, 0x1580, 0x1480, 0x1380, 0x1280, 0x1180, 0x1080,
  0x0780, 0x0680, 0x0580, 0x0480, 0x0380, 0x0280, 0x0180, 0x0080
    0x0f80, 0x0e80, 0x0d80, 0x0c80, 0x0b80, 0x0a80, 0x0980, 0x0880,
};
    0x0780, 0x0680, 0x0580, 0x0480, 0x0380, 0x0280, 0x0180, 0x0080,
    0x0000, 0xffff, 0xfffc, 0xfff7, 0xfff0, 0xffe7, 0xffdc, 0xffcf,
// m_AKAO_VOLUME_TABLE_R[i] = i * 256 + 128;
    0xffc0, 0xffaf, 0xff9c, 0xff87, 0xff70, 0xff57, 0xff3c, 0xff1f,
const uint16_t m_AKAO_VOLUME_TABLE_R[128] = {
    0xff00, 0xfedf, 0xfebc, 0xfe97, 0xfe70, 0xfe47, 0xfe1c, 0xfdef,
  0x0080, 0x0180, 0x0280, 0x0380, 0x0480, 0x0580, 0x0680, 0x0780,
    0xfdc0, 0xfd8f, 0xfd5c, 0xfd27, 0xfcf0, 0xfcb7, 0xfc7c, 0xfc3f,
  0x0880, 0x0980, 0x0a80, 0x0b80, 0x0c80, 0x0d80, 0x0e80, 0x0f80,
    0xfc00, 0xfbbf, 0xfb7c, 0xfb37, 0xfaf0, 0xfaa7, 0xfa5c, 0xfa0f,
  0x1080, 0x1180, 0x1280, 0x1380, 0x1480, 0x1580, 0x1680, 0x1780,
    0xf9c0, 0xf96f, 0xf91c, 0xf8c7, 0xf870, 0xf817, 0xf7bc, 0xf75f,
  0x1880, 0x1980, 0x1a80, 0x1b80, 0x1c80, 0x1d80, 0x1e80, 0x1f80,
    0xf700, 0xf69f, 0xf63c, 0xf5d7, 0xf570, 0xf507, 0xf49c, 0xf42f,
  0x2080, 0x2180, 0x2280, 0x2380, 0x2480, 0x2580, 0x2680, 0x2780,
    0xf3c0, 0xf34f, 0xf2dc, 0xf267, 0xf1f0, 0xf177, 0xf0fc, 0xf07f,
  0x2880, 0x2980, 0x2a80, 0x2b80, 0x2c80, 0x2d80, 0x2e80, 0x2f80,
    0x1000, 0x1081, 0x1104, 0x1189, 0x1210, 0x1299, 0x1324, 0x13b1,
  0x3080, 0x3180, 0x3280, 0x3380, 0x3480, 0x3580, 0x3680, 0x3780,
    0x1440, 0x14d1, 0x1564, 0x15f9, 0x1690, 0x1729, 0x17c4, 0x1861,
  0x3880, 0x3980, 0x3a80, 0x3b80, 0x3c80, 0x3d80, 0x3e80, 0x3f80,
    0x1900, 0x19a1, 0x1a44, 0x1ae9, 0x1b90, 0x1c39, 0x1ce4, 0x1d91,
  0x4080, 0x4180, 0x4280, 0x4380, 0x4480, 0x4580, 0x4680, 0x4780,
    0x1e40, 0x1ef1, 0x1fa4, 0x2059, 0x2110, 0x21c9, 0x2284, 0x2341,
  0x4880, 0x4980, 0x4a80, 0x4b80, 0x4c80, 0x4d80, 0x4e80, 0x4f80,
    0x2400, 0x24c1, 0x2584, 0x2649, 0x2710, 0x27d9, 0x28a4, 0x2971,
  0x5080, 0x5180, 0x5280, 0x5380, 0x5480, 0x5580, 0x5680, 0x5780,
    0x2a40, 0x2b11, 0x2be4, 0x2cb9, 0x2d90, 0x2e69, 0x2f44, 0x3021,
  0x5880, 0x5980, 0x5a80, 0x5b80, 0x5c80, 0x5d80, 0x5e80, 0x5f80,
    0x3100, 0x31e1, 0x32c4, 0x33a9, 0x3490, 0x3579, 0x3664, 0x3751,
  0x6080, 0x6180, 0x6280, 0x6380, 0x6480, 0x6580, 0x6680, 0x6780,
    0x3840, 0x3931, 0x3a24, 0x3b19, 0x3c10, 0x3d09, 0x3e04, 0x3f01
  0x6880, 0x6980, 0x6a80, 0x6b80, 0x6c80, 0x6d80, 0x6e80, 0x6f80,
};
  0x7080, 0x7180, 0x7280, 0x7380, 0x7480, 0x7580, 0x7680, 0x7780,
 
  0x7880, 0x7980, 0x7a80, 0x7b80, 0x7c80, 0x7d80, 0x7e80, 0x7f80
const uint16_t m_AKAO_VOLUME_TABLE_R[256] =
};
{
    0x0080, 0x0180, 0x0280, 0x0380, 0x0480, 0x0580, 0x0680, 0x0780,
left_volume = m_AKAO_VOLUME_TABLE_L[aa_parameter] * ((a8_parameter * a3_parameter * 0x7f) / 128) / 256 / 128;
    0x0880, 0x0980, 0x0a80, 0x0b80, 0x0c80, 0x0d80, 0x0e80, 0x0f80,
    0x1080, 0x1180, 0x1280, 0x1380, 0x1480, 0x1580, 0x1680, 0x1780,
right_volume = m_AKAO_VOLUME_TABLE_R[aa_parameter] * ((a8_parameter * a3_paramater * 0x7f) / 128) / 256 / 128;
    0x1880, 0x1980, 0x1a80, 0x1b80, 0x1c80, 0x1d80, 0x1e80, 0x1f80,
    0x2080, 0x2180, 0x2280, 0x2380, 0x2480, 0x2580, 0x2680, 0x2780,
    0x2880, 0x2980, 0x2a80, 0x2b80, 0x2c80, 0x2d80, 0x2e80, 0x2f80,
    0x3080, 0x3180, 0x3280, 0x3380, 0x3480, 0x3580, 0x3680, 0x3780,
    0x3880, 0x3980, 0x3a80, 0x3b80, 0x3c80, 0x3d80, 0x3e80, 0x3f80,
    0x4080, 0x4180, 0x4280, 0x4380, 0x4480, 0x4580, 0x4680, 0x4780,
    0x4880, 0x4980, 0x4a80, 0x4b80, 0x4c80, 0x4d80, 0x4e80, 0x4f80,
    0x5080, 0x5180, 0x5280, 0x5380, 0x5480, 0x5580, 0x5680, 0x5780,
    0x5880, 0x5980, 0x5a80, 0x5b80, 0x5c80, 0x5d80, 0x5e80, 0x5f80,
    0x6080, 0x6180, 0x6280, 0x6380, 0x6480, 0x6580, 0x6680, 0x6780,
    0x6880, 0x6980, 0x6a80, 0x6b80, 0x6c80, 0x6d80, 0x6e80, 0x6f80,
    0x7080, 0x7180, 0x7280, 0x7380, 0x7480, 0x7580, 0x7680, 0x7780,
    0x7880, 0x7980, 0x7a80, 0x7b80, 0x7c80, 0x7d80, 0x7e80, 0x7f80,
    0x3f01, 0x3e04, 0x3d09, 0x3c10, 0x3b19, 0x3a24, 0x3931, 0x3840,
    0x3751, 0x3664, 0x3579, 0x3490, 0x33a9, 0x32c4, 0x31e1, 0x3100,
    0x3021, 0x2f44, 0x2e69, 0x2d90, 0x2cb9, 0x2be4, 0x2b11, 0x2a40,
    0x2971, 0x28a4, 0x27d9, 0x2710, 0x2649, 0x2584, 0x24c1, 0x2400,
    0x2341, 0x2284, 0x21c9, 0x2110, 0x2059, 0x1fa4, 0x1ef1, 0x1e40,
    0x1d91, 0x1ce4, 0x1c39, 0x1b90, 0x1ae9, 0x1a44, 0x19a1, 0x1900,
    0x1861, 0x17c4, 0x1729, 0x1690, 0x15f9, 0x1564, 0x14d1, 0x1440,
    0x13dc, 0x1324, 0x1299, 0x1210, 0x1189, 0x1104, 0x1081, 0x1000,
    0xf07f, 0xf0fc, 0xf177, 0xf1f0, 0xf267, 0xf2dc, 0xf34f, 0xf3c0,
    0xf42f, 0xf49c, 0xf507, 0xf570, 0xf5d7, 0xf63c, 0xf69f, 0xf700,
    0xf75f, 0xf7bc, 0xf817, 0xf870, 0xf8c7, 0xf91c, 0xf843, 0xf9c0,
    0xfa0f, 0xfa5c, 0xfaa7, 0xfaf0, 0xfb37, 0xfb7c, 0xfbbf, 0xfc00,
    0xfc3f, 0xfc7c, 0xfcb7, 0xfcf0, 0xfd27, 0xfd5c, 0xfd8f, 0xfdc0,
    0xfdef, 0xfe1c, 0xfe47, 0xfe70, 0xfe97, 0xfebc, 0xfedf, 0xff00,
    0xff1f, 0xff3c, 0xff57, 0xff70, 0xff87, 0xff9c, 0xffaf, 0xffc0,
    0xffcf, 0xffdc, 0xffe7, 0xfff0, 0xfff7, 0xfffc, 0xffff, 0x0000
};
 
left_volume = m_AKAO_VOLUME_TABLE_L[aa_parameter] *
((a8_parameter * a3_parameter * 0x7f) / 128) / 256 / 128;
 
right_volume = m_AKAO_VOLUME_TABLE_R[aa_parameter] *
((a8_parameter * a3_paramater * 0x7f) / 128) / 256 / 128;


If there is no A3 opcode in sequence (as in SENSUI.SND for example), default value 0x7f is used.
If there is no A3 opcode in sequence (as in SENSUI.SND for example), default value 0x7f is used.


I'll remove these tables in future and add normal mathematical interpretation of volume calculation.
If there is no A8 opcode in sequence, default value 0x7f.fe is used. (More precisely, 0x3fff is stored in memory.)

Latest revision as of 04:43, 13 June 2020

0xA8, 0xAA, 0xA3 (Channel Volume, Pan, Volume Modifier)

0xA8 has one 8-bit parameter, which used in calculation of base channel volume.

0xAA has one 8-bit parameter, which used in calculation of channel pan (difference between left and right channel volume).

0xA3 has one 8-bit parameter, which used in calculation of base channel volume.

Volume Calculation

// m_AKAO_VOLUME_TABLE_L[i] = 32768 - m_AKAO_VOLUME_TABLE_R[i];
const uint16_t m_AKAO_VOLUME_TABLE_L[128] = {
  0x7f80, 0x7e80, 0x7d80, 0x7c80, 0x7b80, 0x7a80, 0x7980, 0x7880,
  0x7780, 0x7680, 0x7580, 0x7480, 0x7380, 0x7280, 0x7180, 0x7080,
  0x6f80, 0x6e80, 0x6d80, 0x6c80, 0x6b80, 0x6a80, 0x6980, 0x6880,
  0x6780, 0x6680, 0x6580, 0x6480, 0x6380, 0x6280, 0x6180, 0x6080,
  0x5f80, 0x5e80, 0x5d80, 0x5c80, 0x5b80, 0x5a80, 0x5980, 0x5880,
  0x5780, 0x5680, 0x5580, 0x5480, 0x5380, 0x5280, 0x5180, 0x5080,
  0x4f80, 0x4e80, 0x4d80, 0x4c80, 0x4b80, 0x4a80, 0x4980, 0x4880,
  0x4780, 0x4680, 0x4580, 0x4480, 0x4380, 0x4280, 0x4180, 0x4080,
  0x3f80, 0x3e80, 0x3d80, 0x3c80, 0x3b80, 0x3a80, 0x3980, 0x3880,
  0x3780, 0x3680, 0x3580, 0x3480, 0x3380, 0x3280, 0x3180, 0x3080,
  0x2f80, 0x2e80, 0x2d80, 0x2c80, 0x2b80, 0x2a80, 0x2980, 0x2880,
  0x2780, 0x2680, 0x2580, 0x2480, 0x2380, 0x2280, 0x2180, 0x2080,
  0x1f80, 0x1e80, 0x1d80, 0x1c80, 0x1b80, 0x1a80, 0x1980, 0x1880,
  0x1780, 0x1680, 0x1580, 0x1480, 0x1380, 0x1280, 0x1180, 0x1080,
  0x0f80, 0x0e80, 0x0d80, 0x0c80, 0x0b80, 0x0a80, 0x0980, 0x0880,
  0x0780, 0x0680, 0x0580, 0x0480, 0x0380, 0x0280, 0x0180, 0x0080
};

// m_AKAO_VOLUME_TABLE_R[i] = i * 256 + 128;
const uint16_t m_AKAO_VOLUME_TABLE_R[128] = {
  0x0080, 0x0180, 0x0280, 0x0380, 0x0480, 0x0580, 0x0680, 0x0780,
  0x0880, 0x0980, 0x0a80, 0x0b80, 0x0c80, 0x0d80, 0x0e80, 0x0f80,
  0x1080, 0x1180, 0x1280, 0x1380, 0x1480, 0x1580, 0x1680, 0x1780,
  0x1880, 0x1980, 0x1a80, 0x1b80, 0x1c80, 0x1d80, 0x1e80, 0x1f80,
  0x2080, 0x2180, 0x2280, 0x2380, 0x2480, 0x2580, 0x2680, 0x2780,
  0x2880, 0x2980, 0x2a80, 0x2b80, 0x2c80, 0x2d80, 0x2e80, 0x2f80,
  0x3080, 0x3180, 0x3280, 0x3380, 0x3480, 0x3580, 0x3680, 0x3780,
  0x3880, 0x3980, 0x3a80, 0x3b80, 0x3c80, 0x3d80, 0x3e80, 0x3f80,
  0x4080, 0x4180, 0x4280, 0x4380, 0x4480, 0x4580, 0x4680, 0x4780,
  0x4880, 0x4980, 0x4a80, 0x4b80, 0x4c80, 0x4d80, 0x4e80, 0x4f80,
  0x5080, 0x5180, 0x5280, 0x5380, 0x5480, 0x5580, 0x5680, 0x5780,
  0x5880, 0x5980, 0x5a80, 0x5b80, 0x5c80, 0x5d80, 0x5e80, 0x5f80,
  0x6080, 0x6180, 0x6280, 0x6380, 0x6480, 0x6580, 0x6680, 0x6780,
  0x6880, 0x6980, 0x6a80, 0x6b80, 0x6c80, 0x6d80, 0x6e80, 0x6f80,
  0x7080, 0x7180, 0x7280, 0x7380, 0x7480, 0x7580, 0x7680, 0x7780,
  0x7880, 0x7980, 0x7a80, 0x7b80, 0x7c80, 0x7d80, 0x7e80, 0x7f80
};

left_volume = m_AKAO_VOLUME_TABLE_L[aa_parameter] * ((a8_parameter * a3_parameter * 0x7f) / 128) / 256 / 128;

right_volume = m_AKAO_VOLUME_TABLE_R[aa_parameter] * ((a8_parameter * a3_paramater * 0x7f) / 128) / 256 / 128;

If there is no A3 opcode in sequence (as in SENSUI.SND for example), default value 0x7f is used.

If there is no A8 opcode in sequence, default value 0x7f.fe is used. (More precisely, 0x3fff is stored in memory.)